mirror of
https://github.com/neovim/neovim.git
synced 2024-12-24 05:05:00 -07:00
feat(lua): pass keys before mapping to vim.on_key() callback (#28098)
Keys before mapping (i.e. typed keys) are passed as the second argument.
This commit is contained in:
parent
12240600f5
commit
e1ff2c51ca
@ -1640,12 +1640,14 @@ vim.on_key({fn}, {ns_id}) *vim.on_key()*
|
|||||||
Note: ~
|
Note: ~
|
||||||
• {fn} will be removed on error.
|
• {fn} will be removed on error.
|
||||||
• {fn} will not be cleared by |nvim_buf_clear_namespace()|
|
• {fn} will not be cleared by |nvim_buf_clear_namespace()|
|
||||||
• {fn} will receive the keys after mappings have been evaluated
|
|
||||||
|
|
||||||
Parameters: ~
|
Parameters: ~
|
||||||
• {fn} (`fun(key: string)?`) Function invoked on every key press.
|
• {fn} (`fun(key: string, typed: string)?`) Function invoked on
|
||||||
|i_CTRL-V| Passing in nil when {ns_id} is specified removes
|
every key press. |i_CTRL-V| {key} is the key after mappings
|
||||||
the callback associated with namespace {ns_id}.
|
have been applied, and {typed} is the key(s) before mappings
|
||||||
|
are applied, which may be empty if {key} is produced by
|
||||||
|
non-typed keys. When {fn} is nil and {ns_id} is specified,
|
||||||
|
the callback associated with namespace {ns_id} is removed.
|
||||||
• {ns_id} (`integer?`) Namespace ID. If nil or 0, generates and returns
|
• {ns_id} (`integer?`) Namespace ID. If nil or 0, generates and returns
|
||||||
a new |nvim_create_namespace()| id.
|
a new |nvim_create_namespace()| id.
|
||||||
|
|
||||||
|
@ -354,6 +354,9 @@ The following changes to existing APIs or features add new behavior.
|
|||||||
|
|
||||||
• |vim.region()| can use a string accepted by |getpos()| as position.
|
• |vim.region()| can use a string accepted by |getpos()| as position.
|
||||||
|
|
||||||
|
• |vim.on_key()| callbacks receive a second argument for keys typed before
|
||||||
|
mappings are applied.
|
||||||
|
|
||||||
• |vim.diagnostic.config()| now accepts a function for the virtual_text.prefix
|
• |vim.diagnostic.config()| now accepts a function for the virtual_text.prefix
|
||||||
option, which allows for rendering e.g., diagnostic severities differently.
|
option, which allows for rendering e.g., diagnostic severities differently.
|
||||||
|
|
||||||
|
@ -654,11 +654,14 @@ local on_key_cbs = {} --- @type table<integer,function>
|
|||||||
---
|
---
|
||||||
---@note {fn} will be removed on error.
|
---@note {fn} will be removed on error.
|
||||||
---@note {fn} will not be cleared by |nvim_buf_clear_namespace()|
|
---@note {fn} will not be cleared by |nvim_buf_clear_namespace()|
|
||||||
---@note {fn} will receive the keys after mappings have been evaluated
|
|
||||||
---
|
---
|
||||||
---@param fn fun(key: string)? Function invoked on every key press. |i_CTRL-V|
|
---@param fn fun(key: string, typed: string)?
|
||||||
--- Passing in nil when {ns_id} is specified removes the
|
--- Function invoked on every key press. |i_CTRL-V|
|
||||||
--- callback associated with namespace {ns_id}.
|
--- {key} is the key after mappings have been applied, and
|
||||||
|
--- {typed} is the key(s) before mappings are applied, which
|
||||||
|
--- may be empty if {key} is produced by non-typed keys.
|
||||||
|
--- When {fn} is nil and {ns_id} is specified, the callback
|
||||||
|
--- associated with namespace {ns_id} is removed.
|
||||||
---@param ns_id integer? Namespace ID. If nil or 0, generates and returns a
|
---@param ns_id integer? Namespace ID. If nil or 0, generates and returns a
|
||||||
--- new |nvim_create_namespace()| id.
|
--- new |nvim_create_namespace()| id.
|
||||||
---
|
---
|
||||||
@ -684,11 +687,11 @@ end
|
|||||||
|
|
||||||
--- Executes the on_key callbacks.
|
--- Executes the on_key callbacks.
|
||||||
---@private
|
---@private
|
||||||
function vim._on_key(char)
|
function vim._on_key(buf, typed_buf)
|
||||||
local failed_ns_ids = {}
|
local failed_ns_ids = {}
|
||||||
local failed_messages = {}
|
local failed_messages = {}
|
||||||
for k, v in pairs(on_key_cbs) do
|
for k, v in pairs(on_key_cbs) do
|
||||||
local ok, err_msg = pcall(v, char)
|
local ok, err_msg = pcall(v, buf, typed_buf)
|
||||||
if not ok then
|
if not ok then
|
||||||
vim.on_key(nil, k)
|
vim.on_key(nil, k)
|
||||||
table.insert(failed_ns_ids, k)
|
table.insert(failed_ns_ids, k)
|
||||||
|
@ -153,6 +153,12 @@
|
|||||||
type init_array[INIT_SIZE]; \
|
type init_array[INIT_SIZE]; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define KVI_INITIAL_VALUE(v) { \
|
||||||
|
.size = 0, \
|
||||||
|
.capacity = ARRAY_SIZE((v).init_array), \
|
||||||
|
.items = (v).init_array \
|
||||||
|
}
|
||||||
|
|
||||||
/// Initialize vector with preallocated array
|
/// Initialize vector with preallocated array
|
||||||
///
|
///
|
||||||
/// @param[out] v Vector to initialize.
|
/// @param[out] v Vector to initialize.
|
||||||
@ -218,6 +224,17 @@ static inline void *_memcpy_free(void *const restrict dest, void *const restrict
|
|||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
#define kvi_concat_len(v, data, len) \
|
||||||
|
if (len > 0) { \
|
||||||
|
kvi_ensure_more_space(v, len); \
|
||||||
|
assert((v).items); \
|
||||||
|
memcpy((v).items + (v).size, data, sizeof((v).items[0]) * len); \
|
||||||
|
(v).size = (v).size + len; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define kvi_concat(v, str) kvi_concat_len(v, str, strlen(str))
|
||||||
|
#define kvi_splice(v1, v0) kvi_concat_len(v1, (v0).items, (v0).size)
|
||||||
|
|
||||||
/// Get location where to store new element to a vector with preallocated array
|
/// Get location where to store new element to a vector with preallocated array
|
||||||
///
|
///
|
||||||
/// @param[in,out] v Vector to push to.
|
/// @param[in,out] v Vector to push to.
|
||||||
|
@ -94,6 +94,12 @@ static buffheader_T readbuf1 = { { NULL, { NUL } }, NULL, 0, 0 };
|
|||||||
/// Second read ahead buffer. Used for redo.
|
/// Second read ahead buffer. Used for redo.
|
||||||
static buffheader_T readbuf2 = { { NULL, { NUL } }, NULL, 0, 0 };
|
static buffheader_T readbuf2 = { { NULL, { NUL } }, NULL, 0, 0 };
|
||||||
|
|
||||||
|
/// Buffer used to store typed characters for vim.on_key().
|
||||||
|
static kvec_withinit_t(char, MAXMAPLEN) on_key_buf = KVI_INITIAL_VALUE(on_key_buf);
|
||||||
|
|
||||||
|
/// Number of following bytes that should not be stored for vim.on_key().
|
||||||
|
static size_t no_on_key_len = 0;
|
||||||
|
|
||||||
static int typeahead_char = 0; ///< typeahead char that's not flushed
|
static int typeahead_char = 0; ///< typeahead char that's not flushed
|
||||||
|
|
||||||
/// When block_redo is true the redo buffer will not be changed.
|
/// When block_redo is true the redo buffer will not be changed.
|
||||||
@ -994,14 +1000,19 @@ int ins_typebuf(char *str, int noremap, int offset, bool nottyped, bool silent)
|
|||||||
/// Uses cmd_silent, KeyTyped and KeyNoremap to restore the flags belonging to
|
/// Uses cmd_silent, KeyTyped and KeyNoremap to restore the flags belonging to
|
||||||
/// the char.
|
/// the char.
|
||||||
///
|
///
|
||||||
|
/// @param no_on_key don't store these bytes for vim.on_key()
|
||||||
|
///
|
||||||
/// @return the length of what was inserted
|
/// @return the length of what was inserted
|
||||||
int ins_char_typebuf(int c, int modifiers)
|
int ins_char_typebuf(int c, int modifiers, bool no_on_key)
|
||||||
{
|
{
|
||||||
char buf[MB_MAXBYTES * 3 + 4];
|
char buf[MB_MAXBYTES * 3 + 4];
|
||||||
unsigned len = special_to_buf(c, modifiers, true, buf);
|
unsigned len = special_to_buf(c, modifiers, true, buf);
|
||||||
assert(len < sizeof(buf));
|
assert(len < sizeof(buf));
|
||||||
buf[len] = NUL;
|
buf[len] = NUL;
|
||||||
ins_typebuf(buf, KeyNoremap, 0, !KeyTyped, cmd_silent);
|
ins_typebuf(buf, KeyNoremap, 0, !KeyTyped, cmd_silent);
|
||||||
|
if (KeyTyped && no_on_key) {
|
||||||
|
no_on_key_len += len;
|
||||||
|
}
|
||||||
return (int)len;
|
return (int)len;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1162,12 +1173,22 @@ static void gotchars(const uint8_t *chars, size_t len)
|
|||||||
updatescript(buf[i]);
|
updatescript(buf[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reg_recording != 0) {
|
|
||||||
buf[buflen] = NUL;
|
buf[buflen] = NUL;
|
||||||
|
|
||||||
|
if (reg_recording != 0) {
|
||||||
add_buff(&recordbuff, (char *)buf, (ptrdiff_t)buflen);
|
add_buff(&recordbuff, (char *)buf, (ptrdiff_t)buflen);
|
||||||
// remember how many chars were last recorded
|
// remember how many chars were last recorded
|
||||||
last_recorded_len += buflen;
|
last_recorded_len += buflen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (buflen > no_on_key_len) {
|
||||||
|
vim_unescape_ks((char *)buf + no_on_key_len);
|
||||||
|
kvi_concat(on_key_buf, (char *)buf + no_on_key_len);
|
||||||
|
no_on_key_len = 0;
|
||||||
|
} else {
|
||||||
|
no_on_key_len -= buflen;
|
||||||
|
}
|
||||||
|
|
||||||
buflen = 0;
|
buflen = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1185,6 +1206,7 @@ static void gotchars(const uint8_t *chars, size_t len)
|
|||||||
void gotchars_ignore(void)
|
void gotchars_ignore(void)
|
||||||
{
|
{
|
||||||
uint8_t nop_buf[3] = { K_SPECIAL, KS_EXTRA, KE_IGNORE };
|
uint8_t nop_buf[3] = { K_SPECIAL, KS_EXTRA, KE_IGNORE };
|
||||||
|
no_on_key_len += 3;
|
||||||
gotchars(nop_buf, 3);
|
gotchars(nop_buf, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1655,9 +1677,13 @@ int vgetc(void)
|
|||||||
if (!no_mapping && KeyTyped && mod_mask == MOD_MASK_ALT && !(State & MODE_TERMINAL)
|
if (!no_mapping && KeyTyped && mod_mask == MOD_MASK_ALT && !(State & MODE_TERMINAL)
|
||||||
&& !is_mouse_key(c)) {
|
&& !is_mouse_key(c)) {
|
||||||
mod_mask = 0;
|
mod_mask = 0;
|
||||||
int len = ins_char_typebuf(c, 0);
|
int len = ins_char_typebuf(c, 0, false);
|
||||||
ins_char_typebuf(ESC, 0);
|
ins_char_typebuf(ESC, 0, false);
|
||||||
ungetchars(len + 3); // K_SPECIAL KS_MODIFIER MOD_MASK_ALT takes 3 more bytes
|
int old_len = len + 3; // K_SPECIAL KS_MODIFIER MOD_MASK_ALT takes 3 more bytes
|
||||||
|
ungetchars(old_len);
|
||||||
|
if (on_key_buf.size >= (size_t)old_len) {
|
||||||
|
on_key_buf.size -= (size_t)old_len;
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1673,7 +1699,9 @@ int vgetc(void)
|
|||||||
may_garbage_collect = false;
|
may_garbage_collect = false;
|
||||||
|
|
||||||
// Execute Lua on_key callbacks.
|
// Execute Lua on_key callbacks.
|
||||||
nlua_execute_on_key(c);
|
nlua_execute_on_key(c, on_key_buf.items, on_key_buf.size);
|
||||||
|
kvi_destroy(on_key_buf);
|
||||||
|
kvi_init(on_key_buf);
|
||||||
|
|
||||||
// Need to process the character before we know it's safe to do something
|
// Need to process the character before we know it's safe to do something
|
||||||
// else.
|
// else.
|
||||||
|
@ -2064,7 +2064,7 @@ char *nlua_register_table_as_callable(const typval_T *const arg)
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nlua_execute_on_key(int c)
|
void nlua_execute_on_key(int c, char *typed_buf, size_t typed_len)
|
||||||
{
|
{
|
||||||
char buf[MB_MAXBYTES * 3 + 4];
|
char buf[MB_MAXBYTES * 3 + 4];
|
||||||
size_t buf_len = special_to_buf(c, mod_mask, false, buf);
|
size_t buf_len = special_to_buf(c, mod_mask, false, buf);
|
||||||
@ -2085,9 +2085,12 @@ void nlua_execute_on_key(int c)
|
|||||||
// [ vim, vim._on_key, buf ]
|
// [ vim, vim._on_key, buf ]
|
||||||
lua_pushlstring(lstate, buf, buf_len);
|
lua_pushlstring(lstate, buf, buf_len);
|
||||||
|
|
||||||
|
// [ vim, vim._on_key, buf, typed_buf ]
|
||||||
|
lua_pushlstring(lstate, typed_buf, typed_len);
|
||||||
|
|
||||||
int save_got_int = got_int;
|
int save_got_int = got_int;
|
||||||
got_int = false; // avoid interrupts when the key typed is Ctrl-C
|
got_int = false; // avoid interrupts when the key typed is Ctrl-C
|
||||||
if (nlua_pcall(lstate, 1, 0)) {
|
if (nlua_pcall(lstate, 2, 0)) {
|
||||||
nlua_error(lstate,
|
nlua_error(lstate,
|
||||||
_("Error executing vim.on_key Lua callback: %.*s"));
|
_("Error executing vim.on_key Lua callback: %.*s"));
|
||||||
}
|
}
|
||||||
|
@ -1265,7 +1265,7 @@ void wait_return(int redraw)
|
|||||||
} else if (vim_strchr("\r\n ", c) == NULL && c != Ctrl_C) {
|
} else if (vim_strchr("\r\n ", c) == NULL && c != Ctrl_C) {
|
||||||
// Put the character back in the typeahead buffer. Don't use the
|
// Put the character back in the typeahead buffer. Don't use the
|
||||||
// stuff buffer, because lmaps wouldn't work.
|
// stuff buffer, because lmaps wouldn't work.
|
||||||
ins_char_typebuf(vgetc_char, vgetc_mod_mask);
|
ins_char_typebuf(vgetc_char, vgetc_mod_mask, true);
|
||||||
do_redraw = true; // need a redraw even though there is
|
do_redraw = true; // need a redraw even though there is
|
||||||
// typeahead
|
// typeahead
|
||||||
}
|
}
|
||||||
@ -3431,7 +3431,7 @@ int do_dialog(int type, const char *title, const char *message, const char *butt
|
|||||||
}
|
}
|
||||||
if (c == ':' && ex_cmd) {
|
if (c == ':' && ex_cmd) {
|
||||||
retval = dfltbutton;
|
retval = dfltbutton;
|
||||||
ins_char_typebuf(':', 0);
|
ins_char_typebuf(':', 0, false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1078,7 +1078,7 @@ static int normal_execute(VimState *state, int key)
|
|||||||
// When "restart_edit" is set fake a "d"elete command, Insert mode will restart automatically.
|
// When "restart_edit" is set fake a "d"elete command, Insert mode will restart automatically.
|
||||||
// Insert the typed character in the typeahead buffer, so that it can
|
// Insert the typed character in the typeahead buffer, so that it can
|
||||||
// be mapped in Insert mode. Required for ":lmap" to work.
|
// be mapped in Insert mode. Required for ":lmap" to work.
|
||||||
int len = ins_char_typebuf(vgetc_char, vgetc_mod_mask);
|
int len = ins_char_typebuf(vgetc_char, vgetc_mod_mask, true);
|
||||||
|
|
||||||
// When recording and gotchars() was called the character will be
|
// When recording and gotchars() was called the character will be
|
||||||
// recorded again, remove the previous recording.
|
// recorded again, remove the previous recording.
|
||||||
|
@ -1631,7 +1631,7 @@ end:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int len = ins_char_typebuf(vgetc_char, vgetc_mod_mask);
|
int len = ins_char_typebuf(vgetc_char, vgetc_mod_mask, true);
|
||||||
if (KeyTyped) {
|
if (KeyTyped) {
|
||||||
ungetchars(len);
|
ungetchars(len);
|
||||||
}
|
}
|
||||||
|
@ -141,4 +141,29 @@ describe('meta-keys #8226 #13042', function()
|
|||||||
// This is some text: bar
|
// This is some text: bar
|
||||||
// This is some text: baz]])
|
// This is some text: baz]])
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('ALT/META with vim.on_key()', function()
|
||||||
|
feed('ifoo<CR>bar<CR>baz<Esc>gg0')
|
||||||
|
|
||||||
|
exec_lua [[
|
||||||
|
keys = {}
|
||||||
|
typed = {}
|
||||||
|
|
||||||
|
vim.on_key(function(buf, typed_buf)
|
||||||
|
table.insert(keys, vim.fn.keytrans(buf))
|
||||||
|
table.insert(typed, vim.fn.keytrans(typed_buf))
|
||||||
|
end)
|
||||||
|
]]
|
||||||
|
|
||||||
|
-- <M-"> is reinterpreted as <Esc>"
|
||||||
|
feed('qrviw"ayc$FOO.<M-">apq')
|
||||||
|
expect([[
|
||||||
|
FOO.foo
|
||||||
|
bar
|
||||||
|
baz]])
|
||||||
|
|
||||||
|
-- vim.on_key() callback should only receive <Esc>"
|
||||||
|
eq('qrviw"ayc$FOO.<Esc>"apq', exec_lua [[return table.concat(keys, '')]])
|
||||||
|
eq('qrviw"ayc$FOO.<Esc>"apq', exec_lua [[return table.concat(typed, '')]])
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
@ -3012,13 +3012,18 @@ describe('lua stdlib', function()
|
|||||||
|
|
||||||
exec_lua [[
|
exec_lua [[
|
||||||
keys = {}
|
keys = {}
|
||||||
|
typed = {}
|
||||||
|
|
||||||
vim.on_key(function(buf)
|
vim.on_key(function(buf, typed_buf)
|
||||||
if buf:byte() == 27 then
|
if buf:byte() == 27 then
|
||||||
buf = "<ESC>"
|
buf = "<ESC>"
|
||||||
end
|
end
|
||||||
|
if typed_buf:byte() == 27 then
|
||||||
|
typed_buf = "<ESC>"
|
||||||
|
end
|
||||||
|
|
||||||
table.insert(keys, buf)
|
table.insert(keys, buf)
|
||||||
|
table.insert(typed, typed_buf)
|
||||||
end)
|
end)
|
||||||
]]
|
]]
|
||||||
|
|
||||||
@ -3026,20 +3031,41 @@ describe('lua stdlib', function()
|
|||||||
|
|
||||||
-- It has escape in the keys pressed
|
-- It has escape in the keys pressed
|
||||||
eq('inext 🤦 lines å …<ESC>', exec_lua [[return table.concat(keys, '')]])
|
eq('inext 🤦 lines å …<ESC>', exec_lua [[return table.concat(keys, '')]])
|
||||||
|
eq('inext 🤦 lines å …<ESC>', exec_lua [[return table.concat(typed, '')]])
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('tracks input with modifiers', function()
|
it('tracks input with modifiers', function()
|
||||||
exec_lua [[
|
exec_lua [[
|
||||||
keys = {}
|
keys = {}
|
||||||
|
typed = {}
|
||||||
|
|
||||||
vim.on_key(function(buf)
|
vim.on_key(function(buf, typed_buf)
|
||||||
table.insert(keys, vim.fn.keytrans(buf))
|
table.insert(keys, vim.fn.keytrans(buf))
|
||||||
|
table.insert(typed, vim.fn.keytrans(typed_buf))
|
||||||
end)
|
end)
|
||||||
]]
|
]]
|
||||||
|
|
||||||
feed([[i<C-V><C-;><C-V><C-…><Esc>]])
|
feed([[i<C-V><C-;><C-V><C-…><Esc>]])
|
||||||
|
|
||||||
eq('i<C-V><C-;><C-V><C-…><Esc>', exec_lua [[return table.concat(keys, '')]])
|
eq('i<C-V><C-;><C-V><C-…><Esc>', exec_lua [[return table.concat(keys, '')]])
|
||||||
|
eq('i<C-V><C-;><C-V><C-…><Esc>', exec_lua [[return table.concat(typed, '')]])
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('works with character find and Select mode', function()
|
||||||
|
insert('12345')
|
||||||
|
|
||||||
|
exec_lua [[
|
||||||
|
typed = {}
|
||||||
|
|
||||||
|
vim.cmd('snoremap # @')
|
||||||
|
|
||||||
|
vim.on_key(function(buf, typed_buf)
|
||||||
|
table.insert(typed, vim.fn.keytrans(typed_buf))
|
||||||
|
end)
|
||||||
|
]]
|
||||||
|
|
||||||
|
feed('F3gHβγδεζ<Esc>gH…<Esc>gH#$%^')
|
||||||
|
eq('F3gHβγδεζ<Esc>gH…<Esc>gH#$%^', exec_lua [[return table.concat(typed, '')]])
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('allows removing on_key listeners', function()
|
it('allows removing on_key listeners', function()
|
||||||
@ -3101,23 +3127,29 @@ describe('lua stdlib', function()
|
|||||||
eq('inext l', exec_lua [[ return table.concat(keys, '') ]])
|
eq('inext l', exec_lua [[ return table.concat(keys, '') ]])
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('processes mapped keys, not unmapped keys', function()
|
it('argument 1 is keys after mapping, argument 2 is typed keys', function()
|
||||||
exec_lua [[
|
exec_lua [[
|
||||||
keys = {}
|
keys = {}
|
||||||
|
typed = {}
|
||||||
|
|
||||||
vim.cmd("inoremap hello world")
|
vim.cmd("inoremap hello world")
|
||||||
|
|
||||||
vim.on_key(function(buf)
|
vim.on_key(function(buf, typed_buf)
|
||||||
if buf:byte() == 27 then
|
if buf:byte() == 27 then
|
||||||
buf = "<ESC>"
|
buf = "<ESC>"
|
||||||
end
|
end
|
||||||
|
if typed_buf:byte() == 27 then
|
||||||
|
typed_buf = "<ESC>"
|
||||||
|
end
|
||||||
|
|
||||||
table.insert(keys, buf)
|
table.insert(keys, buf)
|
||||||
|
table.insert(typed, typed_buf)
|
||||||
end)
|
end)
|
||||||
]]
|
]]
|
||||||
insert('hello')
|
insert('hello')
|
||||||
|
|
||||||
eq('iworld<ESC>', exec_lua [[return table.concat(keys, '')]])
|
eq('iworld<ESC>', exec_lua [[return table.concat(keys, '')]])
|
||||||
|
eq('ihello<ESC>', exec_lua [[return table.concat(typed, '')]])
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('can call vim.fn functions on Ctrl-C #17273', function()
|
it('can call vim.fn functions on Ctrl-C #17273', function()
|
||||||
|
Loading…
Reference in New Issue
Block a user