patch 8.1.0487: no menus specifically for the terminal window

Problem:    No menus specifically for the terminal window.
Solution:   Add :tlmenu. (Yee Cheng Chin, closes #3439) Add a menu test.
This commit is contained in:
Bram Moolenaar
2018-10-19 22:36:53 +02:00
parent 42a4ea10af
commit 4c5d815256
19 changed files with 271 additions and 122 deletions

View File

@ -5,6 +5,7 @@
" Last Change: 2001 May 27
aunmenu *
tlunmenu *
silent! unlet did_install_default_menus
silent! unlet did_install_syntax_menu

View File

@ -835,13 +835,14 @@ MenuPopup Just before showing the popup menu (under the
right mouse button). Useful for adjusting the
menu for what is under the cursor or mouse
pointer.
The pattern is matched against a single
character representing the mode:
The pattern is matched against one or two
characters representing the mode:
n Normal
v Visual
o Operator-pending
i Insert
c Command line
tl Terminal
*OptionSet*
OptionSet After setting an option. The pattern is
matched against the long option name.

View File

@ -547,15 +547,16 @@ floating menus that do not appear on the main menu bar.
5.2 Creating New Menus *creating-menus*
*:me* *:menu* *:noreme* *:noremenu*
*:am* *:amenu* *:an* *:anoremenu*
*:nme* *:nmenu* *:nnoreme* *:nnoremenu*
*:ome* *:omenu* *:onoreme* *:onoremenu*
*:vme* *:vmenu* *:vnoreme* *:vnoremenu*
*:xme* *:xmenu* *:xnoreme* *:xnoremenu*
*:sme* *:smenu* *:snoreme* *:snoremenu*
*:ime* *:imenu* *:inoreme* *:inoremenu*
*:cme* *:cmenu* *:cnoreme* *:cnoremenu*
*:me* *:menu* *:noreme* *:noremenu*
*:am* *:amenu* *:an* *:anoremenu*
*:nme* *:nmenu* *:nnoreme* *:nnoremenu*
*:ome* *:omenu* *:onoreme* *:onoremenu*
*:vme* *:vmenu* *:vnoreme* *:vnoremenu*
*:xme* *:xmenu* *:xnoreme* *:xnoremenu*
*:sme* *:smenu* *:snoreme* *:snoremenu*
*:ime* *:imenu* *:inoreme* *:inoremenu*
*:cme* *:cmenu* *:cnoreme* *:cnoremenu*
*:tlm* *:tlmenu* *:tln* *:tlnoremenu*
*E330* *E327* *E331* *E336* *E333*
*E328* *E329* *E337* *E792*
To create a new menu item, use the ":menu" commands. They are mostly like
@ -571,6 +572,10 @@ the mouse button down on this will pop up a menu containing the item
"Big Changes", which is a sub-menu containing the item "Delete All Spaces",
which when selected, performs the operation.
To create a menu for terminal mode, use |:tlmenu| instead of |:tmenu| unlike
key mapping (|:tmap|). This is because |:tmenu| is already used for defining
tooltips for menus. See |terminal-typing|.
Special characters in a menu name:
& The next character is the shortcut key. Make sure each
@ -589,9 +594,9 @@ With the shortcut "F" (while keeping the <Alt> key pressed), and then "O",
this menu can be used. The second part is shown as "Open :e". The ":e"
is right aligned, and the "O" is underlined, to indicate it is the shortcut.
The ":amenu" command can be used to define menu entries for all modes at once.
To make the command work correctly, a character is automatically inserted for
some modes:
The ":amenu" command can be used to define menu entries for all modes at once,
except for Terminal mode. To make the command work correctly, a character is
automatically inserted for some modes:
mode inserted appended ~
Normal nothing nothing
Visual <C-C> <C-\><C-G>
@ -865,6 +870,16 @@ be used to complete the name of the menu item.
insert-mode menu Eg: >
:emenu File.Exit
:[range]em[enu] {mode} {menu} Like above, but execute the menu for {mode}:
'n': |:nmenu| Normal mode
'v': |:vmenu| Visual mode
's': |:smenu| Select mode
'o': |:omenu| Operator-pending mode
't': |:tlmenu| Terminal mode
'i': |:imenu| Insert mode
'c': |:cmenu| Cmdline mode
If the console-mode vim has been compiled with WANT_MENU defined, you can
use :emenu to access useful menu items you may have got used to from GUI
mode. See 'wildmenu' for an option that works well with this. See
@ -885,6 +900,7 @@ using the last visual selection.
*:sunme* *:sunmenu*
*:iunme* *:iunmenu*
*:cunme* *:cunmenu*
*:tlu* *:tlunmenu*
To delete a menu item or a whole submenu, use the unmenu commands, which are
analogous to the unmap commands. Eg: >
:unmenu! Edit.Paste
@ -951,6 +967,8 @@ See section |42.4| in the user manual.
:tu[nmenu] {menupath} Remove a tip for a menu or tool.
{only in X11 and Win32 GUI}
Note: To create menus for terminal mode, use |:tlmenu| instead.
When a tip is defined for a menu item, it appears in the command-line area
when the mouse is over that item, much like a standard Windows menu hint in
the status bar. (Except when Vim is in Command-line mode, when of course

View File

@ -1583,6 +1583,9 @@ tag command action ~
|:tjump| :tj[ump] like ":tselect", but jump directly when there
is only one match
|:tlast| :tl[ast] jump to last matching tag
|:tlmenu| :tlm[enu] add menu for Terminal-Job mode
|:tlnoremenu| :tln[oremenu] like ":noremenu" but for Terminal-Job mode
|:tlunmenu| :tlu[nmenu] remove menu for Terminal-Job mode
|:tmapclear| :tmapc[lear] remove all mappings for Terminal-Job mode
|:tmap| :tma[p] like ":map" but for Terminal-Job mode
|:tmenu| :tm[enu] define menu tooltip

View File

@ -3185,6 +3185,12 @@ $VIM_POSIX vi_diff.txt /*$VIM_POSIX*
:tjump tagsrch.txt /*:tjump*
:tl tagsrch.txt /*:tl*
:tlast tagsrch.txt /*:tlast*
:tlm gui.txt /*:tlm*
:tlmenu gui.txt /*:tlmenu*
:tln gui.txt /*:tln*
:tlnoremenu gui.txt /*:tlnoremenu*
:tlu gui.txt /*:tlu*
:tlunmenu gui.txt /*:tlunmenu*
:tm gui.txt /*:tm*
:tma map.txt /*:tma*
:tmap map.txt /*:tmap*

View File

@ -114,6 +114,9 @@ break: >
tnoremap <Esc> <C-W>N
set notimeout ttimeout timeoutlen=100
You can also create menus similar to terminal mode mappings, but you have to
use |:tlmenu| instead of |:tmenu|.
< *options-in-terminal*
After opening the terminal window and setting 'buftype' to "terminal" the
TerminalOpen autocommand event is triggered. This makes it possible to set

View File

@ -95,9 +95,6 @@ Terminal emulator window:
Key mapping times out when using a timer in Gvim. (Michael Henry, 2018 Sep 9,
#3417)
Patch to check for directory access in term_start(). (Jason Franklin, 2018 Oct
15)
Does not build with MinGW out of the box:
- _stat64 is not defined, need to use "struct stat" in vim.h
- WINVER conflict, should use 0x0600 by default?
@ -189,8 +186,6 @@ Memory leak in test_terminal:
gethostbyname() is old, use getaddrinfo() if available. (#3227)
Delete the src/main.aap file?
matchaddpos() gets slow with many matches. Proposal by Rick Howe, 2018 Jul
19.
@ -198,8 +193,6 @@ Patch to support ":tag <tagkind> <tagname>". (emmrk, 2018 May 7, #2871)
Use something like ":tag {kind}/{tagname}".
Not ready to include.
Patch to support menus in terminal: ":tlmenu". (Yee Cheng Chin, #3439)
:pedit resets the 'buflisted' option unexpectedly. (Wang Shidong, 2018 Oct 12,
#3536)
@ -2223,8 +2216,6 @@ still delete them. Also convert all buffer file names?
"gqip" in Insert mode has an off-by-one error, causing it to reflow text.
(Raul Coronado, 2009 Nov 2)
Update src/testdir/main.aap.
Something wrong with session that has "cd" commands and "badd", in such a way
that Vim doesn't find the edited file in the buffer list, causing the
ATTENTION message? (Tony Mechelynck, 2008 Dec 1)

View File

@ -150,7 +150,8 @@ like the variations on the ":map" command:
:menu! Insert and Command-line mode
:imenu Insert mode
:cmenu Command-line mode
:amenu All modes
:tlmenu Terminal mode
:amenu All modes (except for Terminal mode)
To avoid that the commands of a menu item are being mapped, use the command
":noremenu", ":nnoremenu", ":anoremenu", etc.

View File

@ -160,6 +160,9 @@ vnoremenu 20.350 &Edit.&Copy<Tab>"+y "+y
cnoremenu 20.350 &Edit.&Copy<Tab>"+y <C-Y>
nnoremenu 20.360 &Edit.&Paste<Tab>"+gP "+gP
cnoremenu &Edit.&Paste<Tab>"+gP <C-R>+
if exists(':tlmenu')
tlnoremenu &Edit.&Paste<Tab>"+gP <C-W>"+
endif
exe 'vnoremenu <script> &Edit.&Paste<Tab>"+gP ' . paste#paste_cmd['v']
exe 'inoremenu <script> &Edit.&Paste<Tab>"+gP ' . paste#paste_cmd['i']
nnoremenu 20.370 &Edit.Put\ &Before<Tab>[p [p

View File

@ -407,7 +407,7 @@ syn case match
" Menus {{{2
" =====
syn cluster vimMenuList contains=vimMenuBang,vimMenuPriority,vimMenuName,vimMenuMod
syn keyword vimCommand am[enu] an[oremenu] aun[menu] cme[nu] cnoreme[nu] cunme[nu] ime[nu] inoreme[nu] iunme[nu] me[nu] nme[nu] nnoreme[nu] noreme[nu] nunme[nu] ome[nu] onoreme[nu] ounme[nu] unme[nu] vme[nu] vnoreme[nu] vunme[nu] skipwhite nextgroup=@vimMenuList
syn keyword vimCommand am[enu] an[oremenu] aun[menu] cme[nu] cnoreme[nu] cunme[nu] ime[nu] inoreme[nu] iunme[nu] me[nu] nme[nu] nnoreme[nu] noreme[nu] nunme[nu] ome[nu] onoreme[nu] ounme[nu] tlm[enu] tln[oremenu] tlu[nmenu] unme[nu] vme[nu] vnoreme[nu] vunme[nu] skipwhite nextgroup=@vimMenuList
syn match vimMenuName "[^ \t\\<]\+" contained nextgroup=vimMenuNameMore,vimMenuMap
syn match vimMenuPriority "\d\+\(\.\d\+\)*" contained skipwhite nextgroup=vimMenuName
syn match vimMenuNameMore "\c\\\s\|<tab>\|\\\." contained nextgroup=vimMenuName,vimMenuNameMore contains=vimNotation

View File

@ -25,12 +25,12 @@ static const unsigned short cmdidxs1[26] =
/* r */ 351,
/* s */ 370,
/* t */ 437,
/* u */ 477,
/* v */ 488,
/* w */ 506,
/* x */ 521,
/* y */ 530,
/* z */ 531
/* u */ 480,
/* v */ 491,
/* w */ 509,
/* x */ 524,
/* y */ 533,
/* z */ 534
};
/*
@ -60,7 +60,7 @@ static const unsigned char cmdidxs2[26][26] =
/* q */ { 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
/* r */ { 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 18, 0, 0, 0, 0 },
/* s */ { 2, 6, 15, 0, 18, 22, 0, 24, 25, 0, 0, 28, 30, 34, 38, 40, 0, 48, 0, 49, 0, 61, 62, 0, 63, 0 },
/* t */ { 2, 0, 19, 0, 22, 24, 0, 25, 0, 26, 0, 27, 28, 31, 33, 34, 0, 35, 37, 0, 38, 0, 0, 0, 0, 0 },
/* t */ { 2, 0, 19, 0, 22, 24, 0, 25, 0, 26, 0, 27, 31, 34, 36, 37, 0, 38, 40, 0, 41, 0, 0, 0, 0, 0 },
/* u */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
/* v */ { 0, 0, 0, 0, 1, 0, 0, 0, 4, 0, 0, 0, 9, 12, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 0, 0 },
/* w */ { 2, 0, 0, 0, 0, 0, 0, 3, 4, 0, 0, 0, 0, 8, 0, 9, 10, 0, 12, 0, 13, 14, 0, 0, 0, 0 },
@ -69,4 +69,4 @@ static const unsigned char cmdidxs2[26][26] =
/* z */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};
static const int command_count = 544;
static const int command_count = 547;

View File

@ -20,9 +20,10 @@
* 1. Add an entry in the table below. Keep it sorted on the shortest
* version of the command name that works. If it doesn't start with a
* lower case letter, add it at the end.
* 2. Add a "case: CMD_xxx" in the big switch in ex_docmd.c.
* 3. Add an entry in the index for Ex commands at ":help ex-cmd-index".
* 4. Add documentation in ../doc/xxx.txt. Add a tag for both the short and
* 2. Run "make cmdidxs" to re-generate ex_cmdidxs.h.
* 3. Add a "case: CMD_xxx" in the big switch in ex_docmd.c.
* 4. Add an entry in the index for Ex commands at ":help ex-cmd-index".
* 5. Add documentation in ../doc/xxx.txt. Add a tag for both the short and
* long name of the command.
*/
@ -176,7 +177,7 @@ EX(CMD_bdelete, "bdelete", ex_bunload,
BANG|RANGE|NOTADR|BUFNAME|COUNT|EXTRA|TRLBAR,
ADDR_BUFFERS),
EX(CMD_behave, "behave", ex_behave,
NEEDARG|WORD1|TRLBAR|CMDWIN,
BANG|NEEDARG|WORD1|TRLBAR|CMDWIN,
ADDR_LINES),
EX(CMD_belowright, "belowright", ex_wrongmodifier,
NEEDARG|EXTRA|NOTRLCOM,
@ -1498,6 +1499,15 @@ EX(CMD_tjump, "tjump", ex_tag,
EX(CMD_tlast, "tlast", ex_tag,
BANG|TRLBAR,
ADDR_LINES),
EX(CMD_tlmenu, "tlmenu", ex_menu,
RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
ADDR_LINES),
EX(CMD_tlnoremenu, "tlnoremenu", ex_menu,
RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
ADDR_LINES),
EX(CMD_tlunmenu, "tlunmenu", ex_menu,
RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
ADDR_LINES),
EX(CMD_tmenu, "tmenu", ex_menu,
RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
ADDR_LINES),

View File

@ -4283,6 +4283,7 @@ set_one_cmd_context(
case CMD_omenu: case CMD_onoremenu: case CMD_ounmenu:
case CMD_imenu: case CMD_inoremenu: case CMD_iunmenu:
case CMD_cmenu: case CMD_cnoremenu: case CMD_cunmenu:
case CMD_tlmenu: case CMD_tlnoremenu: case CMD_tlunmenu:
case CMD_tmenu: case CMD_tunmenu:
case CMD_popup: case CMD_tearoff: case CMD_emenu:
return set_context_in_menu_cmd(xp, cmd, arg, forceit);

View File

@ -58,7 +58,7 @@ static void menu_unescape_name(char_u *p);
static char_u *menu_translate_tab_and_shift(char_u *arg_start);
/* The character for each menu mode */
static char_u menu_mode_chars[] = {'n', 'v', 's', 'o', 'i', 'c', 't'};
static char *menu_mode_chars[] = {"n", "v", "s", "o", "i", "c", "tl", "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");
@ -1196,7 +1196,7 @@ show_menus_recursive(vimmenu_T *menu, int modes, int depth)
return;
for (i = 0; i < depth + 2; i++)
MSG_PUTS(" ");
msg_putchar(menu_mode_chars[bit]);
msg_puts((char_u*)menu_mode_chars[bit]);
if (menu->noremap[bit] == REMAP_NONE)
msg_putchar('*');
else if (menu->noremap[bit] == REMAP_SCRIPT)
@ -1645,6 +1645,12 @@ get_menu_cmd_modes(
modes = MENU_INSERT_MODE;
break;
case 't':
if (*cmd == 'l') /* tlmenu, tlunmenu, tlnoremenu */
{
modes = MENU_TERMINAL_MODE;
++cmd;
break;
}
modes = MENU_TIP_MODE; /* tmenu */
break;
case 'c': /* cmenu */
@ -1687,12 +1693,18 @@ popup_mode_name(char_u *name, int idx)
{
char_u *p;
int len = (int)STRLEN(name);
char *mode_chars = menu_mode_chars[idx];
int mode_chars_len = (int)strlen(mode_chars);
int i;
p = vim_strnsave(name, len + 1);
p = vim_strnsave(name, len + mode_chars_len);
if (p != NULL)
{
mch_memmove(p + 6, p + 5, (size_t)(len - 4));
p[5] = menu_mode_chars[idx];
mch_memmove(p + 5 + mode_chars_len, p + 5, (size_t)(len - 4));
for (i = 0; i < mode_chars_len; ++i)
{
p[5 + i] = menu_mode_chars[idx][i];
}
}
return p;
}
@ -1712,6 +1724,10 @@ get_menu_index(vimmenu_T *menu, int state)
idx = MENU_INDEX_INSERT;
else if (state & CMDLINE)
idx = MENU_INDEX_CMDLINE;
#ifdef FEAT_TERMINAL
else if (term_use_loop())
idx = MENU_INDEX_TERMINAL;
#endif
else if (VIsual_active)
{
if (VIsual_select)
@ -1872,6 +1888,12 @@ menu_is_tearoff(char_u *name UNUSED)
static int
get_menu_mode(void)
{
#ifdef FEAT_TERMINAL
if (term_use_loop())
{
return MENU_INDEX_TERMINAL;
}
#endif
if (VIsual_active)
{
if (VIsual_select)
@ -1910,23 +1932,20 @@ get_menu_mode_flag(void)
show_popupmenu(void)
{
vimmenu_T *menu;
int mode;
int menu_mode;
char* mode;
int mode_len;
mode = get_menu_mode();
if (mode == MENU_INDEX_INVALID)
menu_mode = get_menu_mode();
if (menu_mode == MENU_INDEX_INVALID)
return;
mode = menu_mode_chars[mode];
mode = menu_mode_chars[menu_mode];
mode_len = (int)strlen(mode);
{
char_u ename[2];
ename[0] = mode;
ename[1] = NUL;
apply_autocmds(EVENT_MENUPOPUP, ename, NULL, FALSE, curbuf);
}
apply_autocmds(EVENT_MENUPOPUP, (char_u*)mode, NULL, FALSE, curbuf);
for (menu = root_menu; menu != NULL; menu = menu->next)
if (STRNCMP("PopUp", menu->name, 5) == 0 && menu->name[5] == mode)
if (STRNCMP("PopUp", menu->name, 5) == 0 && STRNCMP(menu->name + 5, mode, mode_len) == 0)
break;
/* Only show a popup when it is defined and has entries */
@ -2249,82 +2268,86 @@ gui_destroy_tearoffs_recurse(vimmenu_T *menu)
/*
* Execute "menu". Use by ":emenu" and the window toolbar.
* "eap" is NULL for the window toolbar.
* "mode_idx" specifies a MENU_INDEX_ value, use -1 to depend on the current
* state.
*/
void
execute_menu(exarg_T *eap, vimmenu_T *menu)
execute_menu(exarg_T *eap, vimmenu_T *menu, int mode_idx)
{
char_u *mode;
int idx = -1;
int idx = mode_idx;
/* Use the Insert mode entry when returning to Insert mode. */
if (restart_edit
if (idx < 0)
{
/* Use the Insert mode entry when returning to Insert mode. */
if (restart_edit
#ifdef FEAT_EVAL
&& !current_sctx.sc_sid
&& !current_sctx.sc_sid
#endif
)
{
mode = (char_u *)"Insert";
idx = MENU_INDEX_INSERT;
}
else if (VIsual_active)
{
mode = (char_u *)"Visual";
idx = MENU_INDEX_VISUAL;
}
else if (eap != NULL && eap->addr_count)
{
pos_T tpos;
mode = (char_u *)"Visual";
idx = MENU_INDEX_VISUAL;
/* GEDDES: This is not perfect - but it is a
* quick way of detecting whether we are doing this from a
* selection - see if the range matches up with the visual
* select start and end. */
if ((curbuf->b_visual.vi_start.lnum == eap->line1)
&& (curbuf->b_visual.vi_end.lnum) == eap->line2)
)
{
/* Set it up for visual mode - equivalent to gv. */
VIsual_mode = curbuf->b_visual.vi_mode;
tpos = curbuf->b_visual.vi_end;
curwin->w_cursor = curbuf->b_visual.vi_start;
curwin->w_curswant = curbuf->b_visual.vi_curswant;
idx = MENU_INDEX_INSERT;
}
else
#ifdef FEAT_TERMINAL
else if (term_use_loop())
{
/* Set it up for line-wise visual mode */
VIsual_mode = 'V';
curwin->w_cursor.lnum = eap->line1;
curwin->w_cursor.col = 1;
tpos.lnum = eap->line2;
tpos.col = MAXCOL;
idx = MENU_INDEX_TERMINAL;
}
#endif
else if (VIsual_active)
{
idx = MENU_INDEX_VISUAL;
}
else if (eap != NULL && eap->addr_count)
{
pos_T tpos;
idx = MENU_INDEX_VISUAL;
/* GEDDES: This is not perfect - but it is a
* quick way of detecting whether we are doing this from a
* selection - see if the range matches up with the visual
* select start and end. */
if ((curbuf->b_visual.vi_start.lnum == eap->line1)
&& (curbuf->b_visual.vi_end.lnum) == eap->line2)
{
/* Set it up for visual mode - equivalent to gv. */
VIsual_mode = curbuf->b_visual.vi_mode;
tpos = curbuf->b_visual.vi_end;
curwin->w_cursor = curbuf->b_visual.vi_start;
curwin->w_curswant = curbuf->b_visual.vi_curswant;
}
else
{
/* Set it up for line-wise visual mode */
VIsual_mode = 'V';
curwin->w_cursor.lnum = eap->line1;
curwin->w_cursor.col = 1;
tpos.lnum = eap->line2;
tpos.col = MAXCOL;
#ifdef FEAT_VIRTUALEDIT
tpos.coladd = 0;
tpos.coladd = 0;
#endif
}
/* Activate visual mode */
VIsual_active = TRUE;
VIsual_reselect = TRUE;
check_cursor();
VIsual = curwin->w_cursor;
curwin->w_cursor = tpos;
check_cursor();
/* Adjust the cursor to make sure it is in the correct pos
* for exclusive mode */
if (*p_sel == 'e' && gchar_cursor() != NUL)
++curwin->w_cursor.col;
}
/* Activate visual mode */
VIsual_active = TRUE;
VIsual_reselect = TRUE;
check_cursor();
VIsual = curwin->w_cursor;
curwin->w_cursor = tpos;
check_cursor();
/* Adjust the cursor to make sure it is in the correct pos
* for exclusive mode */
if (*p_sel == 'e' && gchar_cursor() != NUL)
++curwin->w_cursor.col;
}
/* For the WinBar menu always use the Normal mode menu. */
if (idx == -1 || eap == NULL)
{
mode = (char_u *)"Normal";
idx = MENU_INDEX_NORMAL;
}
if (idx != MENU_INDEX_INVALID && menu->strings[idx] != NULL)
{
@ -2351,7 +2374,35 @@ execute_menu(exarg_T *eap, vimmenu_T *menu)
TRUE, menu->silent[idx]);
}
else if (eap != NULL)
{
char_u *mode;
switch (idx)
{
case MENU_INDEX_VISUAL:
mode = (char_u *)"Visual";
break;
case MENU_INDEX_SELECT:
mode = (char_u *)"Select";
break;
case MENU_INDEX_OP_PENDING:
mode = (char_u *)"Op-pending";
break;
case MENU_INDEX_TERMINAL:
mode = (char_u *)"Terminal";
break;
case MENU_INDEX_INSERT:
mode = (char_u *)"Insert";
break;
case MENU_INDEX_CMDLINE:
mode = (char_u *)"Cmdline";
break;
// case MENU_INDEX_TIP: cannot happen
default:
mode = (char_u *)"Normal";
}
EMSG2(_("E335: Menu not defined for %s mode"), mode);
}
}
/*
@ -2364,9 +2415,29 @@ ex_emenu(exarg_T *eap)
vimmenu_T *menu;
char_u *name;
char_u *saved_name;
char_u *arg = eap->arg;
char_u *p;
int gave_emsg = FALSE;
int mode_idx = -1;
saved_name = vim_strsave(eap->arg);
if (arg[0] && VIM_ISWHITE(arg[1]))
{
switch (arg[0])
{
case 'n': mode_idx = MENU_INDEX_NORMAL; break;
case 'v': mode_idx = MENU_INDEX_VISUAL; break;
case 's': mode_idx = MENU_INDEX_SELECT; break;
case 'o': mode_idx = MENU_INDEX_OP_PENDING; break;
case 't': mode_idx = MENU_INDEX_TERMINAL; break;
case 'i': mode_idx = MENU_INDEX_INSERT; break;
case 'c': mode_idx = MENU_INDEX_CMDLINE; break;
default: EMSG2(_(e_invarg2), arg);
return;
}
arg = skipwhite(arg + 2);
}
saved_name = vim_strsave(arg);
if (saved_name == NULL)
return;
@ -2384,6 +2455,7 @@ ex_emenu(exarg_T *eap)
if (*p == NUL && menu->children != NULL)
{
EMSG(_("E333: Menu path must lead to a menu item"));
gave_emsg = TRUE;
menu = NULL;
}
else if (*p != NUL && menu->children == NULL)
@ -2403,12 +2475,13 @@ ex_emenu(exarg_T *eap)
vim_free(saved_name);
if (menu == NULL)
{
EMSG2(_("E334: Menu not found: %s"), eap->arg);
if (!gave_emsg)
EMSG2(_("E334: Menu not found: %s"), arg);
return;
}
/* Found the menu, so execute. */
execute_menu(eap, menu);
// Found the menu, so execute.
execute_menu(eap, menu, mode_idx);
}
/*
@ -2445,7 +2518,7 @@ winbar_click(win_T *wp, int col)
check_cursor();
}
execute_menu(NULL, item->wb_menu);
execute_menu(NULL, item->wb_menu, -1);
if (save_curwin != NULL)
{

View File

@ -1176,7 +1176,7 @@ pum_execute_menu(vimmenu_T *menu, int mode)
if ((mp->modes & mp->enabled & mode) && idx++ == pum_selected)
{
vim_memset(&ea, 0, sizeof(ea));
execute_menu(&ea, mp);
execute_menu(&ea, mp, -1);
break;
}
}

View File

@ -19,7 +19,7 @@ void gui_create_initial_menus(vimmenu_T *menu);
void gui_update_menus(int modes);
int gui_is_menu_shortcut(int key);
void gui_mch_toggle_tearoffs(int enable);
void execute_menu(exarg_T *eap, vimmenu_T *menu);
void execute_menu(exarg_T *eap, vimmenu_T *menu, int mode_idx);
void ex_emenu(exarg_T *eap);
void winbar_click(win_T *wp, int col);
vimmenu_T *gui_find_menu(char_u *path_name);

View File

@ -3101,8 +3101,9 @@ typedef struct cursor_entry
#define MENU_INDEX_OP_PENDING 3
#define MENU_INDEX_INSERT 4
#define MENU_INDEX_CMDLINE 5
#define MENU_INDEX_TIP 6
#define MENU_MODES 7
#define MENU_INDEX_TERMINAL 6
#define MENU_INDEX_TIP 7
#define MENU_MODES 8
/* Menu modes */
#define MENU_NORMAL_MODE (1 << MENU_INDEX_NORMAL)
@ -3111,6 +3112,7 @@ typedef struct cursor_entry
#define MENU_OP_PENDING_MODE (1 << MENU_INDEX_OP_PENDING)
#define MENU_INSERT_MODE (1 << MENU_INDEX_INSERT)
#define MENU_CMDLINE_MODE (1 << MENU_INDEX_CMDLINE)
#define MENU_TERMINAL_MODE (1 << MENU_INDEX_TERMINAL)
#define MENU_TIP_MODE (1 << MENU_INDEX_TIP)
#define MENU_ALL_MODES ((1 << MENU_INDEX_TIP) - 1)
/*note MENU_INDEX_TIP is not a 'real' mode*/

View File

@ -30,3 +30,37 @@ func Test_translate_menu()
source $VIMRUNTIME/delmenu.vim
endfunc
func Test_menu_commands()
nmenu 2 Test.FooBar :let g:did_menu = 'normal'<CR>
vmenu 2 Test.FooBar :let g:did_menu = 'visual'<CR>
smenu 2 Test.FooBar :let g:did_menu = 'select'<CR>
omenu 2 Test.FooBar :let g:did_menu = 'op-pending'<CR>
tlmenu 2 Test.FooBar :let g:did_menu = 'terminal'<CR>
imenu 2 Test.FooBar :let g:did_menu = 'insert'<CR>
cmenu 2 Test.FooBar :let g:did_menu = 'cmdline'<CR>
emenu n Test.FooBar
call assert_equal('normal', g:did_menu)
emenu v Test.FooBar
call assert_equal('visual', g:did_menu)
emenu s Test.FooBar
call assert_equal('select', g:did_menu)
emenu o Test.FooBar
call assert_equal('op-pending', g:did_menu)
emenu t Test.FooBar
call assert_equal('terminal', g:did_menu)
emenu i Test.FooBar
call assert_equal('insert', g:did_menu)
emenu c Test.FooBar
call assert_equal('cmdline', g:did_menu)
aunmenu Test.FooBar
tlunmenu Test.FooBar
call assert_fails('emenu n Test.FooBar', 'E334:')
nmenu 2 Test.FooBar.Child :let g:did_menu = 'foobar'<CR>
call assert_fails('emenu n Test.FooBar', 'E333:')
nunmenu Test.FooBar.Child
unlet g:did_menu
endfun

View File

@ -792,6 +792,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
487,
/**/
486,
/**/