diff options
-rw-r--r-- | BSDmakefile | 4 | ||||
-rw-r--r-- | CONTRIBUTING.md | 8 | ||||
-rw-r--r-- | runtime/doc/deprecated.txt | 3 | ||||
-rw-r--r-- | runtime/doc/develop.txt | 41 | ||||
-rw-r--r-- | runtime/doc/lua.txt | 35 | ||||
-rw-r--r-- | runtime/doc/starting.txt | 12 | ||||
-rw-r--r-- | runtime/doc/vim_diff.txt | 24 | ||||
-rw-r--r-- | src/nvim/getchar.c | 4 | ||||
-rw-r--r-- | src/nvim/lua/executor.c | 12 | ||||
-rw-r--r-- | src/nvim/lua/vim.lua | 51 | ||||
-rw-r--r-- | src/nvim/main.c | 2 | ||||
-rw-r--r-- | test/functional/api/server_notifications_spec.lua | 8 | ||||
-rw-r--r-- | test/functional/lua/vim_spec.lua | 72 |
13 files changed, 140 insertions, 136 deletions
diff --git a/BSDmakefile b/BSDmakefile index 93b7dc7f3d..f81223bafa 100644 --- a/BSDmakefile +++ b/BSDmakefile @@ -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" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4d93c979ed..2a565574fa 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -29,10 +29,10 @@ Reporting problems Developer guidelines -------------------- -- Nvim developers should read `:help dev`. -- External UI developers should read `:help dev-ui`. -- API client developers should read `:help dev-api-client`. -- Nvim developers are _strongly encouraged_ to install `ninja` for faster builds. +- Read `:help dev` if you are working on Nvim core. +- Read `:help dev-ui` if you are developing a UI. +- Read `:help dev-api-client` if you are developing an API client. +- Install `ninja` for faster builds of Nvim. ``` sudo apt-get install ninja-build make distclean diff --git a/runtime/doc/deprecated.txt b/runtime/doc/deprecated.txt index 3b5287ee44..861aed4884 100644 --- a/runtime/doc/deprecated.txt +++ b/runtime/doc/deprecated.txt @@ -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-<* diff --git a/runtime/doc/develop.txt b/runtime/doc/develop.txt index 60a3f870a9..14f35acce3 100644 --- a/runtime/doc/develop.txt +++ b/runtime/doc/develop.txt @@ -127,14 +127,20 @@ Sometimes a GUI or other application may want to force a provider to DOCUMENTATION *dev-doc* -- Do not prefix help tags with "nvim-". Use |vim_diff.txt| to document - differences from Vim; no other distinction is necessary. -- If a Vim feature is removed, delete its help section and move its tag to - |vim_diff.txt|. -- Move deprecated features to |deprecated.txt|. +- "Just say it". Avoid mushy, colloquial phrasing in all documentation + (docstrings, user manual, website materials, newsletters, …). Don't mince + words. Personality and flavor, used sparingly, are welcome--but in general, + optimize for the reader's time and energy: be "precise yet concise". + - Prefer the active voice: "Foo does X", not "X is done by Foo". +- Vim differences: + - Do not prefix help tags with "nvim-". Use |vim_diff.txt| to catalog + differences from Vim; no other distinction is necessary. + - If a Vim feature is removed, delete its help section and move its tag to + |vim_diff.txt|. +- Mention deprecated features in |deprecated.txt| and delete their old doc. - Use consistent language. - - "terminal" in a help tag always means "the embedded terminal emulator", not - "the user host terminal". + - "terminal" in a help tag always means "the embedded terminal emulator", + not "the user host terminal". - Use "tui-" to prefix help tags related to the host terminal, and "TUI" in prose if possible. - Docstrings: do not start parameter descriptions with "The" or "A" unless it @@ -222,13 +228,13 @@ LUA *dev-lua* - Keep the core Lua modules |lua-stdlib| simple. Avoid elaborate OOP or pseudo-OOP designs. Plugin authors just want functions to call, they don't - want to learn a big, fancy inheritance hierarchy. So we should avoid complex - objects: tables are usually better. + want to learn a big, fancy inheritance hierarchy. Thus avoid specialized + objects; tables or values are usually better. API *dev-api* -Use this template to name new API functions: +Use this template to name new RPC |API| functions: nvim_{thing}_{action}_{arbitrary-qualifiers} If the function acts on an object then {thing} is the name of that object @@ -356,4 +362,19 @@ External UIs are expected to implement these common features: published in this event. See also "mouse_on", "mouse_off". +NAMING *dev-naming* + +Naming is important. Consistent naming in the API and UI helps both users and +developers discover and intuitively understand related concepts ("families"), +and reduces cognitive burden. Discoverability encourages code re-use and +likewise avoids redundant, overlapping mechanisms, which reduces code +surface-area, and thereby minimizes bugs... + +Naming conventions ~ + +Use the "on_" prefix to name event handlers and also the interface for +"registering" such handlers (on_key). The dual nature is acceptable to avoid +a confused collection of naming conventions for these related concepts. + + vim:tw=78:ts=8:noet:ft=help:norl: diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt index a44b2e42f5..5d600eae99 100644 --- a/runtime/doc/lua.txt +++ b/runtime/doc/lua.txt @@ -576,11 +576,11 @@ If you want to exclude visual selections from highlighting on yank, use vim.highlight.on_yank({opts}) *vim.highlight.on_yank()* Highlights the yanked text. The fields of the optional dict {opts} control the highlight: - - {higroup} highlight group for yanked region (default `"IncSearch"`) + - {higroup} highlight group for yanked region (default |hl-IncSearch|) - {timeout} time in ms before highlight is cleared (default `150`) - {on_macro} highlight when executing macro (default `false`) - {on_visual} highlight when yanking visual selection (default `true`) - - {event} event structure (default `vim.v.event`) + - {event} event structure (default |v:event|) vim.highlight.range({bufnr}, {ns}, {higroup}, {start}, {finish}, {rtype}, {inclusive}) *vim.highlight.range()* @@ -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. diff --git a/runtime/doc/starting.txt b/runtime/doc/starting.txt index d6b54fbd01..87a48e6d2a 100644 --- a/runtime/doc/starting.txt +++ b/runtime/doc/starting.txt @@ -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. diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt index 4b134926a2..a5fcef2800 100644 --- a/runtime/doc/vim_diff.txt +++ b/runtime/doc/vim_diff.txt @@ -6,16 +6,16 @@ Differences between Nvim and Vim *vim-differences* -Nvim differs from Vim in many ways, although editor and VimL features are -mostly identical. This document is a complete and centralized reference of -the differences. +Nvim differs from Vim in many ways, although editor and Vimscript (not +Vim9script) features are mostly identical. This document is a complete and +centralized reference of the differences. Type |gO| to see the table of contents. ============================================================================== 1. Configuration *nvim-config* -- Use `$XDG_CONFIG_HOME/nvim/init.vim` instead of `.vimrc` for configuration. +- Use `$XDG_CONFIG_HOME/nvim/init.vim` instead of `.vimrc` for your |config|. - Use `$XDG_CONFIG_HOME/nvim` instead of `.vim` to store configuration files. - Use `$XDG_DATA_HOME/nvim/shada/main.shada` instead of `.viminfo` for persistent session information. |shada| @@ -78,6 +78,8 @@ the differences. Default Mappings ~ *default-mappings* +Nvim creates the following default mappings at |startup|. You can disable any +of these in your config by simply removing the mapping, e.g. ":unmap Y". > nnoremap Y y$ nnoremap <C-L> <Cmd>nohlsearch<Bar>diffupdate<CR><C-L> @@ -101,17 +103,19 @@ nvim_cmdwin: MAJOR COMPONENTS ~ API |API| -Lua scripting |lua| Job control |job-control| -Remote plugins |remote-plugin| +LSP framework |lsp| +Lua scripting |lua| +Parsing engine |treesitter| Providers Clipboard |provider-clipboard| Node.js plugins |provider-nodejs| Python plugins |provider-python| Ruby plugins |provider-ruby| +Remote plugins |remote-plugin| Shared data |shada| -Embedded terminal |terminal| -VimL parser |nvim_parse_expression()| +Terminal emulator |terminal| +Vimscript parser |nvim_parse_expression()| XDG base directories |xdg| USER EXPERIENCE ~ @@ -160,7 +164,7 @@ FEATURES ~ Command-line highlighting: The expression prompt (|@=|, |c_CTRL-R_=|, |i_CTRL-R_=|) is highlighted - using a built-in VimL expression parser. |expr-highlight| + using a built-in Vimscript expression parser. |expr-highlight| *E5408* *E5409* |input()|, |inputdialog()| support custom highlighting. |input()-highlight| *g:Nvim_color_cmdline* @@ -413,7 +417,7 @@ TUI: UI/Display: |Visual| selection highlights the character at cursor. |visual-use| -VimL (Vim script) compatibility: +Vimscript compatibility: `count` does not alias to |v:count| `errmsg` does not alias to |v:errmsg| `shell_error` does not alias to |v:shell_error| diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index 28f58e2c34..11e3b9bc2d 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -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; } diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 5cd9894f9d..a8b10f86f5 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.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 ] diff --git a/src/nvim/lua/vim.lua b/src/nvim/lua/vim.lua index 34b314b40d..c6bbdee7ad 100644 --- a/src/nvim/lua/vim.lua +++ b/src/nvim/lua/vim.lua @@ -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 + +local on_key_cbs = {} ---- Register a lua {fn} with an {id} to be run after every keystroke. +--- 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 diff --git a/src/nvim/main.c b/src/nvim/main.c index b73f5aad76..716434f32e 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -334,7 +334,7 @@ int main(int argc, char **argv) // prepare screen now, so external UIs can display messages starting = NO_BUFFERS; screenclear(); - TIME_MSG("initialized screen early for UI"); + TIME_MSG("init screen for UI"); } init_default_mappings(); // Default mappings. diff --git a/test/functional/api/server_notifications_spec.lua b/test/functional/api/server_notifications_spec.lua index 279ede81f7..6367cc5caa 100644 --- a/test/functional/api/server_notifications_spec.lua +++ b/test/functional/api/server_notifications_spec.lua @@ -78,10 +78,10 @@ describe('notify', function() end) it('cancels stale events on channel close', function() - if isCI() then - pending('Sporadic hangs on CI (c.f., #14083). Skip until it is fixed.') - return - end + if isCI() then + pending('hangs on CI #14083 #15251') + return + end if helpers.pending_win32(pending) then return end local catchan = eval("jobstart(['cat'], {'rpc': v:true})") local catpath = eval('exepath("cat")') diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua index 0ea914880f..2bedbd1453 100644 --- a/test/functional/lua/vim_spec.lua +++ b/test/functional/lua/vim_spec.lua @@ -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) |