mirror of
https://github.com/neovim/neovim.git
synced 2025-12-07 15:14:04 +00:00
Merge pull request #19170 from zeertzjq/vim-8.0.1558
vim-patch:8.0.{1558,1570,1574,1588},8.1.{0487,0695,1274}: menu features
This commit is contained in:
@@ -5,6 +5,7 @@
|
|||||||
" Last Change: 2019 Dec 10
|
" Last Change: 2019 Dec 10
|
||||||
|
|
||||||
aunmenu *
|
aunmenu *
|
||||||
|
tlunmenu *
|
||||||
|
|
||||||
unlet! g:did_install_default_menus
|
unlet! g:did_install_default_menus
|
||||||
unlet! g:did_install_syntax_menu
|
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
|
right mouse button). Useful for adjusting the
|
||||||
menu for what is under the cursor or mouse
|
menu for what is under the cursor or mouse
|
||||||
pointer.
|
pointer.
|
||||||
The pattern is matched against a single
|
The pattern is matched against one or two
|
||||||
character representing the mode:
|
characters representing the mode:
|
||||||
n Normal
|
n Normal
|
||||||
v Visual
|
v Visual
|
||||||
o Operator-pending
|
o Operator-pending
|
||||||
i Insert
|
i Insert
|
||||||
c Command line
|
c Command line
|
||||||
|
tl Terminal
|
||||||
*ModeChanged*
|
*ModeChanged*
|
||||||
ModeChanged After changing the mode. The pattern is
|
ModeChanged After changing the mode. The pattern is
|
||||||
matched against `'old_mode:new_mode'`, for
|
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",
|
"Big Changes", which is a sub-menu containing the item "Delete All Spaces",
|
||||||
which when selected, performs the operation.
|
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:
|
Special characters in a menu name:
|
||||||
|
|
||||||
& The next character is the shortcut key. Make sure each
|
& 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.
|
is right aligned, and the "O" is underlined, to indicate it is the shortcut.
|
||||||
|
|
||||||
*:am* *:amenu* *:an* *:anoremenu*
|
*:am* *:amenu* *:an* *:anoremenu*
|
||||||
The ":amenu" command can be used to define menu entries for all modes at once.
|
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
|
expect for Terminal mode. To make the command work correctly, a character is
|
||||||
some modes:
|
automatically inserted for some modes:
|
||||||
mode inserted appended ~
|
mode inserted appended ~
|
||||||
Normal nothing nothing
|
Normal nothing nothing
|
||||||
Visual <C-C> <C-\><C-G>
|
Visual <C-C> <C-\><C-G>
|
||||||
@@ -469,6 +473,16 @@ Executing Menus *execute-menus*
|
|||||||
insert-mode menu Eg: >
|
insert-mode menu Eg: >
|
||||||
:emenu File.Exit
|
: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
|
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
|
GUI mode. See 'wildmenu' for an option that works well with this. See
|
||||||
|console-menus| for an example.
|
|console-menus| for an example.
|
||||||
@@ -494,7 +508,9 @@ may be used to complete the name of the menu item for the appropriate mode.
|
|||||||
To remove all menus use: *:unmenu-all* >
|
To remove all menus use: *:unmenu-all* >
|
||||||
:unmenu * " remove all menus in Normal and visual mode
|
:unmenu * " remove all menus in Normal and visual mode
|
||||||
:unmenu! * " remove all menus in Insert and Command-line mode
|
:unmenu! * " remove all menus in Insert and Command-line mode
|
||||||
:aunmenu * " remove all menus in all modes
|
:aunmenu * " remove all menus in all modes, except for Terminal
|
||||||
|
" mode
|
||||||
|
:tlunmenu * " remove all menus in Terminal mode
|
||||||
|
|
||||||
If you want to get rid of the menu bar: >
|
If you want to get rid of the menu bar: >
|
||||||
:set guioptions-=m
|
:set guioptions-=m
|
||||||
@@ -547,6 +563,8 @@ See section |42.4| in the user manual.
|
|||||||
:tu[nmenu] {menupath} Remove a tip for a menu or tool.
|
:tu[nmenu] {menupath} Remove a tip for a menu or tool.
|
||||||
{only in X11 and Win32 GUI}
|
{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 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
|
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
|
the status bar. (Except when Vim is in Command-line mode, when of course
|
||||||
@@ -577,8 +595,8 @@ a menu item - you don't need to do a :tunmenu as well.
|
|||||||
|
|
||||||
5.9 Popup Menus
|
5.9 Popup Menus
|
||||||
|
|
||||||
In the Win32 GUI, you can cause a menu to popup at the cursor. This behaves
|
You can cause a menu to popup at the cursor. This behaves similarly to the
|
||||||
similarly to the PopUp menus except that any menu tree can be popped up.
|
PopUp menus except that any menu tree can be popped up.
|
||||||
|
|
||||||
This command is for backwards compatibility, using it is discouraged, because
|
This command is for backwards compatibility, using it is discouraged, because
|
||||||
it behaves in a strange way.
|
it behaves in a strange way.
|
||||||
@@ -587,7 +605,6 @@ it behaves in a strange way.
|
|||||||
:popu[p] {name} Popup the menu {name}. The menu named must
|
:popu[p] {name} Popup the menu {name}. The menu named must
|
||||||
have at least one subentry, but need not
|
have at least one subentry, but need not
|
||||||
appear on the menu-bar (see |hidden-menus|).
|
appear on the menu-bar (see |hidden-menus|).
|
||||||
{only available for Win32 GUI}
|
|
||||||
|
|
||||||
:popu[p]! {name} Like above, but use the position of the mouse
|
:popu[p]! {name} Like above, but use the position of the mouse
|
||||||
pointer instead of the cursor.
|
pointer instead of the cursor.
|
||||||
|
|||||||
@@ -1622,17 +1622,20 @@ tag command action ~
|
|||||||
|:tjump| :tj[ump] like ":tselect", but jump directly when there
|
|:tjump| :tj[ump] like ":tselect", but jump directly when there
|
||||||
is only one match
|
is only one match
|
||||||
|:tlast| :tl[ast] jump to last matching tag
|
|:tlast| :tl[ast] jump to last matching tag
|
||||||
|:tmapclear| :tmapc[lear] remove all mappings for Terminal-Job mode
|
|:tlmenu| :tlm[enu] add menu for |Terminal-mode|
|
||||||
|:tmap| :tma[p] like ":map" but for Terminal-Job 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
|
|:tmenu| :tm[enu] define menu tooltip
|
||||||
|:tnext| :tn[ext] jump to next matching tag
|
|: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
|
|:topleft| :to[pleft] make split window appear at top or far left
|
||||||
|:tprevious| :tp[revious] jump to previous matching tag
|
|:tprevious| :tp[revious] jump to previous matching tag
|
||||||
|:trewind| :tr[ewind] jump to first matching tag
|
|:trewind| :tr[ewind] jump to first matching tag
|
||||||
|:try| :try execute commands, abort on error or exception
|
|:try| :try execute commands, abort on error or exception
|
||||||
|:tselect| :ts[elect] list matching tags and select one
|
|: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
|
|:tunmenu| :tu[nmenu] remove menu tooltip
|
||||||
|:undo| :u[ndo] undo last change(s)
|
|:undo| :u[ndo] undo last change(s)
|
||||||
|:undojoin| :undoj[oin] join next change with previous undo block
|
|: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-k> <C-w>k
|
||||||
:nnoremap <A-l> <C-w>l
|
: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:
|
Mouse input has the following behavior:
|
||||||
|
|
||||||
- If the program has enabled mouse events, the corresponding events will be
|
- 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
|
:menu! Insert and Command-line mode
|
||||||
:imenu Insert mode
|
:imenu Insert mode
|
||||||
:cmenu Command-line 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
|
To avoid that the commands of a menu item are being mapped, use the command
|
||||||
":noremenu", ":nnoremenu", ":anoremenu", etc.
|
":noremenu", ":nnoremenu", ":anoremenu", etc.
|
||||||
|
|||||||
@@ -164,6 +164,9 @@ if exists(':tlmenu')
|
|||||||
endif
|
endif
|
||||||
nnoremenu 20.360 &Edit.&Paste<Tab>"+gP "+gP
|
nnoremenu 20.360 &Edit.&Paste<Tab>"+gP "+gP
|
||||||
cnoremenu &Edit.&Paste<Tab>"+gP <C-R>+
|
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 'vnoremenu <script> &Edit.&Paste<Tab>"+gP ' . paste#paste_cmd['v']
|
||||||
exe 'inoremenu <script> &Edit.&Paste<Tab>"+gP ' . paste#paste_cmd['i']
|
exe 'inoremenu <script> &Edit.&Paste<Tab>"+gP ' . paste#paste_cmd['i']
|
||||||
nnoremenu 20.370 &Edit.Put\ &Before<Tab>[p [p
|
nnoremenu 20.370 &Edit.Put\ &Before<Tab>[p [p
|
||||||
|
|||||||
@@ -411,7 +411,7 @@ syn case match
|
|||||||
" Menus: {{{2
|
" Menus: {{{2
|
||||||
" =====
|
" =====
|
||||||
syn cluster vimMenuList contains=vimMenuBang,vimMenuPriority,vimMenuName,vimMenuMod
|
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 vimMenuName "[^ \t\\<]\+" contained nextgroup=vimMenuNameMore,vimMenuMap
|
||||||
syn match vimMenuPriority "\d\+\(\.\d\+\)*" contained skipwhite nextgroup=vimMenuName
|
syn match vimMenuPriority "\d\+\(\.\d\+\)*" contained skipwhite nextgroup=vimMenuName
|
||||||
syn match vimMenuNameMore "\c\\\s\|<tab>\|\\\." contained nextgroup=vimMenuName,vimMenuNameMore contains=vimNotation
|
syn match vimMenuNameMore "\c\\\s\|<tab>\|\\\." contained nextgroup=vimMenuName,vimMenuNameMore contains=vimNotation
|
||||||
|
|||||||
@@ -1144,8 +1144,9 @@ enum {
|
|||||||
MENU_INDEX_OP_PENDING = 3,
|
MENU_INDEX_OP_PENDING = 3,
|
||||||
MENU_INDEX_INSERT = 4,
|
MENU_INDEX_INSERT = 4,
|
||||||
MENU_INDEX_CMDLINE = 5,
|
MENU_INDEX_CMDLINE = 5,
|
||||||
MENU_INDEX_TIP = 6,
|
MENU_INDEX_TERMINAL = 6,
|
||||||
MENU_MODES = 7,
|
MENU_INDEX_TIP = 7,
|
||||||
|
MENU_MODES = 8,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct VimMenu vimmenu_T;
|
typedef struct VimMenu vimmenu_T;
|
||||||
|
|||||||
@@ -191,7 +191,7 @@ module.cmds = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
command='behave',
|
command='behave',
|
||||||
flags=bit.bor(NEEDARG, WORD1, TRLBAR, CMDWIN),
|
flags=bit.bor(BANG, NEEDARG, WORD1, TRLBAR, CMDWIN),
|
||||||
addr_type='ADDR_NONE',
|
addr_type='ADDR_NONE',
|
||||||
func='ex_behave',
|
func='ex_behave',
|
||||||
},
|
},
|
||||||
@@ -1991,7 +1991,7 @@ module.cmds = {
|
|||||||
command='popup',
|
command='popup',
|
||||||
flags=bit.bor(NEEDARG, EXTRA, BANG, TRLBAR, NOTRLCOM, CMDWIN),
|
flags=bit.bor(NEEDARG, EXTRA, BANG, TRLBAR, NOTRLCOM, CMDWIN),
|
||||||
addr_type='ADDR_NONE',
|
addr_type='ADDR_NONE',
|
||||||
func='ex_ni',
|
func='ex_popup',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
command='ppop',
|
command='ppop',
|
||||||
@@ -2878,6 +2878,24 @@ module.cmds = {
|
|||||||
addr_type='ADDR_NONE',
|
addr_type='ADDR_NONE',
|
||||||
func='ex_tag',
|
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',
|
command='tmenu',
|
||||||
flags=bit.bor(RANGE, ZEROR, EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN),
|
flags=bit.bor(RANGE, ZEROR, EXTRA, TRLBAR, NOTRLCOM, CTRLV, CMDWIN),
|
||||||
|
|||||||
@@ -62,6 +62,7 @@
|
|||||||
#include "nvim/os/time.h"
|
#include "nvim/os/time.h"
|
||||||
#include "nvim/os_unix.h"
|
#include "nvim/os_unix.h"
|
||||||
#include "nvim/path.h"
|
#include "nvim/path.h"
|
||||||
|
#include "nvim/popupmnu.h"
|
||||||
#include "nvim/quickfix.h"
|
#include "nvim/quickfix.h"
|
||||||
#include "nvim/regexp.h"
|
#include "nvim/regexp.h"
|
||||||
#include "nvim/screen.h"
|
#include "nvim/screen.h"
|
||||||
@@ -4059,6 +4060,9 @@ const char *set_one_cmd_context(expand_T *xp, const char *buff)
|
|||||||
case CMD_cmenu:
|
case CMD_cmenu:
|
||||||
case CMD_cnoremenu:
|
case CMD_cnoremenu:
|
||||||
case CMD_cunmenu:
|
case CMD_cunmenu:
|
||||||
|
case CMD_tlmenu:
|
||||||
|
case CMD_tlnoremenu:
|
||||||
|
case CMD_tlunmenu:
|
||||||
case CMD_tmenu:
|
case CMD_tmenu:
|
||||||
case CMD_tunmenu:
|
case CMD_tunmenu:
|
||||||
case CMD_popup:
|
case CMD_popup:
|
||||||
@@ -7985,6 +7989,11 @@ static void ex_nogui(exarg_T *eap)
|
|||||||
eap->errmsg = N_("E25: Nvim does not have a built-in GUI");
|
eap->errmsg = N_("E25: Nvim does not have a built-in GUI");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ex_popup(exarg_T *eap)
|
||||||
|
{
|
||||||
|
pum_make_popup(eap->arg, eap->forceit);
|
||||||
|
}
|
||||||
|
|
||||||
static void ex_swapname(exarg_T *eap)
|
static void ex_swapname(exarg_T *eap)
|
||||||
{
|
{
|
||||||
if (curbuf->b_ml.ml_mfp == NULL || curbuf->b_ml.ml_mfp->mf_fname == NULL) {
|
if (curbuf->b_ml.ml_mfp == NULL || curbuf->b_ml.ml_mfp->mf_fname == NULL) {
|
||||||
|
|||||||
@@ -986,6 +986,7 @@ EXTERN char e_notset[] INIT(= N_("E764: Option '%s' is not set"));
|
|||||||
EXTERN char e_invalidreg[] INIT(= N_("E850: Invalid register name"));
|
EXTERN char e_invalidreg[] INIT(= N_("E850: Invalid register name"));
|
||||||
EXTERN char e_dirnotf[] INIT(= N_("E919: Directory not found in '%s': \"%s\""));
|
EXTERN char e_dirnotf[] INIT(= N_("E919: Directory not found in '%s': \"%s\""));
|
||||||
EXTERN char e_au_recursive[] INIT(= N_("E952: Autocommand caused recursive behavior"));
|
EXTERN char e_au_recursive[] INIT(= N_("E952: Autocommand caused recursive behavior"));
|
||||||
|
EXTERN char e_menuothermode[] INIT(= N_("E328: Menu only exists in another mode"));
|
||||||
EXTERN char e_autocmd_close[] INIT(= N_("E813: Cannot close autocmd window"));
|
EXTERN char e_autocmd_close[] INIT(= N_("E813: Cannot close autocmd window"));
|
||||||
EXTERN char e_listarg[] INIT(= N_("E686: Argument of %s must be a List"));
|
EXTERN char e_listarg[] INIT(= N_("E686: Argument of %s must be a List"));
|
||||||
EXTERN char e_unsupportedoption[] INIT(= N_("E519: Option not supported"));
|
EXTERN char e_unsupportedoption[] INIT(= N_("E519: Option not supported"));
|
||||||
|
|||||||
317
src/nvim/menu.c
317
src/nvim/menu.c
@@ -11,6 +11,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "nvim/ascii.h"
|
#include "nvim/ascii.h"
|
||||||
|
#include "nvim/autocmd.h"
|
||||||
#include "nvim/charset.h"
|
#include "nvim/charset.h"
|
||||||
#include "nvim/cursor.h"
|
#include "nvim/cursor.h"
|
||||||
#include "nvim/eval.h"
|
#include "nvim/eval.h"
|
||||||
@@ -22,6 +23,7 @@
|
|||||||
#include "nvim/memory.h"
|
#include "nvim/memory.h"
|
||||||
#include "nvim/menu.h"
|
#include "nvim/menu.h"
|
||||||
#include "nvim/message.h"
|
#include "nvim/message.h"
|
||||||
|
#include "nvim/popupmnu.h"
|
||||||
#include "nvim/screen.h"
|
#include "nvim/screen.h"
|
||||||
#include "nvim/state.h"
|
#include "nvim/state.h"
|
||||||
#include "nvim/strings.h"
|
#include "nvim/strings.h"
|
||||||
@@ -36,10 +38,9 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// The character for each menu mode
|
/// 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_notsubmenu[] = N_("E327: Part of menu-item path is not sub-menu");
|
||||||
static char e_othermode[] = N_("E328: Menu only exists in another mode");
|
|
||||||
static char e_nomenu[] = N_("E329: No menu \"%s\"");
|
static char e_nomenu[] = N_("E329: No menu \"%s\"");
|
||||||
|
|
||||||
// Return true if "name" is a window toolbar menu name.
|
// Return true if "name" is a window toolbar menu name.
|
||||||
@@ -571,7 +572,7 @@ static int remove_menu(vimmenu_T **menup, char *name, int modes, bool silent)
|
|||||||
}
|
}
|
||||||
} else if (*name != NUL) {
|
} else if (*name != NUL) {
|
||||||
if (!silent) {
|
if (!silent) {
|
||||||
emsg(_(e_othermode));
|
emsg(_(e_menuothermode));
|
||||||
}
|
}
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
@@ -723,7 +724,7 @@ static dict_T *menu_get_recursive(const vimmenu_T *menu, int modes)
|
|||||||
(menu->noremap[bit] & REMAP_NONE) ? 1 : 0);
|
(menu->noremap[bit] & REMAP_NONE) ? 1 : 0);
|
||||||
tv_dict_add_nr(impl, S_LEN("sid"),
|
tv_dict_add_nr(impl, S_LEN("sid"),
|
||||||
(menu->noremap[bit] & REMAP_SCRIPT) ? 1 : 0);
|
(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 {
|
} else {
|
||||||
@@ -785,7 +786,7 @@ static vimmenu_T *find_menu(vimmenu_T *menu, char *name, int modes)
|
|||||||
emsg(_(e_notsubmenu));
|
emsg(_(e_notsubmenu));
|
||||||
return NULL;
|
return NULL;
|
||||||
} else if ((menu->modes & modes) == 0x0) {
|
} else if ((menu->modes & modes) == 0x0) {
|
||||||
emsg(_(e_othermode));
|
emsg(_(e_menuothermode));
|
||||||
return NULL;
|
return NULL;
|
||||||
} else if (*p == NUL) { // found a full match
|
} else if (*p == NUL) { // found a full match
|
||||||
return menu;
|
return menu;
|
||||||
@@ -859,7 +860,7 @@ static void show_menus_recursive(vimmenu_T *menu, int modes, int depth)
|
|||||||
for (i = 0; i < depth + 2; i++) {
|
for (i = 0; i < depth + 2; i++) {
|
||||||
msg_puts(" ");
|
msg_puts(" ");
|
||||||
}
|
}
|
||||||
msg_putchar(menu_mode_chars[bit]);
|
msg_puts(menu_mode_chars[bit]);
|
||||||
if (menu->noremap[bit] == REMAP_NONE) {
|
if (menu->noremap[bit] == REMAP_NONE) {
|
||||||
msg_putchar('*');
|
msg_putchar('*');
|
||||||
} else if (menu->noremap[bit] == REMAP_SCRIPT) {
|
} else if (menu->noremap[bit] == REMAP_SCRIPT) {
|
||||||
@@ -1213,6 +1214,11 @@ int get_menu_cmd_modes(const char *cmd, bool forceit, int *noremap, int *unmenu)
|
|||||||
modes = MENU_INSERT_MODE;
|
modes = MENU_INSERT_MODE;
|
||||||
break;
|
break;
|
||||||
case 't':
|
case 't':
|
||||||
|
if (*cmd == 'l') { // tlmenu, tlunmenu, tlnoremenu
|
||||||
|
modes = MENU_TERMINAL_MODE;
|
||||||
|
cmd++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
modes = MENU_TIP_MODE; // tmenu
|
modes = MENU_TIP_MODE; // tmenu
|
||||||
break;
|
break;
|
||||||
case 'c': // cmenu
|
case 'c': // cmenu
|
||||||
@@ -1259,9 +1265,13 @@ static char *popup_mode_name(char *name, int idx)
|
|||||||
size_t len = STRLEN(name);
|
size_t len = STRLEN(name);
|
||||||
assert(len >= 4);
|
assert(len >= 4);
|
||||||
|
|
||||||
char *p = xstrnsave(name, len + 1);
|
char *mode_chars = menu_mode_chars[idx];
|
||||||
memmove(p + 6, p + 5, len - 4);
|
size_t mode_chars_len = strlen(mode_chars);
|
||||||
p[5] = menu_mode_chars[idx];
|
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;
|
return p;
|
||||||
}
|
}
|
||||||
@@ -1355,77 +1365,143 @@ static int menu_is_hidden(char *name)
|
|||||||
|| (menu_is_popup(name) && name[5] != NUL);
|
|| (menu_is_popup(name) && name[5] != NUL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute "menu". Use by ":emenu" and the window toolbar.
|
static int get_menu_mode(void)
|
||||||
// "eap" is NULL for the window toolbar.
|
{
|
||||||
static void execute_menu(const exarg_T *eap, vimmenu_T *menu)
|
if (State & MODE_TERMINAL) {
|
||||||
|
return MENU_INDEX_TERMINAL;
|
||||||
|
}
|
||||||
|
if (VIsual_active) {
|
||||||
|
if (VIsual_select) {
|
||||||
|
return MENU_INDEX_SELECT;
|
||||||
|
}
|
||||||
|
return MENU_INDEX_VISUAL;
|
||||||
|
}
|
||||||
|
if (State & MODE_INSERT) {
|
||||||
|
return MENU_INDEX_INSERT;
|
||||||
|
}
|
||||||
|
if ((State & MODE_CMDLINE) || State == MODE_ASKMORE || State == MODE_HITRETURN) {
|
||||||
|
return MENU_INDEX_CMDLINE;
|
||||||
|
}
|
||||||
|
if (finish_op) {
|
||||||
|
return MENU_INDEX_OP_PENDING;
|
||||||
|
}
|
||||||
|
if (State & MODE_NORMAL) {
|
||||||
|
return MENU_INDEX_NORMAL;
|
||||||
|
}
|
||||||
|
if (State & MODE_LANGMAP) { // must be a "r" command, like Insert mode
|
||||||
|
return MENU_INDEX_INSERT;
|
||||||
|
}
|
||||||
|
return MENU_INDEX_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_menu_mode_flag(void)
|
||||||
|
{
|
||||||
|
int mode = get_menu_mode();
|
||||||
|
|
||||||
|
if (mode == MENU_INDEX_INVALID) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1 << mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Display the Special "PopUp" menu as a pop-up at the current mouse
|
||||||
|
/// position. The "PopUpn" menu is for Normal mode, "PopUpi" for Insert mode,
|
||||||
|
/// etc.
|
||||||
|
void show_popupmenu(void)
|
||||||
|
{
|
||||||
|
int menu_mode = get_menu_mode();
|
||||||
|
if (menu_mode == MENU_INDEX_INVALID) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
char *mode = menu_mode_chars[menu_mode];
|
||||||
|
size_t mode_len = strlen(mode);
|
||||||
|
|
||||||
|
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 && STRNCMP(menu->name + 5, mode, mode_len) == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only show a popup when it is defined and has entries
|
||||||
|
if (menu != NULL && menu->children != NULL) {
|
||||||
|
pum_show_popupmenu(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)
|
FUNC_ATTR_NONNULL_ARG(2)
|
||||||
{
|
{
|
||||||
int idx = -1;
|
int idx = mode_idx;
|
||||||
char *mode;
|
|
||||||
|
|
||||||
// Use the Insert mode entry when returning to Insert mode.
|
if (idx < 0) {
|
||||||
if (((State & MODE_INSERT) || restart_edit) && !current_sctx.sc_sid) {
|
// Use the Insert mode entry when returning to Insert mode.
|
||||||
mode = "Insert";
|
if (((State & MODE_INSERT) || restart_edit) && !current_sctx.sc_sid) {
|
||||||
idx = MENU_INDEX_INSERT;
|
idx = MENU_INDEX_INSERT;
|
||||||
} else if (State & MODE_CMDLINE) {
|
} else if (State & MODE_CMDLINE) {
|
||||||
mode = "Command";
|
idx = MENU_INDEX_CMDLINE;
|
||||||
idx = MENU_INDEX_CMDLINE;
|
} else if (State & MODE_TERMINAL) {
|
||||||
} else if (get_real_state() & MODE_VISUAL) {
|
idx = MENU_INDEX_TERMINAL;
|
||||||
// Detect real visual mode -- if we are really in visual mode we
|
} else if (get_real_state() & MODE_VISUAL) {
|
||||||
// don't need to do any guesswork to figure out what the selection
|
// Detect real visual mode -- if we are really in visual mode we
|
||||||
// is. Just execute the visual binding for the menu.
|
// don't need to do any guesswork to figure out what the selection
|
||||||
mode = "Visual";
|
// is. Just execute the visual binding for the menu.
|
||||||
idx = MENU_INDEX_VISUAL;
|
idx = MENU_INDEX_VISUAL;
|
||||||
} else if (eap != NULL && eap->addr_count) {
|
} else if (eap != NULL && eap->addr_count) {
|
||||||
pos_T tpos;
|
pos_T tpos;
|
||||||
|
|
||||||
mode = "Visual";
|
idx = MENU_INDEX_VISUAL;
|
||||||
idx = MENU_INDEX_VISUAL;
|
|
||||||
|
|
||||||
// GEDDES: This is not perfect - but it is a
|
// GEDDES: This is not perfect - but it is a
|
||||||
// quick way of detecting whether we are doing this from a
|
// quick way of detecting whether we are doing this from a
|
||||||
// selection - see if the range matches up with the visual
|
// selection - see if the range matches up with the visual
|
||||||
// select start and end.
|
// select start and end.
|
||||||
if ((curbuf->b_visual.vi_start.lnum == eap->line1)
|
if ((curbuf->b_visual.vi_start.lnum == eap->line1)
|
||||||
&& (curbuf->b_visual.vi_end.lnum) == eap->line2) {
|
&& (curbuf->b_visual.vi_end.lnum) == eap->line2) {
|
||||||
// Set it up for visual mode - equivalent to gv.
|
// Set it up for visual mode - equivalent to gv.
|
||||||
VIsual_mode = curbuf->b_visual.vi_mode;
|
VIsual_mode = curbuf->b_visual.vi_mode;
|
||||||
tpos = curbuf->b_visual.vi_end;
|
tpos = curbuf->b_visual.vi_end;
|
||||||
curwin->w_cursor = curbuf->b_visual.vi_start;
|
curwin->w_cursor = curbuf->b_visual.vi_start;
|
||||||
curwin->w_curswant = curbuf->b_visual.vi_curswant;
|
curwin->w_curswant = curbuf->b_visual.vi_curswant;
|
||||||
} else {
|
} else {
|
||||||
// Set it up for line-wise visual mode
|
// Set it up for line-wise visual mode
|
||||||
VIsual_mode = 'V';
|
VIsual_mode = 'V';
|
||||||
curwin->w_cursor.lnum = eap->line1;
|
curwin->w_cursor.lnum = eap->line1;
|
||||||
curwin->w_cursor.col = 1;
|
curwin->w_cursor.col = 1;
|
||||||
tpos.lnum = eap->line2;
|
tpos.lnum = eap->line2;
|
||||||
tpos.col = MAXCOL;
|
tpos.col = MAXCOL;
|
||||||
tpos.coladd = 0;
|
tpos.coladd = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Activate visual mode
|
// Activate visual mode
|
||||||
VIsual_active = TRUE;
|
VIsual_active = true;
|
||||||
VIsual_reselect = TRUE;
|
VIsual_reselect = true;
|
||||||
check_cursor();
|
check_cursor();
|
||||||
VIsual = curwin->w_cursor;
|
VIsual = curwin->w_cursor;
|
||||||
curwin->w_cursor = tpos;
|
curwin->w_cursor = tpos;
|
||||||
|
|
||||||
check_cursor();
|
check_cursor();
|
||||||
|
|
||||||
// Adjust the cursor to make sure it is in the correct pos
|
// Adjust the cursor to make sure it is in the correct pos
|
||||||
// for exclusive mode
|
// for exclusive mode
|
||||||
if (*p_sel == 'e' && gchar_cursor() != NUL) {
|
if (*p_sel == 'e' && gchar_cursor() != NUL) {
|
||||||
curwin->w_cursor.col++;
|
curwin->w_cursor.col++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (idx == -1 || eap == NULL) {
|
if (idx == -1 || eap == NULL) {
|
||||||
mode = "Normal";
|
|
||||||
idx = MENU_INDEX_NORMAL;
|
idx = MENU_INDEX_NORMAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(idx != MENU_INDEX_INVALID);
|
assert(idx != MENU_INDEX_INVALID);
|
||||||
if (menu->strings[idx] != NULL) {
|
if (menu->strings[idx] != NULL && (menu->modes & (1 << idx))) {
|
||||||
// When executing a script or function execute the commands right now.
|
// When executing a script or function execute the commands right now.
|
||||||
// Also for the window toolbar
|
// Also for the window toolbar
|
||||||
// Otherwise put them in the typeahead buffer.
|
// Otherwise put them in the typeahead buffer.
|
||||||
@@ -1444,6 +1520,30 @@ static void execute_menu(const exarg_T *eap, vimmenu_T *menu)
|
|||||||
menu->silent[idx]);
|
menu->silent[idx]);
|
||||||
}
|
}
|
||||||
} else if (eap != NULL) {
|
} 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);
|
semsg(_("E335: Menu not defined for %s mode"), mode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1452,9 +1552,43 @@ static void execute_menu(const exarg_T *eap, vimmenu_T *menu)
|
|||||||
// execute it.
|
// execute it.
|
||||||
void ex_emenu(exarg_T *eap)
|
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);
|
vimmenu_T *menu = *get_root_menu(saved_name);
|
||||||
char *name = saved_name;
|
char *name = saved_name;
|
||||||
|
bool gave_emsg = false;
|
||||||
while (*name) {
|
while (*name) {
|
||||||
// Find in the menu hierarchy
|
// Find in the menu hierarchy
|
||||||
char *p = menu_name_skip(name);
|
char *p = menu_name_skip(name);
|
||||||
@@ -1463,6 +1597,7 @@ void ex_emenu(exarg_T *eap)
|
|||||||
if (menu_name_equal(name, menu)) {
|
if (menu_name_equal(name, menu)) {
|
||||||
if (*p == NUL && menu->children != NULL) {
|
if (*p == NUL && menu->children != NULL) {
|
||||||
emsg(_("E333: Menu path must lead to a menu item"));
|
emsg(_("E333: Menu path must lead to a menu item"));
|
||||||
|
gave_emsg = true;
|
||||||
menu = NULL;
|
menu = NULL;
|
||||||
} else if (*p != NUL && menu->children == NULL) {
|
} else if (*p != NUL && menu->children == NULL) {
|
||||||
emsg(_(e_notsubmenu));
|
emsg(_(e_notsubmenu));
|
||||||
@@ -1480,12 +1615,60 @@ void ex_emenu(exarg_T *eap)
|
|||||||
}
|
}
|
||||||
xfree(saved_name);
|
xfree(saved_name);
|
||||||
if (menu == NULL) {
|
if (menu == NULL) {
|
||||||
semsg(_("E334: Menu not found: %s"), eap->arg);
|
if (!gave_emsg) {
|
||||||
|
semsg(_("E334: Menu not found: %s"), arg);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Found the menu, so execute.
|
// 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.
|
||||||
|
vimmenu_T *menu_find(const char *path_name)
|
||||||
|
{
|
||||||
|
vimmenu_T *menu = *get_root_menu(path_name);
|
||||||
|
char *saved_name = xstrdup(path_name);
|
||||||
|
char *name = saved_name;
|
||||||
|
while (*name) {
|
||||||
|
// find the end of one dot-separated name and put a NUL at the dot
|
||||||
|
char *p = menu_name_skip(name);
|
||||||
|
|
||||||
|
while (menu != NULL) {
|
||||||
|
if (menu_name_equal(name, menu)) {
|
||||||
|
if (menu->children == NULL) {
|
||||||
|
// found a menu item instead of a sub-menu
|
||||||
|
if (*p == NUL) {
|
||||||
|
emsg(_("E336: Menu path must lead to a sub-menu"));
|
||||||
|
} else {
|
||||||
|
emsg(_(e_notsubmenu));
|
||||||
|
}
|
||||||
|
menu = NULL;
|
||||||
|
goto theend;
|
||||||
|
}
|
||||||
|
if (*p == NUL) { // found a full match
|
||||||
|
goto theend;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
menu = menu->next;
|
||||||
|
}
|
||||||
|
if (menu == NULL) { // didn't find it
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Found a match, search the sub-menu.
|
||||||
|
menu = menu->children;
|
||||||
|
name = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (menu == NULL) {
|
||||||
|
emsg(_("E337: Menu not found - check menu names"));
|
||||||
|
}
|
||||||
|
theend:
|
||||||
|
xfree(saved_name);
|
||||||
|
return menu;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#define MENU_OP_PENDING_MODE (1 << MENU_INDEX_OP_PENDING)
|
#define MENU_OP_PENDING_MODE (1 << MENU_INDEX_OP_PENDING)
|
||||||
#define MENU_INSERT_MODE (1 << MENU_INDEX_INSERT)
|
#define MENU_INSERT_MODE (1 << MENU_INDEX_INSERT)
|
||||||
#define MENU_CMDLINE_MODE (1 << MENU_INDEX_CMDLINE)
|
#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_TIP_MODE (1 << MENU_INDEX_TIP)
|
||||||
#define MENU_ALL_MODES ((1 << MENU_INDEX_TIP) - 1)
|
#define MENU_ALL_MODES ((1 << MENU_INDEX_TIP) - 1)
|
||||||
/// @}
|
/// @}
|
||||||
|
|||||||
@@ -30,6 +30,49 @@
|
|||||||
static linenr_T orig_topline = 0;
|
static linenr_T orig_topline = 0;
|
||||||
static int orig_topfill = 0;
|
static int orig_topfill = 0;
|
||||||
|
|
||||||
|
/// Translate window coordinates to buffer position without any side effects
|
||||||
|
int get_fpos_of_mouse(pos_T *mpos)
|
||||||
|
{
|
||||||
|
int grid = mouse_grid;
|
||||||
|
int row = mouse_row;
|
||||||
|
int col = mouse_col;
|
||||||
|
|
||||||
|
if (row < 0 || col < 0) { // check if it makes sense
|
||||||
|
return IN_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find the window where the row is in
|
||||||
|
win_T *wp = mouse_find_win(&grid, &row, &col);
|
||||||
|
if (wp == NULL) {
|
||||||
|
return IN_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
// winpos and height may change in win_enter()!
|
||||||
|
if (row + wp->w_winbar_height >= wp->w_height) { // In (or below) status line
|
||||||
|
return IN_STATUS_LINE;
|
||||||
|
}
|
||||||
|
if (col >= wp->w_width) { // In vertical separator line
|
||||||
|
return IN_SEP_LINE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wp != curwin) {
|
||||||
|
return IN_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute the position in the buffer line from the posn on the screen
|
||||||
|
if (mouse_comp_pos(curwin, &row, &col, &mpos->lnum)) {
|
||||||
|
return IN_STATUS_LINE; // past bottom
|
||||||
|
}
|
||||||
|
|
||||||
|
mpos->col = vcol2col(wp, mpos->lnum, col);
|
||||||
|
|
||||||
|
if (mpos->col > 0) {
|
||||||
|
mpos->col--;
|
||||||
|
}
|
||||||
|
mpos->coladd = 0;
|
||||||
|
return IN_BUFFER;
|
||||||
|
}
|
||||||
|
|
||||||
/// Return true if "c" is a mouse key.
|
/// Return true if "c" is a mouse key.
|
||||||
bool is_mouse_key(int c)
|
bool is_mouse_key(int c)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1493,12 +1493,12 @@ static void call_click_def_func(StlClickDefinition *click_defs, int col, int whi
|
|||||||
/// Do the appropriate action for the current mouse click in the current mode.
|
/// Do the appropriate action for the current mouse click in the current mode.
|
||||||
/// Not used for Command-line mode.
|
/// Not used for Command-line mode.
|
||||||
///
|
///
|
||||||
/// Normal Mode:
|
/// Normal and Visual Mode:
|
||||||
/// event modi- position visual change action
|
/// event modi- position visual change action
|
||||||
/// fier cursor window
|
/// fier cursor window
|
||||||
/// left press - yes end yes
|
/// left press - yes end yes
|
||||||
/// left press C yes end yes "^]" (2)
|
/// left press C yes end yes "^]" (2)
|
||||||
/// left press S yes end yes "*" (2)
|
/// left press S yes end (popup: extend) yes "*" (2)
|
||||||
/// left drag - yes start if moved no
|
/// left drag - yes start if moved no
|
||||||
/// left relse - yes start if moved no
|
/// left relse - yes start if moved no
|
||||||
/// middle press - yes if not active no put register
|
/// middle press - yes if not active no put register
|
||||||
@@ -1787,9 +1787,52 @@ bool do_mouse(oparg_T *oap, int c, int dir, long count, bool fixindent)
|
|||||||
if (mouse_model_popup()) {
|
if (mouse_model_popup()) {
|
||||||
if (which_button == MOUSE_RIGHT
|
if (which_button == MOUSE_RIGHT
|
||||||
&& !(mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))) {
|
&& !(mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))) {
|
||||||
// NOTE: Ignore right button down and drag mouse events. Windows only
|
if (!is_click) {
|
||||||
// shows the popup menu on the button up event.
|
// Ignore right button release events, only shows the popup
|
||||||
return false;
|
// menu on the button down event.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
jump_flags = 0;
|
||||||
|
if (STRCMP(p_mousem, "popup_setpos") == 0) {
|
||||||
|
// First set the cursor position before showing the popup
|
||||||
|
// menu.
|
||||||
|
if (VIsual_active) {
|
||||||
|
pos_T m_pos;
|
||||||
|
// set MOUSE_MAY_STOP_VIS if we are outside the
|
||||||
|
// selection or the current window (might have false
|
||||||
|
// negative here)
|
||||||
|
if (mouse_row < curwin->w_winrow
|
||||||
|
|| mouse_row > (curwin->w_winrow + curwin->w_height)) {
|
||||||
|
jump_flags = MOUSE_MAY_STOP_VIS;
|
||||||
|
} else if (get_fpos_of_mouse(&m_pos) != IN_BUFFER) {
|
||||||
|
jump_flags = MOUSE_MAY_STOP_VIS;
|
||||||
|
} else {
|
||||||
|
if ((lt(curwin->w_cursor, VIsual)
|
||||||
|
&& (lt(m_pos, curwin->w_cursor) || lt(VIsual, m_pos)))
|
||||||
|
|| (lt(VIsual, curwin->w_cursor)
|
||||||
|
&& (lt(m_pos, VIsual) || lt(curwin->w_cursor, m_pos)))) {
|
||||||
|
jump_flags = MOUSE_MAY_STOP_VIS;
|
||||||
|
} else if (VIsual_mode == Ctrl_V) {
|
||||||
|
getvcols(curwin, &curwin->w_cursor, &VIsual, &leftcol, &rightcol);
|
||||||
|
getvcol(curwin, &m_pos, NULL, &m_pos.col, NULL);
|
||||||
|
if (m_pos.col < leftcol || m_pos.col > rightcol) {
|
||||||
|
jump_flags = MOUSE_MAY_STOP_VIS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
jump_flags = MOUSE_MAY_STOP_VIS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (jump_flags) {
|
||||||
|
jump_flags = jump_to_mouse(jump_flags, NULL, which_button);
|
||||||
|
update_curbuf(VIsual_active ? INVERTED : VALID);
|
||||||
|
setcursor();
|
||||||
|
ui_flush(); // Update before showing popup menu
|
||||||
|
}
|
||||||
|
show_popupmenu();
|
||||||
|
got_click = false; // ignore release events
|
||||||
|
return (jump_flags & CURSOR_MOVED) != 0;
|
||||||
}
|
}
|
||||||
if (which_button == MOUSE_LEFT
|
if (which_button == MOUSE_LEFT
|
||||||
&& (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_ALT))) {
|
&& (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_ALT))) {
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include "nvim/ex_cmds.h"
|
#include "nvim/ex_cmds.h"
|
||||||
#include "nvim/memline.h"
|
#include "nvim/memline.h"
|
||||||
#include "nvim/memory.h"
|
#include "nvim/memory.h"
|
||||||
|
#include "nvim/menu.h"
|
||||||
#include "nvim/move.h"
|
#include "nvim/move.h"
|
||||||
#include "nvim/option.h"
|
#include "nvim/option.h"
|
||||||
#include "nvim/popupmnu.h"
|
#include "nvim/popupmnu.h"
|
||||||
@@ -512,9 +513,13 @@ void pum_redraw(void)
|
|||||||
char_u *st;
|
char_u *st;
|
||||||
char_u saved = *p;
|
char_u saved = *p;
|
||||||
|
|
||||||
*p = NUL;
|
if (saved != NUL) {
|
||||||
|
*p = NUL;
|
||||||
|
}
|
||||||
st = (char_u *)transstr((const char *)s, true);
|
st = (char_u *)transstr((const char *)s, true);
|
||||||
*p = saved;
|
if (saved != NUL) {
|
||||||
|
*p = saved;
|
||||||
|
}
|
||||||
|
|
||||||
if (pum_rl) {
|
if (pum_rl) {
|
||||||
char *rt = (char *)reverse_text(st);
|
char *rt = (char *)reverse_text(st);
|
||||||
@@ -932,3 +937,181 @@ void pum_set_event_info(dict_T *dict)
|
|||||||
(void)tv_dict_add_bool(dict, S_LEN("scrollbar"),
|
(void)tv_dict_add_bool(dict, S_LEN("scrollbar"),
|
||||||
pum_scrollbar ? kBoolVarTrue : kBoolVarFalse);
|
pum_scrollbar ? kBoolVarTrue : kBoolVarFalse);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void pum_position_at_mouse(int min_width)
|
||||||
|
{
|
||||||
|
pum_anchor_grid = mouse_grid;
|
||||||
|
if (Rows - mouse_row > pum_size) {
|
||||||
|
// Enough space below the mouse row.
|
||||||
|
pum_above = false;
|
||||||
|
pum_row = mouse_row + 1;
|
||||||
|
if (pum_height > Rows - pum_row) {
|
||||||
|
pum_height = Rows - pum_row;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Show above the mouse row, reduce height if it does not fit.
|
||||||
|
pum_above = true;
|
||||||
|
pum_row = mouse_row - pum_size;
|
||||||
|
if (pum_row < 0) {
|
||||||
|
pum_height += pum_row;
|
||||||
|
pum_row = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Columns - mouse_col >= pum_base_width || Columns - mouse_col > min_width) {
|
||||||
|
// Enough space to show at mouse column.
|
||||||
|
pum_col = mouse_col;
|
||||||
|
} else {
|
||||||
|
// Not enough space, right align with window.
|
||||||
|
pum_col = Columns - (pum_base_width > min_width ? min_width : pum_base_width);
|
||||||
|
}
|
||||||
|
|
||||||
|
pum_width = Columns - pum_col;
|
||||||
|
if (pum_width > pum_base_width + 1) {
|
||||||
|
pum_width = pum_base_width + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Select the pum entry at the mouse position.
|
||||||
|
static void pum_select_mouse_pos(void)
|
||||||
|
{
|
||||||
|
if (mouse_grid == pum_grid.handle) {
|
||||||
|
pum_selected = mouse_row;
|
||||||
|
return;
|
||||||
|
} else if (mouse_grid > 1) {
|
||||||
|
pum_selected = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int idx = mouse_row - pum_row;
|
||||||
|
|
||||||
|
if (idx < 0 || idx >= pum_size) {
|
||||||
|
pum_selected = -1;
|
||||||
|
} else if (*pum_array[idx].pum_text != NUL) {
|
||||||
|
pum_selected = idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Execute the currently selected popup menu item.
|
||||||
|
static void pum_execute_menu(vimmenu_T *menu, int mode)
|
||||||
|
{
|
||||||
|
int idx = 0;
|
||||||
|
exarg_T ea;
|
||||||
|
|
||||||
|
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, -1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Open the terminal version of the popup menu and don't return until it is closed.
|
||||||
|
void pum_show_popupmenu(vimmenu_T *menu)
|
||||||
|
{
|
||||||
|
pum_undisplay(true);
|
||||||
|
pum_size = 0;
|
||||||
|
int mode = get_menu_mode_flag();
|
||||||
|
|
||||||
|
for (vimmenu_T *mp = menu->children; mp != NULL; mp = mp->next) {
|
||||||
|
if (menu_is_separator(mp->dname) || (mp->modes & mp->enabled & mode)) {
|
||||||
|
pum_size++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// When there are only Terminal mode menus, using "popup Edit" results in
|
||||||
|
// pum_size being zero.
|
||||||
|
if (pum_size <= 0) {
|
||||||
|
emsg(e_menuothermode);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int idx = 0;
|
||||||
|
pumitem_T *array = (pumitem_T *)xcalloc((size_t)pum_size, sizeof(pumitem_T));
|
||||||
|
|
||||||
|
for (vimmenu_T *mp = menu->children; mp != NULL; mp = mp->next) {
|
||||||
|
if (menu_is_separator(mp->dname)) {
|
||||||
|
array[idx++].pum_text = (char_u *)"";
|
||||||
|
} else if (mp->modes & mp->enabled & mode) {
|
||||||
|
array[idx++].pum_text = (char_u *)mp->dname;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pum_array = array;
|
||||||
|
pum_compute_size();
|
||||||
|
pum_scrollbar = 0;
|
||||||
|
pum_height = pum_size;
|
||||||
|
pum_position_at_mouse(20);
|
||||||
|
|
||||||
|
pum_selected = -1;
|
||||||
|
pum_first = 0;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
pum_is_visible = true;
|
||||||
|
pum_is_drawn = true;
|
||||||
|
pum_redraw();
|
||||||
|
setcursor_mayforce(true);
|
||||||
|
ui_flush();
|
||||||
|
|
||||||
|
int c = vgetc();
|
||||||
|
if (c == ESC || c == Ctrl_C) {
|
||||||
|
break;
|
||||||
|
} else if (c == CAR || c == NL) {
|
||||||
|
// enter: select current item, if any, and close
|
||||||
|
pum_execute_menu(menu, mode);
|
||||||
|
break;
|
||||||
|
} else if (c == 'k' || c == K_UP || c == K_MOUSEUP) {
|
||||||
|
// cursor up: select previous item
|
||||||
|
while (pum_selected > 0) {
|
||||||
|
pum_selected--;
|
||||||
|
if (*array[pum_selected].pum_text != NUL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (c == 'j' || c == K_DOWN || c == K_MOUSEDOWN) {
|
||||||
|
// cursor down: select next item
|
||||||
|
while (pum_selected < pum_size - 1) {
|
||||||
|
pum_selected++;
|
||||||
|
if (*array[pum_selected].pum_text != NUL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (c == K_RIGHTMOUSE) {
|
||||||
|
// Right mouse down: reposition the menu.
|
||||||
|
vungetc(c);
|
||||||
|
break;
|
||||||
|
} else if (c == K_LEFTDRAG || c == K_RIGHTDRAG || c == K_MOUSEMOVE) {
|
||||||
|
// mouse moved: select item in the mouse row
|
||||||
|
pum_select_mouse_pos();
|
||||||
|
} else if (c == K_LEFTMOUSE || c == K_LEFTMOUSE_NM || c == K_RIGHTRELEASE) {
|
||||||
|
// left mouse click: select clicked item, if any, and close;
|
||||||
|
// right mouse release: select clicked item, close if any
|
||||||
|
pum_select_mouse_pos();
|
||||||
|
if (pum_selected >= 0) {
|
||||||
|
pum_execute_menu(menu, mode);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (c == K_LEFTMOUSE || c == K_LEFTMOUSE_NM) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
xfree(array);
|
||||||
|
pum_undisplay(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pum_make_popup(const char *path_name, int use_mouse_pos)
|
||||||
|
{
|
||||||
|
if (!use_mouse_pos) {
|
||||||
|
// Hack: set mouse position at the cursor so that the menu pops up
|
||||||
|
// around there.
|
||||||
|
mouse_row = curwin->w_winrow + curwin->w_wrow;
|
||||||
|
mouse_col = curwin->w_wincol + curwin->w_wcol;
|
||||||
|
}
|
||||||
|
|
||||||
|
vimmenu_T *menu = menu_find(path_name);
|
||||||
|
if (menu != NULL) {
|
||||||
|
pum_show_popupmenu(menu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -298,6 +298,13 @@ void redraw_win_signcol(win_T *wp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Update all windows that are editing the current buffer.
|
||||||
|
void update_curbuf(int type)
|
||||||
|
{
|
||||||
|
redraw_curbuf_later(type);
|
||||||
|
update_screen(type);
|
||||||
|
}
|
||||||
|
|
||||||
/// Redraw the parts of the screen that is marked for redraw.
|
/// Redraw the parts of the screen that is marked for redraw.
|
||||||
///
|
///
|
||||||
/// Most code shouldn't call this directly, rather use redraw_later() and
|
/// Most code shouldn't call this directly, rather use redraw_later() and
|
||||||
@@ -5750,12 +5757,17 @@ static void linecopy(ScreenGrid *grid, int to, int from, int col, int width)
|
|||||||
width * sizeof(sattr_T));
|
width * sizeof(sattr_T));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/// Set cursor to its position in the current window.
|
||||||
* Set cursor to its position in the current window.
|
|
||||||
*/
|
|
||||||
void setcursor(void)
|
void setcursor(void)
|
||||||
{
|
{
|
||||||
if (redrawing()) {
|
setcursor_mayforce(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set cursor to its position in the current window.
|
||||||
|
/// @param force when true, also when not redrawing.
|
||||||
|
void setcursor_mayforce(bool force)
|
||||||
|
{
|
||||||
|
if (force || redrawing()) {
|
||||||
validate_cursor();
|
validate_cursor();
|
||||||
|
|
||||||
ScreenGrid *grid = &curwin->w_grid;
|
ScreenGrid *grid = &curwin->w_grid;
|
||||||
|
|||||||
@@ -36,3 +36,52 @@ func Test_translate_menu()
|
|||||||
|
|
||||||
source $VIMRUNTIME/delmenu.vim
|
source $VIMRUNTIME/delmenu.vim
|
||||||
endfunc
|
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)
|
||||||
|
|
||||||
|
nunmenu Test.FooBar
|
||||||
|
call assert_fails('emenu n Test.FooBar', 'E335: Menu not defined for Normal mode')
|
||||||
|
vunmenu Test.FooBar
|
||||||
|
call assert_fails('emenu v Test.FooBar', 'E335: Menu not defined for Visual mode')
|
||||||
|
vmenu 2 Test.FooBar :let g:did_menu = 'visual'<CR>
|
||||||
|
sunmenu Test.FooBar
|
||||||
|
call assert_fails('emenu s Test.FooBar', 'E335: Menu not defined for Select mode')
|
||||||
|
ounmenu Test.FooBar
|
||||||
|
call assert_fails('emenu o Test.FooBar', 'E335: Menu not defined for Op-pending mode')
|
||||||
|
iunmenu Test.FooBar
|
||||||
|
call assert_fails('emenu i Test.FooBar', 'E335: Menu not defined for Insert mode')
|
||||||
|
cunmenu Test.FooBar
|
||||||
|
call assert_fails('emenu c Test.FooBar', 'E335: Menu not defined for Cmdline mode')
|
||||||
|
tlunmenu Test.FooBar
|
||||||
|
call assert_fails('emenu t Test.FooBar', 'E335: Menu not defined for Terminal mode')
|
||||||
|
|
||||||
|
aunmenu 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
|
||||||
|
|||||||
@@ -913,7 +913,7 @@ func Test_popup_complete_backwards_ctrl_p()
|
|||||||
bwipe!
|
bwipe!
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
fun! Test_complete_o_tab()
|
func Test_complete_o_tab()
|
||||||
CheckFunction test_override
|
CheckFunction test_override
|
||||||
let s:o_char_pressed = 0
|
let s:o_char_pressed = 0
|
||||||
|
|
||||||
@@ -922,7 +922,7 @@ fun! Test_complete_o_tab()
|
|||||||
let s:o_char_pressed = 0
|
let s:o_char_pressed = 0
|
||||||
call feedkeys("\<c-x>\<c-n>", 'i')
|
call feedkeys("\<c-x>\<c-n>", 'i')
|
||||||
endif
|
endif
|
||||||
endf
|
endfunc
|
||||||
|
|
||||||
set completeopt=menu,noselect
|
set completeopt=menu,noselect
|
||||||
new
|
new
|
||||||
@@ -941,7 +941,21 @@ fun! Test_complete_o_tab()
|
|||||||
bwipe!
|
bwipe!
|
||||||
set completeopt&
|
set completeopt&
|
||||||
delfunc s:act_on_text_changed
|
delfunc s:act_on_text_changed
|
||||||
endf
|
endfunc
|
||||||
|
|
||||||
|
func Test_menu_only_exists_in_terminal()
|
||||||
|
if !exists(':tlmenu') || has('gui_running')
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
tlnoremenu &Edit.&Paste<Tab>"+gP <C-W>"+
|
||||||
|
aunmenu *
|
||||||
|
try
|
||||||
|
popup Edit
|
||||||
|
call assert_false(1, 'command should have failed')
|
||||||
|
catch
|
||||||
|
call assert_exception('E328:')
|
||||||
|
endtry
|
||||||
|
endfunc
|
||||||
|
|
||||||
func Test_popup_complete_info_01()
|
func Test_popup_complete_info_01()
|
||||||
new
|
new
|
||||||
|
|||||||
@@ -3748,7 +3748,7 @@ describe('API', function()
|
|||||||
eq("foo", meths.cmd({ cmd = "Foo" }, { output = true }))
|
eq("foo", meths.cmd({ cmd = "Foo" }, { output = true }))
|
||||||
end)
|
end)
|
||||||
it('errors if command is not implemented', function()
|
it('errors if command is not implemented', function()
|
||||||
eq("Command not implemented: popup", pcall_err(meths.cmd, { cmd = "popup" }, {}))
|
eq("Command not implemented: winpos", pcall_err(meths.cmd, { cmd = "winpos" }, {}))
|
||||||
end)
|
end)
|
||||||
it('works with empty arguments list', function()
|
it('works with empty arguments list', function()
|
||||||
meths.cmd({ cmd = "update" }, {})
|
meths.cmd({ cmd = "update" }, {})
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ local get_pathsep = helpers.get_pathsep
|
|||||||
local eq = helpers.eq
|
local eq = helpers.eq
|
||||||
local pcall_err = helpers.pcall_err
|
local pcall_err = helpers.pcall_err
|
||||||
local exec_lua = helpers.exec_lua
|
local exec_lua = helpers.exec_lua
|
||||||
|
local exec = helpers.exec
|
||||||
|
|
||||||
describe('ui/ext_popupmenu', function()
|
describe('ui/ext_popupmenu', function()
|
||||||
local screen
|
local screen
|
||||||
@@ -2359,6 +2360,74 @@ describe('builtin popupmenu', function()
|
|||||||
{2:-- INSERT --} |
|
{2:-- INSERT --} |
|
||||||
]])
|
]])
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('supports mousemodel=popup', function()
|
||||||
|
screen:try_resize(32, 6)
|
||||||
|
exec([[
|
||||||
|
call setline(1, 'popup menu test')
|
||||||
|
set mouse=a mousemodel=popup
|
||||||
|
|
||||||
|
menu PopUp.foo :let g:menustr = 'foo'<CR>
|
||||||
|
menu PopUp.bar :let g:menustr = 'bar'<CR>
|
||||||
|
menu PopUp.baz :let g:menustr = 'baz'<CR>
|
||||||
|
]])
|
||||||
|
meths.input_mouse('right', 'press', '', 0, 0, 4)
|
||||||
|
screen:expect([[
|
||||||
|
^popup menu test |
|
||||||
|
{1:~ }{n: foo }{1: }|
|
||||||
|
{1:~ }{n: bar }{1: }|
|
||||||
|
{1:~ }{n: baz }{1: }|
|
||||||
|
{1:~ }|
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
feed('<Down>')
|
||||||
|
screen:expect([[
|
||||||
|
^popup menu test |
|
||||||
|
{1:~ }{s: foo }{1: }|
|
||||||
|
{1:~ }{n: bar }{1: }|
|
||||||
|
{1:~ }{n: baz }{1: }|
|
||||||
|
{1:~ }|
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
feed('<Down>')
|
||||||
|
screen:expect([[
|
||||||
|
^popup menu test |
|
||||||
|
{1:~ }{n: foo }{1: }|
|
||||||
|
{1:~ }{s: bar }{1: }|
|
||||||
|
{1:~ }{n: baz }{1: }|
|
||||||
|
{1:~ }|
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
feed('<CR>')
|
||||||
|
screen:expect([[
|
||||||
|
^popup menu test |
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
:let g:menustr = 'bar' |
|
||||||
|
]])
|
||||||
|
eq('bar', meths.get_var('menustr'))
|
||||||
|
meths.input_mouse('right', 'press', '', 0, 1, 20)
|
||||||
|
screen:expect([[
|
||||||
|
^popup menu test |
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }{n: foo }{1: }|
|
||||||
|
{1:~ }{n: bar }{1: }|
|
||||||
|
{1:~ }{n: baz }{1: }|
|
||||||
|
:let g:menustr = 'bar' |
|
||||||
|
]])
|
||||||
|
meths.input_mouse('left', 'press', '', 0, 4, 22)
|
||||||
|
screen:expect([[
|
||||||
|
^popup menu test |
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
:let g:menustr = 'baz' |
|
||||||
|
]])
|
||||||
|
eq('baz', meths.get_var('menustr'))
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe('builtin popupmenu with ui/ext_multigrid', function()
|
describe('builtin popupmenu with ui/ext_multigrid', function()
|
||||||
@@ -2450,4 +2519,57 @@ describe('builtin popupmenu with ui/ext_multigrid', function()
|
|||||||
{n: 哦哦哦哦哦哦哦哦哦>}{s: }|
|
{n: 哦哦哦哦哦哦哦哦哦>}{s: }|
|
||||||
]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 11, false, 100}}})
|
]], float_pos={[4] = {{id = -1}, 'NW', 2, 1, 11, false, 100}}})
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('supports mousemodel=popup', function()
|
||||||
|
screen:try_resize(32, 6)
|
||||||
|
exec([[
|
||||||
|
call setline(1, 'popup menu test')
|
||||||
|
set mouse=a mousemodel=popup
|
||||||
|
|
||||||
|
menu PopUp.foo :let g:menustr = 'foo'<CR>
|
||||||
|
menu PopUp.bar :let g:menustr = 'bar'<CR>
|
||||||
|
menu PopUp.baz :let g:menustr = 'baz'<CR>
|
||||||
|
]])
|
||||||
|
meths.input_mouse('right', 'press', '', 2, 1, 20)
|
||||||
|
screen:expect({grid=[[
|
||||||
|
## grid 1
|
||||||
|
[2:--------------------------------]|
|
||||||
|
[2:--------------------------------]|
|
||||||
|
[2:--------------------------------]|
|
||||||
|
[2:--------------------------------]|
|
||||||
|
[2:--------------------------------]|
|
||||||
|
[3:--------------------------------]|
|
||||||
|
## grid 2
|
||||||
|
^popup menu test |
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
## grid 3
|
||||||
|
|
|
||||||
|
## grid 4
|
||||||
|
{n: foo }|
|
||||||
|
{n: bar }|
|
||||||
|
{n: baz }|
|
||||||
|
]], float_pos={[4] = {{id = -1}, 'NW', 2, 2, 19, false, 100}}})
|
||||||
|
meths.input_mouse('left', 'press', '', 4, 2, 2)
|
||||||
|
screen:expect({grid=[[
|
||||||
|
## grid 1
|
||||||
|
[2:--------------------------------]|
|
||||||
|
[2:--------------------------------]|
|
||||||
|
[2:--------------------------------]|
|
||||||
|
[2:--------------------------------]|
|
||||||
|
[2:--------------------------------]|
|
||||||
|
[3:--------------------------------]|
|
||||||
|
## grid 2
|
||||||
|
^popup menu test |
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
{1:~ }|
|
||||||
|
## grid 3
|
||||||
|
:let g:menustr = 'baz' |
|
||||||
|
]]})
|
||||||
|
eq('baz', meths.get_var('menustr'))
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
|||||||
Reference in New Issue
Block a user