docs: lua error patterns #30240

Co-authored-by: Mathias Fussenegger <f.mathias@zignar.net>
Co-authored-by: Ananth Bhaskararaman <antsub@gmail.com>
This commit is contained in:
Justin M. Keyes
2024-09-24 04:46:50 -07:00
committed by GitHub
parent 2276743cb8
commit 3f6bc34e66
13 changed files with 186 additions and 85 deletions

View File

@ -18,6 +18,8 @@ ${NVIM_VERSION}
2. Run the MSI
3. Run `nvim.exe` on your CLI of choice
Note: On Windows "Server" you may need to [install vcruntime140.dll](https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170).
### macOS (x86_64)
1. Download **nvim-macos-x86_64.tar.gz**
@ -34,11 +36,10 @@ ${NVIM_VERSION}
### Linux (x64)
Minimum glibc version to run these releases is 2.31. People requiring releases
that work on older glibc versions can find them at
https://github.com/neovim/neovim-releases.
glibc 2.31 or newer is required. Or you may try the (unsupported) [builds for older glibc](https://github.com/neovim/neovim-releases).
#### AppImage
1. Download **nvim.appimage**
2. Run `chmod u+x nvim.appimage && ./nvim.appimage`
- If your system does not have FUSE you can [extract the appimage](https://github.com/AppImage/AppImageKit/wiki/FUSE#type-2-appimage):

View File

@ -4,6 +4,7 @@
# - pitfalls: https://izzys.casa/2019/02/everything-you-never-wanted-to-know-about-cmake/
# - troubleshooting:
# - variable_watch https://cmake.org/cmake/help/latest/command/variable_watch.html
# - verbose output: cmake --build build --verbose
# Version should match the tested CMAKE_URL in .github/workflows/build.yml.
cmake_minimum_required(VERSION 3.16)

View File

@ -996,6 +996,9 @@ nvim_input({keys}) *nvim_input()*
input buffer and the call is non-blocking (input is processed
asynchronously by the eventloop).
To input blocks of text, |nvim_paste()| is much faster and should be
preferred.
On execution error: does not fail, but updates v:errmsg.
Note: ~
@ -1148,21 +1151,35 @@ nvim_out_write({str}) *nvim_out_write()*
• {str} Message
nvim_paste({data}, {crlf}, {phase}) *nvim_paste()*
Pastes at cursor, in any mode.
Pastes at cursor (in any mode), and sets "redo" so dot (|.|) will repeat
the input. UIs call this to implement "paste", but it's also intended for
use by scripts to input large, dot-repeatable blocks of text (as opposed
to |nvim_input()| which is subject to mappings/events and is thus much
slower).
Invokes the `vim.paste` handler, which handles each mode appropriately.
Sets redo/undo. Faster than |nvim_input()|. Lines break at LF ("\n").
Invokes the |vim.paste()| handler, which handles each mode appropriately.
Errors ('nomodifiable', `vim.paste()` failure, …) are reflected in `err`
but do not affect the return value (which is strictly decided by
`vim.paste()`). On error or cancel, subsequent calls are ignored
("drained") until the next paste is initiated (phase 1 or -1).
Useful in mappings and scripts to insert multiline text. Example: >vim
vim.keymap.set('n', 'x', function()
vim.api.nvim_paste([[
line1
line2
line3
]], false, -1)
end, { buffer = true })
<
Attributes: ~
not allowed when |textlock| is active
Parameters: ~
• {data} Multiline input. May be binary (containing NUL bytes).
• {data} Multiline input. Lines break at LF ("\n"). May be binary
(containing NUL bytes).
• {crlf} Also break lines at CR and CRLF.
• {phase} -1: paste in a single call (i.e. without streaming). To
"stream" a paste, call `nvim_paste` sequentially with these
@ -1176,7 +1193,8 @@ nvim_paste({data}, {crlf}, {phase}) *nvim_paste()*
• false: Client should cancel the paste.
nvim_put({lines}, {type}, {after}, {follow}) *nvim_put()*
Puts text at cursor, in any mode.
Puts text at cursor, in any mode. For dot-repeatable input, use
|nvim_paste()|.
Compare |:put| and |p| which are always linewise.
@ -2460,10 +2478,11 @@ nvim_buf_set_text({buffer}, {start_row}, {start_col}, {end_row}, {end_col},
`start_row = end_row = row` and `start_col = end_col = col`. To delete the
text in a range, use `replacement = {}`.
Prefer |nvim_buf_set_lines()| if you are only adding or deleting entire
lines.
Prefer |nvim_put()| if you want to insert text at the cursor position.
Note: ~
• Prefer |nvim_buf_set_lines()| (for performance) to add or delete
entire lines.
Prefer |nvim_paste()| or |nvim_put()| to insert (instead of replace)
text at cursor.
Attributes: ~
not allowed when |textlock| is active
@ -2476,10 +2495,6 @@ nvim_buf_set_text({buffer}, {start_row}, {start_col}, {end_row}, {end_col},
• {end_col} Ending column (byte offset) on last line, exclusive
• {replacement} Array of lines to use as replacement
See also: ~
• |nvim_buf_set_lines()|
• |nvim_put()|
nvim_buf_set_var({buffer}, {name}, {value}) *nvim_buf_set_var()*
Sets a buffer-scoped (b:) variable

View File

@ -95,9 +95,9 @@ variable is and what it was initialized to. In particular, initialization
should be used instead of declaration and assignment, e.g. >c
int i;
i = f(); // BAD: initialization separate from declaration.
i = f(); // : initialization separate from declaration.
int j = g(); // GOOD: declaration has initialization.
int j = g(); // : declaration has initialization.
Initialization ~
@ -107,16 +107,13 @@ but each initialization should be done on a separate line.
>c
int i;
int j; // GOOD
int i, j; // GOOD: multiple declarations, no initialization.
int j; // ✅
int i, j; // ✅: multiple declarations, no initialization.
int i = 0;
int j = 0; // GOOD: one initialization per line.
int j = 0; // ✅: one initialization per line.
int i = 0, j; // BAD: multiple declarations with initialization.
int i = 0, j = 0; // BAD: multiple declarations with initialization.
int i = 0, j; // ❌: multiple declarations with initialization.
int i = 0, j = 0; // ❌: multiple declarations with initialization.
==============================================================================
Nvim-Specific Magic
@ -152,10 +149,10 @@ Postincrement and Postdecrement ~
Use postfix form (`i++`) in statements. >c
for (int i = 0; i < 3; i++) { }
int j = ++i; // OK: ++i is used as an expression.
int j = ++i; // : ++i is used as an expression.
for (int i = 0; i < 3; ++i) { }
++i; // BAD: ++i is used as a statement.
++i; // : ++i is used as a statement.
Use of const ~
@ -217,7 +214,7 @@ Booleans ~
Use `bool` to represent boolean values. >c
int loaded = 1; // BAD: loaded should have type bool.
int loaded = 1; // : loaded should have type bool.
Conditions ~
@ -382,7 +379,7 @@ Filenames should be all lowercase and can include underscores (`_`).
Use underscores to separate words. Examples of acceptable file names: >
my_useful_file.c
getline_fix.c // OK: getline refers to the glibc function.
getline_fix.c // : getline refers to the glibc function.
C files should end in `.c` and header files should end in `.h`.
@ -415,10 +412,10 @@ instance: `my_exciting_local_variable`.
For example: >c
string table_name; // OK: uses underscore.
string tablename; // OK: all lowercase.
string table_name; // : uses underscore.
string tablename; // : all lowercase.
string tableName; // BAD: mixed case.
string tableName; // : mixed case.
<
Struct Variables ~

View File

@ -307,19 +307,36 @@ See also |dev-naming|.
easier to inspect and print, and inherently compatible with all Lua plugins.
(This guideline doesn't apply to opaque, non-data objects like `vim.cmd`.)
- stdlib functions should follow these common patterns:
- accept iterable instead of table
- exception: in some cases iterable doesn't make sense, e.g. spair() sorts
the input by definition, so there is no reason for it to accept an
iterable, because the input needs to be "reified"; it can't operate on
a "stream".
- return iterable instead of table
- mimic the pairs() or ipairs() interface if the function is intended to be
used in a "for" loop.
- when a result-or-error interface is needed, return `result|nil, nil|errmsg`: >
---@return Foo|nil # Result object, or nil if not found.
---@return nil|string # Error message on failure, or nil on success.
<
- Examples: |vim.ui.open()| |io.open()| |luv-error-handling|
- Return |lua-result-or-message| (`any|nil,nil|string`) to communicate
failure, or choose from |dev-error-patterns| when appropriate.
- Accept iterable instead of only table.
- Note: in some cases iterable doesn't make sense, e.g. spair() sorts the
input by definition, so there is no reason for it to accept an iterable,
because the input needs to be "reified"; it can't operate on a "stream".
- Return an iterable (generator) instead of table, if possible.
- Mimic the pairs() or ipairs() interface if the function is intended for
use in a |for-in| loop.
*dev-error-patterns*
To communicate failure to a consumer, choose from these patterns (in order of
preference):
1. `retval, errmsg`
- When failure is normal, or when it is practical for the consumer to
continue (fallback) in some other way. See |lua-result-or-message|.
2. optional result, no errormsg
- Special case of 1. When there is only a single case of "doesn't exist"
(e.g. cache lookup, dict lookup).
3. `error("no luck")`
- For invalid state ("must not happen"), when failure is exceptional, or at
a low level where the consumers are unlikely to handle it in a meaningful
way. Advantage is that propagation happens for free and it's harder to
accidentally swallow errors. (E.g. using
`uv_handle/pipe:write()` without checking return values is common.)
4. `on_error` parameter
- For async and "visitors" traversing a graph, where many errors may be
collected while work continues.
5. `vim.notify` (sometimes with optional `opts.silent` (async, visitors ^))
- High-level / application-level messages. End-user invokes these directly.
*dev-patterns*
Interface conventions ~

View File

@ -67,7 +67,7 @@ See https://luajit.org/ext_profiler.html or the `p.lua` source for details: >
==============================================================================
LUA CONCEPTS AND IDIOMS *lua-concepts*
Lua is very simple: this means that, while there are some quirks, once you
Lua is very simple, and _consistent_: while there are some quirks, once you
internalize those quirks, everything works the same everywhere. Scopes
(closures) in particular are very consistent, unlike JavaScript or most other
languages.
@ -85,6 +85,36 @@ https://www.lua.org/doc/cacm2018.pdf
- Stackful coroutines enable cooperative multithreading, generators, and
versatile control for both Lua and its host (Nvim).
*lua-error-handling*
Lua functions may throw |lua-errors| for exceptional (unexpected) failures,
which you can handle with |pcall()|.
*lua-result-or-message*
When failure is normal and expected, it's idiomatic to return `nil` which
signals to the caller that failure is not "exceptional" and must be handled.
This "result-or-message" pattern is expressed as the multi-value return type
`any|nil,nil|string`, or in LuaLS notation: >
---@return any|nil # result on success, nil on failure.
---@return nil|string # nil on success, error message on failure.
<
Examples of the "result-or-message" pattern:
- |vim.ui.open()|
- |io.open()|
- |luv-error-handling|
When a caller can't proceed on failure, it's idiomatic to `assert()` the
"result-or-message" result: >lua
local value = assert(fn())
Guidance: use the "result-or-message" pattern for...
- Functions where failure is expected, especially when communicating with the
external world. E.g. HTTP requests or LSP requests often fail because of
server problems, even if the caller did everything right.
- Functions that return a value, e.g. Foo:new().
- When there is a list of known error codes which can be returned as a third
value (like |luv-error-handling|).
<
*iterator*
An iterator is just a function that can be called repeatedly to get the "next"
value of a collection (or any other |iterable|). This interface is expected by
@ -1666,8 +1696,11 @@ vim.on_key({fn}, {ns_id}) *vim.on_key()*
callbacks if on_key() is called without arguments.
vim.paste({lines}, {phase}) *vim.paste()*
Paste handler, invoked by |nvim_paste()| when a conforming UI (such as the
|TUI|) pastes text into the editor.
Paste handler, invoked by |nvim_paste()|.
Note: This is provided only as a "hook", don't call it directly; call
|nvim_paste()| instead, which arranges redo (dot-repeat) and invokes
`vim.paste`.
Example: To remove ANSI color codes when pasting: >lua
vim.paste = (function(overridden)

View File

@ -422,6 +422,10 @@ argument.
Start |RPC| server on pipe or TCP address {addr}. Sets the
primary listen address |v:servername| to {addr}. |serverstart()|
To start the server on-demand with systemd, use a systemd
socket unit and associated service unit running: >
systemd-socket-proxyd --exit-idle-time
<
==============================================================================
Initialization *initialization* *startup*

View File

@ -25,6 +25,9 @@ Note: Windows 10 "Version 1809" or later is required for |:terminal|. To check
your Windows version, run the "winver" command and look for "Version xxxx"
(NOT "OS Build").
Note: On Windows "Server" you may need to install vcruntime140.dll:
https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170
Support types ~
* Tier 1: Officially supported and tested with CI. Any contributed patch

View File

@ -67,7 +67,7 @@ Defaults *nvim-defaults*
- 'langremap' is disabled
- 'laststatus' defaults to 2 (statusline is always shown)
- 'listchars' defaults to "tab:> ,trail:-,nbsp:+"
- 'mouse' defaults to "nvi"
- 'mouse' defaults to "nvi", see |default-mouse| for details
- 'mousemodel' defaults to "popup_setpos"
- 'nrformats' defaults to "bin,hex"
- 'path' defaults to ".,,". The C ftplugin adds "/usr/include" if it exists.
@ -101,12 +101,14 @@ Defaults *nvim-defaults*
DEFAULT MOUSE
*default-mouse* *disable-mouse*
By default the mouse is enabled, and <RightMouse> opens a |popup-menu| with
standard actions ("Cut", "Copy", "Paste", …). Mouse is NOT enabled in
|command-mode| or the |more-prompt|, so you can temporarily disable it just by
typing ":".
By default the mouse is enabled. This means |scroll-mouse-wheel| will scroll
the window instead of moving the cursor; <LeftMouse> click places the cursor;
and <RightMouse> click opens the default |popup-menu| with standard actions.
Mouse is NOT enabled in |Cmdline-mode| or the |more-prompt|, so you can
temporarily disable it just by typing ":". Or if you want to partially or
fully disable the mouse or popup-menu, do any of the following:
Or you can disable the popup-menu using any of the following:
- Disable mouse completely by unsetting the 'mouse' option: >vim
set mouse=
- Change the 'mousemodel', so <RightMouse> extends selection instead of

View File

@ -208,8 +208,10 @@ vim.inspect = vim.inspect
do
local tdots, tick, got_line1, undo_started, trailing_nl = 0, 0, false, false, false
--- Paste handler, invoked by |nvim_paste()| when a conforming UI
--- (such as the |TUI|) pastes text into the editor.
--- Paste handler, invoked by |nvim_paste()|.
---
--- Note: This is provided only as a "hook", don't call it directly; call |nvim_paste()| instead,
--- which arranges redo (dot-repeat) and invokes `vim.paste`.
---
--- Example: To remove ANSI color codes when pasting:
---

View File

@ -744,11 +744,6 @@ function vim.api.nvim_buf_set_option(buffer, name, value) end
--- `start_row = end_row = row` and `start_col = end_col = col`. To delete the
--- text in a range, use `replacement = {}`.
---
--- Prefer `nvim_buf_set_lines()` if you are only adding or deleting entire
--- lines.
---
--- Prefer `nvim_put()` if you want to insert text at the cursor position.
---
--- @param buffer integer Buffer handle, or 0 for current buffer
--- @param start_row integer First line index
--- @param start_col integer Starting column (byte offset) on first line
@ -1484,6 +1479,9 @@ function vim.api.nvim_get_vvar(name) end
--- input buffer and the call is non-blocking (input is processed
--- asynchronously by the eventloop).
---
--- To input blocks of text, `nvim_paste()` is much faster and should be
--- preferred.
---
--- On execution error: does not fail, but updates v:errmsg.
---
--- @param keys string to be typed
@ -1809,17 +1807,34 @@ function vim.api.nvim_parse_cmd(str, opts) end
--- @return table<string,any>
function vim.api.nvim_parse_expression(expr, flags, highlight) end
--- Pastes at cursor, in any mode.
--- Pastes at cursor (in any mode), and sets "redo" so dot (`.`) will repeat
--- the input. UIs call this to implement "paste", but it's also intended for
--- use by scripts to input large, dot-repeatable blocks of text (as opposed
--- to `nvim_input()` which is subject to mappings/events and is thus much
--- slower).
---
--- Invokes the `vim.paste` handler, which handles each mode appropriately.
--- Sets redo/undo. Faster than `nvim_input()`. Lines break at LF ("\n").
--- Invokes the `vim.paste()` handler, which handles each mode appropriately.
---
--- Errors ('nomodifiable', `vim.paste()` failure, …) are reflected in `err`
--- but do not affect the return value (which is strictly decided by
--- `vim.paste()`). On error or cancel, subsequent calls are ignored
--- ("drained") until the next paste is initiated (phase 1 or -1).
---
--- @param data string Multiline input. May be binary (containing NUL bytes).
--- Useful in mappings and scripts to insert multiline text. Example:
---
--- ```vim
--- vim.keymap.set('n', 'x', function()
--- vim.api.nvim_paste([[
--- line1
--- line2
--- line3
--- ]], false, -1)
--- end, { buffer = true })
--- ```
---
---
--- @param data string Multiline input. Lines break at LF ("\n"). May be binary
--- (containing NUL bytes).
--- @param crlf boolean Also break lines at CR and CRLF.
--- @param phase integer -1: paste in a single call (i.e. without streaming). To
--- "stream" a paste, call `nvim_paste` sequentially with these
@ -1830,7 +1845,8 @@ function vim.api.nvim_parse_expression(expr, flags, highlight) end
--- @return boolean
function vim.api.nvim_paste(data, crlf, phase) end
--- Puts text at cursor, in any mode.
--- Puts text at cursor, in any mode. For dot-repeatable input, use
--- `nvim_paste()`.
---
--- Compare `:put` and `p` which are always linewise.
---

View File

@ -462,12 +462,8 @@ end:
/// = row` and `start_col = end_col = col`. To delete the text in a range, use
/// `replacement = {}`.
///
/// Prefer |nvim_buf_set_lines()| if you are only adding or deleting entire lines.
///
/// Prefer |nvim_put()| if you want to insert text at the cursor position.
///
/// @see |nvim_buf_set_lines()|
/// @see |nvim_put()|
/// @note Prefer |nvim_buf_set_lines()| (for performance) to add or delete entire lines.
/// @note Prefer |nvim_paste()| or |nvim_put()| to insert (instead of replace) text at cursor.
///
/// @param channel_id
/// @param buffer Buffer handle, or 0 for current buffer

View File

@ -344,9 +344,10 @@ void nvim_feedkeys(String keys, String mode, Boolean escape_ks)
}
}
/// Queues raw user-input. Unlike |nvim_feedkeys()|, this uses a low-level
/// input buffer and the call is non-blocking (input is processed
/// asynchronously by the eventloop).
/// Queues raw user-input. Unlike |nvim_feedkeys()|, this uses a low-level input buffer and the call
/// is non-blocking (input is processed asynchronously by the eventloop).
///
/// To input blocks of text, |nvim_paste()| is much faster and should be preferred.
///
/// On execution error: does not fail, but updates v:errmsg.
///
@ -1212,17 +1213,30 @@ void nvim_set_current_tabpage(Tabpage tabpage, Error *err)
}
}
/// Pastes at cursor, in any mode.
/// Pastes at cursor (in any mode), and sets "redo" so dot (|.|) will repeat the input. UIs call
/// this to implement "paste", but it's also intended for use by scripts to input large,
/// dot-repeatable blocks of text (as opposed to |nvim_input()| which is subject to mappings/events
/// and is thus much slower).
///
/// Invokes the `vim.paste` handler, which handles each mode appropriately.
/// Sets redo/undo. Faster than |nvim_input()|. Lines break at LF ("\n").
/// Invokes the |vim.paste()| handler, which handles each mode appropriately.
///
/// Errors ('nomodifiable', `vim.paste()` failure, …) are reflected in `err`
/// but do not affect the return value (which is strictly decided by
/// `vim.paste()`). On error or cancel, subsequent calls are ignored
/// ("drained") until the next paste is initiated (phase 1 or -1).
/// Errors ('nomodifiable', `vim.paste()` failure, …) are reflected in `err` but do not affect the
/// return value (which is strictly decided by `vim.paste()`). On error or cancel, subsequent calls
/// are ignored ("drained") until the next paste is initiated (phase 1 or -1).
///
/// @param data Multiline input. May be binary (containing NUL bytes).
/// Useful in mappings and scripts to insert multiline text. Example:
///
/// ```vim
/// vim.keymap.set('n', 'x', function()
/// vim.api.nvim_paste([[
/// line1
/// line2
/// line3
/// ]], false, -1)
/// end, { buffer = true })
/// ```
///
/// @param data Multiline input. Lines break at LF ("\n"). May be binary (containing NUL bytes).
/// @param crlf Also break lines at CR and CRLF.
/// @param phase -1: paste in a single call (i.e. without streaming).
/// To "stream" a paste, call `nvim_paste` sequentially with
@ -1276,7 +1290,7 @@ theend:
return retval;
}
/// Puts text at cursor, in any mode.
/// Puts text at cursor, in any mode. For dot-repeatable input, use |nvim_paste()|.
///
/// Compare |:put| and |p| which are always linewise.
///