mirror of
https://github.com/neovim/neovim.git
synced 2025-09-22 19:18:34 +00:00
vim-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 vim/vim#3439) Add a menu test.
4c5d815256
ADDR_OHTER comes from patch 8.1.1241, which has already been ported.
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
" Last Change: 2019 Dec 10
|
||||
|
||||
aunmenu *
|
||||
tlunmenu *
|
||||
|
||||
unlet! g:did_install_default_menus
|
||||
unlet! g:did_install_syntax_menu
|
||||
|
@@ -727,13 +727,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
|
||||
*ModeChanged*
|
||||
ModeChanged After changing the mode. The pattern is
|
||||
matched against `'old_mode:new_mode'`, for
|
||||
|
@@ -195,6 +195,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-input|.
|
||||
|
||||
Special characters in a menu name:
|
||||
|
||||
& The next character is the shortcut key. Make sure each
|
||||
@@ -214,9 +218,9 @@ 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.
|
||||
|
||||
*:am* *:amenu* *:an* *:anoremenu*
|
||||
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,
|
||||
expect 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>
|
||||
@@ -469,6 +473,16 @@ Executing Menus *execute-menus*
|
||||
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
|
||||
|
||||
|
||||
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
|
||||
|console-menus| for an example.
|
||||
@@ -547,6 +561,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
|
||||
|
@@ -1622,17 +1622,20 @@ 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
|
||||
|:tmapclear| :tmapc[lear] remove all mappings for Terminal-Job mode
|
||||
|:tmap| :tma[p] like ":map" but for Terminal-Job mode
|
||||
|:tlmenu| :tlm[enu] add menu for |Terminal-mode|
|
||||
|:tlnoremenu| :tln[oremenu] like ":noremenu" but for |Terminal-mode|
|
||||
|:tlunmenu| :tlu[nmenu] remove menu for |Terminal-mode|
|
||||
|:tmapclear| :tmapc[lear] remove all mappings for |Terminal-mode|
|
||||
|:tmap| :tma[p] like ":map" but for |Terminal-mode|
|
||||
|:tmenu| :tm[enu] define menu tooltip
|
||||
|:tnext| :tn[ext] jump to next matching tag
|
||||
|:tnoremap| :tno[remap] like ":noremap" but for Terminal-Job mode
|
||||
|:tnoremap| :tno[remap] like ":noremap" but for |Terminal-mode|
|
||||
|:topleft| :to[pleft] make split window appear at top or far left
|
||||
|:tprevious| :tp[revious] jump to previous matching tag
|
||||
|:trewind| :tr[ewind] jump to first matching tag
|
||||
|:try| :try execute commands, abort on error or exception
|
||||
|:tselect| :ts[elect] list matching tags and select one
|
||||
|:tunmap| :tunma[p] like ":unmap" but for Terminal-Job mode
|
||||
|:tunmap| :tunma[p] like ":unmap" but for |Terminal-mode|
|
||||
|:tunmenu| :tu[nmenu] remove menu tooltip
|
||||
|:undo| :u[ndo] undo last change(s)
|
||||
|:undojoin| :undoj[oin] join next change with previous undo block
|
||||
|
@@ -80,6 +80,9 @@ To use `ALT+{h,j,k,l}` to navigate windows from any mode: >
|
||||
:nnoremap <A-k> <C-w>k
|
||||
:nnoremap <A-l> <C-w>l
|
||||
|
||||
You can also create menus similar to terminal mode mappings, but you have to
|
||||
use |:tlmenu| instead of |:tmenu|.
|
||||
|
||||
Mouse input has the following behavior:
|
||||
|
||||
- If the program has enabled mouse events, the corresponding events will be
|
||||
|
@@ -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.
|
||||
|
@@ -164,6 +164,9 @@ if exists(':tlmenu')
|
||||
endif
|
||||
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
|
||||
|
@@ -411,7 +411,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
|
||||
|
@@ -1144,8 +1144,9 @@ enum {
|
||||
MENU_INDEX_OP_PENDING = 3,
|
||||
MENU_INDEX_INSERT = 4,
|
||||
MENU_INDEX_CMDLINE = 5,
|
||||
MENU_INDEX_TIP = 6,
|
||||
MENU_MODES = 7,
|
||||
MENU_INDEX_TERMINAL = 6,
|
||||
MENU_INDEX_TIP = 7,
|
||||
MENU_MODES = 8,
|
||||
};
|
||||
|
||||
typedef struct VimMenu vimmenu_T;
|
||||
|
@@ -191,7 +191,7 @@ module.cmds = {
|
||||
},
|
||||
{
|
||||
command='behave',
|
||||
flags=bit.bor(NEEDARG, WORD1, TRLBAR, CMDWIN),
|
||||
flags=bit.bor(BANG, NEEDARG, WORD1, TRLBAR, CMDWIN),
|
||||
addr_type='ADDR_NONE',
|
||||
func='ex_behave',
|
||||
},
|
||||
@@ -2878,6 +2878,24 @@ module.cmds = {
|
||||
addr_type='ADDR_NONE',
|
||||
func='ex_tag',
|
||||
},
|
||||
{
|
||||
command='tlmenu',
|
||||
flags=bit.bor(RANGE, ZEROR, EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN),
|
||||
addr_type='ADDR_OTHER',
|
||||
func='ex_menu',
|
||||
},
|
||||
{
|
||||
command='tlnoremenu',
|
||||
flags=bit.bor(RANGE, ZEROR, EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN),
|
||||
addr_type='ADDR_OTHER',
|
||||
func='ex_menu',
|
||||
},
|
||||
{
|
||||
command='tlunmenu',
|
||||
flags=bit.bor(RANGE, ZEROR, EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN),
|
||||
addr_type='ADDR_OTHER',
|
||||
func='ex_menu',
|
||||
},
|
||||
{
|
||||
command='tmenu',
|
||||
flags=bit.bor(RANGE, ZEROR, EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN),
|
||||
|
@@ -4060,6 +4060,9 @@ const char *set_one_cmd_context(expand_T *xp, const char *buff)
|
||||
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:
|
||||
|
215
src/nvim/menu.c
215
src/nvim/menu.c
@@ -38,7 +38,7 @@
|
||||
#endif
|
||||
|
||||
/// The character for each menu mode
|
||||
static char 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 e_notsubmenu[] = N_("E327: Part of menu-item path is not sub-menu");
|
||||
static char e_othermode[] = N_("E328: Menu only exists in another mode");
|
||||
@@ -725,7 +725,7 @@ static dict_T *menu_get_recursive(const vimmenu_T *menu, int modes)
|
||||
(menu->noremap[bit] & REMAP_NONE) ? 1 : 0);
|
||||
tv_dict_add_nr(impl, S_LEN("sid"),
|
||||
(menu->noremap[bit] & REMAP_SCRIPT) ? 1 : 0);
|
||||
tv_dict_add_dict(commands, &menu_mode_chars[bit], 1, impl);
|
||||
tv_dict_add_dict(commands, menu_mode_chars[bit], 1, impl);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -861,7 +861,7 @@ static void show_menus_recursive(vimmenu_T *menu, int modes, int depth)
|
||||
for (i = 0; i < depth + 2; i++) {
|
||||
msg_puts(" ");
|
||||
}
|
||||
msg_putchar(menu_mode_chars[bit]);
|
||||
msg_puts(menu_mode_chars[bit]);
|
||||
if (menu->noremap[bit] == REMAP_NONE) {
|
||||
msg_putchar('*');
|
||||
} else if (menu->noremap[bit] == REMAP_SCRIPT) {
|
||||
@@ -1215,6 +1215,11 @@ int get_menu_cmd_modes(const char *cmd, bool forceit, int *noremap, int *unmenu)
|
||||
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
|
||||
@@ -1261,9 +1266,13 @@ static char *popup_mode_name(char *name, int idx)
|
||||
size_t len = STRLEN(name);
|
||||
assert(len >= 4);
|
||||
|
||||
char *p = xstrnsave(name, len + 1);
|
||||
memmove(p + 6, p + 5, len - 4);
|
||||
p[5] = menu_mode_chars[idx];
|
||||
char *mode_chars = menu_mode_chars[idx];
|
||||
size_t mode_chars_len = strlen(mode_chars);
|
||||
char *p = xstrnsave(name, len + mode_chars_len);
|
||||
memmove(p + 5 + mode_chars_len, p + 5, len - 4);
|
||||
for (size_t i = 0; i < mode_chars_len; i++) {
|
||||
p[5 + i] = menu_mode_chars[idx][i];
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
@@ -1359,9 +1368,13 @@ static int menu_is_hidden(char *name)
|
||||
|
||||
static int get_menu_mode(void)
|
||||
{
|
||||
if (State & MODE_TERMINAL) {
|
||||
return MENU_INDEX_TERMINAL;
|
||||
}
|
||||
if (VIsual_active) {
|
||||
if (VIsual_select)
|
||||
if (VIsual_select) {
|
||||
return MENU_INDEX_SELECT;
|
||||
}
|
||||
return MENU_INDEX_VISUAL;
|
||||
}
|
||||
if (State & MODE_INSERT) {
|
||||
@@ -1397,21 +1410,19 @@ int get_menu_mode_flag(void)
|
||||
/// etc.
|
||||
void show_popupmenu(void)
|
||||
{
|
||||
int mode = get_menu_mode();
|
||||
if (mode == MENU_INDEX_INVALID) {
|
||||
int menu_mode = get_menu_mode();
|
||||
if (menu_mode == MENU_INDEX_INVALID) {
|
||||
return;
|
||||
}
|
||||
mode = menu_mode_chars[mode];
|
||||
char *mode = menu_mode_chars[menu_mode];
|
||||
size_t mode_len = strlen(mode);
|
||||
|
||||
char ename[2];
|
||||
ename[0] = (char)mode;
|
||||
ename[1] = NUL;
|
||||
apply_autocmds(EVENT_MENUPOPUP, ename, NULL, false, curbuf);
|
||||
apply_autocmds(EVENT_MENUPOPUP, mode, NULL, false, curbuf);
|
||||
|
||||
vimmenu_T *menu;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1422,72 +1433,71 @@ void show_popupmenu(void)
|
||||
}
|
||||
}
|
||||
|
||||
// Execute "menu". Use by ":emenu" and the window toolbar.
|
||||
// "eap" is NULL for the window toolbar.
|
||||
void execute_menu(const exarg_T *eap, vimmenu_T *menu)
|
||||
/// Execute "menu". Use by ":emenu" and the window toolbar.
|
||||
/// @param eap NULL for the window toolbar.
|
||||
/// @param mode_idx specify a MENU_INDEX_ value, use -1 to depend on the current state
|
||||
void execute_menu(const exarg_T *eap, vimmenu_T *menu, int mode_idx)
|
||||
FUNC_ATTR_NONNULL_ARG(2)
|
||||
{
|
||||
int idx = -1;
|
||||
char *mode;
|
||||
int idx = mode_idx;
|
||||
|
||||
// Use the Insert mode entry when returning to Insert mode.
|
||||
if (((State & MODE_INSERT) || restart_edit) && !current_sctx.sc_sid) {
|
||||
mode = "Insert";
|
||||
idx = MENU_INDEX_INSERT;
|
||||
} else if (State & MODE_CMDLINE) {
|
||||
mode = "Command";
|
||||
idx = MENU_INDEX_CMDLINE;
|
||||
} else if (get_real_state() & MODE_VISUAL) {
|
||||
// Detect real visual mode -- if we are really in visual mode we
|
||||
// don't need to do any guesswork to figure out what the selection
|
||||
// is. Just execute the visual binding for the menu.
|
||||
mode = "Visual";
|
||||
idx = MENU_INDEX_VISUAL;
|
||||
} else if (eap != NULL && eap->addr_count) {
|
||||
pos_T tpos;
|
||||
if (idx < 0) {
|
||||
// Use the Insert mode entry when returning to Insert mode.
|
||||
if (((State & MODE_INSERT) || restart_edit) && !current_sctx.sc_sid) {
|
||||
idx = MENU_INDEX_INSERT;
|
||||
} else if (State & MODE_CMDLINE) {
|
||||
idx = MENU_INDEX_CMDLINE;
|
||||
} else if (State & MODE_TERMINAL) {
|
||||
idx = MENU_INDEX_TERMINAL;
|
||||
} else if (get_real_state() & MODE_VISUAL) {
|
||||
// Detect real visual mode -- if we are really in visual mode we
|
||||
// don't need to do any guesswork to figure out what the selection
|
||||
// is. Just execute the visual binding for the menu.
|
||||
idx = MENU_INDEX_VISUAL;
|
||||
} else if (eap != NULL && eap->addr_count) {
|
||||
pos_T tpos;
|
||||
|
||||
mode = "Visual";
|
||||
idx = MENU_INDEX_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;
|
||||
} 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;
|
||||
tpos.coladd = 0;
|
||||
}
|
||||
// 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;
|
||||
tpos.coladd = 0;
|
||||
}
|
||||
|
||||
// Activate visual mode
|
||||
VIsual_active = TRUE;
|
||||
VIsual_reselect = TRUE;
|
||||
check_cursor();
|
||||
VIsual = curwin->w_cursor;
|
||||
curwin->w_cursor = tpos;
|
||||
// Activate visual mode
|
||||
VIsual_active = true;
|
||||
VIsual_reselect = true;
|
||||
check_cursor();
|
||||
VIsual = curwin->w_cursor;
|
||||
curwin->w_cursor = tpos;
|
||||
|
||||
check_cursor();
|
||||
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++;
|
||||
// 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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (idx == -1 || eap == NULL) {
|
||||
mode = "Normal";
|
||||
idx = MENU_INDEX_NORMAL;
|
||||
}
|
||||
|
||||
@@ -1511,6 +1521,30 @@ void execute_menu(const exarg_T *eap, vimmenu_T *menu)
|
||||
menu->silent[idx]);
|
||||
}
|
||||
} else if (eap != NULL) {
|
||||
char *mode;
|
||||
switch (idx) {
|
||||
case MENU_INDEX_VISUAL:
|
||||
mode = "Visual";
|
||||
break;
|
||||
case MENU_INDEX_SELECT:
|
||||
mode = "Select";
|
||||
break;
|
||||
case MENU_INDEX_OP_PENDING:
|
||||
mode = "Op-pending";
|
||||
break;
|
||||
case MENU_INDEX_TERMINAL:
|
||||
mode = "Terminal";
|
||||
break;
|
||||
case MENU_INDEX_INSERT:
|
||||
mode = "Insert";
|
||||
break;
|
||||
case MENU_INDEX_CMDLINE:
|
||||
mode = "Cmdline";
|
||||
break;
|
||||
// case MENU_INDEX_TIP: cannot happen
|
||||
default:
|
||||
mode = "Normal";
|
||||
}
|
||||
semsg(_("E335: Menu not defined for %s mode"), mode);
|
||||
}
|
||||
}
|
||||
@@ -1519,9 +1553,43 @@ void execute_menu(const exarg_T *eap, vimmenu_T *menu)
|
||||
// execute it.
|
||||
void ex_emenu(exarg_T *eap)
|
||||
{
|
||||
char *saved_name = xstrdup(eap->arg);
|
||||
char *arg = eap->arg;
|
||||
int mode_idx = -1;
|
||||
|
||||
if (arg[0] && ascii_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:
|
||||
semsg(_(e_invarg2), arg);
|
||||
return;
|
||||
}
|
||||
arg = skipwhite(arg + 2);
|
||||
}
|
||||
|
||||
char *saved_name = xstrdup(arg);
|
||||
vimmenu_T *menu = *get_root_menu(saved_name);
|
||||
char *name = saved_name;
|
||||
bool gave_emsg = false;
|
||||
while (*name) {
|
||||
// Find in the menu hierarchy
|
||||
char *p = menu_name_skip(name);
|
||||
@@ -1530,6 +1598,7 @@ void ex_emenu(exarg_T *eap)
|
||||
if (menu_name_equal(name, menu)) {
|
||||
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) {
|
||||
emsg(_(e_notsubmenu));
|
||||
@@ -1547,12 +1616,14 @@ void ex_emenu(exarg_T *eap)
|
||||
}
|
||||
xfree(saved_name);
|
||||
if (menu == NULL) {
|
||||
semsg(_("E334: Menu not found: %s"), eap->arg);
|
||||
if (!gave_emsg) {
|
||||
semsg(_("E334: Menu not found: %s"), arg);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Found the menu, so execute.
|
||||
execute_menu(eap, menu);
|
||||
execute_menu(eap, menu, mode_idx);
|
||||
}
|
||||
|
||||
/// Given a menu descriptor, e.g. "File.New", find it in the menu hierarchy.
|
||||
|
@@ -18,6 +18,7 @@
|
||||
#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)
|
||||
/// @}
|
||||
|
@@ -989,7 +989,7 @@ static void pum_execute_menu(vimmenu_T *menu, int mode)
|
||||
for (vimmenu_T *mp = menu->children; mp != NULL; mp = mp->next) {
|
||||
if ((mp->modes & mp->enabled & mode) && idx++ == pum_selected) {
|
||||
memset(&ea, 0, sizeof(ea));
|
||||
execute_menu(&ea, mp);
|
||||
execute_menu(&ea, mp, -1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@@ -36,3 +36,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
|
||||
|
Reference in New Issue
Block a user