summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2018-10-19 22:36:53 +0200
committerBram Moolenaar <Bram@vim.org>2018-10-19 22:36:53 +0200
commit4c5d815256099b50eca2ec5bf8f9aaa67a890211 (patch)
tree6d626537a4c82f86a43a90bec3fce98e54033949
parent42a4ea10af687ca56b0810bfbb8884b37fc725b3 (diff)
downloadvim-git-4c5d815256099b50eca2ec5bf8f9aaa67a890211.tar.gz
patch 8.1.0487: no menus specifically for the terminal windowv8.1.0487
Problem: No menus specifically for the terminal window. Solution: Add :tlmenu. (Yee Cheng Chin, closes #3439) Add a menu test.
-rw-r--r--runtime/delmenu.vim1
-rw-r--r--runtime/doc/autocmd.txt5
-rw-r--r--runtime/doc/gui.txt42
-rw-r--r--runtime/doc/index.txt3
-rw-r--r--runtime/doc/tags6
-rw-r--r--runtime/doc/terminal.txt3
-rw-r--r--runtime/doc/todo.txt9
-rw-r--r--runtime/doc/usr_42.txt3
-rw-r--r--runtime/menu.vim3
-rw-r--r--runtime/syntax/vim.vim2
-rw-r--r--src/ex_cmdidxs.h16
-rw-r--r--src/ex_cmds.h18
-rw-r--r--src/ex_docmd.c1
-rw-r--r--src/menu.c231
-rw-r--r--src/popupmnu.c2
-rw-r--r--src/proto/menu.pro2
-rw-r--r--src/structs.h6
-rw-r--r--src/testdir/test_menu.vim34
-rw-r--r--src/version.c2
19 files changed, 269 insertions, 120 deletions
diff --git a/runtime/delmenu.vim b/runtime/delmenu.vim
index 81df87d34..5cefe26d3 100644
--- a/runtime/delmenu.vim
+++ b/runtime/delmenu.vim
@@ -5,6 +5,7 @@
" Last Change: 2001 May 27
aunmenu *
+tlunmenu *
silent! unlet did_install_default_menus
silent! unlet did_install_syntax_menu
diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt
index b6e50238f..eae83d4ad 100644
--- a/runtime/doc/autocmd.txt
+++ b/runtime/doc/autocmd.txt
@@ -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.
diff --git a/runtime/doc/gui.txt b/runtime/doc/gui.txt
index 603a4d4ad..c621b40cb 100644
--- a/runtime/doc/gui.txt
+++ b/runtime/doc/gui.txt
@@ -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
diff --git a/runtime/doc/index.txt b/runtime/doc/index.txt
index 1a0d22526..4abd25aa0 100644
--- a/runtime/doc/index.txt
+++ b/runtime/doc/index.txt
@@ -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
diff --git a/runtime/doc/tags b/runtime/doc/tags
index b31d430ca..3936ebc71 100644
--- a/runtime/doc/tags
+++ b/runtime/doc/tags
@@ -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*
diff --git a/runtime/doc/terminal.txt b/runtime/doc/terminal.txt
index abc3d94fb..499a2450a 100644
--- a/runtime/doc/terminal.txt
+++ b/runtime/doc/terminal.txt
@@ -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
diff --git a/runtime/doc/todo.txt b/runtime/doc/todo.txt
index ea1e00a2e..f9c210139 100644
--- a/runtime/doc/todo.txt
+++ b/runtime/doc/todo.txt
@@ -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)
diff --git a/runtime/doc/usr_42.txt b/runtime/doc/usr_42.txt
index 46483613a..290191335 100644
--- a/runtime/doc/usr_42.txt
+++ b/runtime/doc/usr_42.txt
@@ -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.
diff --git a/runtime/menu.vim b/runtime/menu.vim
index 5e4bd1f11..a6ecf3ce5 100644
--- a/runtime/menu.vim
+++ b/runtime/menu.vim
@@ -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
diff --git a/runtime/syntax/vim.vim b/runtime/syntax/vim.vim
index 30c3f2f16..abd2d1801 100644
--- a/runtime/syntax/vim.vim
+++ b/runtime/syntax/vim.vim
@@ -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
diff --git a/src/ex_cmdidxs.h b/src/ex_cmdidxs.h
index 736cc3889..1c435caea 100644
--- a/src/ex_cmdidxs.h
+++ b/src/ex_cmdidxs.h
@@ -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;
diff --git a/src/ex_cmds.h b/src/ex_cmds.h
index 187efea23..c5e0bf449 100644
--- a/src/ex_cmds.h
+++ b/src/ex_cmds.h
@@ -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),
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
index 70acfc83d..d00ca5689 100644
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -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);
diff --git a/src/menu.c b/src/menu.c
index d253e72cb..782235a11 100644
--- a/src/menu.c
+++ b/src/menu.c
@@ -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;
-#ifdef FEAT_VIRTUALEDIT
- tpos.coladd = 0;
+ idx = MENU_INDEX_TERMINAL;
+ }
#endif
+ else if (VIsual_active)
+ {
+ idx = MENU_INDEX_VISUAL;
}
+ else if (eap != NULL && eap->addr_count)
+ {
+ pos_T tpos;
- /* Activate visual mode */
- VIsual_active = TRUE;
- VIsual_reselect = TRUE;
- check_cursor();
- VIsual = curwin->w_cursor;
- curwin->w_cursor = tpos;
+ idx = MENU_INDEX_VISUAL;
- check_cursor();
+ /* 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;
+#endif
+ }
- /* 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;
+
+ 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(eap->arg);
+ 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)
{
diff --git a/src/popupmnu.c b/src/popupmnu.c
index 0f920dc69..c481d4be7 100644
--- a/src/popupmnu.c
+++ b/src/popupmnu.c
@@ -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;
}
}
diff --git a/src/proto/menu.pro b/src/proto/menu.pro
index 63f8d11bd..411c040b4 100644
--- a/src/proto/menu.pro
+++ b/src/proto/menu.pro
@@ -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);
diff --git a/src/structs.h b/src/structs.h
index 560ce42b4..a0c06b5f2 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -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*/
diff --git a/src/testdir/test_menu.vim b/src/testdir/test_menu.vim
index 055d944b1..6462d5196 100644
--- a/src/testdir/test_menu.vim
+++ b/src/testdir/test_menu.vim
@@ -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
diff --git a/src/version.c b/src/version.c
index 726f5eeae..4189eb04a 100644
--- a/src/version.c
+++ b/src/version.c
@@ -793,6 +793,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 487,
+/**/
486,
/**/
485,