xref: /vim-8.2.3635/src/menu.c (revision 51ad4eaa)
1 /* vi:set ts=8 sts=4 sw=4 noet:
2  *
3  * VIM - Vi IMproved		by Bram Moolenaar
4  *				GUI/Motif support by Robert Webb
5  *
6  * Do ":help uganda"  in Vim to read copying and usage conditions.
7  * Do ":help credits" in Vim to see a list of people who contributed.
8  * See README.txt for an overview of the Vim source code.
9  */
10 
11 /*
12  * Code for menus.  Used for the GUI and 'wildmenu'.
13  */
14 
15 #include "vim.h"
16 
17 #if defined(FEAT_MENU) || defined(PROTO)
18 
19 #define MENUDEPTH   10		/* maximum depth of menus */
20 
21 #ifdef FEAT_GUI_W32
22 static int add_menu_path(char_u *, vimmenu_T *, int *, char_u *, int);
23 #else
24 static int add_menu_path(char_u *, vimmenu_T *, int *, char_u *);
25 #endif
26 static int menu_nable_recurse(vimmenu_T *menu, char_u *name, int modes, int enable);
27 static int remove_menu(vimmenu_T **, char_u *, int, int silent);
28 static void free_menu(vimmenu_T **menup);
29 static void free_menu_string(vimmenu_T *, int);
30 static int show_menus(char_u *, int);
31 static void show_menus_recursive(vimmenu_T *, int, int);
32 static int menu_name_equal(char_u *name, vimmenu_T *menu);
33 static int menu_namecmp(char_u *name, char_u *mname);
34 static int get_menu_cmd_modes(char_u *, int, int *, int *);
35 static char_u *popup_mode_name(char_u *name, int idx);
36 static char_u *menu_text(char_u *text, int *mnemonic, char_u **actext);
37 
38 #if defined(FEAT_GUI_W32) && defined(FEAT_TEAROFF)
39 static void gui_create_tearoffs_recurse(vimmenu_T *menu, const char_u *pname, int *pri_tab, int pri_idx);
40 static void gui_add_tearoff(char_u *tearpath, int *pri_tab, int pri_idx);
41 static void gui_destroy_tearoffs_recurse(vimmenu_T *menu);
42 static int s_tearoffs = FALSE;
43 #endif
44 
45 static int menu_is_hidden(char_u *name);
46 #if defined(FEAT_CMDL_COMPL) || (defined(FEAT_GUI_W32) && defined(FEAT_TEAROFF))
47 static int menu_is_tearoff(char_u *name);
48 #endif
49 
50 #if defined(FEAT_MULTI_LANG) || defined(FEAT_TOOLBAR)
51 static char_u *menu_skip_part(char_u *p);
52 #endif
53 #ifdef FEAT_MULTI_LANG
54 static char_u *menutrans_lookup(char_u *name, int len);
55 static void menu_unescape_name(char_u	*p);
56 #endif
57 
58 static char_u *menu_translate_tab_and_shift(char_u *arg_start);
59 
60 /* The character for each menu mode */
61 static char_u	menu_mode_chars[] = {'n', 'v', 's', 'o', 'i', 'c', 't'};
62 
63 static char_u e_notsubmenu[] = N_("E327: Part of menu-item path is not sub-menu");
64 static char_u e_othermode[] = N_("E328: Menu only exists in another mode");
65 static char_u e_nomenu[] = N_("E329: No menu \"%s\"");
66 
67 #ifdef FEAT_TOOLBAR
68 static const char *toolbar_names[] =
69 {
70     /*  0 */ "New", "Open", "Save", "Undo", "Redo",
71     /*  5 */ "Cut", "Copy", "Paste", "Print", "Help",
72     /* 10 */ "Find", "SaveAll", "SaveSesn", "NewSesn", "LoadSesn",
73     /* 15 */ "RunScript", "Replace", "WinClose", "WinMax", "WinMin",
74     /* 20 */ "WinSplit", "Shell", "FindPrev", "FindNext", "FindHelp",
75     /* 25 */ "Make", "TagJump", "RunCtags", "WinVSplit", "WinMaxWidth",
76     /* 30 */ "WinMinWidth", "Exit"
77 };
78 # define TOOLBAR_NAME_COUNT (sizeof(toolbar_names) / sizeof(char *))
79 #endif
80 
81 /*
82  * Return TRUE if "name" is a window toolbar menu name.
83  */
84     static int
85 menu_is_winbar(char_u *name)
86 {
87     return (STRNCMP(name, "WinBar", 6) == 0);
88 }
89 
90     int
91 winbar_height(win_T *wp)
92 {
93     if (wp->w_winbar != NULL && wp->w_winbar->children != NULL)
94 	return 1;
95     return 0;
96 }
97 
98     static vimmenu_T **
99 get_root_menu(char_u *name)
100 {
101     if (menu_is_winbar(name))
102 	return &curwin->w_winbar;
103     return &root_menu;
104 }
105 
106 /*
107  * Do the :menu command and relatives.
108  */
109     void
110 ex_menu(
111     exarg_T	*eap)		    /* Ex command arguments */
112 {
113     char_u	*menu_path;
114     int		modes;
115     char_u	*map_to;
116     int		noremap;
117     int		silent = FALSE;
118     int		special = FALSE;
119     int		unmenu;
120     char_u	*map_buf;
121     char_u	*arg;
122     char_u	*p;
123     int		i;
124 #if defined(FEAT_GUI) && !defined(FEAT_GUI_GTK)
125     int		old_menu_height;
126 # if defined(FEAT_TOOLBAR) && !defined(FEAT_GUI_W32)
127     int		old_toolbar_height;
128 # endif
129 #endif
130     int		pri_tab[MENUDEPTH + 1];
131     int		enable = MAYBE;	    /* TRUE for "menu enable", FALSE for "menu
132 				     * disable */
133 #ifdef FEAT_TOOLBAR
134     char_u	*icon = NULL;
135 #endif
136     vimmenu_T	menuarg;
137     vimmenu_T	**root_menu_ptr;
138 
139     modes = get_menu_cmd_modes(eap->cmd, eap->forceit, &noremap, &unmenu);
140     arg = eap->arg;
141 
142     for (;;)
143     {
144 	if (STRNCMP(arg, "<script>", 8) == 0)
145 	{
146 	    noremap = REMAP_SCRIPT;
147 	    arg = skipwhite(arg + 8);
148 	    continue;
149 	}
150 	if (STRNCMP(arg, "<silent>", 8) == 0)
151 	{
152 	    silent = TRUE;
153 	    arg = skipwhite(arg + 8);
154 	    continue;
155 	}
156 	if (STRNCMP(arg, "<special>", 9) == 0)
157 	{
158 	    special = TRUE;
159 	    arg = skipwhite(arg + 9);
160 	    continue;
161 	}
162 	break;
163     }
164 
165 
166     /* Locate an optional "icon=filename" argument. */
167     if (STRNCMP(arg, "icon=", 5) == 0)
168     {
169 	arg += 5;
170 #ifdef FEAT_TOOLBAR
171 	icon = arg;
172 #endif
173 	while (*arg != NUL && *arg != ' ')
174 	{
175 	    if (*arg == '\\')
176 		STRMOVE(arg, arg + 1);
177 	    MB_PTR_ADV(arg);
178 	}
179 	if (*arg != NUL)
180 	{
181 	    *arg++ = NUL;
182 	    arg = skipwhite(arg);
183 	}
184     }
185 
186     /*
187      * Fill in the priority table.
188      */
189     for (p = arg; *p; ++p)
190 	if (!VIM_ISDIGIT(*p) && *p != '.')
191 	    break;
192     if (VIM_ISWHITE(*p))
193     {
194 	for (i = 0; i < MENUDEPTH && !VIM_ISWHITE(*arg); ++i)
195 	{
196 	    pri_tab[i] = getdigits(&arg);
197 	    if (pri_tab[i] == 0)
198 		pri_tab[i] = 500;
199 	    if (*arg == '.')
200 		++arg;
201 	}
202 	arg = skipwhite(arg);
203     }
204     else if (eap->addr_count && eap->line2 != 0)
205     {
206 	pri_tab[0] = eap->line2;
207 	i = 1;
208     }
209     else
210 	i = 0;
211     while (i < MENUDEPTH)
212 	pri_tab[i++] = 500;
213     pri_tab[MENUDEPTH] = -1;		/* mark end of the table */
214 
215     /*
216      * Check for "disable" or "enable" argument.
217      */
218     if (STRNCMP(arg, "enable", 6) == 0 && VIM_ISWHITE(arg[6]))
219     {
220 	enable = TRUE;
221 	arg = skipwhite(arg + 6);
222     }
223     else if (STRNCMP(arg, "disable", 7) == 0 && VIM_ISWHITE(arg[7]))
224     {
225 	enable = FALSE;
226 	arg = skipwhite(arg + 7);
227     }
228 
229     /*
230      * If there is no argument, display all menus.
231      */
232     if (*arg == NUL)
233     {
234 	show_menus(arg, modes);
235 	return;
236     }
237 
238 #ifdef FEAT_TOOLBAR
239     /*
240      * Need to get the toolbar icon index before doing the translation.
241      */
242     menuarg.iconidx = -1;
243     menuarg.icon_builtin = FALSE;
244     if (menu_is_toolbar(arg))
245     {
246 	menu_path = menu_skip_part(arg);
247 	if (*menu_path == '.')
248 	{
249 	    p = menu_skip_part(++menu_path);
250 	    if (STRNCMP(menu_path, "BuiltIn", 7) == 0)
251 	    {
252 		if (skipdigits(menu_path + 7) == p)
253 		{
254 		    menuarg.iconidx = atoi((char *)menu_path + 7);
255 		    if (menuarg.iconidx >= (int)TOOLBAR_NAME_COUNT)
256 			menuarg.iconidx = -1;
257 		    else
258 			menuarg.icon_builtin = TRUE;
259 		}
260 	    }
261 	    else
262 	    {
263 		for (i = 0; i < (int)TOOLBAR_NAME_COUNT; ++i)
264 		    if (STRNCMP(toolbar_names[i], menu_path, p - menu_path)
265 									 == 0)
266 		    {
267 			menuarg.iconidx = i;
268 			break;
269 		    }
270 	    }
271 	}
272     }
273 #endif
274 
275     menu_path = arg;
276     if (*menu_path == '.')
277     {
278 	EMSG2(_(e_invarg2), menu_path);
279 	goto theend;
280     }
281 
282     map_to = menu_translate_tab_and_shift(arg);
283 
284     /*
285      * If there is only a menu name, display menus with that name.
286      */
287     if (*map_to == NUL && !unmenu && enable == MAYBE)
288     {
289 	show_menus(menu_path, modes);
290 	goto theend;
291     }
292     else if (*map_to != NUL && (unmenu || enable != MAYBE))
293     {
294 	EMSG(_(e_trailing));
295 	goto theend;
296     }
297 #if defined(FEAT_GUI) && !(defined(FEAT_GUI_GTK) || defined(FEAT_GUI_PHOTON))
298     old_menu_height = gui.menu_height;
299 # if defined(FEAT_TOOLBAR) && !defined(FEAT_GUI_W32)
300     old_toolbar_height = gui.toolbar_height;
301 # endif
302 #endif
303 
304     root_menu_ptr = get_root_menu(menu_path);
305     if (root_menu_ptr == &curwin->w_winbar)
306 	/* Assume the window toolbar menu will change. */
307 	redraw_later(NOT_VALID);
308 
309     if (enable != MAYBE)
310     {
311 	/*
312 	 * Change sensitivity of the menu.
313 	 * For the PopUp menu, remove a menu for each mode separately.
314 	 * Careful: menu_nable_recurse() changes menu_path.
315 	 */
316 	if (STRCMP(menu_path, "*") == 0)	/* meaning: do all menus */
317 	    menu_path = (char_u *)"";
318 
319 	if (menu_is_popup(menu_path))
320 	{
321 	    for (i = 0; i < MENU_INDEX_TIP; ++i)
322 		if (modes & (1 << i))
323 		{
324 		    p = popup_mode_name(menu_path, i);
325 		    if (p != NULL)
326 		    {
327 			menu_nable_recurse(*root_menu_ptr, p, MENU_ALL_MODES,
328 								      enable);
329 			vim_free(p);
330 		    }
331 		}
332 	}
333 	menu_nable_recurse(*root_menu_ptr, menu_path, modes, enable);
334     }
335     else if (unmenu)
336     {
337 	/*
338 	 * Delete menu(s).
339 	 */
340 	if (STRCMP(menu_path, "*") == 0)	/* meaning: remove all menus */
341 	    menu_path = (char_u *)"";
342 
343 	/*
344 	 * For the PopUp menu, remove a menu for each mode separately.
345 	 */
346 	if (menu_is_popup(menu_path))
347 	{
348 	    for (i = 0; i < MENU_INDEX_TIP; ++i)
349 		if (modes & (1 << i))
350 		{
351 		    p = popup_mode_name(menu_path, i);
352 		    if (p != NULL)
353 		    {
354 			remove_menu(root_menu_ptr, p, MENU_ALL_MODES, TRUE);
355 			vim_free(p);
356 		    }
357 		}
358 	}
359 
360 	/* Careful: remove_menu() changes menu_path */
361 	remove_menu(root_menu_ptr, menu_path, modes, FALSE);
362     }
363     else
364     {
365 	/*
366 	 * Add menu(s).
367 	 * Replace special key codes.
368 	 */
369 	if (STRICMP(map_to, "<nop>") == 0)	/* "<Nop>" means nothing */
370 	{
371 	    map_to = (char_u *)"";
372 	    map_buf = NULL;
373 	}
374 	else if (modes & MENU_TIP_MODE)
375 	    map_buf = NULL;	/* Menu tips are plain text. */
376 	else
377 	    map_to = replace_termcodes(map_to, &map_buf, FALSE, TRUE, special);
378 	menuarg.modes = modes;
379 #ifdef FEAT_TOOLBAR
380 	menuarg.iconfile = icon;
381 #endif
382 	menuarg.noremap[0] = noremap;
383 	menuarg.silent[0] = silent;
384 	add_menu_path(menu_path, &menuarg, pri_tab, map_to
385 #ifdef FEAT_GUI_W32
386 		, TRUE
387 #endif
388 		);
389 
390 	/*
391 	 * For the PopUp menu, add a menu for each mode separately.
392 	 */
393 	if (menu_is_popup(menu_path))
394 	{
395 	    for (i = 0; i < MENU_INDEX_TIP; ++i)
396 		if (modes & (1 << i))
397 		{
398 		    p = popup_mode_name(menu_path, i);
399 		    if (p != NULL)
400 		    {
401 			/* Include all modes, to make ":amenu" work */
402 			menuarg.modes = modes;
403 #ifdef FEAT_TOOLBAR
404 			menuarg.iconfile = NULL;
405 			menuarg.iconidx = -1;
406 			menuarg.icon_builtin = FALSE;
407 #endif
408 			add_menu_path(p, &menuarg, pri_tab, map_to
409 #ifdef FEAT_GUI_W32
410 				, TRUE
411 #endif
412 					 );
413 			vim_free(p);
414 		    }
415 		}
416 	}
417 
418 	vim_free(map_buf);
419     }
420 
421 #if defined(FEAT_GUI) && !(defined(FEAT_GUI_GTK))
422     /* If the menubar height changed, resize the window */
423     if (gui.in_use
424 	    && (gui.menu_height != old_menu_height
425 # if defined(FEAT_TOOLBAR) && !defined(FEAT_GUI_W32)
426 		|| gui.toolbar_height != old_toolbar_height
427 # endif
428 	    ))
429 	gui_set_shellsize(FALSE, FALSE, RESIZE_VERT);
430 #endif
431     if (root_menu_ptr == &curwin->w_winbar)
432     {
433 	int h = winbar_height(curwin);
434 
435 	if (h != curwin->w_winbar_height)
436 	{
437 	    if (h == 0)
438 		++curwin->w_height;
439 	    else if (curwin->w_height > 0)
440 		--curwin->w_height;
441 	    curwin->w_winbar_height = h;
442 	}
443     }
444 
445 theend:
446     ;
447 }
448 
449 /*
450  * Add the menu with the given name to the menu hierarchy
451  */
452     static int
453 add_menu_path(
454     char_u	*menu_path,
455     vimmenu_T	*menuarg,	/* passes modes, iconfile, iconidx,
456 				   icon_builtin, silent[0], noremap[0] */
457     int		*pri_tab,
458     char_u	*call_data
459 #ifdef FEAT_GUI_W32
460     , int	addtearoff	/* may add tearoff item */
461 #endif
462     )
463 {
464     char_u	*path_name;
465     int		modes = menuarg->modes;
466     vimmenu_T	**menup;
467     vimmenu_T	*menu = NULL;
468     vimmenu_T	*parent;
469     vimmenu_T	**lower_pri;
470     char_u	*p;
471     char_u	*name;
472     char_u	*dname;
473     char_u	*next_name;
474     int		i;
475     int		c;
476     int		d;
477 #ifdef FEAT_GUI
478     int		idx;
479     int		new_idx;
480 #endif
481     int		pri_idx = 0;
482     int		old_modes = 0;
483     int		amenu;
484 #ifdef FEAT_MULTI_LANG
485     char_u	*en_name;
486     char_u	*map_to = NULL;
487 #endif
488     vimmenu_T	**root_menu_ptr;
489 
490     /* Make a copy so we can stuff around with it, since it could be const */
491     path_name = vim_strsave(menu_path);
492     if (path_name == NULL)
493 	return FAIL;
494     root_menu_ptr = get_root_menu(menu_path);
495     menup = root_menu_ptr;
496     parent = NULL;
497     name = path_name;
498     while (*name)
499     {
500 	/* Get name of this element in the menu hierarchy, and the simplified
501 	 * name (without mnemonic and accelerator text). */
502 	next_name = menu_name_skip(name);
503 #ifdef	FEAT_MULTI_LANG
504 	map_to = menutrans_lookup(name, (int)STRLEN(name));
505 	if (map_to != NULL)
506 	{
507 	    en_name = name;
508 	    name = map_to;
509 	}
510 	else
511 	    en_name = NULL;
512 #endif
513 	dname = menu_text(name, NULL, NULL);
514 	if (dname == NULL)
515 	    goto erret;
516 	if (*dname == NUL)
517 	{
518 	    /* Only a mnemonic or accelerator is not valid. */
519 	    EMSG(_("E792: Empty menu name"));
520 	    goto erret;
521 	}
522 
523 	/* See if it's already there */
524 	lower_pri = menup;
525 #ifdef FEAT_GUI
526 	idx = 0;
527 	new_idx = 0;
528 #endif
529 	menu = *menup;
530 	while (menu != NULL)
531 	{
532 	    if (menu_name_equal(name, menu) || menu_name_equal(dname, menu))
533 	    {
534 		if (*next_name == NUL && menu->children != NULL)
535 		{
536 		    if (!sys_menu)
537 			EMSG(_("E330: Menu path must not lead to a sub-menu"));
538 		    goto erret;
539 		}
540 		if (*next_name != NUL && menu->children == NULL
541 #ifdef FEAT_GUI_W32
542 			&& addtearoff
543 #endif
544 			)
545 		{
546 		    if (!sys_menu)
547 			EMSG(_(e_notsubmenu));
548 		    goto erret;
549 		}
550 		break;
551 	    }
552 	    menup = &menu->next;
553 
554 	    /* Count menus, to find where this one needs to be inserted.
555 	     * Ignore menus that are not in the menubar (PopUp and Toolbar) */
556 	    if (parent != NULL || menu_is_menubar(menu->name))
557 	    {
558 #ifdef FEAT_GUI
559 		++idx;
560 #endif
561 		if (menu->priority <= pri_tab[pri_idx])
562 		{
563 		    lower_pri = menup;
564 #ifdef FEAT_GUI
565 		    new_idx = idx;
566 #endif
567 		}
568 	    }
569 	    menu = menu->next;
570 	}
571 
572 	if (menu == NULL)
573 	{
574 	    if (*next_name == NUL && parent == NULL)
575 	    {
576 		EMSG(_("E331: Must not add menu items directly to menu bar"));
577 		goto erret;
578 	    }
579 
580 	    if (menu_is_separator(dname) && *next_name != NUL)
581 	    {
582 		EMSG(_("E332: Separator cannot be part of a menu path"));
583 		goto erret;
584 	    }
585 
586 	    /* Not already there, so lets add it */
587 	    menu = (vimmenu_T *)alloc_clear((unsigned)sizeof(vimmenu_T));
588 	    if (menu == NULL)
589 		goto erret;
590 
591 	    menu->modes = modes;
592 	    menu->enabled = MENU_ALL_MODES;
593 	    menu->name = vim_strsave(name);
594 	    /* separate mnemonic and accelerator text from actual menu name */
595 	    menu->dname = menu_text(name, &menu->mnemonic, &menu->actext);
596 #ifdef	FEAT_MULTI_LANG
597 	    if (en_name != NULL)
598 	    {
599 		menu->en_name = vim_strsave(en_name);
600 		menu->en_dname = menu_text(en_name, NULL, NULL);
601 	    }
602 	    else
603 	    {
604 		menu->en_name = NULL;
605 		menu->en_dname = NULL;
606 	    }
607 #endif
608 	    menu->priority = pri_tab[pri_idx];
609 	    menu->parent = parent;
610 #ifdef FEAT_GUI_MOTIF
611 	    menu->sensitive = TRUE;	    /* the default */
612 #endif
613 #ifdef FEAT_BEVAL_TIP
614 	    menu->tip = NULL;
615 #endif
616 #ifdef FEAT_GUI_ATHENA
617 	    menu->image = None;		    /* X-Windows definition for NULL*/
618 #endif
619 
620 	    /*
621 	     * Add after menu that has lower priority.
622 	     */
623 	    menu->next = *lower_pri;
624 	    *lower_pri = menu;
625 
626 	    old_modes = 0;
627 
628 #ifdef FEAT_TOOLBAR
629 	    menu->iconidx = menuarg->iconidx;
630 	    menu->icon_builtin = menuarg->icon_builtin;
631 	    if (*next_name == NUL && menuarg->iconfile != NULL)
632 		menu->iconfile = vim_strsave(menuarg->iconfile);
633 #endif
634 #if defined(FEAT_GUI_W32) && defined(FEAT_TEAROFF)
635 	    /* the tearoff item must be present in the modes of each item. */
636 	    if (parent != NULL && menu_is_tearoff(parent->children->dname))
637 		parent->children->modes |= modes;
638 #endif
639 	}
640 	else
641 	{
642 	    old_modes = menu->modes;
643 
644 	    /*
645 	     * If this menu option was previously only available in other
646 	     * modes, then make sure it's available for this one now
647 	     * Also enable a menu when it's created or changed.
648 	     */
649 #ifdef FEAT_GUI_W32
650 	    /* If adding a tearbar (addtearoff == FALSE) don't update modes */
651 	    if (addtearoff)
652 #endif
653 	    {
654 		menu->modes |= modes;
655 		menu->enabled |= modes;
656 	    }
657 	}
658 
659 #ifdef FEAT_GUI
660 	/*
661 	 * Add the menu item when it's used in one of the modes, but not when
662 	 * only a tooltip is defined.
663 	 */
664 	if ((old_modes & MENU_ALL_MODES) == 0
665 		&& (menu->modes & MENU_ALL_MODES) != 0)
666 	{
667 	    if (gui.in_use)  /* Otherwise it will be added when GUI starts */
668 	    {
669 		if (*next_name == NUL)
670 		{
671 		    /* Real menu item, not sub-menu */
672 		    gui_mch_add_menu_item(menu, new_idx);
673 
674 		    /* Want to update menus now even if mode not changed */
675 		    force_menu_update = TRUE;
676 		}
677 		else
678 		{
679 		    /* Sub-menu (not at end of path yet) */
680 		    gui_mch_add_menu(menu, new_idx);
681 		}
682 	    }
683 
684 # if defined(FEAT_GUI_W32) & defined(FEAT_TEAROFF)
685 	    /* When adding a new submenu, may add a tearoff item */
686 	    if (	addtearoff
687 		    && *next_name
688 		    && vim_strchr(p_go, GO_TEAROFF) != NULL
689 		    && menu_is_menubar(name))
690 	    {
691 		char_u		*tearpath;
692 
693 		/*
694 		 * The pointers next_name & path_name refer to a string with
695 		 * \'s and ^V's stripped out. But menu_path is a "raw"
696 		 * string, so we must correct for special characters.
697 		 */
698 		tearpath = alloc((unsigned int)STRLEN(menu_path) + TEAR_LEN + 2);
699 		if (tearpath != NULL)
700 		{
701 		    char_u  *s;
702 		    int	    idx;
703 
704 		    STRCPY(tearpath, menu_path);
705 		    idx = (int)(next_name - path_name - 1);
706 		    for (s = tearpath; *s && s < tearpath + idx; MB_PTR_ADV(s))
707 		    {
708 			if ((*s == '\\' || *s == Ctrl_V) && s[1])
709 			{
710 			    ++idx;
711 			    ++s;
712 			}
713 		    }
714 		    tearpath[idx] = NUL;
715 		    gui_add_tearoff(tearpath, pri_tab, pri_idx);
716 		    vim_free(tearpath);
717 		}
718 	    }
719 # endif
720 	}
721 #endif /* FEAT_GUI */
722 
723 	menup = &menu->children;
724 	parent = menu;
725 	name = next_name;
726 	VIM_CLEAR(dname);
727 	if (pri_tab[pri_idx + 1] != -1)
728 	    ++pri_idx;
729     }
730     vim_free(path_name);
731 
732     /*
733      * Only add system menu items which have not been defined yet.
734      * First check if this was an ":amenu".
735      */
736     amenu = ((modes & (MENU_NORMAL_MODE | MENU_INSERT_MODE)) ==
737 				       (MENU_NORMAL_MODE | MENU_INSERT_MODE));
738     if (sys_menu)
739 	modes &= ~old_modes;
740 
741     if (menu != NULL && modes)
742     {
743 #ifdef FEAT_GUI
744 	menu->cb = gui_menu_cb;
745 #endif
746 	p = (call_data == NULL) ? NULL : vim_strsave(call_data);
747 
748 	/* loop over all modes, may add more than one */
749 	for (i = 0; i < MENU_MODES; ++i)
750 	{
751 	    if (modes & (1 << i))
752 	    {
753 		/* free any old menu */
754 		free_menu_string(menu, i);
755 
756 		/* For "amenu", may insert an extra character.
757 		 * Don't do this if adding a tearbar (addtearoff == FALSE).
758 		 * Don't do this for "<Nop>". */
759 		c = 0;
760 		d = 0;
761 		if (amenu && call_data != NULL && *call_data != NUL
762 #ifdef FEAT_GUI_W32
763 		       && addtearoff
764 #endif
765 				       )
766 		{
767 		    switch (1 << i)
768 		    {
769 			case MENU_VISUAL_MODE:
770 			case MENU_SELECT_MODE:
771 			case MENU_OP_PENDING_MODE:
772 			case MENU_CMDLINE_MODE:
773 			    c = Ctrl_C;
774 			    break;
775 			case MENU_INSERT_MODE:
776 			    c = Ctrl_BSL;
777 			    d = Ctrl_O;
778 			    break;
779 		    }
780 		}
781 
782 		if (c != 0)
783 		{
784 		    menu->strings[i] = alloc((unsigned)(STRLEN(call_data) + 5 ));
785 		    if (menu->strings[i] != NULL)
786 		    {
787 			menu->strings[i][0] = c;
788 			if (d == 0)
789 			    STRCPY(menu->strings[i] + 1, call_data);
790 			else
791 			{
792 			    menu->strings[i][1] = d;
793 			    STRCPY(menu->strings[i] + 2, call_data);
794 			}
795 			if (c == Ctrl_C)
796 			{
797 			    int	    len = (int)STRLEN(menu->strings[i]);
798 
799 			    /* Append CTRL-\ CTRL-G to obey 'insertmode'. */
800 			    menu->strings[i][len] = Ctrl_BSL;
801 			    menu->strings[i][len + 1] = Ctrl_G;
802 			    menu->strings[i][len + 2] = NUL;
803 			}
804 		    }
805 		}
806 		else
807 		    menu->strings[i] = p;
808 		menu->noremap[i] = menuarg->noremap[0];
809 		menu->silent[i] = menuarg->silent[0];
810 	    }
811 	}
812 #if defined(FEAT_TOOLBAR) && !defined(FEAT_GUI_W32) \
813 	&& (defined(FEAT_BEVAL_GUI) || defined(FEAT_GUI_GTK))
814 	/* Need to update the menu tip. */
815 	if (modes & MENU_TIP_MODE)
816 	    gui_mch_menu_set_tip(menu);
817 #endif
818     }
819     return OK;
820 
821 erret:
822     vim_free(path_name);
823     vim_free(dname);
824 
825     /* Delete any empty submenu we added before discovering the error.  Repeat
826      * for higher levels. */
827     while (parent != NULL && parent->children == NULL)
828     {
829 	if (parent->parent == NULL)
830 	    menup = root_menu_ptr;
831 	else
832 	    menup = &parent->parent->children;
833 	for ( ; *menup != NULL && *menup != parent; menup = &((*menup)->next))
834 	    ;
835 	if (*menup == NULL) /* safety check */
836 	    break;
837 	parent = parent->parent;
838 	free_menu(menup);
839     }
840     return FAIL;
841 }
842 
843 /*
844  * Set the (sub)menu with the given name to enabled or disabled.
845  * Called recursively.
846  */
847     static int
848 menu_nable_recurse(
849     vimmenu_T	*menu,
850     char_u	*name,
851     int		modes,
852     int		enable)
853 {
854     char_u	*p;
855 
856     if (menu == NULL)
857 	return OK;		/* Got to bottom of hierarchy */
858 
859     /* Get name of this element in the menu hierarchy */
860     p = menu_name_skip(name);
861 
862     /* Find the menu */
863     while (menu != NULL)
864     {
865 	if (*name == NUL || *name == '*' || menu_name_equal(name, menu))
866 	{
867 	    if (*p != NUL)
868 	    {
869 		if (menu->children == NULL)
870 		{
871 		    EMSG(_(e_notsubmenu));
872 		    return FAIL;
873 		}
874 		if (menu_nable_recurse(menu->children, p, modes, enable)
875 								      == FAIL)
876 		    return FAIL;
877 	    }
878 	    else
879 		if (enable)
880 		    menu->enabled |= modes;
881 		else
882 		    menu->enabled &= ~modes;
883 
884 	    /*
885 	     * When name is empty, we are doing all menu items for the given
886 	     * modes, so keep looping, otherwise we are just doing the named
887 	     * menu item (which has been found) so break here.
888 	     */
889 	    if (*name != NUL && *name != '*')
890 		break;
891 	}
892 	menu = menu->next;
893     }
894     if (*name != NUL && *name != '*' && menu == NULL)
895     {
896 	EMSG2(_(e_nomenu), name);
897 	return FAIL;
898     }
899 
900 #ifdef FEAT_GUI
901     /* Want to update menus now even if mode not changed */
902     force_menu_update = TRUE;
903 #endif
904 
905     return OK;
906 }
907 
908 /*
909  * Remove the (sub)menu with the given name from the menu hierarchy
910  * Called recursively.
911  */
912     static int
913 remove_menu(
914     vimmenu_T	**menup,
915     char_u	*name,
916     int		modes,
917     int		silent)		/* don't give error messages */
918 {
919     vimmenu_T	*menu;
920     vimmenu_T	*child;
921     char_u	*p;
922 
923     if (*menup == NULL)
924 	return OK;		/* Got to bottom of hierarchy */
925 
926     /* Get name of this element in the menu hierarchy */
927     p = menu_name_skip(name);
928 
929     /* Find the menu */
930     while ((menu = *menup) != NULL)
931     {
932 	if (*name == NUL || menu_name_equal(name, menu))
933 	{
934 	    if (*p != NUL && menu->children == NULL)
935 	    {
936 		if (!silent)
937 		    EMSG(_(e_notsubmenu));
938 		return FAIL;
939 	    }
940 	    if ((menu->modes & modes) != 0x0)
941 	    {
942 #if defined(FEAT_GUI_W32) & defined(FEAT_TEAROFF)
943 		/*
944 		 * If we are removing all entries for this menu,MENU_ALL_MODES,
945 		 * Then kill any tearoff before we start
946 		 */
947 		if (*p == NUL && modes == MENU_ALL_MODES)
948 		{
949 		    if (IsWindow(menu->tearoff_handle))
950 			DestroyWindow(menu->tearoff_handle);
951 		}
952 #endif
953 		if (remove_menu(&menu->children, p, modes, silent) == FAIL)
954 		    return FAIL;
955 	    }
956 	    else if (*name != NUL)
957 	    {
958 		if (!silent)
959 		    EMSG(_(e_othermode));
960 		return FAIL;
961 	    }
962 
963 	    /*
964 	     * When name is empty, we are removing all menu items for the given
965 	     * modes, so keep looping, otherwise we are just removing the named
966 	     * menu item (which has been found) so break here.
967 	     */
968 	    if (*name != NUL)
969 		break;
970 
971 	    /* Remove the menu item for the given mode[s].  If the menu item
972 	     * is no longer valid in ANY mode, delete it */
973 	    menu->modes &= ~modes;
974 	    if (modes & MENU_TIP_MODE)
975 		free_menu_string(menu, MENU_INDEX_TIP);
976 	    if ((menu->modes & MENU_ALL_MODES) == 0)
977 		free_menu(menup);
978 	    else
979 		menup = &menu->next;
980 	}
981 	else
982 	    menup = &menu->next;
983     }
984     if (*name != NUL)
985     {
986 	if (menu == NULL)
987 	{
988 	    if (!silent)
989 		EMSG2(_(e_nomenu), name);
990 	    return FAIL;
991 	}
992 
993 
994 	/* Recalculate modes for menu based on the new updated children */
995 	menu->modes &= ~modes;
996 #if defined(FEAT_GUI_W32) & defined(FEAT_TEAROFF)
997 	if ((s_tearoffs) && (menu->children != NULL)) /* there's a tear bar.. */
998 	    child = menu->children->next; /* don't count tearoff bar */
999 	else
1000 #endif
1001 	    child = menu->children;
1002 	for ( ; child != NULL; child = child->next)
1003 	    menu->modes |= child->modes;
1004 	if (modes & MENU_TIP_MODE)
1005 	{
1006 	    free_menu_string(menu, MENU_INDEX_TIP);
1007 #if defined(FEAT_TOOLBAR) && !defined(FEAT_GUI_W32) \
1008 	    && (defined(FEAT_BEVAL_GUI) || defined(FEAT_GUI_GTK))
1009 	    /* Need to update the menu tip. */
1010 	    if (gui.in_use)
1011 		gui_mch_menu_set_tip(menu);
1012 #endif
1013 	}
1014 	if ((menu->modes & MENU_ALL_MODES) == 0)
1015 	{
1016 	    /* The menu item is no longer valid in ANY mode, so delete it */
1017 #if defined(FEAT_GUI_W32) & defined(FEAT_TEAROFF)
1018 	    if (s_tearoffs && menu->children != NULL) /* there's a tear bar.. */
1019 		free_menu(&menu->children);
1020 #endif
1021 	    *menup = menu;
1022 	    free_menu(menup);
1023 	}
1024     }
1025 
1026     return OK;
1027 }
1028 
1029 /*
1030  * Remove the WinBar menu from window "wp".
1031  */
1032     void
1033 remove_winbar(win_T *wp)
1034 {
1035     remove_menu(&wp->w_winbar, (char_u *)"", MENU_ALL_MODES, TRUE);
1036     vim_free(wp->w_winbar_items);
1037 }
1038 
1039 /*
1040  * Free the given menu structure and remove it from the linked list.
1041  */
1042     static void
1043 free_menu(vimmenu_T **menup)
1044 {
1045     int		i;
1046     vimmenu_T	*menu;
1047 
1048     menu = *menup;
1049 
1050 #ifdef FEAT_GUI
1051     /* Free machine specific menu structures (only when already created) */
1052     /* Also may rebuild a tearoff'ed menu */
1053     if (gui.in_use)
1054 	gui_mch_destroy_menu(menu);
1055 #endif
1056 
1057     /* Don't change *menup until after calling gui_mch_destroy_menu(). The
1058      * MacOS code needs the original structure to properly delete the menu. */
1059     *menup = menu->next;
1060     vim_free(menu->name);
1061     vim_free(menu->dname);
1062 #ifdef FEAT_MULTI_LANG
1063     vim_free(menu->en_name);
1064     vim_free(menu->en_dname);
1065 #endif
1066     vim_free(menu->actext);
1067 #ifdef FEAT_TOOLBAR
1068     vim_free(menu->iconfile);
1069 # ifdef FEAT_GUI_MOTIF
1070     vim_free(menu->xpm_fname);
1071 # endif
1072 #endif
1073     for (i = 0; i < MENU_MODES; i++)
1074 	free_menu_string(menu, i);
1075     vim_free(menu);
1076 
1077 #ifdef FEAT_GUI
1078     /* Want to update menus now even if mode not changed */
1079     force_menu_update = TRUE;
1080 #endif
1081 }
1082 
1083 /*
1084  * Free the menu->string with the given index.
1085  */
1086     static void
1087 free_menu_string(vimmenu_T *menu, int idx)
1088 {
1089     int		count = 0;
1090     int		i;
1091 
1092     for (i = 0; i < MENU_MODES; i++)
1093 	if (menu->strings[i] == menu->strings[idx])
1094 	    count++;
1095     if (count == 1)
1096 	vim_free(menu->strings[idx]);
1097     menu->strings[idx] = NULL;
1098 }
1099 
1100 /*
1101  * Show the mapping associated with a menu item or hierarchy in a sub-menu.
1102  */
1103     static int
1104 show_menus(char_u *path_name, int modes)
1105 {
1106     char_u	*p;
1107     char_u	*name;
1108     vimmenu_T	*menu;
1109     vimmenu_T	*parent = NULL;
1110 
1111     name = path_name = vim_strsave(path_name);
1112     if (path_name == NULL)
1113 	return FAIL;
1114     menu = *get_root_menu(path_name);
1115 
1116     /* First, find the (sub)menu with the given name */
1117     while (*name)
1118     {
1119 	p = menu_name_skip(name);
1120 	while (menu != NULL)
1121 	{
1122 	    if (menu_name_equal(name, menu))
1123 	    {
1124 		/* Found menu */
1125 		if (*p != NUL && menu->children == NULL)
1126 		{
1127 		    EMSG(_(e_notsubmenu));
1128 		    vim_free(path_name);
1129 		    return FAIL;
1130 		}
1131 		else if ((menu->modes & modes) == 0x0)
1132 		{
1133 		    EMSG(_(e_othermode));
1134 		    vim_free(path_name);
1135 		    return FAIL;
1136 		}
1137 		break;
1138 	    }
1139 	    menu = menu->next;
1140 	}
1141 	if (menu == NULL)
1142 	{
1143 	    EMSG2(_(e_nomenu), name);
1144 	    vim_free(path_name);
1145 	    return FAIL;
1146 	}
1147 	name = p;
1148 	parent = menu;
1149 	menu = menu->children;
1150     }
1151     vim_free(path_name);
1152 
1153     /* Now we have found the matching menu, and we list the mappings */
1154 						    /* Highlight title */
1155     MSG_PUTS_TITLE(_("\n--- Menus ---"));
1156 
1157     show_menus_recursive(parent, modes, 0);
1158     return OK;
1159 }
1160 
1161 /*
1162  * Recursively show the mappings associated with the menus under the given one
1163  */
1164     static void
1165 show_menus_recursive(vimmenu_T *menu, int modes, int depth)
1166 {
1167     int		i;
1168     int		bit;
1169 
1170     if (menu != NULL && (menu->modes & modes) == 0x0)
1171 	return;
1172 
1173     if (menu != NULL)
1174     {
1175 	msg_putchar('\n');
1176 	if (got_int)		/* "q" hit for "--more--" */
1177 	    return;
1178 	for (i = 0; i < depth; i++)
1179 	    MSG_PUTS("  ");
1180 	if (menu->priority)
1181 	{
1182 	    msg_outnum((long)menu->priority);
1183 	    MSG_PUTS(" ");
1184 	}
1185 				/* Same highlighting as for directories!? */
1186 	msg_outtrans_attr(menu->name, HL_ATTR(HLF_D));
1187     }
1188 
1189     if (menu != NULL && menu->children == NULL)
1190     {
1191 	for (bit = 0; bit < MENU_MODES; bit++)
1192 	    if ((menu->modes & modes & (1 << bit)) != 0)
1193 	    {
1194 		msg_putchar('\n');
1195 		if (got_int)		/* "q" hit for "--more--" */
1196 		    return;
1197 		for (i = 0; i < depth + 2; i++)
1198 		    MSG_PUTS("  ");
1199 		msg_putchar(menu_mode_chars[bit]);
1200 		if (menu->noremap[bit] == REMAP_NONE)
1201 		    msg_putchar('*');
1202 		else if (menu->noremap[bit] == REMAP_SCRIPT)
1203 		    msg_putchar('&');
1204 		else
1205 		    msg_putchar(' ');
1206 		if (menu->silent[bit])
1207 		    msg_putchar('s');
1208 		else
1209 		    msg_putchar(' ');
1210 		if ((menu->modes & menu->enabled & (1 << bit)) == 0)
1211 		    msg_putchar('-');
1212 		else
1213 		    msg_putchar(' ');
1214 		MSG_PUTS(" ");
1215 		if (*menu->strings[bit] == NUL)
1216 		    msg_puts_attr((char_u *)"<Nop>", HL_ATTR(HLF_8));
1217 		else
1218 		    msg_outtrans_special(menu->strings[bit], FALSE);
1219 	    }
1220     }
1221     else
1222     {
1223 	if (menu == NULL)
1224 	{
1225 	    menu = root_menu;
1226 	    depth--;
1227 	}
1228 	else
1229 	    menu = menu->children;
1230 
1231 	/* recursively show all children.  Skip PopUp[nvoci]. */
1232 	for (; menu != NULL && !got_int; menu = menu->next)
1233 	    if (!menu_is_hidden(menu->dname))
1234 		show_menus_recursive(menu, modes, depth + 1);
1235     }
1236 }
1237 
1238 #ifdef FEAT_CMDL_COMPL
1239 
1240 /*
1241  * Used when expanding menu names.
1242  */
1243 static vimmenu_T	*expand_menu = NULL;
1244 static vimmenu_T	*expand_menu_alt = NULL;
1245 static int		expand_modes = 0x0;
1246 static int		expand_emenu;	/* TRUE for ":emenu" command */
1247 
1248 /*
1249  * Work out what to complete when doing command line completion of menu names.
1250  */
1251     char_u *
1252 set_context_in_menu_cmd(
1253     expand_T	*xp,
1254     char_u	*cmd,
1255     char_u	*arg,
1256     int		forceit)
1257 {
1258     char_u	*after_dot;
1259     char_u	*p;
1260     char_u	*path_name = NULL;
1261     char_u	*name;
1262     int		unmenu;
1263     vimmenu_T	*menu;
1264     int		expand_menus;
1265 
1266     xp->xp_context = EXPAND_UNSUCCESSFUL;
1267 
1268 
1269     /* Check for priority numbers, enable and disable */
1270     for (p = arg; *p; ++p)
1271 	if (!VIM_ISDIGIT(*p) && *p != '.')
1272 	    break;
1273 
1274     if (!VIM_ISWHITE(*p))
1275     {
1276 	if (STRNCMP(arg, "enable", 6) == 0
1277 		&& (arg[6] == NUL ||  VIM_ISWHITE(arg[6])))
1278 	    p = arg + 6;
1279 	else if (STRNCMP(arg, "disable", 7) == 0
1280 		&& (arg[7] == NUL || VIM_ISWHITE(arg[7])))
1281 	    p = arg + 7;
1282 	else
1283 	    p = arg;
1284     }
1285 
1286     while (*p != NUL && VIM_ISWHITE(*p))
1287 	++p;
1288 
1289     arg = after_dot = p;
1290 
1291     for (; *p && !VIM_ISWHITE(*p); ++p)
1292     {
1293 	if ((*p == '\\' || *p == Ctrl_V) && p[1] != NUL)
1294 	    p++;
1295 	else if (*p == '.')
1296 	    after_dot = p + 1;
1297     }
1298 
1299     /* ":tearoff" and ":popup" only use menus, not entries */
1300     expand_menus = !((*cmd == 't' && cmd[1] == 'e') || *cmd == 'p');
1301     expand_emenu = (*cmd == 'e');
1302     if (expand_menus && VIM_ISWHITE(*p))
1303 	return NULL;	/* TODO: check for next command? */
1304     if (*p == NUL)		/* Complete the menu name */
1305     {
1306 	int try_alt_menu = TRUE;
1307 
1308 	/*
1309 	 * With :unmenu, you only want to match menus for the appropriate mode.
1310 	 * With :menu though you might want to add a menu with the same name as
1311 	 * one in another mode, so match menus from other modes too.
1312 	 */
1313 	expand_modes = get_menu_cmd_modes(cmd, forceit, NULL, &unmenu);
1314 	if (!unmenu)
1315 	    expand_modes = MENU_ALL_MODES;
1316 
1317 	menu = root_menu;
1318 	if (after_dot != arg)
1319 	{
1320 	    path_name = alloc((unsigned)(after_dot - arg));
1321 	    if (path_name == NULL)
1322 		return NULL;
1323 	    vim_strncpy(path_name, arg, after_dot - arg - 1);
1324 	}
1325 	name = path_name;
1326 	while (name != NULL && *name)
1327 	{
1328 	    p = menu_name_skip(name);
1329 	    while (menu != NULL)
1330 	    {
1331 		if (menu_name_equal(name, menu))
1332 		{
1333 		    /* Found menu */
1334 		    if ((*p != NUL && menu->children == NULL)
1335 			|| ((menu->modes & expand_modes) == 0x0))
1336 		    {
1337 			/*
1338 			 * Menu path continues, but we have reached a leaf.
1339 			 * Or menu exists only in another mode.
1340 			 */
1341 			vim_free(path_name);
1342 			return NULL;
1343 		    }
1344 		    break;
1345 		}
1346 		menu = menu->next;
1347 		if (menu == NULL && try_alt_menu)
1348 		{
1349 		    menu = curwin->w_winbar;
1350 		    try_alt_menu = FALSE;
1351 		}
1352 	    }
1353 	    if (menu == NULL)
1354 	    {
1355 		/* No menu found with the name we were looking for */
1356 		vim_free(path_name);
1357 		return NULL;
1358 	    }
1359 	    name = p;
1360 	    menu = menu->children;
1361 	    try_alt_menu = FALSE;
1362 	}
1363 	vim_free(path_name);
1364 
1365 	xp->xp_context = expand_menus ? EXPAND_MENUNAMES : EXPAND_MENUS;
1366 	xp->xp_pattern = after_dot;
1367 	expand_menu = menu;
1368 	if (expand_menu == root_menu)
1369 	    expand_menu_alt = curwin->w_winbar;
1370 	else
1371 	    expand_menu_alt = NULL;
1372     }
1373     else			/* We're in the mapping part */
1374 	xp->xp_context = EXPAND_NOTHING;
1375     return NULL;
1376 }
1377 
1378 /*
1379  * Function given to ExpandGeneric() to obtain the list of (sub)menus (not
1380  * entries).
1381  */
1382     char_u *
1383 get_menu_name(expand_T *xp UNUSED, int idx)
1384 {
1385     static vimmenu_T	*menu = NULL;
1386     static int		did_alt_menu = FALSE;
1387     char_u		*str;
1388 #ifdef FEAT_MULTI_LANG
1389     static  int		should_advance = FALSE;
1390 #endif
1391 
1392     if (idx == 0)	    /* first call: start at first item */
1393     {
1394 	menu = expand_menu;
1395 	did_alt_menu = FALSE;
1396 #ifdef FEAT_MULTI_LANG
1397 	should_advance = FALSE;
1398 #endif
1399     }
1400 
1401     /* Skip PopUp[nvoci]. */
1402     while (menu != NULL && (menu_is_hidden(menu->dname)
1403 	    || menu_is_separator(menu->dname)
1404 	    || menu_is_tearoff(menu->dname)
1405 	    || menu->children == NULL))
1406     {
1407 	menu = menu->next;
1408 	if (menu == NULL && !did_alt_menu)
1409 	{
1410 	    menu = expand_menu_alt;
1411 	    did_alt_menu = TRUE;
1412 	}
1413     }
1414 
1415     if (menu == NULL)	    /* at end of linked list */
1416 	return NULL;
1417 
1418     if (menu->modes & expand_modes)
1419 #ifdef FEAT_MULTI_LANG
1420 	if (should_advance)
1421 	    str = menu->en_dname;
1422 	else
1423 	{
1424 #endif
1425 	    str = menu->dname;
1426 #ifdef FEAT_MULTI_LANG
1427 	    if (menu->en_dname == NULL)
1428 		should_advance = TRUE;
1429 	}
1430 #endif
1431     else
1432 	str = (char_u *)"";
1433 
1434 #ifdef FEAT_MULTI_LANG
1435     if (should_advance)
1436 #endif
1437     {
1438 	/* Advance to next menu entry. */
1439 	menu = menu->next;
1440 	if (menu == NULL && !did_alt_menu)
1441 	{
1442 	    menu = expand_menu_alt;
1443 	    did_alt_menu = TRUE;
1444 	}
1445     }
1446 
1447 #ifdef FEAT_MULTI_LANG
1448     should_advance = !should_advance;
1449 #endif
1450 
1451     return str;
1452 }
1453 
1454 /*
1455  * Function given to ExpandGeneric() to obtain the list of menus and menu
1456  * entries.
1457  */
1458     char_u *
1459 get_menu_names(expand_T *xp UNUSED, int idx)
1460 {
1461     static vimmenu_T	*menu = NULL;
1462     static int		did_alt_menu = FALSE;
1463 #define TBUFFER_LEN 256
1464     static char_u	tbuffer[TBUFFER_LEN]; /*hack*/
1465     char_u		*str;
1466 #ifdef FEAT_MULTI_LANG
1467     static  int		should_advance = FALSE;
1468 #endif
1469 
1470     if (idx == 0)	    /* first call: start at first item */
1471     {
1472 	menu = expand_menu;
1473 	did_alt_menu = FALSE;
1474 #ifdef FEAT_MULTI_LANG
1475 	should_advance = FALSE;
1476 #endif
1477     }
1478 
1479     /* Skip Browse-style entries, popup menus and separators. */
1480     while (menu != NULL
1481 	    && (   menu_is_hidden(menu->dname)
1482 		|| (expand_emenu && menu_is_separator(menu->dname))
1483 		|| menu_is_tearoff(menu->dname)
1484 #ifndef FEAT_BROWSE
1485 		|| menu->dname[STRLEN(menu->dname) - 1] == '.'
1486 #endif
1487 	       ))
1488     {
1489 	menu = menu->next;
1490 	if (menu == NULL && !did_alt_menu)
1491 	{
1492 	    menu = expand_menu_alt;
1493 	    did_alt_menu = TRUE;
1494 	}
1495     }
1496 
1497     if (menu == NULL)	    /* at end of linked list */
1498 	return NULL;
1499 
1500     if (menu->modes & expand_modes)
1501     {
1502 	if (menu->children != NULL)
1503 	{
1504 #ifdef FEAT_MULTI_LANG
1505 	    if (should_advance)
1506 		vim_strncpy(tbuffer, menu->en_dname, TBUFFER_LEN - 2);
1507 	    else
1508 	    {
1509 #endif
1510 		vim_strncpy(tbuffer, menu->dname,  TBUFFER_LEN - 2);
1511 #ifdef FEAT_MULTI_LANG
1512 		if (menu->en_dname == NULL)
1513 		    should_advance = TRUE;
1514 	    }
1515 #endif
1516 	    /* hack on menu separators:  use a 'magic' char for the separator
1517 	     * so that '.' in names gets escaped properly */
1518 	    STRCAT(tbuffer, "\001");
1519 	    str = tbuffer;
1520 	}
1521 	else
1522 #ifdef FEAT_MULTI_LANG
1523 	{
1524 	    if (should_advance)
1525 		str = menu->en_dname;
1526 	    else
1527 	    {
1528 #endif
1529 		str = menu->dname;
1530 #ifdef FEAT_MULTI_LANG
1531 		if (menu->en_dname == NULL)
1532 		    should_advance = TRUE;
1533 	    }
1534 	}
1535 #endif
1536     }
1537     else
1538 	str = (char_u *)"";
1539 
1540 #ifdef FEAT_MULTI_LANG
1541     if (should_advance)
1542 #endif
1543     {
1544 	/* Advance to next menu entry. */
1545 	menu = menu->next;
1546 	if (menu == NULL && !did_alt_menu)
1547 	{
1548 	    menu = expand_menu_alt;
1549 	    did_alt_menu = TRUE;
1550 	}
1551     }
1552 
1553 #ifdef FEAT_MULTI_LANG
1554     should_advance = !should_advance;
1555 #endif
1556 
1557     return str;
1558 }
1559 #endif /* FEAT_CMDL_COMPL */
1560 
1561 /*
1562  * Skip over this element of the menu path and return the start of the next
1563  * element.  Any \ and ^Vs are removed from the current element.
1564  * "name" may be modified.
1565  */
1566     char_u *
1567 menu_name_skip(char_u *name)
1568 {
1569     char_u  *p;
1570 
1571     for (p = name; *p && *p != '.'; MB_PTR_ADV(p))
1572     {
1573 	if (*p == '\\' || *p == Ctrl_V)
1574 	{
1575 	    STRMOVE(p, p + 1);
1576 	    if (*p == NUL)
1577 		break;
1578 	}
1579     }
1580     if (*p)
1581 	*p++ = NUL;
1582     return p;
1583 }
1584 
1585 /*
1586  * Return TRUE when "name" matches with menu "menu".  The name is compared in
1587  * two ways: raw menu name and menu name without '&'.  ignore part after a TAB.
1588  */
1589     static int
1590 menu_name_equal(char_u *name, vimmenu_T *menu)
1591 {
1592 #ifdef FEAT_MULTI_LANG
1593     if (menu->en_name != NULL
1594 	    && (menu_namecmp(name, menu->en_name)
1595 		|| menu_namecmp(name, menu->en_dname)))
1596 	return TRUE;
1597 #endif
1598     return menu_namecmp(name, menu->name) || menu_namecmp(name, menu->dname);
1599 }
1600 
1601     static int
1602 menu_namecmp(char_u *name, char_u *mname)
1603 {
1604     int		i;
1605 
1606     for (i = 0; name[i] != NUL && name[i] != TAB; ++i)
1607 	if (name[i] != mname[i])
1608 	    break;
1609     return ((name[i] == NUL || name[i] == TAB)
1610 	    && (mname[i] == NUL || mname[i] == TAB));
1611 }
1612 
1613 /*
1614  * Return the modes specified by the given menu command (eg :menu! returns
1615  * MENU_CMDLINE_MODE | MENU_INSERT_MODE).
1616  * If "noremap" is not NULL, then the flag it points to is set according to
1617  * whether the command is a "nore" command.
1618  * If "unmenu" is not NULL, then the flag it points to is set according to
1619  * whether the command is an "unmenu" command.
1620  */
1621     static int
1622 get_menu_cmd_modes(
1623     char_u  *cmd,
1624     int	    forceit,	    /* Was there a "!" after the command? */
1625     int	    *noremap,
1626     int	    *unmenu)
1627 {
1628     int	    modes;
1629 
1630     switch (*cmd++)
1631     {
1632 	case 'v':			/* vmenu, vunmenu, vnoremenu */
1633 	    modes = MENU_VISUAL_MODE | MENU_SELECT_MODE;
1634 	    break;
1635 	case 'x':			/* xmenu, xunmenu, xnoremenu */
1636 	    modes = MENU_VISUAL_MODE;
1637 	    break;
1638 	case 's':			/* smenu, sunmenu, snoremenu */
1639 	    modes = MENU_SELECT_MODE;
1640 	    break;
1641 	case 'o':			/* omenu */
1642 	    modes = MENU_OP_PENDING_MODE;
1643 	    break;
1644 	case 'i':			/* imenu */
1645 	    modes = MENU_INSERT_MODE;
1646 	    break;
1647 	case 't':
1648 	    modes = MENU_TIP_MODE;	/* tmenu */
1649 	    break;
1650 	case 'c':			/* cmenu */
1651 	    modes = MENU_CMDLINE_MODE;
1652 	    break;
1653 	case 'a':			/* amenu */
1654 	    modes = MENU_INSERT_MODE | MENU_CMDLINE_MODE | MENU_NORMAL_MODE
1655 				    | MENU_VISUAL_MODE | MENU_SELECT_MODE
1656 				    | MENU_OP_PENDING_MODE;
1657 	    break;
1658 	case 'n':
1659 	    if (*cmd != 'o')		/* nmenu, not noremenu */
1660 	    {
1661 		modes = MENU_NORMAL_MODE;
1662 		break;
1663 	    }
1664 	    /* FALLTHROUGH */
1665 	default:
1666 	    --cmd;
1667 	    if (forceit)		/* menu!! */
1668 		modes = MENU_INSERT_MODE | MENU_CMDLINE_MODE;
1669 	    else			/* menu */
1670 		modes = MENU_NORMAL_MODE | MENU_VISUAL_MODE | MENU_SELECT_MODE
1671 						       | MENU_OP_PENDING_MODE;
1672     }
1673 
1674     if (noremap != NULL)
1675 	*noremap = (*cmd == 'n' ? REMAP_NONE : REMAP_YES);
1676     if (unmenu != NULL)
1677 	*unmenu = (*cmd == 'u');
1678     return modes;
1679 }
1680 
1681 /*
1682  * Modify a menu name starting with "PopUp" to include the mode character.
1683  * Returns the name in allocated memory (NULL for failure).
1684  */
1685     static char_u *
1686 popup_mode_name(char_u *name, int idx)
1687 {
1688     char_u	*p;
1689     int		len = (int)STRLEN(name);
1690 
1691     p = vim_strnsave(name, len + 1);
1692     if (p != NULL)
1693     {
1694 	mch_memmove(p + 6, p + 5, (size_t)(len - 4));
1695 	p[5] = menu_mode_chars[idx];
1696     }
1697     return p;
1698 }
1699 
1700 #if defined(FEAT_GUI) || defined(PROTO)
1701 /*
1702  * Return the index into the menu->strings or menu->noremap arrays for the
1703  * current state.  Returns MENU_INDEX_INVALID if there is no mapping for the
1704  * given menu in the current mode.
1705  */
1706     int
1707 get_menu_index(vimmenu_T *menu, int state)
1708 {
1709     int		idx;
1710 
1711     if ((state & INSERT))
1712 	idx = MENU_INDEX_INSERT;
1713     else if (state & CMDLINE)
1714 	idx = MENU_INDEX_CMDLINE;
1715     else if (VIsual_active)
1716     {
1717 	if (VIsual_select)
1718 	    idx = MENU_INDEX_SELECT;
1719 	else
1720 	    idx = MENU_INDEX_VISUAL;
1721     }
1722     else if (state == HITRETURN || state == ASKMORE)
1723 	idx = MENU_INDEX_CMDLINE;
1724     else if (finish_op)
1725 	idx = MENU_INDEX_OP_PENDING;
1726     else if ((state & NORMAL))
1727 	idx = MENU_INDEX_NORMAL;
1728     else
1729 	idx = MENU_INDEX_INVALID;
1730 
1731     if (idx != MENU_INDEX_INVALID && menu->strings[idx] == NULL)
1732 	idx = MENU_INDEX_INVALID;
1733     return idx;
1734 }
1735 #endif
1736 
1737 /*
1738  * Duplicate the menu item text and then process to see if a mnemonic key
1739  * and/or accelerator text has been identified.
1740  * Returns a pointer to allocated memory, or NULL for failure.
1741  * If mnemonic != NULL, *mnemonic is set to the character after the first '&'.
1742  * If actext != NULL, *actext is set to the text after the first TAB.
1743  */
1744     static char_u *
1745 menu_text(char_u *str, int *mnemonic, char_u **actext)
1746 {
1747     char_u	*p;
1748     char_u	*text;
1749 
1750     /* Locate accelerator text, after the first TAB */
1751     p = vim_strchr(str, TAB);
1752     if (p != NULL)
1753     {
1754 	if (actext != NULL)
1755 	    *actext = vim_strsave(p + 1);
1756 	text = vim_strnsave(str, (int)(p - str));
1757     }
1758     else
1759 	text = vim_strsave(str);
1760 
1761     /* Find mnemonic characters "&a" and reduce "&&" to "&". */
1762     for (p = text; p != NULL; )
1763     {
1764 	p = vim_strchr(p, '&');
1765 	if (p != NULL)
1766 	{
1767 	    if (p[1] == NUL)	    /* trailing "&" */
1768 		break;
1769 	    if (mnemonic != NULL && p[1] != '&')
1770 #if !defined(__MVS__) || defined(MOTIF390_MNEMONIC_FIXED)
1771 		*mnemonic = p[1];
1772 #else
1773 	    {
1774 		/*
1775 		 * Well there is a bug in the Motif libraries on OS390 Unix.
1776 		 * The mnemonic keys needs to be converted to ASCII values
1777 		 * first.
1778 		 * This behavior has been seen in 2.8 and 2.9.
1779 		 */
1780 		char c = p[1];
1781 		__etoa_l(&c, 1);
1782 		*mnemonic = c;
1783 	    }
1784 #endif
1785 	    STRMOVE(p, p + 1);
1786 	    p = p + 1;
1787 	}
1788     }
1789     return text;
1790 }
1791 
1792 /*
1793  * Return TRUE if "name" can be a menu in the MenuBar.
1794  */
1795     int
1796 menu_is_menubar(char_u *name)
1797 {
1798     return (!menu_is_popup(name)
1799 	    && !menu_is_toolbar(name)
1800 	    && !menu_is_winbar(name)
1801 	    && *name != MNU_HIDDEN_CHAR);
1802 }
1803 
1804 /*
1805  * Return TRUE if "name" is a popup menu name.
1806  */
1807     int
1808 menu_is_popup(char_u *name)
1809 {
1810     return (STRNCMP(name, "PopUp", 5) == 0);
1811 }
1812 
1813 #if (defined(FEAT_GUI_MOTIF) && (XmVersion <= 1002)) || defined(PROTO)
1814 /*
1815  * Return TRUE if "name" is part of a popup menu.
1816  */
1817     int
1818 menu_is_child_of_popup(vimmenu_T *menu)
1819 {
1820     while (menu->parent != NULL)
1821 	menu = menu->parent;
1822     return menu_is_popup(menu->name);
1823 }
1824 #endif
1825 
1826 /*
1827  * Return TRUE if "name" is a toolbar menu name.
1828  */
1829     int
1830 menu_is_toolbar(char_u *name)
1831 {
1832     return (STRNCMP(name, "ToolBar", 7) == 0);
1833 }
1834 
1835 /*
1836  * Return TRUE if the name is a menu separator identifier: Starts and ends
1837  * with '-'
1838  */
1839     int
1840 menu_is_separator(char_u *name)
1841 {
1842     return (name[0] == '-' && name[STRLEN(name) - 1] == '-');
1843 }
1844 
1845 /*
1846  * Return TRUE if the menu is hidden:  Starts with ']'
1847  */
1848     static int
1849 menu_is_hidden(char_u *name)
1850 {
1851     return (name[0] == ']') || (menu_is_popup(name) && name[5] != NUL);
1852 }
1853 
1854 #if defined(FEAT_CMDL_COMPL) \
1855 	|| (defined(FEAT_GUI_W32) && defined(FEAT_TEAROFF))
1856 /*
1857  * Return TRUE if the menu is the tearoff menu.
1858  */
1859     static int
1860 menu_is_tearoff(char_u *name UNUSED)
1861 {
1862 #ifdef FEAT_GUI
1863     return (STRCMP(name, TEAR_STRING) == 0);
1864 #else
1865     return FALSE;
1866 #endif
1867 }
1868 #endif
1869 
1870 #if defined(FEAT_GUI) || defined(FEAT_TERM_POPUP_MENU) || defined(PROTO)
1871 
1872     static int
1873 get_menu_mode(void)
1874 {
1875     if (VIsual_active)
1876     {
1877 	if (VIsual_select)
1878 	    return MENU_INDEX_SELECT;
1879 	return MENU_INDEX_VISUAL;
1880     }
1881     if (State & INSERT)
1882 	return MENU_INDEX_INSERT;
1883     if ((State & CMDLINE) || State == ASKMORE || State == HITRETURN)
1884 	return MENU_INDEX_CMDLINE;
1885     if (finish_op)
1886 	return MENU_INDEX_OP_PENDING;
1887     if (State & NORMAL)
1888 	return MENU_INDEX_NORMAL;
1889     if (State & LANGMAP)	/* must be a "r" command, like Insert mode */
1890 	return MENU_INDEX_INSERT;
1891     return MENU_INDEX_INVALID;
1892 }
1893 
1894     int
1895 get_menu_mode_flag(void)
1896 {
1897     int mode = get_menu_mode();
1898 
1899     if (mode == MENU_INDEX_INVALID)
1900 	return 0;
1901     return 1 << mode;
1902 }
1903 
1904 /*
1905  * Display the Special "PopUp" menu as a pop-up at the current mouse
1906  * position.  The "PopUpn" menu is for Normal mode, "PopUpi" for Insert mode,
1907  * etc.
1908  */
1909     void
1910 show_popupmenu(void)
1911 {
1912     vimmenu_T	*menu;
1913     int		mode;
1914 
1915     mode = get_menu_mode();
1916     if (mode == MENU_INDEX_INVALID)
1917 	return;
1918     mode = menu_mode_chars[mode];
1919 
1920     {
1921 	char_u	    ename[2];
1922 
1923 	ename[0] = mode;
1924 	ename[1] = NUL;
1925 	apply_autocmds(EVENT_MENUPOPUP, ename, NULL, FALSE, curbuf);
1926     }
1927 
1928     for (menu = root_menu; menu != NULL; menu = menu->next)
1929 	if (STRNCMP("PopUp", menu->name, 5) == 0 && menu->name[5] == mode)
1930 	    break;
1931 
1932     /* Only show a popup when it is defined and has entries */
1933     if (menu != NULL && menu->children != NULL)
1934     {
1935 # if defined(FEAT_GUI)
1936 	if (gui.in_use)
1937 	{
1938 	    /* Update the menus now, in case the MenuPopup autocommand did
1939 	     * anything. */
1940 	    gui_update_menus(0);
1941 	    gui_mch_show_popupmenu(menu);
1942 	}
1943 # endif
1944 #  if defined(FEAT_GUI) && defined(FEAT_TERM_POPUP_MENU)
1945 	else
1946 #  endif
1947 #  if defined(FEAT_TERM_POPUP_MENU)
1948 	    pum_show_popupmenu(menu);
1949 #  endif
1950     }
1951 }
1952 #endif
1953 
1954 #if defined(FEAT_GUI) || defined(PROTO)
1955 
1956 /*
1957  * Check that a pointer appears in the menu tree.  Used to protect from using
1958  * a menu that was deleted after it was selected but before the event was
1959  * handled.
1960  * Return OK or FAIL.  Used recursively.
1961  */
1962     int
1963 check_menu_pointer(vimmenu_T *root, vimmenu_T *menu_to_check)
1964 {
1965     vimmenu_T	*p;
1966 
1967     for (p = root; p != NULL; p = p->next)
1968 	if (p == menu_to_check
1969 		|| (p->children != NULL
1970 		    && check_menu_pointer(p->children, menu_to_check) == OK))
1971 	    return OK;
1972     return FAIL;
1973 }
1974 
1975 /*
1976  * After we have started the GUI, then we can create any menus that have been
1977  * defined.  This is done once here.  add_menu_path() may have already been
1978  * called to define these menus, and may be called again.  This function calls
1979  * itself recursively.	Should be called at the top level with:
1980  * gui_create_initial_menus(root_menu);
1981  */
1982     void
1983 gui_create_initial_menus(vimmenu_T *menu)
1984 {
1985     int		idx = 0;
1986 
1987     while (menu != NULL)
1988     {
1989 	/* Don't add a menu when only a tip was defined. */
1990 	if (menu->modes & MENU_ALL_MODES)
1991 	{
1992 	    if (menu->children != NULL)
1993 	    {
1994 		gui_mch_add_menu(menu, idx);
1995 		gui_create_initial_menus(menu->children);
1996 	    }
1997 	    else
1998 		gui_mch_add_menu_item(menu, idx);
1999 	}
2000 	menu = menu->next;
2001 	++idx;
2002     }
2003 }
2004 
2005 /*
2006  * Used recursively by gui_update_menus (see below)
2007  */
2008     static void
2009 gui_update_menus_recurse(vimmenu_T *menu, int mode)
2010 {
2011     int		grey;
2012 
2013     while (menu)
2014     {
2015 	if ((menu->modes & menu->enabled & mode)
2016 # if defined(FEAT_GUI_W32) && defined(FEAT_TEAROFF)
2017 		|| menu_is_tearoff(menu->dname)
2018 # endif
2019 	   )
2020 	    grey = FALSE;
2021 	else
2022 	    grey = TRUE;
2023 # ifdef FEAT_GUI_ATHENA
2024 	/* Hiding menus doesn't work for Athena, it can cause a crash. */
2025 	gui_mch_menu_grey(menu, grey);
2026 # else
2027 	/* Never hide a toplevel menu, it may make the menubar resize or
2028 	 * disappear. Same problem for ToolBar items. */
2029 	if (vim_strchr(p_go, GO_GREY) != NULL || menu->parent == NULL
2030 #  ifdef FEAT_TOOLBAR
2031 		|| menu_is_toolbar(menu->parent->name)
2032 #  endif
2033 		   )
2034 	    gui_mch_menu_grey(menu, grey);
2035 	else
2036 	    gui_mch_menu_hidden(menu, grey);
2037 # endif
2038 	gui_update_menus_recurse(menu->children, mode);
2039 	menu = menu->next;
2040     }
2041 }
2042 
2043 /*
2044  * Make sure only the valid menu items appear for this mode.  If
2045  * force_menu_update is not TRUE, then we only do this if the mode has changed
2046  * since last time.  If "modes" is not 0, then we use these modes instead.
2047  */
2048     void
2049 gui_update_menus(int modes)
2050 {
2051     static int	    prev_mode = -1;
2052     int		    mode = 0;
2053 
2054     if (modes != 0x0)
2055 	mode = modes;
2056     else
2057 	mode = get_menu_mode_flag();
2058 
2059     if (force_menu_update || mode != prev_mode)
2060     {
2061 	gui_update_menus_recurse(root_menu, mode);
2062 	gui_mch_draw_menubar();
2063 	prev_mode = mode;
2064 	force_menu_update = FALSE;
2065 # ifdef FEAT_GUI_W32
2066 	/* This can leave a tearoff as active window - make sure we
2067 	 * have the focus <negri>*/
2068 	gui_mch_activate_window();
2069 # endif
2070     }
2071 }
2072 
2073 # if defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_MOTIF) \
2074     || defined(FEAT_GUI_GTK) || defined(FEAT_GUI_PHOTON) || defined(PROTO)
2075 /*
2076  * Check if a key is used as a mnemonic for a toplevel menu.
2077  * Case of the key is ignored.
2078  */
2079     int
2080 gui_is_menu_shortcut(int key)
2081 {
2082     vimmenu_T	*menu;
2083 
2084     if (key < 256)
2085 	key = TOLOWER_LOC(key);
2086     for (menu = root_menu; menu != NULL; menu = menu->next)
2087 	if (menu->mnemonic == key
2088 		|| (menu->mnemonic < 256 && TOLOWER_LOC(menu->mnemonic) == key))
2089 	    return TRUE;
2090     return FALSE;
2091 }
2092 # endif
2093 #endif /* FEAT_GUI */
2094 
2095 #if (defined(FEAT_GUI_W32) && defined(FEAT_TEAROFF)) || defined(PROTO)
2096 
2097 /*
2098  * Deal with tearoff items that are added like a menu item.
2099  * Currently only for Win32 GUI.  Others may follow later.
2100  */
2101 
2102     void
2103 gui_mch_toggle_tearoffs(int enable)
2104 {
2105     int		pri_tab[MENUDEPTH + 1];
2106     int		i;
2107 
2108     if (enable)
2109     {
2110 	for (i = 0; i < MENUDEPTH; ++i)
2111 	    pri_tab[i] = 500;
2112 	pri_tab[MENUDEPTH] = -1;
2113 	gui_create_tearoffs_recurse(root_menu, (char_u *)"", pri_tab, 0);
2114     }
2115     else
2116 	gui_destroy_tearoffs_recurse(root_menu);
2117     s_tearoffs = enable;
2118 }
2119 
2120 /*
2121  * Recursively add tearoff items
2122  */
2123     static void
2124 gui_create_tearoffs_recurse(
2125     vimmenu_T		*menu,
2126     const char_u	*pname,
2127     int			*pri_tab,
2128     int			pri_idx)
2129 {
2130     char_u	*newpname = NULL;
2131     int		len;
2132     char_u	*s;
2133     char_u	*d;
2134 
2135     if (pri_tab[pri_idx + 1] != -1)
2136 	++pri_idx;
2137     while (menu != NULL)
2138     {
2139 	if (menu->children != NULL && menu_is_menubar(menu->name))
2140 	{
2141 	    /* Add the menu name to the menu path.  Insert a backslash before
2142 	     * dots (it's used to separate menu names). */
2143 	    len = (int)STRLEN(pname) + (int)STRLEN(menu->name);
2144 	    for (s = menu->name; *s; ++s)
2145 		if (*s == '.' || *s == '\\')
2146 		    ++len;
2147 	    newpname = alloc(len + TEAR_LEN + 2);
2148 	    if (newpname != NULL)
2149 	    {
2150 		STRCPY(newpname, pname);
2151 		d = newpname + STRLEN(newpname);
2152 		for (s = menu->name; *s; ++s)
2153 		{
2154 		    if (*s == '.' || *s == '\\')
2155 			*d++ = '\\';
2156 		    *d++ = *s;
2157 		}
2158 		*d = NUL;
2159 
2160 		/* check if tearoff already exists */
2161 		if (STRCMP(menu->children->name, TEAR_STRING) != 0)
2162 		{
2163 		    gui_add_tearoff(newpname, pri_tab, pri_idx - 1);
2164 		    *d = NUL;			/* remove TEAR_STRING */
2165 		}
2166 
2167 		STRCAT(newpname, ".");
2168 		gui_create_tearoffs_recurse(menu->children, newpname,
2169 							    pri_tab, pri_idx);
2170 		vim_free(newpname);
2171 	    }
2172 	}
2173 	menu = menu->next;
2174     }
2175 }
2176 
2177 /*
2178  * Add tear-off menu item for a submenu.
2179  * "tearpath" is the menu path, and must have room to add TEAR_STRING.
2180  */
2181     static void
2182 gui_add_tearoff(char_u *tearpath, int *pri_tab, int pri_idx)
2183 {
2184     char_u	*tbuf;
2185     int		t;
2186     vimmenu_T	menuarg;
2187 
2188     tbuf = alloc(5 + (unsigned int)STRLEN(tearpath));
2189     if (tbuf != NULL)
2190     {
2191 	tbuf[0] = K_SPECIAL;
2192 	tbuf[1] = K_SECOND(K_TEAROFF);
2193 	tbuf[2] = K_THIRD(K_TEAROFF);
2194 	STRCPY(tbuf + 3, tearpath);
2195 	STRCAT(tbuf + 3, "\r");
2196 
2197 	STRCAT(tearpath, ".");
2198 	STRCAT(tearpath, TEAR_STRING);
2199 
2200 	/* Priority of tear-off is always 1 */
2201 	t = pri_tab[pri_idx + 1];
2202 	pri_tab[pri_idx + 1] = 1;
2203 
2204 #ifdef FEAT_TOOLBAR
2205 	menuarg.iconfile = NULL;
2206 	menuarg.iconidx = -1;
2207 	menuarg.icon_builtin = FALSE;
2208 #endif
2209 	menuarg.noremap[0] = REMAP_NONE;
2210 	menuarg.silent[0] = TRUE;
2211 
2212 	menuarg.modes = MENU_ALL_MODES;
2213 	add_menu_path(tearpath, &menuarg, pri_tab, tbuf, FALSE);
2214 
2215 	menuarg.modes = MENU_TIP_MODE;
2216 	add_menu_path(tearpath, &menuarg, pri_tab,
2217 		(char_u *)_("Tear off this menu"), FALSE);
2218 
2219 	pri_tab[pri_idx + 1] = t;
2220 	vim_free(tbuf);
2221     }
2222 }
2223 
2224 /*
2225  * Recursively destroy tearoff items
2226  */
2227     static void
2228 gui_destroy_tearoffs_recurse(vimmenu_T *menu)
2229 {
2230     while (menu)
2231     {
2232 	if (menu->children)
2233 	{
2234 	    /* check if tearoff exists */
2235 	    if (STRCMP(menu->children->name, TEAR_STRING) == 0)
2236 	    {
2237 		/* Disconnect the item and free the memory */
2238 		free_menu(&menu->children);
2239 	    }
2240 	    if (menu->children != NULL) /* if not the last one */
2241 		gui_destroy_tearoffs_recurse(menu->children);
2242 	}
2243 	menu = menu->next;
2244     }
2245 }
2246 
2247 #endif /* FEAT_GUI_W32 && FEAT_TEAROFF */
2248 
2249 /*
2250  * Execute "menu".  Use by ":emenu" and the window toolbar.
2251  * "eap" is NULL for the window toolbar.
2252  */
2253     void
2254 execute_menu(exarg_T *eap, vimmenu_T *menu)
2255 {
2256     char_u	*mode;
2257     int		idx = -1;
2258 
2259     /* Use the Insert mode entry when returning to Insert mode. */
2260     if (restart_edit
2261 #ifdef FEAT_EVAL
2262 	    && !current_SID
2263 #endif
2264 	    )
2265     {
2266 	mode = (char_u *)"Insert";
2267 	idx = MENU_INDEX_INSERT;
2268     }
2269     else if (VIsual_active)
2270     {
2271 	mode = (char_u *)"Visual";
2272 	idx = MENU_INDEX_VISUAL;
2273     }
2274     else if (eap != NULL && eap->addr_count)
2275     {
2276 	pos_T	tpos;
2277 
2278 	mode = (char_u *)"Visual";
2279 	idx = MENU_INDEX_VISUAL;
2280 
2281 	/* GEDDES: This is not perfect - but it is a
2282 	 * quick way of detecting whether we are doing this from a
2283 	 * selection - see if the range matches up with the visual
2284 	 * select start and end.  */
2285 	if ((curbuf->b_visual.vi_start.lnum == eap->line1)
2286 		&& (curbuf->b_visual.vi_end.lnum) == eap->line2)
2287 	{
2288 	    /* Set it up for visual mode - equivalent to gv.  */
2289 	    VIsual_mode = curbuf->b_visual.vi_mode;
2290 	    tpos = curbuf->b_visual.vi_end;
2291 	    curwin->w_cursor = curbuf->b_visual.vi_start;
2292 	    curwin->w_curswant = curbuf->b_visual.vi_curswant;
2293 	}
2294 	else
2295 	{
2296 	    /* Set it up for line-wise visual mode */
2297 	    VIsual_mode = 'V';
2298 	    curwin->w_cursor.lnum = eap->line1;
2299 	    curwin->w_cursor.col = 1;
2300 	    tpos.lnum = eap->line2;
2301 	    tpos.col = MAXCOL;
2302 #ifdef FEAT_VIRTUALEDIT
2303 	    tpos.coladd = 0;
2304 #endif
2305 	}
2306 
2307 	/* Activate visual mode */
2308 	VIsual_active = TRUE;
2309 	VIsual_reselect = TRUE;
2310 	check_cursor();
2311 	VIsual = curwin->w_cursor;
2312 	curwin->w_cursor = tpos;
2313 
2314 	check_cursor();
2315 
2316 	/* Adjust the cursor to make sure it is in the correct pos
2317 	 * for exclusive mode */
2318 	if (*p_sel == 'e' && gchar_cursor() != NUL)
2319 	    ++curwin->w_cursor.col;
2320     }
2321 
2322     /* For the WinBar menu always use the Normal mode menu. */
2323     if (idx == -1 || eap == NULL)
2324     {
2325 	mode = (char_u *)"Normal";
2326 	idx = MENU_INDEX_NORMAL;
2327     }
2328 
2329     if (idx != MENU_INDEX_INVALID && menu->strings[idx] != NULL)
2330     {
2331 	/* When executing a script or function execute the commands right now.
2332 	 * Also for the window toolbar.
2333 	 * Otherwise put them in the typeahead buffer. */
2334 	if (eap == NULL
2335 #ifdef FEAT_EVAL
2336 		|| current_SID != 0
2337 #endif
2338 	   )
2339 	{
2340 	    save_state_T save_state;
2341 
2342 	    ++ex_normal_busy;
2343 	    if (save_current_state(&save_state))
2344 		exec_normal_cmd(menu->strings[idx], menu->noremap[idx],
2345 							   menu->silent[idx]);
2346 	    restore_current_state(&save_state);
2347 	    --ex_normal_busy;
2348 	}
2349 	else
2350 	    ins_typebuf(menu->strings[idx], menu->noremap[idx], 0,
2351 						     TRUE, menu->silent[idx]);
2352     }
2353     else if (eap != NULL)
2354 	EMSG2(_("E335: Menu not defined for %s mode"), mode);
2355 }
2356 
2357 /*
2358  * Given a menu descriptor, e.g. "File.New", find it in the menu hierarchy and
2359  * execute it.
2360  */
2361     void
2362 ex_emenu(exarg_T *eap)
2363 {
2364     vimmenu_T	*menu;
2365     char_u	*name;
2366     char_u	*saved_name;
2367     char_u	*p;
2368 
2369     saved_name = vim_strsave(eap->arg);
2370     if (saved_name == NULL)
2371 	return;
2372 
2373     menu = *get_root_menu(saved_name);
2374     name = saved_name;
2375     while (*name)
2376     {
2377 	/* Find in the menu hierarchy */
2378 	p = menu_name_skip(name);
2379 
2380 	while (menu != NULL)
2381 	{
2382 	    if (menu_name_equal(name, menu))
2383 	    {
2384 		if (*p == NUL && menu->children != NULL)
2385 		{
2386 		    EMSG(_("E333: Menu path must lead to a menu item"));
2387 		    menu = NULL;
2388 		}
2389 		else if (*p != NUL && menu->children == NULL)
2390 		{
2391 		    EMSG(_(e_notsubmenu));
2392 		    menu = NULL;
2393 		}
2394 		break;
2395 	    }
2396 	    menu = menu->next;
2397 	}
2398 	if (menu == NULL || *p == NUL)
2399 	    break;
2400 	menu = menu->children;
2401 	name = p;
2402     }
2403     vim_free(saved_name);
2404     if (menu == NULL)
2405     {
2406 	EMSG2(_("E334: Menu not found: %s"), eap->arg);
2407 	return;
2408     }
2409 
2410     /* Found the menu, so execute. */
2411     execute_menu(eap, menu);
2412 }
2413 
2414 /*
2415  * Handle a click in the window toolbar of "wp" at column "col".
2416  */
2417     void
2418 winbar_click(win_T *wp, int col)
2419 {
2420     int		idx;
2421 
2422     if (wp->w_winbar_items == NULL)
2423 	return;
2424     for (idx = 0; wp->w_winbar_items[idx].wb_menu != NULL; ++idx)
2425     {
2426 	winbar_item_T *item = &wp->w_winbar_items[idx];
2427 
2428 	if (col >= item->wb_startcol && col <= item->wb_endcol)
2429 	{
2430 	    win_T *save_curwin = NULL;
2431 	    pos_T   save_visual = VIsual;
2432 	    int	    save_visual_active = VIsual_active;
2433 	    int	    save_visual_select = VIsual_select;
2434 	    int	    save_visual_reselect = VIsual_reselect;
2435 	    int	    save_visual_mode = VIsual_mode;
2436 
2437 	    if (wp != curwin)
2438 	    {
2439 		/* Clicking in the window toolbar of a not-current window.
2440 		 * Make that window the current one and save Visual mode. */
2441 		save_curwin = curwin;
2442 		VIsual_active = FALSE;
2443 		curwin = wp;
2444 		curbuf = curwin->w_buffer;
2445 		check_cursor();
2446 	    }
2447 
2448 	    execute_menu(NULL, item->wb_menu);
2449 
2450 	    if (save_curwin != NULL)
2451 	    {
2452 		curwin = save_curwin;
2453 		curbuf = curwin->w_buffer;
2454 		VIsual = save_visual;
2455 		VIsual_active = save_visual_active;
2456 		VIsual_select = save_visual_select;
2457 		VIsual_reselect = save_visual_reselect;
2458 		VIsual_mode = save_visual_mode;
2459 	    }
2460 	}
2461     }
2462 }
2463 
2464 #if defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_GTK) \
2465 	|| defined(FEAT_TERM_POPUP_MENU) \
2466 	|| defined(FEAT_BEVAL_TIP) || defined(PROTO)
2467 /*
2468  * Given a menu descriptor, e.g. "File.New", find it in the menu hierarchy.
2469  */
2470     vimmenu_T *
2471 gui_find_menu(char_u *path_name)
2472 {
2473     vimmenu_T	*menu = NULL;
2474     char_u	*name;
2475     char_u	*saved_name;
2476     char_u	*p;
2477 
2478     menu = *get_root_menu(path_name);
2479 
2480     saved_name = vim_strsave(path_name);
2481     if (saved_name == NULL)
2482 	return NULL;
2483 
2484     name = saved_name;
2485     while (*name)
2486     {
2487 	/* find the end of one dot-separated name and put a NUL at the dot */
2488 	p = menu_name_skip(name);
2489 
2490 	while (menu != NULL)
2491 	{
2492 	    if (menu_name_equal(name, menu))
2493 	    {
2494 		if (menu->children == NULL)
2495 		{
2496 		    /* found a menu item instead of a sub-menu */
2497 		    if (*p == NUL)
2498 			EMSG(_("E336: Menu path must lead to a sub-menu"));
2499 		    else
2500 			EMSG(_(e_notsubmenu));
2501 		    menu = NULL;
2502 		    goto theend;
2503 		}
2504 		if (*p == NUL)	    /* found a full match */
2505 		    goto theend;
2506 		break;
2507 	    }
2508 	    menu = menu->next;
2509 	}
2510 	if (menu == NULL)	/* didn't find it */
2511 	    break;
2512 
2513 	/* Found a match, search the sub-menu. */
2514 	menu = menu->children;
2515 	name = p;
2516     }
2517 
2518     if (menu == NULL)
2519 	EMSG(_("E337: Menu not found - check menu names"));
2520 theend:
2521     vim_free(saved_name);
2522     return menu;
2523 }
2524 #endif
2525 
2526 #ifdef FEAT_MULTI_LANG
2527 /*
2528  * Translation of menu names.  Just a simple lookup table.
2529  */
2530 
2531 typedef struct
2532 {
2533     char_u	*from;		/* English name */
2534     char_u	*from_noamp;	/* same, without '&' */
2535     char_u	*to;		/* translated name */
2536 } menutrans_T;
2537 
2538 static garray_T menutrans_ga = {0, 0, 0, 0, NULL};
2539 #endif
2540 
2541 /*
2542  * ":menutrans".
2543  * This function is also defined without the +multi_lang feature, in which
2544  * case the commands are ignored.
2545  */
2546     void
2547 ex_menutranslate(exarg_T *eap UNUSED)
2548 {
2549 #ifdef FEAT_MULTI_LANG
2550     char_u		*arg = eap->arg;
2551     menutrans_T		*tp;
2552     int			i;
2553     char_u		*from, *from_noamp, *to;
2554 
2555     if (menutrans_ga.ga_itemsize == 0)
2556 	ga_init2(&menutrans_ga, (int)sizeof(menutrans_T), 5);
2557 
2558     /*
2559      * ":menutrans clear": clear all translations.
2560      */
2561     if (STRNCMP(arg, "clear", 5) == 0 && ends_excmd(*skipwhite(arg + 5)))
2562     {
2563 	tp = (menutrans_T *)menutrans_ga.ga_data;
2564 	for (i = 0; i < menutrans_ga.ga_len; ++i)
2565 	{
2566 	    vim_free(tp[i].from);
2567 	    vim_free(tp[i].from_noamp);
2568 	    vim_free(tp[i].to);
2569 	}
2570 	ga_clear(&menutrans_ga);
2571 # ifdef FEAT_EVAL
2572 	/* Delete all "menutrans_" global variables. */
2573 	del_menutrans_vars();
2574 # endif
2575     }
2576     else
2577     {
2578 	/* ":menutrans from to": add translation */
2579 	from = arg;
2580 	arg = menu_skip_part(arg);
2581 	to = skipwhite(arg);
2582 	*arg = NUL;
2583 	arg = menu_skip_part(to);
2584 	if (arg == to)
2585 	    EMSG(_(e_invarg));
2586 	else
2587 	{
2588 	    if (ga_grow(&menutrans_ga, 1) == OK)
2589 	    {
2590 		tp = (menutrans_T *)menutrans_ga.ga_data;
2591 		from = vim_strsave(from);
2592 		if (from != NULL)
2593 		{
2594 		    from_noamp = menu_text(from, NULL, NULL);
2595 		    to = vim_strnsave(to, (int)(arg - to));
2596 		    if (from_noamp != NULL && to != NULL)
2597 		    {
2598 			menu_translate_tab_and_shift(from);
2599 			menu_translate_tab_and_shift(to);
2600 			menu_unescape_name(from);
2601 			menu_unescape_name(to);
2602 			tp[menutrans_ga.ga_len].from = from;
2603 			tp[menutrans_ga.ga_len].from_noamp = from_noamp;
2604 			tp[menutrans_ga.ga_len].to = to;
2605 			++menutrans_ga.ga_len;
2606 		    }
2607 		    else
2608 		    {
2609 			vim_free(from);
2610 			vim_free(from_noamp);
2611 			vim_free(to);
2612 		    }
2613 		}
2614 	    }
2615 	}
2616     }
2617 #endif
2618 }
2619 
2620 #if defined(FEAT_MULTI_LANG) || defined(FEAT_TOOLBAR)
2621 /*
2622  * Find the character just after one part of a menu name.
2623  */
2624     static char_u *
2625 menu_skip_part(char_u *p)
2626 {
2627     while (*p != NUL && *p != '.' && !VIM_ISWHITE(*p))
2628     {
2629 	if ((*p == '\\' || *p == Ctrl_V) && p[1] != NUL)
2630 	    ++p;
2631 	++p;
2632     }
2633     return p;
2634 }
2635 #endif
2636 
2637 #ifdef FEAT_MULTI_LANG
2638 /*
2639  * Lookup part of a menu name in the translations.
2640  * Return a pointer to the translation or NULL if not found.
2641  */
2642     static char_u *
2643 menutrans_lookup(char_u *name, int len)
2644 {
2645     menutrans_T		*tp = (menutrans_T *)menutrans_ga.ga_data;
2646     int			i;
2647     char_u		*dname;
2648 
2649     for (i = 0; i < menutrans_ga.ga_len; ++i)
2650 	if (STRNICMP(name, tp[i].from, len) == 0 && tp[i].from[len] == NUL)
2651 	    return tp[i].to;
2652 
2653     /* Now try again while ignoring '&' characters. */
2654     i = name[len];
2655     name[len] = NUL;
2656     dname = menu_text(name, NULL, NULL);
2657     name[len] = i;
2658     if (dname != NULL)
2659     {
2660 	for (i = 0; i < menutrans_ga.ga_len; ++i)
2661 	    if (STRICMP(dname, tp[i].from_noamp) == 0)
2662 	    {
2663 		vim_free(dname);
2664 		return tp[i].to;
2665 	    }
2666 	vim_free(dname);
2667     }
2668 
2669     return NULL;
2670 }
2671 
2672 /*
2673  * Unescape the name in the translate dictionary table.
2674  */
2675     static void
2676 menu_unescape_name(char_u *name)
2677 {
2678     char_u  *p;
2679 
2680     for (p = name; *p && *p != '.'; MB_PTR_ADV(p))
2681 	if (*p == '\\')
2682 	    STRMOVE(p, p + 1);
2683 }
2684 #endif /* FEAT_MULTI_LANG */
2685 
2686 /*
2687  * Isolate the menu name.
2688  * Skip the menu name, and translate <Tab> into a real TAB.
2689  */
2690     static char_u *
2691 menu_translate_tab_and_shift(char_u *arg_start)
2692 {
2693     char_u	*arg = arg_start;
2694 
2695     while (*arg && !VIM_ISWHITE(*arg))
2696     {
2697 	if ((*arg == '\\' || *arg == Ctrl_V) && arg[1] != NUL)
2698 	    arg++;
2699 	else if (STRNICMP(arg, "<TAB>", 5) == 0)
2700 	{
2701 	    *arg = TAB;
2702 	    STRMOVE(arg + 1, arg + 5);
2703 	}
2704 	arg++;
2705     }
2706     if (*arg != NUL)
2707 	*arg++ = NUL;
2708     arg = skipwhite(arg);
2709 
2710     return arg;
2711 }
2712 
2713 #endif /* FEAT_MENU */
2714