neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

dev_arch.txt (16814B)


      1 *dev_arch.txt*          Nvim
      2 
      3 
      4                            NVIM REFERENCE MANUAL
      5 
      6 
      7 How to develop Nvim, explanation of modules and subsystems    *dev-arch*
      8 
      9 Module-specific details are documented at the top of each module
     10 (`terminal.c`, `undo.c`, …). The top of each major module has (or should have)
     11 an overview in a comment at the top of its file.
     12 
     13 The purpose of this document is to give:
     14 
     15 1. an overview of how it all fits together
     16 2. how-to guides for common tasks such as:
     17    - (TODO) deprecating public functions
     18    - (TODO) adding a new public (API) function or (UI) event
     19 
     20                                  Type |gO| to see the table of contents.
     21 
     22 ==============================================================================
     23 Project layout: where things go
     24 
     25 C CODE
     26 
     27 - Nvim C code lives in `src/nvim/`.
     28    - This includes third-party components which we have forked and fully
     29      "own", meaning we no longer track the upstream. In particular: `vterm/`
     30      and `tui/termkey/`.
     31 - Vendored third-party components live in `src/*`.
     32    - `src/tee/` and `src/xxd/` have their own build files. They are shipped
     33      with the Windows artifact to ensure those tools exists there.
     34    - Other components like `src/cjson/` and `src/mpack/` are included with
     35      Nvim itself. These vendored sources are synced from upstream, we do not
     36      "own" them.
     37 
     38 See also "MAINTAIN.md".
     39 
     40 Generated C files use these filename conventions to hint their purpose:
     41 - `*.c`, `*.generated.c` - full C files, with all includes, etc.
     42 - `*.c.h` - parametrized C files, contain all necessary includes, but require
     43  defining macros before actually using. Example: `typval_encode.c.h`
     44 - `*.h` - full headers, with all includes. Does not apply to `*.generated.h`.
     45 - `*.h.generated.h` - exported functions’ declarations.
     46 - `*.c.generated.h` - static functions’ declarations.
     47 
     48 
     49 LUA CODE
     50 
     51 Lua code lives in one of four places:
     52 
     53 1. Plugins! Not everything needs to live on `vim.*`. Plugins are the correct
     54   model for non-essential features which the user may disable or replace with
     55   a third-party plugin, and which do not have a formal API. Examples:
     56   "editorconfig", "comment".
     57   - "opt-out": `runtime/plugin/`
     58   - "opt-in": `runtime/pack/dist/opt/`
     59 2. `runtime/lua/vim/` (the runtime): Lazy-loaded modules. Examples: `treesitter`, `lpeg`.
     60 3. `runtime/lua/vim/_core/shared.lua`: pure Lua functions which always are available.
     61   Used in the test runner, and worker threads/processes launched from Nvim.
     62 4. `runtime/lua/vim/_core/`: Eager-loaded code which directly interacts with the Nvim
     63   editor state. Only available in the main thread. See |dev-lua-builtin|
     64   below.
     65 
     66 The top-level `vim.` namespace is for fundamental Lua and editor features. Use
     67 submodules (`vim.foo`) for everything else (but avoid excessive "nesting"), or
     68 plugins (see above).
     69 
     70 Compatibility with Vim's `if_lua` is explicitly a non-goal.
     71 
     72                                                             *dev-lua-builtin*
     73 Lua modules that are necessary even if VIMRUNTIME is invalid (generally, data
     74 structures and essential utilities), must be compiled into the `nvim` binary.
     75 There are two ways to do that:
     76 - if they are private, put the code file in `runtime/lua/vim/_core/`
     77 - if they are public, choose a new filepath in `runtime/lua/vim/`
     78  and add it to VIM_MODULE_FILE in src/nvim/CMakeLists.txt.
     79 
     80 
     81 ==============================================================================
     82 Data structures
     83 
     84 - StringBuilder
     85 - kvec or garray.c for dynamic lists / vectors (use StringBuilder for strings)
     86 
     87 Use `kvec.h` for most lists. When you absolutely need a linked list, use
     88 `src/nvim/lib/queue_defs.h` which defines an "intrusive" linked list.
     89 
     90 Buffer text is stored as a tree of line segments, defined in `src/nvim/memline.c`.
     91 The central idea is found in `ml_find_line`.
     92 
     93 Many of the editor concepts are defined as Lua data files:
     94 
     95 - Events (autocmds): src/nvim/auevents.lua
     96 - Ex (cmdline) commands: src/nvim/ex_cmds.lua
     97 - Options: src/nvim/options.lua
     98 - Vimscript functions: src/nvim/eval.lua
     99 - v: variables: src/nvim/vvars.lua
    100 
    101 ==============================================================================
    102 Events                                                            *dev-events*
    103 
    104 The events historically called "autocmds", referred to here as "editor events"
    105 or simply "events", are high-level events for use by plugins, user config, and
    106 the Nvim editor. (There is an unrelated, low-level concept defined by the
    107 `event/defs.h#Event` struct, which is just a bag of data passed along the
    108 internal |event-loop|.)
    109 
    110 Where possible, new editor events should be implemented using `aucmd_defer()`
    111 (and where possible, old events migrate to this), so they are processed in
    112 a predictable manner, which avoids crashes and race conditions. See
    113 `do_markset_autocmd` for an example.
    114 
    115 ==============================================================================
    116 UI events                                                      *dev-ui-events*
    117 
    118 The long-term vision is that UI events are just another type of "editor event"
    119 (formerly known as "autocmds"). There is no real reason that we have separate
    120 types of user-facing or plugin-facing events. Events are events. Their
    121 "transport" is irrelevant and any event should be possible to emit over any
    122 transport (editor or RPC).
    123 
    124 Meanwhile the current situation is that UI events are a particular RPC event
    125 packaged in a generic `redraw` notification. They also can be listened to
    126 in-process via |vim.ui_attach()|.
    127 
    128 UI events are deferred to UIs, which implies a deepcopy of the UI event data.
    129 
    130 The source files most directly involved with UI events are:
    131 1. `src/nvim/ui.*`: calls handler functions of registered UI structs (independent from msgpack-rpc)
    132 2. `src/nvim/api/ui.*`: forwards messages over msgpack-rpc to remote UIs.
    133 
    134 UI events are defined in `src/nvim/api/ui_events.in.h` , this file is not
    135 compiled directly, rather it parsed by
    136 `src/gen/gen_api_ui_events.lua` which autogenerates wrapper
    137 functions used by the source files above. It also generates metadata
    138 accessible as `api_info().ui_events`.
    139 
    140 See commit d3a8e9217f39c59dd7762bd22a76b8bd03ca85ff for an example of adding
    141 a new UI event. Remember to bump NVIM_API_LEVEL if it wasn't already during
    142 this development cycle.
    143 
    144 Other references:
    145 - |msgpack-rpc|
    146 - |ui|
    147 - https://github.com/neovim/neovim/pull/3246
    148 - https://github.com/neovim/neovim/pull/18375
    149 - https://github.com/neovim/neovim/pull/21605
    150 
    151 
    152 ==============================================================================
    153 API
    154 
    155                                                        *dev-api-fast*
    156 API functions and Vimscript "eval" functions may be marked as |api-fast| which
    157 means they are safe to call in Lua callbacks and other scenarios. A function
    158 CANNOT be marked as "fast" if it could trigger `os_breakcheck()`, which may
    159 "yield" the current execution and start a new execution of code not expecting
    160 this:
    161 - accidentally recursing into a function not expecting this.
    162 - changing (global) state without restoring it before returning to the
    163  "yielded" callsite.
    164 
    165 In practice, this means any code that could trigger `os_breakcheck()` cannot
    166 be "fast". For example, commit 3940c435e405 fixed such a bug with
    167 `nvim__get_runtime` by explicitly disallowing `os_breakcheck()` via the
    168 `EW_NOBREAK` flag.
    169 
    170 Common examples of non-fast code: regexp matching, wildcard expansion,
    171 expression evaluation.
    172 
    173 
    174 ==============================================================================
    175 The event-loop                                                    *event-loop*
    176 
    177 The internal, low-level, libuv event-loop (|luv-event-loop|) is used to
    178 schedule arbitrary work in a predictable way. One such obvious use-case for
    179 scheduling is deferred editor-events (autocmds). Another example is
    180 |job-control|.
    181 
    182 ASYNC EVENT SUPPORT
    183 
    184 One of the features Nvim added is the support for handling arbitrary
    185 asynchronous events, which can include:
    186 
    187 - RPC requests
    188 - job control callbacks
    189 - timers
    190 
    191 Nvim implements this functionality by entering another event loop while
    192 waiting for characters, so instead of: >py
    193 
    194  def state_enter(on_state, data):
    195    do
    196      key = readkey()           # Read a key from the user
    197    while on_state(data, key)   # Invoke callback for the current state
    198 
    199 the Nvim program loop is more like: >py
    200 
    201  def state_enter(on_state, data):
    202    do
    203      event = read_next_event() # Read an event from the OS
    204    while on_state(data, event) # Invoke callback for current state
    205 
    206 where `event` is something the operating system delivers to us, including (but
    207 not limited to) user input. The `read_next_event()` part is internally
    208 implemented by libuv, the platform layer used by Nvim.
    209 
    210 Since Nvim inherited its code from Vim, the states are not prepared to receive
    211 "arbitrary events", so we use a special key to represent those (When a state
    212 receives an "arbitrary event", it normally doesn't do anything other than
    213 update the screen).
    214 
    215 MAIN LOOP
    216 
    217 The `Loop` structure (which describes `main_loop`) abstracts multiple queues
    218 into one loop: >
    219 
    220    uv_loop_t uv;
    221    MultiQueue *events;
    222    MultiQueue *thread_events;
    223    MultiQueue *fast_events;
    224 
    225 `loop_poll_events` checks `Loop.uv` and `Loop.fast_events` whenever Nvim is
    226 idle, and also at `os_breakcheck` intervals.
    227 
    228 MultiQueue is cool because you can attach throw-away "child queues" trivially.
    229 For example `do_os_system()` does this (for every spawned process!) to
    230 automatically route events onto the `main_loop`: >
    231 
    232    Process *proc = &uvproc.process;
    233    MultiQueue *events = multiqueue_new_child(main_loop.events);
    234    proc->events = events;
    235 
    236 
    237 NVIM LIFECYCLE
    238 
    239 How Nvim processes input.
    240 
    241 Consider a typical Vim-like editing session:
    242 
    243 01. Vim displays the welcome screen
    244 02. User types: `:`
    245 03. Vim enters command-line mode
    246 04. User types: `edit README.txt<CR>`
    247 05. Vim opens the file and returns to normal mode
    248 06. User types: `G`
    249 07. Vim navigates to the end of the file
    250 09. User types: `5`
    251 10. Vim enters count-pending mode
    252 11. User types: `d`
    253 12. Vim enters operator-pending mode
    254 13. User types: `w`
    255 14. Vim deletes 5 words
    256 15. User types: `g`
    257 16. Vim enters the "g command mode"
    258 17. User types: `g`
    259 18. Vim goes to the beginning of the file
    260 19. User types: `i`
    261 20. Vim enters insert mode
    262 21. User types: `word<ESC>`
    263 22. Vim inserts "word" at the beginning and returns to normal mode
    264 
    265 Note that we split user actions into sequences of inputs that change the state
    266 of the editor. While there's no documentation about a "g command mode" (step
    267 16), internally it is implemented similarly to "operator-pending mode".
    268 
    269 From this we can see that Vim has the behavior of an input-driven state machine
    270 (more specifically, a pushdown automaton since it requires a stack for
    271 transitioning back from states). Assuming each state has a callback responsible
    272 for handling keys, this pseudocode represents the main program loop: >py
    273 
    274  def state_enter(state_callback, data):
    275    do
    276      key = readkey()                 # read a key from the user
    277    while state_callback(data, key)   # invoke the callback for the current state
    278 <
    279 
    280 That is, each state is entered by calling `state_enter` and passing a
    281 state-specific callback and data. Here is a high-level pseudocode for a program
    282 that implements something like the workflow described above: >py
    283 
    284  def main()
    285    state_enter(normal_state, {}):
    286 
    287  def normal_state(data, key):
    288    if key == ':':
    289      state_enter(command_line_state, {})
    290    elif key == 'i':
    291      state_enter(insert_state, {})
    292    elif key == 'd':
    293      state_enter(delete_operator_state, {})
    294    elif key == 'g':
    295      state_enter(g_command_state, {})
    296    elif is_number(key):
    297      state_enter(get_operator_count_state, {'count': key})
    298    elif key == 'G'
    299      jump_to_eof()
    300    return true
    301 
    302  def command_line_state(data, key):
    303    if key == '<cr>':
    304      if data['input']:
    305        execute_ex_command(data['input'])
    306      return false
    307    elif key == '<esc>'
    308      return false
    309 
    310    if not data['input']:
    311      data['input'] = ''
    312 
    313    data['input'] += key
    314    return true
    315 
    316  def delete_operator_state(data, key):
    317    count = data['count'] or 1
    318    if key == 'w':
    319      delete_word(count)
    320    elif key == '$':
    321      delete_to_eol(count)
    322    return false  # return to normal mode
    323 
    324  def g_command_state(data, key):
    325    if key == 'g':
    326      go_top()
    327    elif key == 'v':
    328      reselect()
    329    return false  # return to normal mode
    330 
    331  def get_operator_count_state(data, key):
    332    if is_number(key):
    333      data['count'] += key
    334      return true
    335    unshift_key(key)  # return key to the input buffer
    336    state_enter(delete_operator_state, data)
    337    return false
    338 
    339  def insert_state(data, key):
    340    if key == '<esc>':
    341      return false  # exit insert mode
    342    self_insert(key)
    343    return true
    344 <
    345 
    346 The above gives an idea of how Nvim is organized internally. Some states like
    347 the `g_command_state` or `get_operator_count_state` do not have a dedicated
    348 `state_enter` callback, but are implicitly embedded into other states (this
    349 will change later as we continue the refactoring effort). To start reading the
    350 actual code, here's the recommended order:
    351 
    352 1. `state_enter()` function (state.c). This is the actual program loop,
    353   note that a `VimState` structure is used, which contains function pointers
    354   for the callback and state data.
    355 2. `main()` function (main.c). After all startup, `normal_enter` is called
    356   at the end of function to enter normal mode.
    357 3. `normal_enter()` function (normal.c) is a small wrapper for setting
    358   up the NormalState structure and calling `state_enter`.
    359 4. `normal_check()` function (normal.c) is called before each iteration of
    360   normal mode.
    361 5. `normal_execute()` function (normal.c) is called when a key is read in normal
    362   mode.
    363 
    364 The basic structure described for normal mode in 3, 4 and 5 is used for other
    365 modes managed by the `state_enter` loop:
    366 
    367 - command-line mode: `command_line_{enter,check,execute}()`(`ex_getln.c`)
    368 - insert mode: `insert_{enter,check,execute}()`(`edit.c`)
    369 - terminal mode: `terminal_{enter,execute}()`(`terminal.c`)
    370 
    371 IMPORTANT VARIABLES
    372 
    373 The current mode is stored in `State`.  The values it can have are `MODE_NORMAL`,
    374 `MODE_INSERT`, `MODE_CMDLINE`, and a few others.
    375 
    376 The current window is `curwin`.  The current buffer is `curbuf`.  These point
    377 to structures with the cursor position in the window, option values, the file
    378 name, etc.
    379 
    380 All the global variables are declared in `globals.h`.
    381 
    382 THE MAIN EVENT-LOOP
    383 
    384 The main loop is implemented in state_enter. The basic idea is that Vim waits
    385 for the user to type a character and processes it until another character is
    386 needed.  Thus there are several places where Vim waits for a character to be
    387 typed.  The `vgetc()` function is used for this.  It also handles mapping.
    388 
    389 What we consider the "Nvim event loop" is actually a wrapper around `uv_run` to
    390 handle both the `fast_events` queue and possibly (a suitable subset of) deferred
    391 events. Therefore "raw" `vim.uv.run()` is often not enough to "yield" from Lua
    392 plugins; instead they can call `vim.wait(0)`.
    393 
    394 Updating the screen is mostly postponed until a command or a sequence of
    395 commands has finished.  The work is done by `update_screen()`, which calls
    396 `win_update()` for every window, which calls `win_line()` for every line.
    397 See the start of [drawscreen.c](drawscreen.c) for more explanations.
    398 
    399 COMMAND-LINE MODE
    400 
    401 When typing a `:`, `normal_cmd()` will call `getcmdline()` to obtain a line with
    402 an Ex command.  `getcmdline()` calls a loop that will handle each typed
    403 character.  It returns when hitting `<CR>` or `<Esc>` or some other character that
    404 ends the command line mode.
    405 
    406 EX COMMANDS
    407 
    408 Ex commands are handled by the function `do_cmdline()`.  It does the generic
    409 parsing of the `:` command line and calls `do_one_cmd()` for each separate
    410 command.  It also takes care of while loops.
    411 
    412 `do_one_cmd()` parses the range and generic arguments and puts them in the
    413 exarg_t and passes it to the function that handles the command.
    414 
    415 The `:` commands are listed in [ex_cmds.lua](ex_cmds.lua).
    416 
    417 NORMAL MODE COMMANDS
    418 
    419 The Normal mode commands are handled by the `normal_cmd()` function.  It also
    420 handles the optional count and an extra character for some commands.  These
    421 are passed in a `cmdarg_T` to the function that handles the command.
    422 
    423 There is a table `nv_cmds` in [normal.c](normal.c) which
    424 lists the first character of every
    425 command.  The second entry of each item is the name of the function that
    426 handles the command.
    427 
    428 INSERT MODE COMMANDS
    429 
    430 When doing an `i` or `a` command, `normal_cmd()` will call the `edit()` function.
    431 It contains a loop that waits for the next character and handles it.  It
    432 returns when leaving Insert mode.
    433 
    434 
    435 ==============================================================================
    436 
    437 vim:tw=78:ts=8:sw=4:et:ft=help:norl: