diff options
author | Bram Moolenaar <Bram@vim.org> | 2018-10-19 22:36:53 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2018-10-19 22:36:53 +0200 |
commit | 4c5d815256099b50eca2ec5bf8f9aaa67a890211 (patch) | |
tree | 6d626537a4c82f86a43a90bec3fce98e54033949 | |
parent | 42a4ea10af687ca56b0810bfbb8884b37fc725b3 (diff) | |
download | vim-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.vim | 1 | ||||
-rw-r--r-- | runtime/doc/autocmd.txt | 5 | ||||
-rw-r--r-- | runtime/doc/gui.txt | 42 | ||||
-rw-r--r-- | runtime/doc/index.txt | 3 | ||||
-rw-r--r-- | runtime/doc/tags | 6 | ||||
-rw-r--r-- | runtime/doc/terminal.txt | 3 | ||||
-rw-r--r-- | runtime/doc/todo.txt | 9 | ||||
-rw-r--r-- | runtime/doc/usr_42.txt | 3 | ||||
-rw-r--r-- | runtime/menu.vim | 3 | ||||
-rw-r--r-- | runtime/syntax/vim.vim | 2 | ||||
-rw-r--r-- | src/ex_cmdidxs.h | 16 | ||||
-rw-r--r-- | src/ex_cmds.h | 18 | ||||
-rw-r--r-- | src/ex_docmd.c | 1 | ||||
-rw-r--r-- | src/menu.c | 231 | ||||
-rw-r--r-- | src/popupmnu.c | 2 | ||||
-rw-r--r-- | src/proto/menu.pro | 2 | ||||
-rw-r--r-- | src/structs.h | 6 | ||||
-rw-r--r-- | src/testdir/test_menu.vim | 34 | ||||
-rw-r--r-- | src/version.c | 2 |
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, |