-
-
Notifications
You must be signed in to change notification settings - Fork 6.3k
[RFC] implement <Cmd> key #4419
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
It is convenient, like how |
At least |
And |
Also it always ends operator-pending mode. It works to change We could allow a command to optionally not end operator-pending mode like |
I think it seems good feature. |
Given vim's recent work on channels and messaging it should likely also support "just executing a command" directly at any (mapped) input state (of implementation complexity I have no idea) But nvim's new state mechanism made this completely clear in neovim (sometimes, refactors make code easier to understand :) |
Works great, interesting. diff --git a/runtime/syntax/vim.vim b/runtime/syntax/vim.vim
index cf51830..215f213 100644
--- a/runtime/syntax/vim.vim
+++ b/runtime/syntax/vim.vim
@@ -307,11 +307,11 @@ syn keyword vimUnmap cu[nmap] iu[nmap] lu[nmap] nun[map] ou[nmap] sunm[ap] unm[
syn keyword nvimUnmap tunm[ap] skipwhite nextgroup=vimMapBang,vimMapMod,vimMapLhs
syn match vimMapLhs contained "\S\+" contains=vimNotation,vimCtrlChar skipwhite nextgroup=vimMapRhs
syn match vimMapBang contained "!" skipwhite nextgroup=vimMapMod,vimMapLhs
-syn match vimMapMod contained "\c<\(buffer\|expr\|\(local\)\=leader\|nowait\|plug\|script\|sid\|unique\|silent\)\+>" contains=vimMapModKey,vimMapModErr skipwhite nextgroup=vimMapMod,vimMapLhs
+syn match vimMapMod contained "\c<\(command\|buffer\|expr\|\(local\)\=leader\|nowait\|plug\|script\|sid\|unique\|silent\)\+>" contains=vimMapModKey,vimMapModErr skipwhite nextgroup=vimMapMod,vimMapLhs
syn match vimMapRhs contained ".*" contains=vimNotation,vimCtrlChar skipnl nextgroup=vimMapRhsExtend
syn match vimMapRhsExtend contained "^\s*\\.*$" contains=vimContinue
syn case ignore
-syn keyword vimMapModKey contained buffer expr leader localleader nowait plug script sid silent unique
+syn keyword vimMapModKey contained command buffer expr leader localleader nowait plug script sid silent unique
syn case match |
I haven't thought of the name really, maybe it should be |
src/nvim/eval.c
Outdated
@@ -12339,6 +12339,7 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact) | |||
dict_add_nr_str(dict, "rhs", 0L, mp->m_orig_str); | |||
dict_add_nr_str(dict, "noremap", mp->m_noremap ? 1L : 0L, NULL); | |||
dict_add_nr_str(dict, "expr", mp->m_expr ? 1L : 0L, NULL); | |||
dict_add_nr_str(dict, "command", mp->m_cmd ? 1L : 0L, NULL); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks shifted.
|
src/nvim/getchar.c
Outdated
@@ -2035,8 +2037,13 @@ static int vgetorpeek(int advance) | |||
save_m_str = vim_strsave(mp->m_str); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
switch (mp->m_type)
.
Thanks for the comments. Tests are missing as well... |
Tests I would write:
After adding all the tests I guess you would not think this PR is so simple. Expecting tests to find some bugs. |
Thanks for the laundry list. 👍 I should clarify: the "simplicity" is because were executing commands in contexts were we already are processing arbitrary commands (autocommands, rpc calls), so we already must have "reasonable" behavior for |
c60e4f2
to
6aa13ea
Compare
src/nvim/ex_getln.c
Outdated
} else if (s->c == K_COMMAND) { | ||
// NB: we use getexmodeline to not invoke K_COMMAND nestedly | ||
// but it should probably be "incomplete keyseq" state | ||
do_cmdline(NULL, getcmdkeycmd, NULL, 0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the comment mentions getexmodeline
, is it stale?
test/functional/ui/input_spec.lua
Outdated
eq(eval('m'), 't') | ||
end) | ||
|
||
it('behaves correctly in visual mode', function() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can just remove "behaves correctly" from these descriptions, it's redundant
test/functional/ui/input_spec.lua
Outdated
feed_command('noremap! '..lhs..' <Cmd>'..rhs..'<cr>') | ||
end | ||
|
||
cmdmap('<f3> ', 'let m = mode(1)') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is the space after <f3>
significant?
Is there a test for recursive nnoremap <f3> <cmd>foo<cr>
nmap <f4> <cmd><f3><cr> Is the list proposed by @ZyX-I in #4419 (comment) covered by the tests, or why not?
|
Recursive invocation is disabled, but I suppose a test should test exactly that. At a quick glance tests for
I would associate cmdline with cmdline mode, this is also what |
85a7383
to
29e4dc8
Compare
e967d20
to
81fbd1e
Compare
2530721
to
ae404da
Compare
@justinmk I think I've covered the entire list now. Also added quite a bit of screen tests, which makes it easier to see what the tests are doing, also because screen tests. |
if (s->c == K_EVENT) { | ||
multiqueue_process_events(main_loop.events); | ||
} else { | ||
do_cmdline(NULL, getcmdkeycmd, NULL, DOCMD_NOWAIT); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why DOCMD_NOWAIT here, but 0
in the insert_handle_key
case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because it displays error messages in a way that makes sense in the respective mode.
If you want the mapping to do any of these let the returned characters do | ||
that. | ||
that. Alternatively use a |<Cmd>| mapping which doesn't have these |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
<expr>
is not title-case so I guess <cmd>
should not be either.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But <Cmd>
is a special key, not a flag (yes, confusing to use <>
for both, but that's vim for you), so it should be title-case.
runtime/doc/map.txt
Outdated
noremap <f3> <Cmd>echo mode(1)<cr> | ||
|
||
*E5520* | ||
The command must be complete and ended with a `<Cr>`. If the command is |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't need backticks around keycodes in the help. Also it's spelled <CR>
everywhere, :helpgrep <Cr>
returns no results.
Should also use <CR>
in the error messages.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done so!
FEATURES: 3cc7ebf #7234 built-in VimL expression parser 6a7c904 #4419 implement <Cmd> key to invoke command in any mode b836328 #7679 'startup: treat stdin as text instead of commands' 58b210e :digraphs : highlight with hl-SpecialKey #2690 7a13611 #8276 'startup: Let `-s -` read from stdin' 1e71978 events: VimSuspend, VimResume #8280 1e7d5e8 #6272 'stdpath()' f96d99a #8247 server: introduce --listen e8c39f7 #8226 insert-mode: interpret unmapped META as ESC 98e7112 msg: do not scroll entire screen (#8088) f72630b #8055 let negative 'writedelay' show all redraws 5d2dd2e win: has("wsl") on Windows Subsystem for Linux #7330 a4f6cec cmdline: CmdlineEnter and CmdlineLeave autocommands (#7422) 207b7ca #6844 channels: support buffered output and bytes sockets/stdio API: f85cbea #7917 API: buffer updates 418abfc #6743 API: list information about all channels/jobs. 36b2e3f #8375 API: nvim_get_commands 273d2cd #8329 API: Make nvim_set_option() update `:verbose set …` 8d40b36 #8371 API: more reliable/descriptive VimL errors ebb1acb #8353 API: nvim_call_dict_function 9f994bb #8004 API: nvim_list_uis 3405704 #7520 API/UI: forward option updates to UIs 911b1e4 #7821 API: improve nvim_command_output WINDOWS OS: 9cefd83 #8084, #8516 build/win: support MSVC ee4e1fd win: Fix reading content from stdin (#8267) TUI: ffb8904 #8309 TUI: add support for mouse release events in urxvt 8d5a46e #8081 TUI: implement "standout" attribute 6071637 TUI: support TERM=konsole-256color 67848c0 #7653 TUI: report TUI info with -V3 ('verbose' >= 3) 3d0ee17 TUI/rxvt: enable focus-reporting d109f56 #7640 TUI: 'term' option: reflect effective terminal behavior FIXES: ed6a113 #8273 'job-control: avoid kill-timer race' 4e02f1a #8107 'jobs: separate process-group' 451c48a terminal: flush vterm output buffer on pty output #8486 5d6732f :checkhealth fixes #8335 53f11dc #8218 'Fix errors reported by PVS' d05712f inccommand: pause :terminal redraws (#8307) 51af911 inccommand: do not execute trailing commands #8256 84359a4 terminal: resize to the max dimensions (#8249) d49c1dd #8228 Make vim_fgets() return the same values as in Vim 60e96a4 screen: winhl=Normal:Background should not override syntax (#8093) 0c59ac1 #5908 'shada: Also save numbered marks' ba87a2c cscope: ignore EINTR while reading the prompt (#8079) b1412dc #7971 ':terminal Enter/Leave should not increment jumplist' 3a5721e TUI: libtermkey: force CSI driver for mouse input #7948 6ff13d7 #7720 TUI: faster startup 1c6e956 #7862 TUI: fix resize-related segfaults a58c909 #7676 TUI: always hide cursor when flushing, never flush buffers during unibilium output 303e1df #7624 TUI: disable BCE almost always 249bdb0 #7761 mark: Make sure that jumplist item will not have zero lnum 6f41ce0 #7704 macOS: Set $LANG based on the system locale a043899 #7633 'Retry fgets on EINTR' CHANGES: ad60927 #8304 default to 'nofsync' f3f1970 #8035 defaults: 'fillchars' a6052c7 #7984 defaults: sidescroll=1 b69fa86 #7888 defaults: enable cscopeverbose 7c4bb23 defaults: do :filetype stuff unless explicitly "off" 2aa308c #5658 'Apply :lmap in macros' 8ce6393 terminal: Leave 'relativenumber' alone (#8360) e46534b #4486 refactor: Remove maxmem, maxmemtot options 131aad9 win: defaults: 'shellcmdflag', 'shellxquote' #7343 c57d315 #8031 jobwait(): return -2 on interrupt also with timeout 6452831 clipboard: macOS: fallback to tmux if pbcopy is broken #7940 300d365 #7919 Make 'langnoremap' apply directly after a map ada1956 #7880 'lua/executor: Remove lightuserdata' INTERNAL: de0a954 #7806 internal statistics for list impl dee78a4 #7708 rewrite internal list impl
I'm not sure we actually want this, but implementation turned out to be surprisingly simple (probably due to the existing work on K_EVENT), so I thought the best way to spawn some discussion was to show a prototype.
The command will execute the same way as an autocommand or remote
vim_command
.I've tested serial and nested invocation works as expected.
Pros:
This allows you to do
and the command will actually be executed in visual mode if it is active so
mode()
showsv
. (and visual mode will not be left unless the command leaves it).Also this works: (compare
:help complete()
)Cons:
Doesn't really enable anything that can't already be done with
:map <expr>
,:imap <c-r>=...<cr>
or:map <c-u>...<cr>
with some quirks and workarounds. As it adds yet another mapping mode, mental overhead of implementing plugin mappings could just as well increase instead of decrease.vim might not add it, so it will result in an incompatibility. (I relied on neovim-isms to convince myself the semantics and implementation was sound)