mirror of
https://github.com/neovim/neovim.git
synced 2024-12-20 03:05:11 -07:00
feat(lua)!: register_keystroke_callback => on_key
Analogous to nodejs's `on('data', …)` interface, here on_key is the "add
listener" interface.
ref 3ccdbc570d
#12536
BREAKING_CHANGE: vim.register_keystroke_callback() is now an error.
This commit is contained in:
parent
4eb1ebbcf7
commit
69fe427df4
@ -1,4 +1,4 @@
|
||||
.DONE:
|
||||
@echo "Please use GNU Make (gmake) to build neovim"
|
||||
@echo "Use GNU Make (gmake) to build neovim"
|
||||
.DEFAULT:
|
||||
@echo "Please use GNU Make (gmake) to build neovim"
|
||||
@echo "Use GNU Make (gmake) to build neovim"
|
||||
|
@ -14,6 +14,7 @@ updated.
|
||||
|
||||
API ~
|
||||
*nvim_buf_clear_highlight()* Use |nvim_buf_clear_namespace()| instead.
|
||||
*nvim_buf_set_virtual_text()* Use |nvim_buf_set_extmark()| instead.
|
||||
*nvim_command_output()* Use |nvim_exec()| instead.
|
||||
*nvim_execute_lua()* Use |nvim_exec_lua()| instead.
|
||||
|
||||
@ -54,6 +55,8 @@ Functions ~
|
||||
without stopping the job. Use chanclose(id) to close
|
||||
any socket.
|
||||
|
||||
Lua ~
|
||||
*vim.register_keystroke_callback()* Use |vim.on_key()| instead.
|
||||
|
||||
Modifiers ~
|
||||
*cpo-<*
|
||||
|
@ -356,4 +356,11 @@ External UIs are expected to implement these common features:
|
||||
published in this event. See also "mouse_on", "mouse_off".
|
||||
|
||||
|
||||
NAMING *dev-naming*
|
||||
|
||||
Naming is very important. Consistent naming in the API and UI helps users
|
||||
discover and intuitively understand related "families" of things. It reduces
|
||||
cognitive burden.
|
||||
|
||||
|
||||
vim:tw=78:ts=8:noet:ft=help:norl:
|
||||
|
@ -1243,37 +1243,6 @@ region({bufnr}, {pos1}, {pos2}, {regtype}, {inclusive}) *vim.region()*
|
||||
Return: ~
|
||||
region lua table of the form {linenr = {startcol,endcol}}
|
||||
|
||||
*vim.register_keystroke_callback()*
|
||||
register_keystroke_callback({fn}, {ns_id})
|
||||
Register a lua {fn} with an {id} to be run after every
|
||||
keystroke.
|
||||
|
||||
If {fn} is nil, it removes the callback for the associated
|
||||
{ns_id}
|
||||
Note:
|
||||
{fn} will not be cleared from |nvim_buf_clear_namespace()|
|
||||
|
||||
Note:
|
||||
{fn} will receive the keystrokes after mappings have been
|
||||
evaluated
|
||||
|
||||
Parameters: ~
|
||||
{fn} function: Function to call. It should take one
|
||||
argument, which is a string. The string will contain
|
||||
the literal keys typed. See |i_CTRL-V|
|
||||
{ns_id} number? Namespace ID. If not passed or 0, will
|
||||
generate and return a new namespace ID from
|
||||
|nvim_create_namesapce()|
|
||||
|
||||
Return: ~
|
||||
number Namespace ID associated with {fn}
|
||||
|
||||
Note:
|
||||
{fn} will be automatically removed if an error occurs
|
||||
while calling. This is to prevent the annoying situation
|
||||
of every keystroke erroring while trying to remove a
|
||||
broken callback.
|
||||
|
||||
schedule_wrap({cb}) *vim.schedule_wrap()*
|
||||
Defers callback `cb` until the Nvim API is safe to call.
|
||||
|
||||
|
@ -329,12 +329,12 @@ argument.
|
||||
-w{number} Set the 'window' option to {number}.
|
||||
|
||||
*-w*
|
||||
-w {scriptout} All the characters that you type are recorded in the file
|
||||
"scriptout", until you exit Vim. This is useful if you want
|
||||
to create a script file to be used with "vim -s" or
|
||||
":source!". When the "scriptout" file already exists, new
|
||||
characters are appended. See also |complex-repeat|.
|
||||
{scriptout} cannot start with a digit.
|
||||
-w {scriptout} All keys that you type are recorded in the file "scriptout",
|
||||
until you exit Vim. Useful to create a script file to be used
|
||||
with "vim -s" or ":source!". Appends to the "scriptout" file
|
||||
if it already exists. {scriptout} cannot start with a digit.
|
||||
See also |vim.on_key()|.
|
||||
See also |complex-repeat|.
|
||||
|
||||
*-W*
|
||||
-W {scriptout} Like -w, but do not append, overwrite an existing file.
|
||||
|
@ -1563,8 +1563,8 @@ int vgetc(void)
|
||||
*/
|
||||
may_garbage_collect = false;
|
||||
|
||||
// Exec lua callbacks for on_keystroke
|
||||
nlua_execute_log_keystroke(c);
|
||||
// Execute Lua on_key callbacks.
|
||||
nlua_execute_on_key(c);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
@ -1499,7 +1499,7 @@ int nlua_expand_pat(expand_T *xp,
|
||||
lua_getfield(lstate, -1, "_expand_pat");
|
||||
luaL_checktype(lstate, -1, LUA_TFUNCTION);
|
||||
|
||||
// [ vim, vim._log_keystroke, buf ]
|
||||
// [ vim, vim._on_key, buf ]
|
||||
lua_pushlstring(lstate, (const char *)pat, STRLEN(pat));
|
||||
|
||||
if (lua_pcall(lstate, 1, 2, 0) != 0) {
|
||||
@ -1773,7 +1773,7 @@ char_u *nlua_register_table_as_callable(typval_T *const arg)
|
||||
return name;
|
||||
}
|
||||
|
||||
void nlua_execute_log_keystroke(int c)
|
||||
void nlua_execute_on_key(int c)
|
||||
{
|
||||
char_u buf[NUMBUFLEN];
|
||||
size_t buf_len = special_to_buf(c, mod_mask, false, buf);
|
||||
@ -1787,17 +1787,17 @@ void nlua_execute_log_keystroke(int c)
|
||||
// [ vim ]
|
||||
lua_getglobal(lstate, "vim");
|
||||
|
||||
// [ vim, vim._log_keystroke ]
|
||||
lua_getfield(lstate, -1, "_log_keystroke");
|
||||
// [ vim, vim._on_key]
|
||||
lua_getfield(lstate, -1, "_on_key");
|
||||
luaL_checktype(lstate, -1, LUA_TFUNCTION);
|
||||
|
||||
// [ vim, vim._log_keystroke, buf ]
|
||||
// [ vim, vim._on_key, buf ]
|
||||
lua_pushlstring(lstate, (const char *)buf, buf_len);
|
||||
|
||||
if (lua_pcall(lstate, 1, 0, 0)) {
|
||||
nlua_error(
|
||||
lstate,
|
||||
_("Error executing vim.log_keystroke lua callback: %.*s"));
|
||||
_("Error executing vim.on_key Lua callback: %.*s"));
|
||||
}
|
||||
|
||||
// [ vim ]
|
||||
|
@ -4,6 +4,7 @@
|
||||
-- 1. runtime/lua/vim/ (the runtime): For "nice to have" features, e.g. the
|
||||
-- `inspect` and `lpeg` modules.
|
||||
-- 2. runtime/lua/vim/shared.lua: Code shared between Nvim and tests.
|
||||
-- (This will go away if we migrate to nvim as the test-runner.)
|
||||
-- 3. src/nvim/lua/: Compiled-into Nvim itself.
|
||||
--
|
||||
-- Guideline: "If in doubt, put it in the runtime".
|
||||
@ -426,26 +427,35 @@ function vim.notify(msg, log_level, _opts)
|
||||
end
|
||||
|
||||
|
||||
local on_keystroke_callbacks = {}
|
||||
function vim.register_keystroke_callback()
|
||||
error('vim.register_keystroke_callback is deprecated, instead use: vim.on_key')
|
||||
end
|
||||
|
||||
--- Register a lua {fn} with an {id} to be run after every keystroke.
|
||||
local on_key_cbs = {}
|
||||
|
||||
--- Adds Lua function {fn} with namespace id {ns_id} as a listener to every,
|
||||
--- yes every, input key.
|
||||
---
|
||||
---@param fn function: Function to call. It should take one argument, which is a string.
|
||||
--- The string will contain the literal keys typed.
|
||||
--- See |i_CTRL-V|
|
||||
--- The Nvim command-line option |-w| is related but does not support callbacks
|
||||
--- and cannot be toggled dynamically.
|
||||
---
|
||||
---@param fn function: Callback function. It should take one string argument.
|
||||
--- On each key press, Nvim passes the key char to fn(). |i_CTRL-V|
|
||||
--- If {fn} is nil, it removes the callback for the associated {ns_id}
|
||||
---@param ns_id number? Namespace ID. If not passed or 0, will generate and return a new
|
||||
--- namespace ID from |nvim_create_namesapce()|
|
||||
---@param ns_id number? Namespace ID. If nil or 0, generates and returns a new
|
||||
--- |nvim_create_namesapce()| id.
|
||||
---
|
||||
---@return number Namespace ID associated with {fn}
|
||||
---@return number Namespace id associated with {fn}. Or count of all callbacks
|
||||
---if on_key() is called without arguments.
|
||||
---
|
||||
---@note {fn} will be automatically removed if an error occurs while calling.
|
||||
--- This is to prevent the annoying situation of every keystroke erroring
|
||||
--- while trying to remove a broken callback.
|
||||
---@note {fn} will not be cleared from |nvim_buf_clear_namespace()|
|
||||
---@note {fn} will receive the keystrokes after mappings have been evaluated
|
||||
function vim.register_keystroke_callback(fn, ns_id)
|
||||
---@note {fn} will be removed if an error occurs while calling.
|
||||
---@note {fn} will not be cleared by |nvim_buf_clear_namespace()|
|
||||
---@note {fn} will receive the keys after mappings have been evaluated
|
||||
function vim.on_key(fn, ns_id)
|
||||
if fn == nil and ns_id == nil then
|
||||
return #on_key_cbs
|
||||
end
|
||||
|
||||
vim.validate {
|
||||
fn = { fn, 'c', true},
|
||||
ns_id = { ns_id, 'n', true }
|
||||
@ -455,20 +465,19 @@ function vim.register_keystroke_callback(fn, ns_id)
|
||||
ns_id = vim.api.nvim_create_namespace('')
|
||||
end
|
||||
|
||||
on_keystroke_callbacks[ns_id] = fn
|
||||
on_key_cbs[ns_id] = fn
|
||||
return ns_id
|
||||
end
|
||||
|
||||
--- Function that executes the keystroke callbacks.
|
||||
--- Executes the on_key callbacks.
|
||||
---@private
|
||||
function vim._log_keystroke(char)
|
||||
function vim._on_key(char)
|
||||
local failed_ns_ids = {}
|
||||
local failed_messages = {}
|
||||
for k, v in pairs(on_keystroke_callbacks) do
|
||||
for k, v in pairs(on_key_cbs) do
|
||||
local ok, err_msg = pcall(v, char)
|
||||
if not ok then
|
||||
vim.register_keystroke_callback(nil, k)
|
||||
|
||||
vim.on_key(nil, k)
|
||||
table.insert(failed_ns_ids, k)
|
||||
table.insert(failed_messages, err_msg)
|
||||
end
|
||||
@ -476,7 +485,7 @@ function vim._log_keystroke(char)
|
||||
|
||||
if failed_ns_ids[1] then
|
||||
error(string.format(
|
||||
"Error executing 'on_keystroke' with ns_ids of '%s'\n With messages: %s",
|
||||
"Error executing 'on_key' with ns_ids '%s'\n Messages: %s",
|
||||
table.concat(failed_ns_ids, ", "),
|
||||
table.concat(failed_messages, "\n")))
|
||||
end
|
||||
|
@ -6,6 +6,7 @@ local funcs = helpers.funcs
|
||||
local meths = helpers.meths
|
||||
local dedent = helpers.dedent
|
||||
local command = helpers.command
|
||||
local insert = helpers.insert
|
||||
local clear = helpers.clear
|
||||
local eq = helpers.eq
|
||||
local ok = helpers.ok
|
||||
@ -1881,7 +1882,7 @@ describe('lua stdlib', function()
|
||||
end)
|
||||
|
||||
it('vim.region', function()
|
||||
helpers.insert(helpers.dedent( [[
|
||||
insert(helpers.dedent( [[
|
||||
text tααt tααt text
|
||||
text tαxt txtα tex
|
||||
text tαxt tαxt
|
||||
@ -1889,65 +1890,67 @@ describe('lua stdlib', function()
|
||||
eq({5,15}, exec_lua[[ return vim.region(0,{1,5},{1,14},'v',true)[1] ]])
|
||||
end)
|
||||
|
||||
describe('vim.execute_on_keystroke', function()
|
||||
it('should keep track of keystrokes', function()
|
||||
helpers.insert([[hello world ]])
|
||||
describe('vim.on_key', function()
|
||||
it('tracks keystrokes', function()
|
||||
insert([[hello world ]])
|
||||
|
||||
exec_lua [[
|
||||
KeysPressed = {}
|
||||
keys = {}
|
||||
|
||||
vim.register_keystroke_callback(function(buf)
|
||||
vim.on_key(function(buf)
|
||||
if buf:byte() == 27 then
|
||||
buf = "<ESC>"
|
||||
end
|
||||
|
||||
table.insert(KeysPressed, buf)
|
||||
table.insert(keys, buf)
|
||||
end)
|
||||
]]
|
||||
|
||||
helpers.insert([[next 🤦 lines å ]])
|
||||
insert([[next 🤦 lines å ]])
|
||||
|
||||
-- It has escape in the keys pressed
|
||||
eq('inext 🤦 lines å <ESC>', exec_lua [[return table.concat(KeysPressed, '')]])
|
||||
eq('inext 🤦 lines å <ESC>', exec_lua [[return table.concat(keys, '')]])
|
||||
end)
|
||||
|
||||
it('should allow removing trackers.', function()
|
||||
helpers.insert([[hello world]])
|
||||
it('allows removing on_key listeners', function()
|
||||
insert([[hello world]])
|
||||
|
||||
exec_lua [[
|
||||
KeysPressed = {}
|
||||
keys = {}
|
||||
|
||||
return vim.register_keystroke_callback(function(buf)
|
||||
return vim.on_key(function(buf)
|
||||
if buf:byte() == 27 then
|
||||
buf = "<ESC>"
|
||||
end
|
||||
|
||||
table.insert(KeysPressed, buf)
|
||||
table.insert(keys, buf)
|
||||
end, vim.api.nvim_create_namespace("logger"))
|
||||
]]
|
||||
|
||||
helpers.insert([[next lines]])
|
||||
insert([[next lines]])
|
||||
|
||||
exec_lua("vim.register_keystroke_callback(nil, vim.api.nvim_create_namespace('logger'))")
|
||||
eq(1, exec_lua('return vim.on_key()'))
|
||||
exec_lua("vim.on_key(nil, vim.api.nvim_create_namespace('logger'))")
|
||||
eq(0, exec_lua('return vim.on_key()'))
|
||||
|
||||
helpers.insert([[more lines]])
|
||||
insert([[more lines]])
|
||||
|
||||
-- It has escape in the keys pressed
|
||||
eq('inext lines<ESC>', exec_lua [[return table.concat(KeysPressed, '')]])
|
||||
eq('inext lines<ESC>', exec_lua [[return table.concat(keys, '')]])
|
||||
end)
|
||||
|
||||
it('should not call functions that error again.', function()
|
||||
helpers.insert([[hello world]])
|
||||
it('skips any function that caused an error', function()
|
||||
insert([[hello world]])
|
||||
|
||||
exec_lua [[
|
||||
KeysPressed = {}
|
||||
keys = {}
|
||||
|
||||
return vim.register_keystroke_callback(function(buf)
|
||||
return vim.on_key(function(buf)
|
||||
if buf:byte() == 27 then
|
||||
buf = "<ESC>"
|
||||
end
|
||||
|
||||
table.insert(KeysPressed, buf)
|
||||
table.insert(keys, buf)
|
||||
|
||||
if buf == 'l' then
|
||||
error("Dumb Error")
|
||||
@ -1955,35 +1958,30 @@ describe('lua stdlib', function()
|
||||
end)
|
||||
]]
|
||||
|
||||
helpers.insert([[next lines]])
|
||||
helpers.insert([[more lines]])
|
||||
insert([[next lines]])
|
||||
insert([[more lines]])
|
||||
|
||||
-- Only the first letter gets added. After that we remove the callback
|
||||
eq('inext l', exec_lua [[ return table.concat(KeysPressed, '') ]])
|
||||
eq('inext l', exec_lua [[ return table.concat(keys, '') ]])
|
||||
end)
|
||||
|
||||
it('should process mapped keys, not unmapped keys', function()
|
||||
it('processes mapped keys, not unmapped keys', function()
|
||||
exec_lua [[
|
||||
KeysPressed = {}
|
||||
keys = {}
|
||||
|
||||
vim.cmd("inoremap hello world")
|
||||
|
||||
vim.register_keystroke_callback(function(buf)
|
||||
vim.on_key(function(buf)
|
||||
if buf:byte() == 27 then
|
||||
buf = "<ESC>"
|
||||
end
|
||||
|
||||
table.insert(KeysPressed, buf)
|
||||
table.insert(keys, buf)
|
||||
end)
|
||||
]]
|
||||
insert("hello")
|
||||
|
||||
helpers.insert("hello")
|
||||
|
||||
local next_status = exec_lua [[
|
||||
return table.concat(KeysPressed, '')
|
||||
]]
|
||||
|
||||
eq("iworld<ESC>", next_status)
|
||||
eq('iworld<ESC>', exec_lua[[return table.concat(keys, '')]])
|
||||
end)
|
||||
end)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user