mirror of
https://github.com/neovim/neovim.git
synced 2024-12-20 11:15:14 -07:00
fc4385ad94
closes #24141 closes #24746
505 lines
21 KiB
Plaintext
505 lines
21 KiB
Plaintext
*develop.txt* Nvim
|
|
|
|
|
|
NVIM REFERENCE MANUAL
|
|
|
|
|
|
Development of Nvim *development* *dev*
|
|
|
|
This reference describes design constraints and guidelines, for developing
|
|
Nvim applications or Nvim itself.
|
|
Architecture and internal concepts are covered in src/nvim/README.md
|
|
|
|
Nvim is free and open source. Everybody is encouraged to contribute.
|
|
https://github.com/neovim/neovim/blob/master/CONTRIBUTING.md
|
|
|
|
Type |gO| to see the table of contents.
|
|
|
|
==============================================================================
|
|
Design goals *design-goals*
|
|
|
|
Most important things come first (roughly). Some items conflict; this is
|
|
intentional. A balance must be found.
|
|
|
|
|
|
NVIM IS... IMPROVED *design-improved*
|
|
|
|
The Neo bits of Nvim should make it a better Vim, without becoming a
|
|
completely different editor.
|
|
- In matters of taste, prefer Vim/Unix tradition. If there is no relevant
|
|
Vim/Unix tradition, consider the "common case".
|
|
- There is no limit to the features that can be added. Select new features
|
|
based on (1) what users ask for, (2) how much effort it takes to implement
|
|
and (3) someone actually implementing it.
|
|
- Backwards compatibility is a feature. The RPC API in particular should
|
|
never break.
|
|
|
|
|
|
NVIM IS... WELL DOCUMENTED *design-documented*
|
|
|
|
- A feature that isn't documented is a useless feature. A patch for a new
|
|
feature must include the documentation.
|
|
- Documentation should be comprehensive and understandable. Use examples.
|
|
- Don't make the text unnecessarily long. Less documentation means that an
|
|
item is easier to find.
|
|
|
|
|
|
NVIM IS... FAST AND SMALL *design-speed-size*
|
|
|
|
Keep Nvim small and fast. This directly affects versatility and usability.
|
|
- Computers are becoming faster and bigger each year. Vim can grow too, but
|
|
no faster than computers are growing. Keep Vim usable on older systems.
|
|
- Many users start Vim from a shell very often. Startup time must be short.
|
|
- Commands must work efficiently. The time they consume must be as small as
|
|
possible. Useful commands may take longer.
|
|
- Don't forget that some people use Vim over a slow connection. Minimize the
|
|
communication overhead.
|
|
- Vim is a component among other components. Don't turn it into a massive
|
|
application, but have it work well together with other programs
|
|
("composability").
|
|
|
|
|
|
NVIM IS... MAINTAINABLE *design-maintain*
|
|
|
|
- The source code should not become a mess. It should be reliable code.
|
|
- Use comments in a useful way! Quoting the function name and argument names
|
|
is NOT useful. Do explain what they are for.
|
|
- Porting to another platform should be made easy, without having to change
|
|
too much platform-independent code.
|
|
- Use the object-oriented spirit: Put data and code together. Minimize the
|
|
knowledge spread to other parts of the code.
|
|
|
|
|
|
NVIM IS... NOT *design-not*
|
|
|
|
Nvim is not an operating system; instead it should be composed with other
|
|
tools or hosted as a component. Marvim once said: "Unlike Emacs, Nvim does not
|
|
include the kitchen sink... but it's good for plumbing."
|
|
|
|
|
|
==============================================================================
|
|
Developer guidelines *dev-guidelines*
|
|
|
|
|
|
PROVIDERS *dev-provider*
|
|
|
|
A primary goal of Nvim is to allow extension of the editor without special
|
|
knowledge in the core. Some core functions are delegated to "providers"
|
|
implemented as external scripts.
|
|
|
|
Examples:
|
|
|
|
1. In the Vim source code, clipboard logic accounts for more than 1k lines of
|
|
C source code (ui.c), to perform two tasks that are now accomplished with
|
|
shell commands such as xclip or pbcopy/pbpaste.
|
|
|
|
2. Python scripting support: Vim has three files dedicated to embedding the
|
|
Python interpreter: if_python.c, if_python3.c and if_py_both.h. Together
|
|
these files sum about 9.5k lines of C source code. In contrast, Nvim Python
|
|
scripting is performed by an external host process implemented in ~2k lines
|
|
of Python.
|
|
|
|
The provider framework invokes Vimscript from C. It is composed of two
|
|
functions in eval.c:
|
|
|
|
- eval_call_provider(name, method, arguments, discard): calls
|
|
provider#{name}#Call with the method and arguments. If discard is true, any
|
|
value returned by the provider will be discarded and empty value will be
|
|
returned.
|
|
- eval_has_provider(name): Checks the `g:loaded_{name}_provider` variable
|
|
which must be set to 2 by the provider script to indicate that it is
|
|
"enabled and working". Called by |has()| to check if features are available.
|
|
|
|
For example, the Python provider is implemented by the
|
|
"autoload/provider/python.vim" script, which sets `g:loaded_python_provider`
|
|
to 2 only if a valid external Python host is found. Then `has("python")`
|
|
reflects whether Python support is working.
|
|
|
|
*provider-reload*
|
|
Sometimes a GUI or other application may want to force a provider to
|
|
"reload". To reload a provider, undefine its "loaded" flag, then use
|
|
|:runtime| to reload it: >vim
|
|
|
|
:unlet g:loaded_clipboard_provider
|
|
:runtime autoload/provider/clipboard.vim
|
|
|
|
|
|
DOCUMENTATION *dev-doc*
|
|
|
|
- "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".
|
|
- "The words you choose are an essential part of the user experience."
|
|
https://developer.apple.com/design/human-interface-guidelines/writing
|
|
- "...without being overly colloquial or frivolous."
|
|
https://developers.google.com/style/tone
|
|
- Write docstrings (as opposed to inline comments) with present tense ("Gets"),
|
|
not imperative ("Get"). This tends to reduce ambiguity and improve clarity
|
|
by describing "What" instead of "How". >
|
|
GOOD:
|
|
/// Gets a highlight definition.
|
|
BAD:
|
|
/// Get a highlight definition.
|
|
- Avoid starting docstrings with "The" or "A" unless needed to avoid
|
|
ambiguity. This is a visual aid and reduces noise. >
|
|
GOOD:
|
|
/// @param dirname Path fragment before `pend`
|
|
BAD:
|
|
/// @param dirname The path fragment before `pend`
|
|
- 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".
|
|
- Use "tui-" to prefix help tags related to the host terminal, and "TUI"
|
|
in prose if possible.
|
|
|
|
Documentation format ~
|
|
|
|
For Nvim-owned docs, use the following strict subset of "vimdoc" to ensure
|
|
the help doc renders nicely in other formats (such as HTML:
|
|
https://neovim.io/doc/user ).
|
|
|
|
Strict "vimdoc" subset:
|
|
|
|
- Use lists (like this!) prefixed with "-" or "•", for adjacent lines that you
|
|
don't want to auto-wrap. Lists are always rendered with "flow" layout
|
|
(soft-wrapped) instead of preformatted (hard-wrapped) layout common in
|
|
legacy :help docs.
|
|
- Limitation: currently the parser https://github.com/neovim/tree-sitter-vimdoc
|
|
does not understand numbered listitems, so use a bullet symbol (- or •)
|
|
before numbered items, e.g. "• 1." instead of "1.".
|
|
- Separate blocks (paragraphs) of content by a blank line.
|
|
- Do not use indentation in random places—that prevents the page from using
|
|
"flow" layout. If you need a preformatted section, put it in
|
|
a |help-codeblock| starting with ">".
|
|
|
|
C docstrings ~
|
|
|
|
Nvim API documentation lives in the source code, as docstrings (Doxygen
|
|
comments) on the function definitions. The |api| :help is generated
|
|
from the docstrings defined in src/nvim/api/*.c.
|
|
|
|
Docstring format:
|
|
- Lines start with `///`
|
|
- Special tokens start with `@` followed by the token name:
|
|
`@note`, `@param`, `@returns`
|
|
- Limited markdown is supported.
|
|
- List-items start with `-` (useful to nest or "indent")
|
|
- Use ``` for code samples.
|
|
Code samples can be annotated as `vim` or `lua`
|
|
|
|
Example: the help for |nvim_open_win()| is generated from a docstring defined
|
|
in src/nvim/api/win_config.c like this: >
|
|
|
|
/// Opens a new window.
|
|
/// ...
|
|
///
|
|
/// Example (Lua): window-relative float
|
|
///
|
|
/// ```lua
|
|
/// vim.api.nvim_open_win(0, false, {
|
|
/// relative='win',
|
|
/// row=3,
|
|
/// col=3,
|
|
/// width=12,
|
|
/// height=3,
|
|
/// })
|
|
/// ```
|
|
///
|
|
/// @param buffer Buffer to display
|
|
/// @param enter Enter the window
|
|
/// @param config Map defining the window configuration. Keys:
|
|
/// - relative: Sets the window layout, relative to:
|
|
/// - "editor" The global editor grid.
|
|
/// - "win" Window given by the `win` field.
|
|
/// - "cursor" Cursor position in current window.
|
|
/// ...
|
|
/// @param[out] err Error details, if any
|
|
///
|
|
/// @return Window handle, or 0 on error
|
|
|
|
|
|
Lua docstrings ~
|
|
*dev-lua-doc*
|
|
Lua documentation lives in the source code, as docstrings on the function
|
|
definitions. The |lua-vim| :help is generated from the docstrings.
|
|
|
|
Docstring format:
|
|
- Use LuaCATS annotations: https://luals.github.io/wiki/annotations/
|
|
- Limited markdown is supported.
|
|
- List-items start with `-` (useful to nest or "indent")
|
|
- Use ``` for code samples.
|
|
Code samples can be annotated as `vim` or `lua`
|
|
- Use `@nodoc` to prevent documentation generation.
|
|
- Files which has `@meta` are only used for typing and documentation.
|
|
|
|
Example: the help for |vim.paste()| is generated from a docstring decorating
|
|
vim.paste in runtime/lua/vim/_editor.lua like this: >
|
|
|
|
--- Paste handler, invoked by |nvim_paste()| when a conforming UI
|
|
--- (such as the |TUI|) pastes text into the editor.
|
|
---
|
|
--- Example: To remove ANSI color codes when pasting:
|
|
---
|
|
--- ```lua
|
|
--- vim.paste = (function()
|
|
--- local overridden = vim.paste
|
|
--- ...
|
|
--- end)()
|
|
--- ```
|
|
---
|
|
--- @see |paste|
|
|
---
|
|
--- @param lines ...
|
|
--- @param phase ...
|
|
--- @returns false if client should cancel the paste.
|
|
|
|
|
|
LUA STDLIB DESIGN GUIDELINES *dev-lua*
|
|
|
|
See also |dev-naming|.
|
|
|
|
- Keep the core Lua modules |lua-stdlib| simple. Avoid elaborate OOP or
|
|
pseudo-OOP designs. Plugin authors just want functions to call, not a big,
|
|
fancy inheritance hierarchy.
|
|
- Avoid requiring or returning special objects in the Nvim stdlib. Plain
|
|
tables or values are easier to serialize, easier to construct from literals,
|
|
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 "hydrated", 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.
|
|
|
|
Interface conventions ~
|
|
|
|
- When accepting a buffer id, etc., 0 means "current buffer", nil means "all
|
|
buffers". Likewise for window id, tabpage id, etc.
|
|
- Examples: |vim.lsp.codelens.clear()| |vim.diagnostic.enable()|
|
|
- Any function signature that accepts a callback function should define the
|
|
callback as the LAST parameter, if possible. This improves readability of
|
|
calls by placing the less "noisy" arguments near the start. >
|
|
GOOD:
|
|
filter(table, opts, function() … end)
|
|
BAD:
|
|
filter(function() … end, table, opts)
|
|
|
|
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
|
|
- clear: Clears state but does not destroy the container
|
|
- create: Creates a new (non-trivial) thing (TODO: rename to "def"?)
|
|
- del: Deletes a thing (or group of things)
|
|
- detach: Dispose attached listener (TODO: rename to "un"?)
|
|
- eval: Evaluates an expression
|
|
- exec: Executes code
|
|
- fmt: Formats
|
|
- get: Gets things (often by a query)
|
|
- inspect: Presents a high-level, often interactive, view
|
|
- open: Opens something (a buffer, window, …)
|
|
- parse: Parses something into a structured form
|
|
- set: Sets a thing (or group of things)
|
|
- try_{verb}: Best-effort operation, failure returns null or error obj
|
|
|
|
Do NOT use these deprecated verbs:
|
|
- list: Redundant with "get"
|
|
- show: Redundant with "print", "echo"
|
|
- notify: Redundant with "print", "echo"
|
|
|
|
Use consistent names for {noun} (nouns) in API functions: buffer is called
|
|
"buf" everywhere, not "buffer" in some places and "buf" in others.
|
|
- buf: Buffer
|
|
- chan: |channel|
|
|
- cmd: Command
|
|
- cmdline: Command-line UI or input
|
|
- fn: Function
|
|
- hl: Highlight
|
|
- pos: Position
|
|
- proc: System process
|
|
- tabpage: Tabpage
|
|
- win: Window
|
|
|
|
Do NOT use these deprecated nouns:
|
|
- buffer
|
|
- callback Use on_foo instead
|
|
- command
|
|
- window
|
|
|
|
*dev-name-events*
|
|
Use the "on_" prefix to name event-handling callbacks 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.
|
|
|
|
Editor |events| (autocommands) are historically named like: >
|
|
{Noun}{Event}
|
|
|
|
Use this format to name API (RPC) events: >
|
|
nvim_{noun}_{event-name}_event
|
|
|
|
Example: >
|
|
nvim_buf_changedtick_event
|
|
<
|
|
*dev-name-api*
|
|
Use this format to name new RPC |API| functions: >
|
|
nvim_{noun}_{verb}_{arbitrary-qualifiers}
|
|
|
|
If the function acts on an object then {noun} is the name of that object
|
|
(e.g. "buf" or "win"). If the function operates in a "global" context then
|
|
{noun} is usually omitted (but consider "namespacing" your global operations
|
|
with a {noun} that groups functions under a common concept).
|
|
|
|
- Example: `nvim_get_keymap('v')` operates in a global context (first
|
|
parameter is not a Buffer). The "get" verb indicates that it gets anything
|
|
matching the given filter parameter. A "list" verb is unnecessary because
|
|
`nvim_get_keymap('')` (empty filter) returns all items.
|
|
- Example: `nvim_buf_del_mark` acts on a `Buffer` object (the first parameter)
|
|
and uses the "del" {verb}.
|
|
|
|
|
|
API-CLIENT *dev-api-client*
|
|
|
|
*api-client*
|
|
API clients wrap the Nvim |API| to provide idiomatic "SDKs" for their
|
|
respective platforms (see |jargon|). You can build a new API client for your
|
|
favorite platform or programming language.
|
|
|
|
List of API clients:
|
|
https://github.com/neovim/neovim/wiki/Related-projects#api-clients
|
|
|
|
*pynvim*
|
|
The Python client is the reference implementation for API clients.
|
|
https://github.com/neovim/pynvim
|
|
|
|
Standard Features ~
|
|
|
|
- API clients exist to hide msgpack-rpc details. The wrappers can be
|
|
automatically generated by reading the |api-metadata| from Nvim. |api-mapping|
|
|
- Clients should call |nvim_set_client_info()| after connecting, so users and
|
|
plugins can detect the client by handling the |ChanInfo| event. This avoids
|
|
the need for special variables or other client hints.
|
|
- Clients should handle |nvim_error_event| notifications, which will be sent
|
|
if an async request to nvim was rejected or caused an error.
|
|
|
|
Package Naming ~
|
|
|
|
API client packages should NOT be named something ambiguous like "neovim" or
|
|
"python-client". Use "nvim" as a prefix/suffix to some other identifier
|
|
following ecosystem conventions.
|
|
|
|
For example, Python packages tend to have "py" in the name, so "pynvim" is
|
|
a good name: it's idiomatic and unambiguous. If the package is named "neovim",
|
|
it confuses users, and complicates documentation and discussions.
|
|
|
|
Examples of API-client package names:
|
|
- GOOD: nvim-racket
|
|
- GOOD: pynvim
|
|
- BAD: python-client
|
|
- BAD: neovim_
|
|
|
|
API client implementation guidelines ~
|
|
|
|
- Separate the transport layer from the rest of the library. |rpc-connecting|
|
|
- Use a MessagePack library that implements at least version 5 of the
|
|
MessagePack spec, which supports the BIN and EXT types used by Nvim.
|
|
- Use a single-threaded event loop library/pattern.
|
|
- Use a fiber/coroutine library for the language being used for implementing
|
|
a client. These greatly simplify concurrency and allow the library to
|
|
expose a blocking API on top of a non-blocking event loop without the
|
|
complexity that comes with preemptive multitasking.
|
|
- Don't assume anything about the order of responses to RPC requests.
|
|
- Clients should expect requests, which must be handled immediately because
|
|
Nvim is blocked while waiting for the client response.
|
|
- Clients should expect notifications, but these can be handled "ASAP" (rather
|
|
than immediately) because they won't block Nvim.
|
|
- For C/C++ projects, consider libmpack instead of the msgpack.org library.
|
|
https://github.com/libmpack/libmpack/
|
|
libmpack is small (no dependencies, can inline into your C/C++ project) and
|
|
efficient (no allocations). It also implements msgpack-RPC, the protocol
|
|
required by Nvim.
|
|
https://github.com/msgpack-rpc/msgpack-rpc
|
|
|
|
|
|
EXTERNAL UI *dev-ui*
|
|
|
|
External UIs should be aware of the |api-contract|. In particular, future
|
|
versions of Nvim may add new items to existing events. The API is strongly
|
|
backwards-compatible, but clients must not break if new (optional) fields are
|
|
added to existing events.
|
|
|
|
Standard Features ~
|
|
|
|
External UIs are expected to implement these common features:
|
|
|
|
- Call |nvim_set_client_info()| after connecting, so users and plugins can
|
|
detect the UI by handling the |ChanInfo| event. This avoids the need for
|
|
special variables and UI-specific config files (gvimrc, macvimrc, …).
|
|
- Cursor style (shape, color) should conform to the 'guicursor' properties
|
|
delivered with the mode_info_set UI event.
|
|
- Send the ALT/META ("Option" on macOS) key as a |<M-| chord.
|
|
- Send the "super" key (Windows key, Apple key) as a |<D-| chord.
|
|
- Avoid mappings that conflict with the Nvim keymap-space; GUIs have many new
|
|
chords (<C-,> <C-Enter> <C-S-x> <D-x>) and patterns ("shift shift") that do
|
|
not potentially conflict with Nvim defaults, plugins, etc.
|
|
- Consider the "option_set" |ui-global| event as a hint for other GUI
|
|
behaviors. Various UI-related options ('guifont', 'ambiwidth', …) are
|
|
published in this event. See also "mouse_on", "mouse_off".
|
|
- UIs generally should NOT set |$NVIM_APPNAME| (unless explicitly requested by
|
|
the user).
|
|
|
|
|
|
vim:tw=78:ts=8:sw=4:et:ft=help:norl:
|