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: