(or ALWAYS
for "continuation callbacks"—functions called exactly once).
- Improves readability by placing the less "noisy" arguments near the start.
- Consistent with luv.
- Useful for future async lib which transforms functions of the form
`function(<args>, cb(<ret)>))` => `function(<args>) -> <ret>`.
- Example: >lua
-- ✅ OK:
filter(…, opts, function() … end)
-- ❌ NO:
filter(function() … end, …, opts)
-- ❌ NO:
filter(…, function() … end, opts)
- "Enable" ("toggle") interface and behavior:
- `enable(…, nil)` and `enable(…, {buf=nil})` are synonyms and control the
the "global" enablement of a feature.
- `is_enabled(nil)` and `is_enabled({buf=nil})`, likewise, query the
global state of the feature.
- `enable(…, {buf: number})` sets a buffer-local "enable" flag.
- `is_enabled({buf: number})`, likewise, queries the buffer-local state of
the feature.
- See |vim.lsp.inlay_hint.enable()| and |vim.lsp.inlay_hint.is_enabled()|
for a reference implementation of these "best practices".
- NOTE: open questions: https://github.com/neovim/neovim/issues/28603
- Transformation functions should also have "filter" functionality (when
appropriate): when the function returns a nil value it excludes (filters
out) its input, else the transformed value is used.
- Example: See the format() field of |vim.diagnostic.Opts.Float|.
API DESIGN GUIDELINES *dev-api*
See also |dev-naming|.
- When adding an API, check the following:
- What precedents did you draw from? How does your solution compare to them?
- Does your new API allow future expansion? How? Or why not?
- Is the new API similar to existing APIs? Do we need to deprecate the old ones?
- Did you cross-reference related concepts in the docs?
- Avoid "mutually exclusive" parameters--via constraints or limitations, if
necessary. For example nvim_create_autocmd() has mutually exclusive
"callback" and "command" args; but the "command" arg could be eliminated by
simply not supporting Vimscript function names, and treating a string
"callback" arg as an Ex command (which can call Vimscript functions). The
"buffer" arg could also be eliminated by treating a number "pattern" as
a buffer number.
- Avoid functions that depend on cursor position, current buffer, etc. Instead
the function should take a position parameter, buffer parameter, etc.
Where things go ~
- API (libnvim/RPC): exposes low-level internals, or fundamental things (such
as `nvim_exec_lua()`) needed by clients or C consumers.
- Lua stdlib = high-level functionality that builds on top of the API.
NAMING GUIDELINES *dev-naming*
Naming is exceedingly important: the name of a thing is the primary interface
for uses it, discusses it, searches for it, shares it... Consistent
naming in the stdlib, 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 ~
In general, look for precedent when choosing a name, that is, look at existing
(non-deprecated) functions. In particular, see below...
*dev-name-common*
Use existing common {verb} names (actions) if possible:
- add: Appends or inserts into a collection
- attach: Listens to something to get events from it (TODO: rename to "on"?)
- call: Calls a function
- cancel: Cancels or dismisses an event or interaction, typically
user-initiated and without error. (Compare "abort", which
cancels and signals error/failure.)
- clear: Clears state but does not destroy the container
- create: Creates a new (non-trivial) thing