2473 lines · 55.8 KB · C
RawDownload
/* vi:set ts=8 sts=4 sw=4: * * VIM - Vi IMproved		by Bram Moolenaar *				GUI/Motif support by Robert Webb * * Do ":help uganda"  in Vim to read copying and usage conditions. * Do ":help credits" in Vim to see a list of people who contributed. * See README.txt for an overview of the Vim source code. */ /* * Code for menus.  Used for the GUI and 'wildmenu'. */ #include "vim.h" #if defined(FEAT_MENU) || defined(PROTO) #define MENUDEPTH   10		/* maximum depth of menus */ #ifdef FEAT_GUI_W32static int add_menu_path __ARGS((char_u *, vimmenu_T *, int *, char_u *, int));#elsestatic int add_menu_path __ARGS((char_u *, vimmenu_T *, int *, char_u *));#endifstatic int menu_nable_recurse __ARGS((vimmenu_T *menu, char_u *name, int modes, int enable));static int remove_menu __ARGS((vimmenu_T **, char_u *, int, int silent));static void free_menu __ARGS((vimmenu_T **menup));static void free_menu_string __ARGS((vimmenu_T *, int));static int show_menus __ARGS((char_u *, int));static void show_menus_recursive __ARGS((vimmenu_T *, int, int));static int menu_name_equal __ARGS((char_u *name, vimmenu_T *menu));static int menu_namecmp __ARGS((char_u *name, char_u *mname));static int get_menu_cmd_modes __ARGS((char_u *, int, int *, int *));static char_u *popup_mode_name __ARGS((char_u *name, int idx));static char_u *menu_text __ARGS((char_u *text, int *mnemonic, char_u **actext));#ifdef FEAT_GUIstatic int get_menu_mode __ARGS((void));static void gui_update_menus_recurse __ARGS((vimmenu_T *, int));#endif #if defined(FEAT_GUI_W32) && defined(FEAT_TEAROFF)static void gui_create_tearoffs_recurse __ARGS((vimmenu_T *menu, const char_u *pname, int *pri_tab, int pri_idx));static void gui_add_tearoff __ARGS((char_u *tearpath, int *pri_tab, int pri_idx));static void gui_destroy_tearoffs_recurse __ARGS((vimmenu_T *menu));static int s_tearoffs = FALSE;#endif static int menu_is_hidden __ARGS((char_u *name));#if defined(FEAT_CMDL_COMPL) || (defined(FEAT_GUI_W32) && defined(FEAT_TEAROFF))static int menu_is_tearoff __ARGS((char_u *name));#endif #if defined(FEAT_MULTI_LANG) || defined(FEAT_TOOLBAR)static char_u *menu_skip_part __ARGS((char_u *p));#endif#ifdef FEAT_MULTI_LANGstatic char_u *menutrans_lookup __ARGS((char_u *name, int len));#endif /* The character for each menu mode */static char_u	menu_mode_chars[] = {'n', 'v', 's', 'o', 'i', 'c', 't'}; static char_u e_notsubmenu[] = N_("E327: Part of menu-item path is not sub-menu");static char_u e_othermode[] = N_("E328: Menu only exists in another mode");static char_u e_nomenu[] = N_("E329: No menu \"%s\""); #ifdef FEAT_TOOLBARstatic const char *toolbar_names[] ={    /*  0 */ "New", "Open", "Save", "Undo", "Redo",    /*  5 */ "Cut", "Copy", "Paste", "Print", "Help",    /* 10 */ "Find", "SaveAll", "SaveSesn", "NewSesn", "LoadSesn",    /* 15 */ "RunScript", "Replace", "WinClose", "WinMax", "WinMin",    /* 20 */ "WinSplit", "Shell", "FindPrev", "FindNext", "FindHelp",    /* 25 */ "Make", "TagJump", "RunCtags", "WinVSplit", "WinMaxWidth",    /* 30 */ "WinMinWidth", "Exit"};# define TOOLBAR_NAME_COUNT (sizeof(toolbar_names) / sizeof(char *))#endif /* * Do the :menu command and relatives. */    voidex_menu(eap)    exarg_T	*eap;		    /* Ex command arguments */{    char_u	*menu_path;    int		modes;    char_u	*map_to;    int		noremap;    int		silent = FALSE;    int		special = FALSE;    int		unmenu;    char_u	*map_buf;    char_u	*arg;    char_u	*p;    int		i;#if defined(FEAT_GUI) && !defined(FEAT_GUI_GTK)    int		old_menu_height;# if defined(FEAT_TOOLBAR) && !defined(FEAT_GUI_W32) && !defined(FEAT_GUI_W16)    int		old_toolbar_height;# endif#endif    int		pri_tab[MENUDEPTH + 1];    int		enable = MAYBE;	    /* TRUE for "menu enable", FALSE for "menu				     * disable */#ifdef FEAT_MULTI_LANG    char_u	*tofree = NULL;    char_u	*new_cmd;#endif#ifdef FEAT_TOOLBAR    char_u	*icon = NULL;#endif    vimmenu_T	menuarg;     modes = get_menu_cmd_modes(eap->cmd, eap->forceit, &noremap, &unmenu);    arg = eap->arg;     for (;;)    {	if (STRNCMP(arg, "<script>", 8) == 0)	{	    noremap = REMAP_SCRIPT;	    arg = skipwhite(arg + 8);	    continue;	}	if (STRNCMP(arg, "<silent>", 8) == 0)	{	    silent = TRUE;	    arg = skipwhite(arg + 8);	    continue;	}	if (STRNCMP(arg, "<special>", 9) == 0)	{	    special = TRUE;	    arg = skipwhite(arg + 9);	    continue;	}	break;    }      /* Locate an optional "icon=filename" argument. */    if (STRNCMP(arg, "icon=", 5) == 0)    {	arg += 5;#ifdef FEAT_TOOLBAR	icon = arg;#endif	while (*arg != NUL && *arg != ' ')	{	    if (*arg == '\\')		mch_memmove(arg, arg + 1, STRLEN(arg));	    mb_ptr_adv(arg);	}	if (*arg != NUL)	{	    *arg++ = NUL;	    arg = skipwhite(arg);	}    }     /*     * Fill in the priority table.     */    for (p = arg; *p; ++p)	if (!VIM_ISDIGIT(*p) && *p != '.')	    break;    if (vim_iswhite(*p))    {	for (i = 0; i < MENUDEPTH && !vim_iswhite(*arg); ++i)	{	    pri_tab[i] = getdigits(&arg);	    if (pri_tab[i] == 0)		pri_tab[i] = 500;	    if (*arg == '.')		++arg;	}	arg = skipwhite(arg);    }    else if (eap->addr_count && eap->line2 != 0)    {	pri_tab[0] = eap->line2;	i = 1;    }    else	i = 0;    while (i < MENUDEPTH)	pri_tab[i++] = 500;    pri_tab[MENUDEPTH] = -1;		/* mark end of the table */     /*     * Check for "disable" or "enable" argument.     */    if (STRNCMP(arg, "enable", 6) == 0 && vim_iswhite(arg[6]))    {	enable = TRUE;	arg = skipwhite(arg + 6);    }    else if (STRNCMP(arg, "disable", 7) == 0 && vim_iswhite(arg[7]))    {	enable = FALSE;	arg = skipwhite(arg + 7);    }     /*     * If there is no argument, display all menus.     */    if (*arg == NUL)    {	show_menus(arg, modes);	return;    } #ifdef FEAT_TOOLBAR    /*     * Need to get the toolbar icon index before doing the translation.     */    menuarg.iconidx = -1;    menuarg.icon_builtin = FALSE;    if (menu_is_toolbar(arg))    {	menu_path = menu_skip_part(arg);	if (*menu_path == '.')	{	    p = menu_skip_part(++menu_path);	    if (STRNCMP(menu_path, "BuiltIn", 7) == 0)	    {		if (skipdigits(menu_path + 7) == p)		{		    menuarg.iconidx = atoi((char *)menu_path + 7);		    if (menuarg.iconidx >= TOOLBAR_NAME_COUNT)			menuarg.iconidx = -1;		    else			menuarg.icon_builtin = TRUE;		}	    }	    else	    {		for (i = 0; i < TOOLBAR_NAME_COUNT; ++i)		    if (STRNCMP(toolbar_names[i], menu_path, p - menu_path)									 == 0)		    {			menuarg.iconidx = i;			break;		    }	    }	}    }#endif #ifdef FEAT_MULTI_LANG    /*     * Translate menu names as specified with ":menutrans" commands.     */    menu_path = arg;    while (*menu_path)    {	/* find the end of one part and check if it should be translated */	p = menu_skip_part(menu_path);	map_to = menutrans_lookup(menu_path, (int)(p - menu_path));	if (map_to != NULL)	{	    /* found a match: replace with the translated part */	    i = (int)STRLEN(map_to);	    new_cmd = alloc((unsigned)STRLEN(arg) + i + 1);	    if (new_cmd == NULL)		break;	    mch_memmove(new_cmd, arg, menu_path - arg);	    mch_memmove(new_cmd + (menu_path - arg), map_to, (size_t)i);	    STRCPY(new_cmd + (menu_path - arg) + i, p);	    p = new_cmd + (menu_path - arg) + i;	    vim_free(tofree);	    tofree = new_cmd;	    arg = new_cmd;	}	if (*p != '.')	    break;	menu_path = p + 1;    }#endif     /*     * Isolate the menu name.     * Skip the menu name, and translate <Tab> into a real TAB.     */    menu_path = arg;    if (*menu_path == '.')    {	EMSG2(_(e_invarg2), menu_path);	goto theend;    }     while (*arg && !vim_iswhite(*arg))    {	if ((*arg == '\\' || *arg == Ctrl_V) && arg[1] != NUL)	    arg++;	else if (STRNICMP(arg, "<TAB>", 5) == 0)	{	    *arg = TAB;	    mch_memmove(arg + 1, arg + 5, STRLEN(arg + 4));	}	arg++;    }    if (*arg != NUL)	*arg++ = NUL;    arg = skipwhite(arg);    map_to = arg;     /*     * If there is only a menu name, display menus with that name.     */    if (*map_to == NUL && !unmenu && enable == MAYBE)    {	show_menus(menu_path, modes);	goto theend;    }    else if (*map_to != NUL && (unmenu || enable != MAYBE))    {	EMSG(_(e_trailing));	goto theend;    }#if defined(FEAT_GUI) && !(defined(FEAT_GUI_GTK) || defined(FEAT_GUI_PHOTON))    old_menu_height = gui.menu_height;# if defined(FEAT_TOOLBAR) && !defined(FEAT_GUI_W32) && !defined(FEAT_GUI_W16)    old_toolbar_height = gui.toolbar_height;# endif#endif     if (enable != MAYBE)    {	/*	 * Change sensitivity of the menu.	 * For the PopUp menu, remove a menu for each mode separately.	 * Careful: menu_nable_recurse() changes menu_path.	 */	if (STRCMP(menu_path, "*") == 0)	/* meaning: do all menus */	    menu_path = (char_u *)""; 	if (menu_is_popup(menu_path))	{	    for (i = 0; i < MENU_INDEX_TIP; ++i)		if (modes & (1 << i))		{		    p = popup_mode_name(menu_path, i);		    if (p != NULL)		    {			menu_nable_recurse(root_menu, p, MENU_ALL_MODES,								      enable);			vim_free(p);		    }		}	}	menu_nable_recurse(root_menu, menu_path, modes, enable);    }    else if (unmenu)    {	/*	 * Delete menu(s).	 */	if (STRCMP(menu_path, "*") == 0)	/* meaning: remove all menus */	    menu_path = (char_u *)""; 	/*	 * For the PopUp menu, remove a menu for each mode separately.	 */	if (menu_is_popup(menu_path))	{	    for (i = 0; i < MENU_INDEX_TIP; ++i)		if (modes & (1 << i))		{		    p = popup_mode_name(menu_path, i);		    if (p != NULL)		    {			remove_menu(&root_menu, p, MENU_ALL_MODES, TRUE);			vim_free(p);		    }		}	} 	/* Careful: remove_menu() changes menu_path */	remove_menu(&root_menu, menu_path, modes, FALSE);    }    else    {	/*	 * Add menu(s).	 * Replace special key codes.	 */	if (STRICMP(map_to, "<nop>") == 0)	/* "<Nop>" means nothing */	{	    map_to = (char_u *)"";	    map_buf = NULL;	}	else if (modes & MENU_TIP_MODE)	    map_buf = NULL;	/* Menu tips are plain text. */	else	    map_to = replace_termcodes(map_to, &map_buf, FALSE, TRUE, special);	menuarg.modes = modes;#ifdef FEAT_TOOLBAR	menuarg.iconfile = icon;#endif	menuarg.noremap[0] = noremap;	menuarg.silent[0] = silent;	add_menu_path(menu_path, &menuarg, pri_tab, map_to#ifdef FEAT_GUI_W32		, TRUE#endif		); 	/*	 * For the PopUp menu, add a menu for each mode separately.	 */	if (menu_is_popup(menu_path))	{	    for (i = 0; i < MENU_INDEX_TIP; ++i)		if (modes & (1 << i))		{		    p = popup_mode_name(menu_path, i);		    if (p != NULL)		    {			/* Include all modes, to make ":amenu" work */			menuarg.modes = modes;#ifdef FEAT_TOOLBAR			menuarg.iconfile = NULL;			menuarg.iconidx = -1;			menuarg.icon_builtin = FALSE;#endif			add_menu_path(p, &menuarg, pri_tab, map_to#ifdef FEAT_GUI_W32				, TRUE#endif					 );			vim_free(p);		    }		}	} 	vim_free(map_buf);    } #if defined(FEAT_GUI) && !(defined(FEAT_GUI_GTK))    /* If the menubar height changed, resize the window */    if (gui.in_use	    && (gui.menu_height != old_menu_height# if defined(FEAT_TOOLBAR) && !defined(FEAT_GUI_W32) && !defined(FEAT_GUI_W16)		|| gui.toolbar_height != old_toolbar_height# endif	    ))	gui_set_shellsize(FALSE, FALSE, RESIZE_VERT);#endif theend:#ifdef FEAT_MULTI_LANG    vim_free(tofree);#else    ;#endif} /* * Add the menu with the given name to the menu hierarchy */    static intadd_menu_path(menu_path, menuarg, pri_tab, call_data#ifdef FEAT_GUI_W32	, addtearoff#endif	)    char_u	*menu_path;    vimmenu_T	*menuarg;	/* passes modes, iconfile, iconidx,				   icon_builtin, silent[0], noremap[0] */    int		*pri_tab;    char_u	*call_data;#ifdef FEAT_GUI_W32    int		addtearoff;	/* may add tearoff item */#endif{    char_u	*path_name;    int		modes = menuarg->modes;    vimmenu_T	**menup;    vimmenu_T	*menu = NULL;    vimmenu_T	*parent;    vimmenu_T	**lower_pri;    char_u	*p;    char_u	*name;    char_u	*dname;    char_u	*next_name;    int		i;    int		c;#ifdef FEAT_GUI    int		idx;    int		new_idx;#endif    int		pri_idx = 0;    int		old_modes = 0;    int		amenu; 

Lines 1–500 of 2473.