commit c05ff026bc8f4e8a1ee48b19ea384f7feb6e2d79
parent 07d0da64ed51202f0dbd92d43c89aa5f246b175e
Author: Justin M. Keyes <justinkz@gmail.com>
Date: Thu, 23 Oct 2025 20:15:52 -0400
Merge #36028 docs
Diffstat:
19 files changed, 778 insertions(+), 787 deletions(-)
diff --git a/runtime/doc/debug.txt b/runtime/doc/debug.txt
@@ -1,163 +0,0 @@
-*debug.txt* Nvim
-
-
- VIM REFERENCE MANUAL by Bram Moolenaar
-
-
-Debugging Vim *debug-vim*
-
-This is for debugging Vim itself, when it doesn't work properly.
-For debugging Vim scripts, functions, etc. see |debug-scripts|
-
- Type |gO| to see the table of contents.
-
-==============================================================================
-
-1. Location of a crash, using gcc and gdb *debug-gcc* *gdb*
-
-When Vim crashes in one of the test files, and you are using gcc for
-compilation, here is what you can do to find out exactly where Vim crashes.
-This also applies when using the MingW tools.
-
-1. Compile Vim with the "-g" option (there is a line in the src/Makefile for
- this, which you can uncomment). Also make sure "strip" is disabled (do not
- install it, or use the line "STRIP = /bin/true").
-
-2. Execute these commands (replace "11" with the test that fails): >
- cd testdir
- gdb ../vim
- run -u unix.vim -U NONE -s dotest.in test11.in
-
-3. Check where Vim crashes, gdb should give a message for this.
-
-4. Get a stack trace from gdb with this command: >
- where
-< You can check out different places in the stack trace with: >
- frame 3
-< Replace "3" with one of the numbers in the stack trace.
-
-==============================================================================
-
-2. Locating memory leaks *debug-leaks* *valgrind*
-
-If you suspect Vim is leaking memory and you are using Linux, the valgrind
-tool is very useful to pinpoint memory leaks.
-
-First of all, build Vim with EXITFREE defined. Search for this in MAKEFILE
-and uncomment the line.
-
-Use this command to start Vim:
->
- valgrind --log-file=valgrind.log --leak-check=full ./vim
-
-Note: Vim will run much slower. If your vimrc is big or you have several
-plugins you need to be patient for startup, or run with the "-u NONE"
-argument.
-
-There are often a few leaks from libraries, such as getpwuid() and
-XtVaAppCreateShell(). Those are unavoidable. The number of bytes should be
-very small a Kbyte or less.
-
-==============================================================================
-
-3. Windows Bug Reporting *debug-win32*
-
-If the Windows version of Vim crashes in a reproducible manner, you can take
-some steps to provide a useful bug report.
-
-
-3.1 GENERIC ~
-
-You must obtain the debugger symbols (PDB) file for your executable: gvim.pdb
-for gvim.exe, or vim.pdb for vim.exe. The PDB should be available from the
-same place that you obtained the executable. Be sure to use the PDB that
-matches the EXE (same date).
-
-If you built the executable yourself with the Microsoft Visual C++ compiler,
-then the PDB was built with the EXE.
-
-If you have Visual Studio, use that instead of the VC Toolkit and WinDbg.
-
-For other compilers, you should always use the corresponding debugger: gdb
-(see above |debug-gcc|) for the Cygwin and MinGW compilers.
-
-
- *debug-vs2005*
-3.2 Debugging Vim crashes with Visual Studio 2005/Visual C++ 2005 Express ~
-
-First launch vim.exe or gvim.exe and then launch Visual Studio. (If you don't
-have Visual Studio, follow the instructions at |get-ms-debuggers| to obtain a
-free copy of Visual C++ 2005 Express Edition.)
-
-On the Tools menu, click Attach to Process. Choose the Vim process.
-
-In Vim, reproduce the crash. A dialog will appear in Visual Studio, telling
-you about the unhandled exception in the Vim process. Click Break to break
-into the process.
-
-Visual Studio will pop up another dialog, telling you that no symbols are
-loaded and that the source code cannot be displayed. Click OK.
-
-Several windows will open. Right-click in the Call Stack window. Choose Load
-Symbols. The Find Symbols dialog will open, looking for (g)vim.pdb. Navigate
-to the directory where you have the PDB file and click Open.
-
-At this point, you should have a full call stack with vim function names and
-line numbers. Double-click one of the lines and the Find Source dialog will
-appear. Navigate to the directory where the Vim source is (if you have it.)
-
-If you don't know how to debug this any further, follow the instructions
-at ":help bug-report". Paste the call stack into the bug report.
-
-If you have a non-free version of Visual Studio, you can save a minidump via
-the Debug menu and send it with the bug report. A minidump is a small file
-(<100KB), which contains information about the state of your process.
-Visual C++ 2005 Express Edition cannot save minidumps and it cannot be
-installed as a just-in-time debugger. Use WinDbg, |debug-windbg|, if you
-need to save minidumps or you want a just-in-time (postmortem) debugger.
-
- *debug-windbg*
-3.3 Debugging Vim crashes with WinDbg ~
-
-See |get-ms-debuggers| to obtain a copy of WinDbg.
-
-As with the Visual Studio IDE, you can attach WinDbg to a running Vim process.
-You can also have your system automatically invoke WinDbg as a postmortem
-debugger. To set WinDbg as your postmortem debugger, run "windbg -I".
-
-To attach WinDbg to a running Vim process, launch WinDbg. On the File menu,
-choose Attach to a Process. Select the Vim process and click OK.
-
-At this point, choose Symbol File Path on the File menu, and add the folder
-containing your Vim PDB to the sympath. If you have Vim source available,
-use Source File Path on the File menu. You can now open source files in
-WinDbg and set breakpoints, if you like. Reproduce your crash. WinDbg should
-open the source file at the point of the crash. Using the View menu, you can
-examine the call stack, local variables, watch windows, and so on.
-
-If WinDbg is your postmortem debugger, you do not need to attach WinDbg to
-your Vim process. Simply reproduce the crash and WinDbg will launch
-automatically. As above, set the Symbol File Path and the Source File Path.
-
-To save a minidump, type the following at the WinDbg command line: >
- .dump vim.dmp
-<
- *debug-minidump*
-3.4 Opening a Minidump ~
-
-If you have a minidump file, you can open it in Visual Studio or in WinDbg.
-
-In Visual Studio 2005: on the File menu, choose Open, then Project/Solution.
-Navigate to the .dmp file and open it. Now press F5 to invoke the debugger.
-Follow the instructions in |debug-vs2005| to set the Symbol File Path.
-
-In WinDbg: choose Open Crash Dump on the File menu. Follow the instructions
-in |debug-windbg| to set the Symbol File Path.
-
- *get-ms-debuggers*
-3.5 Obtaining Microsoft Debugging Tools ~
-
-Visual Studio 2017 Community Edition can be downloaded for free from:
- https://visualstudio.microsoft.com/downloads/
-
- vim:tw=78:ts=8:noet:ft=help:norl:
diff --git a/runtime/doc/dev_arch.txt b/runtime/doc/dev_arch.txt
@@ -6,26 +6,79 @@
How to develop Nvim, explanation of modules and subsystems *dev-arch*
-The top of each major module has (or should have) an overview in a comment at
-the top of its file. The purpose of this document is to give:
+Module-specific details are documented at the top of each module
+(`terminal.c`, `undo.c`, …). The top of each major module has (or should have)
+an overview in a comment at the top of its file.
+
+The purpose of this document is to give:
1. an overview of how it all fits together
2. how-to guides for common tasks such as:
- - deprecating public functions
- - adding a new public (API) function
- - adding a new public (UI) event
-3. TODO: move src/nvim/README.md into this doc.
+ - (TODO) deprecating public functions
+ - (TODO) adding a new public (API) function or (UI) event
Type |gO| to see the table of contents.
==============================================================================
+Filename conventions
+
+The source filenames use extensions to hint about their purpose.
+
+- `*.c`, `*.generated.c` - full C files, with all includes, etc.
+- `*.c.h` - parametrized C files, contain all necessary includes, but require
+ defining macros before actually using. Example: `typval_encode.c.h`
+- `*.h` - full headers, with all includes. Does *not* apply to `*.generated.h`.
+- `*.h.generated.h` - exported functions’ declarations.
+- `*.c.generated.h` - static functions’ declarations.
+
+==============================================================================
Data structures
+- StringBuilder
+- kvec or garray.c for dynamic lists / vectors (use StringBuilder for strings)
+
Use `kvec.h` for most lists. When you absolutely need a linked list, use
`lib/queue_defs.h` which defines an "intrusive" linked list.
+Buffer text is stored as a tree of line segments, defined in `src/nvim/memline.c`.
+The central idea is found in `ml_find_line`.
+
+Many of the editor concepts are defined as Lua data files:
+
+- Events (autocmds): src/nvim/auevents.lua
+- Ex (cmdline) commands: src/nvim/ex_cmds.lua
+- Options: src/nvim/options.lua
+- Vimscript functions: src/nvim/eval.lua
+- v: variables: src/nvim/vvars.lua
+
+==============================================================================
+Events *dev-events*
+
+The events historically called "autocmds", referred to here as "editor events"
+or simply "events", are high-level events for use by plugins, user config, and
+the Nvim editor. (There is an unrelated, low-level concept defined by the
+`event/defs.h#Event` struct, which is just a bag of data passed along the
+internal |event-loop|.)
+
+All new editor events must be implemented using `aucmd_defer()` (and where
+possible, old events should be migrated to this), so that they are processed
+in a predictable manner, which avoids crashes and race conditions. See
+`do_markset_autocmd` for an example.
+
==============================================================================
-UI events
+UI events *dev-ui-events*
+
+The long-term vision is that UI events are just another type of "editor event"
+(formerly known as "autocmds"). There is no real reason that we have separate
+types of user-facing or plugin-facing events. Events are events. Their
+"transport" is irrelevant and any event should be possible to emit over any
+transport (editor or RPC).
+
+Meanwhile the current situation is that UI events are a particular RPC event
+packaged in a generic `redraw` notification. They also can be listened to
+in-process via |vim.ui_attach()|.
+
+UI events are deferred to UIs, which implies a deepcopy of the UI event data.
The source files most directly involved with UI events are:
1. `src/nvim/ui.*`: calls handler functions of registered UI structs (independent from msgpack-rpc)
@@ -38,12 +91,8 @@ functions used by the source files above. It also generates metadata
accessible as `api_info().ui_events`.
See commit d3a8e9217f39c59dd7762bd22a76b8bd03ca85ff for an example of adding
-a new UI event.
-
-UI events are deferred to UIs, which implies a deepcopy of the UI event data.
-
-Remember to bump NVIM_API_LEVEL if it wasn't already during this development
-cycle.
+a new UI event. Remember to bump NVIM_API_LEVEL if it wasn't already during
+this development cycle.
Other references:
- |msgpack-rpc|
@@ -76,5 +125,268 @@ expression evaluation.
==============================================================================
+The event-loop *event-loop*
+
+The internal, low-level, libuv event-loop (|luv-event-loop|) is used to
+schedule arbitrary work in a predictable way. One such obvious use-case for
+scheduling is deferred editor-events (autocmds). Another example is
+|job-control|.
+
+ASYNC EVENT SUPPORT
+
+One of the features Nvim added is the support for handling arbitrary
+asynchronous events, which can include:
+
+- RPC requests
+- job control callbacks
+- timers
+
+Nvim implements this functionality by entering another event loop while
+waiting for characters, so instead of: >py
+
+ def state_enter(state_callback, data):
+ do
+ key = readkey() # read a key from the user
+ while state_callback(data, key) # invoke the callback for the current state
+<
+
+The Nvim program loop is more like: >py
+
+ def state_enter(state_callback, data):
+ do
+ event = read_next_event() # read an event from the operating system
+ while state_callback(data, event) # invoke the callback for the current state
+<
+
+where `event` is something the operating system delivers to us, including (but
+not limited to) user input. The `read_next_event()` part is internally
+implemented by libuv, the platform layer used by Nvim.
+
+Since Nvim inherited its code from Vim, the states are not prepared to receive
+"arbitrary events", so we use a special key to represent those (When a state
+receives an "arbitrary event", it normally doesn't do anything other than
+update the screen).
+
+MAIN LOOP
+
+The `Loop` structure (which describes `main_loop`) abstracts multiple queues
+into one loop: >
+
+ uv_loop_t uv;
+ MultiQueue *events;
+ MultiQueue *thread_events;
+ MultiQueue *fast_events;
+
+`loop_poll_events` checks `Loop.uv` and `Loop.fast_events` whenever Nvim is
+idle, and also at `os_breakcheck` intervals.
+
+MultiQueue is cool because you can attach throw-away "child queues" trivially.
+For example `do_os_system()` does this (for every spawned process!) to
+automatically route events onto the `main_loop`: >
+
+ Process *proc = &uvproc.process;
+ MultiQueue *events = multiqueue_new_child(main_loop.events);
+ proc->events = events;
+
+
+NVIM LIFECYCLE
+
+How Nvim processes input.
+
+Consider a typical Vim-like editing session:
+
+01. Vim displays the welcome screen
+02. User types: `:`
+03. Vim enters command-line mode
+04. User types: `edit README.txt<CR>`
+05. Vim opens the file and returns to normal mode
+06. User types: `G`
+07. Vim navigates to the end of the file
+09. User types: `5`
+10. Vim enters count-pending mode
+11. User types: `d`
+12. Vim enters operator-pending mode
+13. User types: `w`
+14. Vim deletes 5 words
+15. User types: `g`
+16. Vim enters the "g command mode"
+17. User types: `g`
+18. Vim goes to the beginning of the file
+19. User types: `i`
+20. Vim enters insert mode
+21. User types: `word<ESC>`
+22. Vim inserts "word" at the beginning and returns to normal mode
+
+Note that we split user actions into sequences of inputs that change the state
+of the editor. While there's no documentation about a "g command mode" (step
+16), internally it is implemented similarly to "operator-pending mode".
+
+From this we can see that Vim has the behavior of an input-driven state machine
+(more specifically, a pushdown automaton since it requires a stack for
+transitioning back from states). Assuming each state has a callback responsible
+for handling keys, this pseudocode represents the main program loop: >py
+
+ def state_enter(state_callback, data):
+ do
+ key = readkey() # read a key from the user
+ while state_callback(data, key) # invoke the callback for the current state
+<
+
+That is, each state is entered by calling `state_enter` and passing a
+state-specific callback and data. Here is a high-level pseudocode for a program
+that implements something like the workflow described above: >py
+
+ def main()
+ state_enter(normal_state, {}):
+
+ def normal_state(data, key):
+ if key == ':':
+ state_enter(command_line_state, {})
+ elif key == 'i':
+ state_enter(insert_state, {})
+ elif key == 'd':
+ state_enter(delete_operator_state, {})
+ elif key == 'g':
+ state_enter(g_command_state, {})
+ elif is_number(key):
+ state_enter(get_operator_count_state, {'count': key})
+ elif key == 'G'
+ jump_to_eof()
+ return true
+
+ def command_line_state(data, key):
+ if key == '<cr>':
+ if data['input']:
+ execute_ex_command(data['input'])
+ return false
+ elif key == '<esc>'
+ return false
+
+ if not data['input']:
+ data['input'] = ''
+
+ data['input'] += key
+ return true
+
+ def delete_operator_state(data, key):
+ count = data['count'] or 1
+ if key == 'w':
+ delete_word(count)
+ elif key == '$':
+ delete_to_eol(count)
+ return false # return to normal mode
+
+ def g_command_state(data, key):
+ if key == 'g':
+ go_top()
+ elif key == 'v':
+ reselect()
+ return false # return to normal mode
+
+ def get_operator_count_state(data, key):
+ if is_number(key):
+ data['count'] += key
+ return true
+ unshift_key(key) # return key to the input buffer
+ state_enter(delete_operator_state, data)
+ return false
+
+ def insert_state(data, key):
+ if key == '<esc>':
+ return false # exit insert mode
+ self_insert(key)
+ return true
+<
+
+The above gives an idea of how Nvim is organized internally. Some states like
+the `g_command_state` or `get_operator_count_state` do not have a dedicated
+`state_enter` callback, but are implicitly embedded into other states (this
+will change later as we continue the refactoring effort). To start reading the
+actual code, here's the recommended order:
+
+1. `state_enter()` function (state.c). This is the actual program loop,
+ note that a `VimState` structure is used, which contains function pointers
+ for the callback and state data.
+2. `main()` function (main.c). After all startup, `normal_enter` is called
+ at the end of function to enter normal mode.
+3. `normal_enter()` function (normal.c) is a small wrapper for setting
+ up the NormalState structure and calling `state_enter`.
+4. `normal_check()` function (normal.c) is called before each iteration of
+ normal mode.
+5. `normal_execute()` function (normal.c) is called when a key is read in normal
+ mode.
+
+The basic structure described for normal mode in 3, 4 and 5 is used for other
+modes managed by the `state_enter` loop:
+
+- command-line mode: `command_line_{enter,check,execute}()`(`ex_getln.c`)
+- insert mode: `insert_{enter,check,execute}()`(`edit.c`)
+- terminal mode: `terminal_{enter,execute}()`(`terminal.c`)
+
+IMPORTANT VARIABLES
+
+The current mode is stored in `State`. The values it can have are `MODE_NORMAL`,
+`MODE_INSERT`, `MODE_CMDLINE`, and a few others.
+
+The current window is `curwin`. The current buffer is `curbuf`. These point
+to structures with the cursor position in the window, option values, the file
+name, etc.
+
+All the global variables are declared in `globals.h`.
+
+THE MAIN EVENT-LOOP
+
+The main loop is implemented in state_enter. The basic idea is that Vim waits
+for the user to type a character and processes it until another character is
+needed. Thus there are several places where Vim waits for a character to be
+typed. The `vgetc()` function is used for this. It also handles mapping.
+
+What we consider the "Nvim event loop" is actually a wrapper around `uv_run` to
+handle both the `fast_events` queue and possibly (a suitable subset of) deferred
+events. Therefore "raw" `vim.uv.run()` is often not enough to "yield" from Lua
+plugins; instead they can call `vim.wait(0)`.
+
+Updating the screen is mostly postponed until a command or a sequence of
+commands has finished. The work is done by `update_screen()`, which calls
+`win_update()` for every window, which calls `win_line()` for every line.
+See the start of [drawscreen.c](drawscreen.c) for more explanations.
+
+COMMAND-LINE MODE
+
+When typing a `:`, `normal_cmd()` will call `getcmdline()` to obtain a line with
+an Ex command. `getcmdline()` calls a loop that will handle each typed
+character. It returns when hitting `<CR>` or `<Esc>` or some other character that
+ends the command line mode.
+
+EX COMMANDS
+
+Ex commands are handled by the function `do_cmdline()`. It does the generic
+parsing of the `:` command line and calls `do_one_cmd()` for each separate
+command. It also takes care of while loops.
+
+`do_one_cmd()` parses the range and generic arguments and puts them in the
+exarg_t and passes it to the function that handles the command.
+
+The `:` commands are listed in [ex_cmds.lua](ex_cmds.lua).
+
+NORMAL MODE COMMANDS
+
+The Normal mode commands are handled by the `normal_cmd()` function. It also
+handles the optional count and an extra character for some commands. These
+are passed in a `cmdarg_T` to the function that handles the command.
+
+There is a table `nv_cmds` in [normal.c](normal.c) which
+lists the first character of every
+command. The second entry of each item is the name of the function that
+handles the command.
+
+INSERT MODE COMMANDS
+
+When doing an `i` or `a` command, `normal_cmd()` will call the `edit()` function.
+It contains a loop that waits for the next character and handles it. It
+returns when leaving Insert mode.
+
+
+==============================================================================
vim:tw=78:ts=8:sw=4:et:ft=help:norl:
diff --git a/runtime/doc/dev_tools.txt b/runtime/doc/dev_tools.txt
@@ -6,15 +6,221 @@
Tools and techniques for developing Nvim *dev-tools*
-The following advice is helpful when working on or debugging issues with Nvim
-itself.
-
-TODO: merge |debug.txt| into here.
+This is for developing or debugging Nvim itself.
Type |gO| to see the table of contents.
==============================================================================
-Backtraces *dev-tools-backtrace*
+Logs *dev-tools-logs*
+
+Low-level log messages sink to `$NVIM_LOG_FILE`.
+
+UI events are logged at DEBUG level. >
+
+ rm -rf build/
+ make CMAKE_EXTRA_FLAGS="-DLOG_DEBUG"
+
+Use `LOG_CALLSTACK()` (Linux only) to log the current stacktrace. To log to an
+alternate file (e.g. stderr) use `LOG_CALLSTACK_TO_FILE(FILE*)`. Requires
+`-no-pie` ([ref](https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=860394#15)): >
+
+ rm -rf build/
+ make CMAKE_EXTRA_FLAGS="-DLOG_DEBUG -DCMAKE_C_FLAGS=-no-pie"
+
+Many log messages have a shared prefix, such as "UI" or "RPC". Use the shell to
+filter the log, e.g. at DEBUG level you might want to exclude UI messages: >
+
+ tail -F ~/.local/state/nvim/log | cat -v | stdbuf -o0 grep -v UI | stdbuf -o0 tee -a log
+
+
+==============================================================================
+Reproducible build
+
+To make a reproducible build of Nvim, set cmake variable `LUA_GEN_PRG` to
+a LuaJIT binary built with `LUAJIT_SECURITY_PRN=0`. See commit
+cb757f2663e6950e655c6306d713338dfa66b18d.
+
+
+==============================================================================
+Debug TUI *dev-tools-tui*
+
+TUI INSPECT
+
+Use the Ghostty https://ghostty.org/ inspector tool to observe and query the
+output and events from any terminal application such as Nvim.
+
+TERMINFO LOGGING
+
+At 'verbose' level 3, Nvim logs its internal terminfo state, so you can see
+exactly what terminfo values it is using on the current system. >
+
+ nvim -V3log
+
+TUI DEBUGGING WITH GDB LLDB
+
+Launching the Nvim TUI involves two processes, one for main editor state and one
+for rendering the TUI. Both of these processes use the nvim binary, so somewhat
+confusingly setting a breakpoint in either will generally succeed but may not be
+hit depending on which process the breakpoints were set in.
+
+To debug the main process, you can debug the nvim binary with the `--headless`
+flag which does not launch the TUI and will allow you to set breakpoints in code
+not related to TUI rendering like so: >
+
+ lldb -- ./build/bin/nvim --headless --listen ~/.cache/nvim/debug-server.pipe
+
+While in lldb, enter `run`. You can then attach to the headless process in a
+new terminal window to interact with the editor like so: >
+
+ ./build/bin/nvim --remote-ui --server ~/.cache/nvim/debug-server.pipe
+
+Conversely for debugging TUI rendering, you can start a headless process and
+debug the remote-ui process multiple times without losing editor state.
+
+For details on using nvim-dap and automatically debugging the child (main)
+process, see [here](https://zignar.net/2023/02/17/debugging-neovim-with-neovim-and-nvim-dap/)
+
+TUI REDRAW
+
+For debugging Nvim TUI redraw behavior it is sometimes useful to slow down its
+redraws. Set the 'writedelay' and 'redrawdebug' options to see where and when
+the UI is painted. >
+
+ :set writedelay=50 rdb=compositor
+
+Note: Nvim uses an internal screenbuffer to only send minimal updates even if a large
+region is repainted internally. To also highlight excess internal redraws, use >
+
+ :set writedelay=50 rdb=compositor,nodelta
+
+TUI TRACE
+
+In the rare case that you want to collect a trace of terminal output, the
+ancient `script` command is still the "state of the art". The libvterm
+`vterm-dump` utility formats the result for human-readability.
+
+Record a Nvim terminal session and format it with `vterm-dump`: >sh
+
+ script foo
+ ./build/bin/nvim -u NONE
+ # Exit the script session with CTRL-d
+
+ # Use `vterm-dump` utility to format the result.
+ ./.deps/usr/bin/vterm-dump foo > bar
+
+Then you can compare `bar` with another session, to debug TUI behavior.
+
+TERMINAL REFERENCE
+
+- `man terminfo`
+- https://github.com/vim/vim/blob/0124320c97b0fbbb44613f42fc1c34fee6181fc8/src/libvterm/doc/seqs.txt
+- https://invisible-island.net/xterm/ctlseqs/ctlseqs.html
+
+==============================================================================
+Debug Performance *dev-tools-perf*
+
+PROFILING (EASY)
+
+For debugging performance bottlenecks in any code, there is a simple (and very
+effective) approach:
+
+1. Run the slow code in a loop.
+2. Break execution ~5 times and save the stacktrace.
+3. The cause of the bottleneck will (almost always) appear in most of the stacktraces.
+
+
+PROFILING (FANCY)
+
+For more advanced profiling, consider `perf` + `flamegraph`.
+
+
+USDT PROFILING (POWERFUL)
+
+Or you can use USDT probes via `NVIM_PROBE` ([#12036](https://github.com/neovim/neovim/pull/12036)).
+
+> USDT is basically a way to define stable probe points in userland binaries.
+> The benefit of bcc is the ability to define logic to go along with the probe
+> points.
+
+Tools:
+- bpftrace provides an awk-like language to the kernel bytecode, BPF.
+- BCC provides a subset of C. Provides more complex logic than bpftrace, but takes a bit more effort.
+
+Example using bpftrace to track slow vim functions, and print out any files
+that were opened during the trace. At the end, it prints a histogram of
+function timing: >
+
+ #!/usr/bin/env bpftrace
+
+ BEGIN {
+ @depth = -1;
+ }
+
+ tracepoint:sched:sched_process_fork /@pidmap[args->parent_pid]/ {
+ @pidmap[args->child_pid] = 1;
+ }
+
+ tracepoint:sched:sched_process_exit /@pidmap[args->pid]/ {
+ delete(@pidmap[args->pid]);
+ }
+
+ usdt:build/bin/nvim:neovim:eval__call_func__entry {
+ @pidmap[pid] = 1;
+ @depth++;
+ @funcentry[@depth] = nsecs;
+ }
+
+ usdt:build/bin/nvim:neovim:eval__call_func__return {
+ $func = str(arg0);
+ $msecs = (nsecs - @funcentry[@depth]) / 1000000;
+
+ @time_histo = hist($msecs);
+
+ if ($msecs >= 1000) {
+ printf("%u ms for %s\n", $msecs, $func);
+ print(@files);
+ }
+
+ clear(@files);
+ delete(@funcentry[@depth]);
+ @depth--;
+ }
+
+ tracepoint:syscalls:sys_enter_open,
+ tracepoint:syscalls:sys_enter_openat {
+ if (@pidmap[pid] == 1 && @depth >= 0) {
+ @files[str(args->filename)] = count();
+ }
+ }
+
+ END {
+ clear(@depth);
+ }
+
+ $ sudo bpftrace funcslower.bt
+ 1527 ms for Slower
+ @files[/usr/lib/libstdc++.so.6]: 2
+ @files[/etc/fish/config.fish]: 2
+ <snip>
+
+ ^C
+ @time_histo:
+ [0] 71430 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@|
+ [1] 346 | |
+ [2, 4) 208 | |
+ [4, 8) 91 | |
+ [8, 16) 22 | |
+ [16, 32) 85 | |
+ [32, 64) 7 | |
+ [64, 128) 0 | |
+ [128, 256) 0 | |
+ [256, 512) 6 | |
+ [512, 1K) 1 | |
+ [1K, 2K) 5 | |
+<
+
+==============================================================================
+Backtraces *dev-tools-backtrace*
LINUX
@@ -83,6 +289,53 @@ https://developer.apple.com/library/archive/technotes/tn2124/_index.html#//apple
but note that some of the things on this page are out of date (such as enabling
core dumps with `/etc/launchd.conf`).
+
+WINDOWS
+
+If the Windows version of Nvim crashes in a reproducible manner, you can take
+some steps to provide a useful bug report.
+
+You must obtain the debugger symbols (PDB) file for the Nvim executable: nvim.pdb.
+The PDB should be available from the same place that you obtained the
+executable (TODO: not currently provided by Nvim CI releases). Be sure to use
+the PDB that matches the EXE (same build).
+
+If you built the executable yourself with the Microsoft Visual C++ compiler,
+then the PDB was built with the EXE.
+
+If you have Visual Studio, use that instead of the VC Toolkit and WinDbg.
+
+For other compilers, always use the corresponding debugger: gdb or lldb.
+
+Debugging Nvim crashes with Visual Studio 2005 ~
+
+First launch nvim.exe and then launch Visual Studio. (If you don't have
+Visual Studio, get it from https://visualstudio.microsoft.com/downloads/).
+
+On the Tools menu, click Attach to Process. Choose the Nvim process.
+
+In Nvim, reproduce the crash. A dialog will appear in Visual Studio, telling
+you about the unhandled exception in the Nvim process. Click Break to break
+into the process.
+
+Visual Studio will pop up another dialog, telling you that no symbols are
+loaded and that the source code cannot be displayed. Click OK.
+
+Several windows will open. Right-click in the Call Stack window. Choose Load
+Symbols. The Find Symbols dialog will open, looking for (g)vim.pdb. Navigate
+to the directory where you have the PDB file and click Open.
+
+At this point, you should have a full call stack with vim function names and
+line numbers. Double-click one of the lines and the Find Source dialog will
+navigate to the directory where the Nvim source is (if you have it.)
+
+If you don't know how to debug this any further, follow the instructions
+at ":help bug-report". Paste the call stack into the bug report.
+
+From Visual Studio you can also try saving a minidump via the Debug menu and
+send it with the bug report. A minidump is a small file (<100KB), which
+contains information about the state of your process.
+
==============================================================================
Gdb *dev-tools-gdb*
@@ -194,5 +447,42 @@ example:
(gdb) target remote localhost:6666
(gdb) br main
<
+==============================================================================
+Debugging crashes or memory leaks *dev-tools-asan*
+
+BUILD WITH ASAN
+
+Building Nvim with Clang sanitizers (Address Sanitizer: ASan, Undefined
+Behavior Sanitizer: UBSan, Memory Sanitizer: MSan, Thread Sanitizer: TSan) is
+a good way to catch undefined behavior, leaks and other errors as soon as they
+happen. It's significantly faster than Valgrind.
+
+Requires clang 3.4 or later, and `llvm-symbolizer` must be in `$PATH`: >
+
+ clang --version
+
+Build Nvim with sanitizer instrumentation (choose one): >
+
+ CC=clang make CMAKE_EXTRA_FLAGS="-DENABLE_ASAN_UBSAN=ON"
+ CC=clang make CMAKE_EXTRA_FLAGS="-DENABLE_MSAN=ON"
+ CC=clang make CMAKE_EXTRA_FLAGS="-DENABLE_TSAN=ON"
+
+Create a directory to store logs: >
+
+ mkdir -p "$HOME/logs"
+
+Configure the sanitizer(s) via these environment variables: >
+
+ # Change to detect_leaks=1 to detect memory leaks (slower, noisier).
+ export ASAN_OPTIONS="detect_leaks=0:log_path=$HOME/logs/asan"
+ # Show backtraces in the logs.
+ export MSAN_OPTIONS="log_path=${HOME}/logs/msan"
+ export TSAN_OPTIONS="log_path=${HOME}/logs/tsan"
+
+Logs will be written to `${HOME}/logs/*san.PID` then.
+
+For more information: https://github.com/google/sanitizers/wiki/SanitizerCommonFlags
+
+
vim:tw=78:ts=8:et:ft=help:norl:
diff --git a/runtime/doc/develop.txt b/runtime/doc/develop.txt
@@ -475,6 +475,7 @@ everywhere, not "buffer" in some places and "buf" in others.
- chan: |channel|
- cmd: Command
- cmdline: Command-line UI or input
+ - dir: Directory
- fn: Function
- hl: Highlight
- pos: Position
diff --git a/runtime/doc/editing.txt b/runtime/doc/editing.txt
@@ -87,6 +87,9 @@ g CTRL-G Prints the current position of the cursor in five
If the buffer did have a name, that name becomes the
|alternate-file| name. An unlisted buffer is created
to hold the old name.
+
+ See |nvim_buf_set_name()| to avoid filename escaping.
+
*:0file*
:0f[ile][!] Remove the name of the current buffer. The optional !
avoids truncating the message, as with |:file|.
diff --git a/runtime/doc/faq.txt b/runtime/doc/faq.txt
@@ -11,12 +11,14 @@ Frequently asked Questions *faq*
General Questions *faq-general*
-WHERE SHOULD I PUT MY CONFIG (VIMRC)? ~
+------------------------------------------------------------------------------
+WHERE SHOULD I PUT MY CONFIG (VIMRC)?
See |config|; you can copy (or symlink) your existing vimrc. |nvim-from-vim|
-HOW STABLE IS THE DEVELOPMENT (PRE-RELEASE) VERSION? ~
+------------------------------------------------------------------------------
+HOW STABLE IS THE DEVELOPMENT (PRE-RELEASE) VERSION?
The unstable (pre-release)
https://github.com/neovim/neovim/releases/tag/nightly version of Nvim
@@ -29,14 +31,16 @@ Use the stable (release) https://github.com/neovim/neovim/releases/latest
version for a more predictable experience.
-CAN I USE LUA-BASED VIM PLUGINS (E.G. NEOCOMPLETE)? ~
+------------------------------------------------------------------------------
+CAN I USE LUA-BASED VIM PLUGINS (E.G. NEOCOMPLETE)?
No. Starting with Nvim 0.2 PR #4411
https://github.com/neovim/neovim/pull/4411 Lua is built-in, but the legacy
Vim `if_lua` interface is not supported.
-HOW CAN I USE "TRUE COLOR" IN THE TERMINAL? ~
+------------------------------------------------------------------------------
+HOW CAN I USE "TRUE COLOR" IN THE TERMINAL?
Truecolor (24bit colors) are enabled by default if a supporting terminal is
detected. If your terminal is not detected but you are sure it supports
@@ -45,7 +49,8 @@ truecolor, add this to your |init.vim|:
set termguicolors
<
-NVIM SHOWS WEIRD SYMBOLS (`�[2 q`) WHEN CHANGING MODES ~
+------------------------------------------------------------------------------
+NVIM SHOWS WEIRD SYMBOLS (`�[2 q`) WHEN CHANGING MODES
This is a bug in your terminal emulator. It happens because Nvim sends
cursor-shape termcodes by default, if the terminal appears to be
@@ -63,7 +68,8 @@ To workaround the issue, you can:
See also |$TERM| for recommended values of `$TERM`.
-HOW TO CHANGE CURSOR SHAPE IN THE TERMINAL? ~
+------------------------------------------------------------------------------
+HOW TO CHANGE CURSOR SHAPE IN THE TERMINAL?
- For Nvim 0.1.7 or older: see the note about `NVIM_TUI_ENABLE_CURSOR_SHAPE` in `man nvim`.
- For Nvim 0.2 or newer: cursor styling is controlled by the 'guicursor' option.
@@ -83,7 +89,8 @@ HOW TO CHANGE CURSOR SHAPE IN THE TERMINAL? ~
https://github.com/neovim/neovim/issues/2537
-HOW TO CHANGE CURSOR COLOR IN THE TERMINAL? ~
+------------------------------------------------------------------------------
+HOW TO CHANGE CURSOR COLOR IN THE TERMINAL?
Cursor styling (shape, color, behavior) is controlled by 'guicursor', even in
the terminal. Cursor color (as opposed to shape) only works if
@@ -98,7 +105,8 @@ which sets different colors in insert-mode and normal-mode:
:set guicursor=n-v-c:block-Cursor/lCursor,i-ci-ve:ver25-Cursor2/lCursor2,r-cr:hor20,o:hor50
<
-CURSOR STYLE ISN'T RESTORED AFTER EXITING OR SUSPENDING AND RESUMING NVIM ~
+------------------------------------------------------------------------------
+CURSOR STYLE ISN'T RESTORED AFTER EXITING OR SUSPENDING AND RESUMING NVIM
Terminals do not provide a way to query the cursor style. Use autocommands to
manage the cursor style:
@@ -110,14 +118,16 @@ manage the cursor style:
au VimLeave,VimSuspend * set guicursor=a:block-blinkon0
<
-CURSOR SHAPE DOESN'T CHANGE IN TMUX ~
+------------------------------------------------------------------------------
+CURSOR SHAPE DOESN'T CHANGE IN TMUX
tmux decides that, not Nvim. See |tui-cursor-shape| for a fix.
See #3165 https://github.com/neovim/neovim/pull/3165 for discussion.
-CURSOR FLICKER IN TMUX? ~
+------------------------------------------------------------------------------
+CURSOR FLICKER IN TMUX?
If cursor `_` appears and disappears very quickly when opening nvim without a
document under tmux, and you set |ctermbg| in `EndOfBuffer` and `Normal`, try
@@ -127,7 +137,8 @@ setting these to `NONE`:
hi Normal ctermbg=NONE ctermfg=200 cterm=NONE
<
-WHAT HAPPENED TO --remote AND FRIENDS? ~
+------------------------------------------------------------------------------
+WHAT HAPPENED TO --remote AND FRIENDS?
|--remote| is partly supported. |clientserver|
@@ -138,7 +149,8 @@ https://github.com/mhinz/neovim-remote instead.
Runtime issues *faq-runtime*
-COPYING TO X11 PRIMARY SELECTION WITH THE MOUSE DOESN'T WORK ~
+------------------------------------------------------------------------------
+COPYING TO X11 PRIMARY SELECTION WITH THE MOUSE DOESN'T WORK
`clipboard=autoselect` is not implemented yet
https://github.com/neovim/neovim/issues/2325. You may find this workaround to
@@ -148,7 +160,8 @@ be useful:
vnoremap <2-LeftRelease> "*ygv
<
-MY CTRL-H MAPPING DOESN'T WORK ~
+------------------------------------------------------------------------------
+MY CTRL-H MAPPING DOESN'T WORK
This was fixed in Nvim 0.2. If you are running Nvim 0.1.7 or older,
adjust your terminal's "kbs" (key_backspace) terminfo entry:
@@ -160,7 +173,8 @@ adjust your terminal's "kbs" (key_backspace) terminfo entry:
commands).
-<HOME> OR SOME OTHER "SPECIAL" KEY DOESN'T WORK ~
+------------------------------------------------------------------------------
+<HOME> OR SOME OTHER "SPECIAL" KEY DOESN'T WORK
Make sure |$TERM| is set correctly.
@@ -169,7 +183,8 @@ Make sure |$TERM| is set correctly.
Try `TERM=xterm-256color`.
-:! AND SYSTEM() DO WEIRD THINGS WITH INTERACTIVE PROCESSES ~
+------------------------------------------------------------------------------
+:! AND SYSTEM() DO WEIRD THINGS WITH INTERACTIVE PROCESSES
Interactive commands are supported by |:terminal| in Nvim. But |:!| and
|system()| do not support interactive commands, primarily because Nvim UIs use
@@ -181,7 +196,8 @@ See also #1496 https://github.com/neovim/neovim/issues/1496 and #8217
https://github.com/neovim/neovim/issues/8217#issuecomment-402152307.
-PYTHON SUPPORT ISN'T WORKING ~
+------------------------------------------------------------------------------
+PYTHON SUPPORT ISN'T WORKING
Run |:checkhealth| in Nvim for automatic diagnosis.
@@ -202,7 +218,8 @@ Other hints:
- The python `neovim` module was renamed to `pynvim` (long ago).
-:CHECKHEALTH REPORTS E5009: INVALID $VIMRUNTIME ~
+------------------------------------------------------------------------------
+:CHECKHEALTH REPORTS E5009: INVALID $VIMRUNTIME
This means |$VIMRUNTIME| or 'runtimepath' is broken.
@@ -210,7 +227,8 @@ This means |$VIMRUNTIME| or 'runtimepath' is broken.
- The |$VIMRUNTIME| directory contents should be readable by the current user.
- Verify that `:echo &runtimepath` contains the $VIMRUNTIME path.
-NEOVIM CAN'T FIND ITS RUNTIME ~
+------------------------------------------------------------------------------
+NEOVIM CAN'T FIND ITS RUNTIME
This is the case if `:help nvim` shows `E149: Sorry, no help for nvim`.
@@ -223,7 +241,8 @@ Also make sure that you don't accidentally overwrite your runtimepath
'runtimepath').
-NEOVIM IS SLOW ~
+------------------------------------------------------------------------------
+NEOVIM IS SLOW
Use a fast terminal emulator:
@@ -244,7 +263,8 @@ If it reports `Build type: Debug` and you're building Nvim from source, see
https://github.com/neovim/neovim/blob/master/BUILD.md.
-COLORS AREN'T DISPLAYED CORRECTLY ~
+------------------------------------------------------------------------------
+COLORS AREN'T DISPLAYED CORRECTLY
Ensure that |$TERM| is set correctly.
@@ -268,7 +288,8 @@ For GNU `screen`, configure your `.screenrc`
NOTE: Nvim ignores `t_Co` and other |t_xx| terminal codes.
-NEOVIM CAN'T READ UTF-8 CHARACTERS ~
+------------------------------------------------------------------------------
+NEOVIM CAN'T READ UTF-8 CHARACTERS
Run the following from the command line:
>bash
@@ -280,7 +301,8 @@ If there's no results, you might not be using a UTF-8 locale. See these issues:
- https://github.com/neovim/neovim/issues/2386
-ESC IN TMUX OR GNU SCREEN IS DELAYED ~
+------------------------------------------------------------------------------
+ESC IN TMUX OR GNU SCREEN IS DELAYED
This is a common problem
https://www.google.com/?q=tmux%20vim%20escape%20delay in `tmux` / `screen`
@@ -311,7 +333,8 @@ Nvim 0.3 mimics the Vim behavior while still fully supporting ALT mappings. See
|i_ALT|.
-ESC IN GNU SCREEN IS LOST WHEN MOUSE MODE IS ENABLED ~
+------------------------------------------------------------------------------
+ESC IN GNU SCREEN IS LOST WHEN MOUSE MODE IS ENABLED
This happens because of a bug in screen https://savannah.gnu.org/bugs/?60196 :
in mouse mode, screen assumes that `ESC` is part of a mouse sequence and will
@@ -321,7 +344,8 @@ this other than double-pressing escape, which causes a single escape to be
passed through to Nvim.
-CALLING INPUTLIST(), ECHOMSG, ... IN FILETYPE PLUGINS AND AUTOCMD DOES NOT WORK ~
+------------------------------------------------------------------------------
+CALLING INPUTLIST(), ECHOMSG, ... IN FILETYPE PLUGINS AND AUTOCMD DOES NOT WORK
- https://github.com/neovim/neovim/issues/10008
- https://github.com/neovim/neovim/issues/10116
@@ -336,7 +360,8 @@ workaround, use `set shortmess-=F` or use `unsilent` as follows.
autocmd BufNewFile * unsilent echomsg 'The autocmd has been fired.'
<
-G:CLIPBOARD SETTINGS ARE NOT USED. ~
+------------------------------------------------------------------------------
+G:CLIPBOARD SETTINGS ARE NOT USED.
If the clipboard provider is already loaded, you will need to reload it after
configuration. Use the following configuration.
@@ -368,19 +393,22 @@ Or, if you want automatic reloading when assigning to |g:clipboard|, set
Build issues *faq-build*
-GENERAL BUILD ISSUES ~
+------------------------------------------------------------------------------
+GENERAL BUILD ISSUES
Run `make distclean && make` to rule out a stale build environment causing the
failure.
-SETTINGS IN LOCAL.MK DON'T TAKE EFFECT ~
+------------------------------------------------------------------------------
+SETTINGS IN LOCAL.MK DON'T TAKE EFFECT
CMake caches build settings, so you might need to run `rm -r build && make`
after modifying `local.mk`.
-CMAKE ERRORS ~
+------------------------------------------------------------------------------
+CMAKE ERRORS
`configure_file Problem configuring file`
@@ -389,7 +417,8 @@ root user, then later run an unprivileged `make`. To fix this, run
`rm -rf build` and try again.
-GENERATING HELPTAGS FAILED ~
+------------------------------------------------------------------------------
+GENERATING HELPTAGS FAILED
If re-installation fails with "Generating helptags failed", try removing the
previously installed runtime directory (if `CMAKE_INSTALL_PREFIX` is not set
@@ -402,13 +431,15 @@ during building, the default is `/usr/local/share/nvim`):
Design *faq-design*
-WHY NOT USE JSON FOR RPC? ~
+------------------------------------------------------------------------------
+WHY NOT USE JSON FOR RPC?
- JSON cannot easily/efficiently handle binary data
- JSON specification is ambiguous: https://seriot.ch/parsing_json.php
-WHY EMBED LUA INSTEAD OF X? ~
+------------------------------------------------------------------------------
+WHY EMBED LUA INSTEAD OF X?
- Lua is a very small language, ideal for embedding. The biggest advantage of
Python/Ruby/etc is their huge collection of libraries, but that isn't
@@ -435,7 +466,8 @@ See also:
- Discussion Python embedding https://lobste.rs/s/pnuak4/mercurial_s_journey_reflections_on#c_zshdwy
-WHY LUA 5.1 INSTEAD OF LUA 5.3+? ~
+------------------------------------------------------------------------------
+WHY LUA 5.1 INSTEAD OF LUA 5.3+?
Lua 5.1 is a different language than 5.3. The Lua org makes breaking changes
with every new version, so even if we switched (not upgraded, but switched) to
@@ -447,12 +479,14 @@ Nvim itself already is a pretty good "stdlib" for Lua, and we will continue to
grow and enhance it. Changing the rules of Lua gains nothing in this context.
-WILL NEOVIM TRANSLATE VIMSCRIPT TO LUA, INSTEAD OF EXECUTING VIMSCRIPT DIRECTLY? ~
+------------------------------------------------------------------------------
+WILL NEOVIM TRANSLATE VIMSCRIPT TO LUA, INSTEAD OF EXECUTING VIMSCRIPT DIRECTLY?
We have no plans for transpiling Vimscript. It was explored in https://github.com/tjdevries/vim9jit
-ARE PLUGIN AUTHORS ENCOURAGED TO PORT THEIR PLUGINS FROM VIMSCRIPT TO LUA? DO YOU PLAN ON SUPPORTING VIMSCRIPT INDEFINITELY? (#1152) ~
+------------------------------------------------------------------------------
+ARE PLUGIN AUTHORS ENCOURAGED TO PORT THEIR PLUGINS FROM VIMSCRIPT TO LUA? DO YOU PLAN ON SUPPORTING VIMSCRIPT INDEFINITELY?
We don't anticipate any reason to deprecate Vimscript, which is a valuable DSL
https://en.wikipedia.org/wiki/Domain-specific_language for text-editing tasks.
diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt
@@ -30,7 +30,7 @@ Follow these steps to get LSP features:
2. Define a new config |lsp-new-config| (or install https://github.com/neovim/nvim-lspconfig).
Example: >lua
- vim.lsp.config['luals'] = {
+ vim.lsp.config['lua_ls'] = {
-- Command and arguments to start the server.
cmd = { 'lua-language-server' },
-- Filetypes to automatically attach to.
@@ -52,7 +52,7 @@ Follow these steps to get LSP features:
3. Use |vim.lsp.enable()| to enable the config.
Example: >lua
- vim.lsp.enable('luals')
+ vim.lsp.enable('lua_ls')
<
4. Open a code file matching one of the `filetypes` specified in the config.
Note: Depending on the LSP server, you may need to ensure your project has
@@ -997,8 +997,8 @@ config({name}, {cfg}) *vim.lsp.config()*
filetypes = { 'c', 'cpp' },
}
<
- • Get the resolved configuration for "luals": >lua
- local cfg = vim.lsp.config.luals
+ • Get the resolved configuration for "lua_ls": >lua
+ local cfg = vim.lsp.config.lua_ls
<
Attributes: ~
@@ -1014,7 +1014,7 @@ enable({name}, {enable}) *vim.lsp.enable()*
Examples: >lua
vim.lsp.enable('clangd')
- vim.lsp.enable({'luals', 'pyright'})
+ vim.lsp.enable({'lua_ls', 'pyright'})
<
Example: *lsp-restart* Passing `false` stops and detaches the client(s).
@@ -1689,12 +1689,12 @@ Lua module: vim.lsp.client *lsp-client*
Fields: ~
• {before_init}? (`fun(params: lsp.InitializeParams, config: vim.lsp.ClientConfig)`)
- Callback invoked before the LSP "initialize"
- phase, where `params` contains the parameters
- being sent to the server and `config` is the
- config that was passed to |vim.lsp.start()|.
- You can use this to modify parameters before
- they are sent.
+ Callback which can modify parameters before
+ they are sent to the server. Invoked before LSP
+ "initialize" phase (after `cmd` is invoked),
+ where `params` is the parameters being sent to
+ the server and `config` is the config passed to
+ |vim.lsp.start()|.
• {capabilities}? (`lsp.ClientCapabilities`) Map overriding the
default capabilities defined by
|vim.lsp.protocol.make_client_capabilities()|,
diff --git a/runtime/doc/lua-plugin.txt b/runtime/doc/lua-plugin.txt
@@ -217,6 +217,11 @@ Consider making use of 'filetype' for any functionality that is specific to
a filetype, by putting the initialization logic in a `ftplugin/{filetype}.lua`
script.
+For buffers owned by your plugin (often used to show a custom UI or view),
+typically your plugin will set a custom 'filetype'. In that case, it's useful
+to set the 'filetype' "as late as possible", so that users can override
+buffer-local settings after your plugin has (re)initialized the buffer.
+
FILETYPE EXAMPLE
A plugin tailored to Rust development might have initialization in
@@ -240,6 +245,10 @@ A plugin tailored to Rust development might have initialization in
==============================================================================
Configuration *lua-plugin-config*
+To allow users to override buffer-local configuration for filetypes owned by
+your plugin, publish a |FileType| event, "as late as possible".
+|lua-plugin-filetype|
+
Once you have merged the default configuration with the user's config, you
should validate configs.
@@ -251,6 +260,32 @@ Validations could include:
check, to reduce overhead.
==============================================================================
+UI *lua-plugin-ui*
+
+Some plugins have their own "UI" which they present in a buffer that the
+plugin "owns". In that buffer typically you will want to provide custom
+actions.
+
+Besides creating |<Plug>| mappings, you may want to consider providing actions
+by defining an in-process LSP server. Offering actions as code-actions
+|vim.lsp.buf.code_action()| means the user can see all available actions using
+the default |gra| mapping to view the code-actions menu. They can even define
+mappings to a specific action by invoking `vim.lsp.buf.code_action()` with the
+`filter` + `apply` parameters: >lua
+
+ vim.lsp.buf.code_action({
+ apply = true,
+ filter = function(a)
+ return a.title == 'Do something'
+ end,
+ })
+<
+
+Example: See `runtime/lua/vim/pack/_lsp.lua` for how vim.pack defines an
+in-process LSP server to provide interactive features in its `nvim-pack://`
+buffer.
+
+==============================================================================
Troubleshooting *lua-plugin-troubleshooting*
While developing a plugin, you can use the |:restart| command to see the
diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt
@@ -1710,7 +1710,7 @@ vim.is_callable({f}) *vim.is_callable()*
Returns true if object `f` can be called as a function.
Parameters: ~
- • {f} (`any`) Any object
+ • {f} (`any?`) Any object
Return: ~
(`boolean`) `true` if `f` is callable, else `false`
@@ -1727,7 +1727,7 @@ vim.isarray({t}) *vim.isarray()*
|rpcrequest()| or |vim.fn|.
Parameters: ~
- • {t} (`table?`)
+ • {t} (`any?`)
Return: ~
(`boolean`) `true` if array-like table, else `false`.
diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt
@@ -80,7 +80,6 @@ EVENTS
message UI that mimics the legacy message grid. Benefit: reduced UI event
traffic and more flexibility for UIs.
The `msg_history_show` event has an additional "prev_cmd" argument.
-• A new `empty` message kind is emitted for an empty (e.g. `:echo ""`) message.
HIGHLIGHTS
@@ -88,12 +87,11 @@ HIGHLIGHTS
LSP
-• `root_markers` in |vim.lsp.Config| can now be ordered by priority.
+• JSON "null" values in LSP messages are represented as |vim.NIL| instead of `nil`.
+ Missing fields (as opposed to JSON "null") are still represented as `nil`.
• The function set with |vim.lsp.log.set_format_func()| is now given all
arguments corresponding to a log entry instead of the individual arguments.
-• `vim.lsp.semantic_tokens.start/stop` now renamed to
- `vim.lsp.semantic_tokens.enable`
-• Missing fields in LSP messages are now represented using |vim.NIL| instead of nil.
+• Renamed `vim.lsp.semantic_tokens` `start()/stop()` to `enable()`.
• |vim.lsp.util.convert_signature_help_to_markdown_lines()| activeParameter
handling updated:
• Values < 0 are now treated as `nil` instead of 0.
@@ -103,7 +101,6 @@ LSP
LUA
• Renamed `vim.diff` to `vim.text.diff`.
-• |vim.net.request()| adds a minimal HTTP GET API using curl.
OPTIONS
@@ -120,7 +117,6 @@ TREESITTER
`metadata[capture_id].offset`. The offset will be applied in
|vim.treesitter.get_range()|, which should be preferred over reading
metadata directly for retrieving node ranges.
-• |Query:iter_captures()| supports specifying starting and ending columns.
TUI
@@ -203,6 +199,7 @@ EDITOR
EVENTS
+• A new `empty` message kind is emitted for an empty (e.g. `:echo ""`) message.
• |CmdlineLeave| sets |v:char| to the character that stops the Cmdline mode.
• |CmdlineLeavePre| triggered before preparing to leave the command line.
• New `append` parameter for |ui-messages| `msg_show` event.
@@ -220,7 +217,7 @@ HIGHLIGHTS
LSP
• |vim.lsp.ClientConfig| gained `workspace_required`.
-• You can control priority of |vim.lsp.Config| `root_markers`.
+• You can control the priority of |vim.lsp.Config| `root_markers`.
• Support for `textDocument/documentColor`: |lsp-document_color|
https://microsoft.github.io/language-server-protocol/specification/#textDocument_documentColor
• Support for `textDocument/colorPresentation |lsp-document_color|
@@ -261,6 +258,7 @@ LSP
LUA
+• |vim.net.request()| can fetch files via HTTP GET requests.
• |vim.wait()| returns the callback results.
• Lua type annotations for `vim.uv`.
• |vim.hl.range()| now allows multiple timed highlights.
@@ -330,6 +328,7 @@ TERMINAL
TREESITTER
+• |Query:iter_captures()| supports specifying starting and ending columns.
• |:EditQuery| command gained tab-completion, works with injected languages.
TUI
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
@@ -301,9 +301,9 @@ end
--- filetypes = { 'c', 'cpp' },
--- }
--- ```
---- - Get the resolved configuration for "luals":
+--- - Get the resolved configuration for "lua_ls":
--- ```lua
---- local cfg = vim.lsp.config.luals
+--- local cfg = vim.lsp.config.lua_ls
--- ```
---
---@since 13
@@ -522,7 +522,7 @@ end
---
--- ```lua
--- vim.lsp.enable('clangd')
---- vim.lsp.enable({'luals', 'pyright'})
+--- vim.lsp.enable({'lua_ls', 'pyright'})
--- ```
---
--- Example: [lsp-restart]() Passing `false` stops and detaches the client(s). Thus you can
diff --git a/runtime/lua/vim/lsp/client.lua b/runtime/lua/vim/lsp/client.lua
@@ -34,9 +34,9 @@ local all_clients = {}
--- @class vim.lsp.ClientConfig
---
---- Callback invoked before the LSP "initialize" phase, where `params` contains the parameters
---- being sent to the server and `config` is the config that was passed to |vim.lsp.start()|.
---- You can use this to modify parameters before they are sent.
+--- Callback which can modify parameters before they are sent to the server. Invoked before LSP
+--- "initialize" phase (after `cmd` is invoked), where `params` is the parameters being sent to the
+--- server and `config` is the config passed to |vim.lsp.start()|.
--- @field before_init? fun(params: lsp.InitializeParams, config: vim.lsp.ClientConfig)
---
--- Map overriding the default capabilities defined by |vim.lsp.protocol.make_client_capabilities()|,
diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua
@@ -826,7 +826,7 @@ end
---
---@see https://github.com/openresty/luajit2#tableisarray
---
----@param t? table
+---@param t? any
---@return boolean `true` if array-like table, else `false`.
function vim.isarray(t)
if type(t) ~= 'table' then
@@ -1246,7 +1246,7 @@ end
--- Returns true if object `f` can be called as a function.
---
----@param f any Any object
+---@param f? any Any object
---@return boolean `true` if `f` is callable, else `false`
function vim.is_callable(f)
if type(f) == 'function' then
diff --git a/runtime/lua/vim/treesitter/_headings.lua b/runtime/lua/vim/treesitter/_headings.lua
@@ -95,7 +95,7 @@ function M.show_toc(qf_height)
-- add indentation for nicer list formatting
for _, heading in pairs(headings) do
-- Quickfix trims whitespace, so use non-breaking space instead
- heading.text = ('\194\160'):rep(heading.level - 1) .. heading.text
+ heading.text = ('\194\160'):rep((heading.level - 1) * 2) .. heading.text
end
vim.fn.setloclist(0, headings, ' ')
vim.fn.setloclist(0, {}, 'a', { title = 'Table of contents' })
diff --git a/src/gen/gen_help_html.lua b/src/gen/gen_help_html.lua
@@ -91,6 +91,7 @@ local new_layout = {
local redirects = {
['api-ui-events'] = 'ui',
['credits'] = 'backers',
+ ['dev_tools'] = 'debug',
['plugins'] = 'editorconfig',
['terminal'] = 'nvim_terminal_emulator',
['tui'] = 'term',
diff --git a/src/nvim/README.md b/src/nvim/README.md
@@ -1,526 +1,5 @@
-Nvim core
-=========
+## Moved to:
-Module-specific details are documented at the top of each module (`terminal.c`, `undo.c`, …).
-
-See `:help dev` for guidelines.
-
-Filename conventions
---------------------
-
-The source files use extensions to hint about their purpose.
-
-- `*.c`, `*.generated.c` - full C files, with all includes, etc.
-- `*.c.h` - parametrized C files, contain all necessary includes, but require
- defining macros before actually using. Example: `typval_encode.c.h`
-- `*.h` - full headers, with all includes. Does *not* apply to `*.generated.h`.
-- `*.h.generated.h` - exported functions’ declarations.
-- `*.c.generated.h` - static functions’ declarations.
-
-Common structures
------------------
-
-- StringBuilder
-- kvec or garray.c for dynamic lists / vectors (use StringBuilder for strings)
-
-Logs
-----
-
-Low-level log messages sink to `$NVIM_LOG_FILE`.
-
-UI events are logged at DEBUG level.
-
- rm -rf build/
- make CMAKE_EXTRA_FLAGS="-DLOG_DEBUG"
-
-Use `LOG_CALLSTACK()` (Linux only) to log the current stacktrace. To log to an
-alternate file (e.g. stderr) use `LOG_CALLSTACK_TO_FILE(FILE*)`. Requires
-`-no-pie` ([ref](https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=860394#15)):
-
- rm -rf build/
- make CMAKE_EXTRA_FLAGS="-DLOG_DEBUG -DCMAKE_C_FLAGS=-no-pie"
-
-Many log messages have a shared prefix, such as "UI" or "RPC". Use the shell to
-filter the log, e.g. at DEBUG level you might want to exclude UI messages:
-
- tail -F ~/.local/state/nvim/log | cat -v | stdbuf -o0 grep -v UI | stdbuf -o0 tee -a log
-
-Build with ASAN
----------------
-
-Building Nvim with Clang sanitizers (Address Sanitizer: ASan, Undefined
-Behavior Sanitizer: UBSan, Memory Sanitizer: MSan, Thread Sanitizer: TSan) is
-a good way to catch undefined behavior, leaks and other errors as soon as they
-happen. It's significantly faster than Valgrind.
-
-Requires clang 3.4 or later, and `llvm-symbolizer` must be in `$PATH`:
-
- clang --version
-
-Build Nvim with sanitizer instrumentation (choose one):
-
- CC=clang make CMAKE_EXTRA_FLAGS="-DENABLE_ASAN_UBSAN=ON"
- CC=clang make CMAKE_EXTRA_FLAGS="-DENABLE_MSAN=ON"
- CC=clang make CMAKE_EXTRA_FLAGS="-DENABLE_TSAN=ON"
-
-Create a directory to store logs:
-
- mkdir -p "$HOME/logs"
-
-Configure the sanitizer(s) via these environment variables:
-
- # Change to detect_leaks=1 to detect memory leaks (slower, noisier).
- export ASAN_OPTIONS="detect_leaks=0:log_path=$HOME/logs/asan"
- # Show backtraces in the logs.
- export MSAN_OPTIONS="log_path=${HOME}/logs/msan"
- export TSAN_OPTIONS="log_path=${HOME}/logs/tsan"
-
-Logs will be written to `${HOME}/logs/*san.PID` then.
-
-For more information: https://github.com/google/sanitizers/wiki/SanitizerCommonFlags
-
-Reproducible build
-------------------
-
-To make a reproducible build of Nvim, set cmake variable `LUA_GEN_PRG` to
-a LuaJIT binary built with `LUAJIT_SECURITY_PRN=0`. See commit
-cb757f2663e6950e655c6306d713338dfa66b18d.
-
-Debug: Performance
-------------------
-
-### Profiling (easy)
-
-For debugging performance bottlenecks in any code, there is a simple (and very
-effective) approach:
-
-1. Run the slow code in a loop.
-2. Break execution ~5 times and save the stacktrace.
-3. The cause of the bottleneck will (almost always) appear in most of the stacktraces.
-
-### Profiling (fancy)
-
-For more advanced profiling, consider `perf` + `flamegraph`.
-
-### USDT profiling (powerful)
-
-Or you can use USDT probes via `NVIM_PROBE` ([#12036](https://github.com/neovim/neovim/pull/12036)).
-
-> USDT is basically a way to define stable probe points in userland binaries.
-> The benefit of bcc is the ability to define logic to go along with the probe
-> points.
-
-Tools:
-- bpftrace provides an awk-like language to the kernel bytecode, BPF.
-- BCC provides a subset of C. Provides more complex logic than bpftrace, but takes a bit more effort.
-
-Example using bpftrace to track slow vim functions, and print out any files
-that were opened during the trace. At the end, it prints a histogram of
-function timing:
-
- #!/usr/bin/env bpftrace
-
- BEGIN {
- @depth = -1;
- }
-
- tracepoint:sched:sched_process_fork /@pidmap[args->parent_pid]/ {
- @pidmap[args->child_pid] = 1;
- }
-
- tracepoint:sched:sched_process_exit /@pidmap[args->pid]/ {
- delete(@pidmap[args->pid]);
- }
-
- usdt:build/bin/nvim:neovim:eval__call_func__entry {
- @pidmap[pid] = 1;
- @depth++;
- @funcentry[@depth] = nsecs;
- }
-
- usdt:build/bin/nvim:neovim:eval__call_func__return {
- $func = str(arg0);
- $msecs = (nsecs - @funcentry[@depth]) / 1000000;
-
- @time_histo = hist($msecs);
-
- if ($msecs >= 1000) {
- printf("%u ms for %s\n", $msecs, $func);
- print(@files);
- }
-
- clear(@files);
- delete(@funcentry[@depth]);
- @depth--;
- }
-
- tracepoint:syscalls:sys_enter_open,
- tracepoint:syscalls:sys_enter_openat {
- if (@pidmap[pid] == 1 && @depth >= 0) {
- @files[str(args->filename)] = count();
- }
- }
-
- END {
- clear(@depth);
- }
-
- $ sudo bpftrace funcslower.bt
- 1527 ms for Slower
- @files[/usr/lib/libstdc++.so.6]: 2
- @files[/etc/fish/config.fish]: 2
- <snip>
-
- ^C
- @time_histo:
- [0] 71430 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@|
- [1] 346 | |
- [2, 4) 208 | |
- [4, 8) 91 | |
- [8, 16) 22 | |
- [16, 32) 85 | |
- [32, 64) 7 | |
- [64, 128) 0 | |
- [128, 256) 0 | |
- [256, 512) 6 | |
- [512, 1K) 1 | |
- [1K, 2K) 5 | |
-
-Debug: TUI
-----------
-
-### TUI troubleshoot
-
-Nvim logs its internal terminfo state at 'verbose' level 3. This makes it
-possible to see exactly what terminfo values Nvim is using on any system.
-
- nvim -V3log
-
-### TUI Debugging with gdb/lldb
-
-Launching the nvim TUI involves two processes, one for main editor state and one
-for rendering the TUI. Both of these processes use the nvim binary, so somewhat
-confusingly setting a breakpoint in either will generally succeed but may not be
-hit depending on which process the breakpoints were set in.
-
-To debug the main process, you can debug the nvim binary with the `--headless`
-flag which does not launch the TUI and will allow you to set breakpoints in code
-not related to TUI rendering like so:
-
- lldb -- ./build/bin/nvim --headless --listen ~/.cache/nvim/debug-server.pipe
-
-While in lldb, enter `run`. You can then attach to the headless process in a
-new terminal window to interact with the editor like so:
-
- ./build/bin/nvim --remote-ui --server ~/.cache/nvim/debug-server.pipe
-
-Conversely for debugging TUI rendering, you can start a headless process and
-debug the remote-ui process multiple times without losing editor state.
-
-For details on using nvim-dap and automatically debugging the child (main)
-process, see
-[here](https://zignar.net/2023/02/17/debugging-neovim-with-neovim-and-nvim-dap/)
-
-### TUI trace
-
-The ancient `script` command is still the "state of the art" for tracing
-terminal behavior. The libvterm `vterm-dump` utility formats the result for
-human-readability.
-
-Record a Nvim terminal session and format it with `vterm-dump`:
-
- script foo
- ./build/bin/nvim -u NONE
- # Exit the script session with CTRL-d
-
- # Use `vterm-dump` utility to format the result.
- ./.deps/usr/bin/vterm-dump foo > bar
-
-Then you can compare `bar` with another session, to debug TUI behavior.
-
-### TUI redraw
-
-Set the 'writedelay' and 'redrawdebug' options to see where and when the UI is painted.
-
- :set writedelay=50 rdb=compositor
-
-Note: neovim uses an internal screenbuffer to only send minimal updates even if a large
-region is repainted internally. To also highlight excess internal redraws, use
-
- :set writedelay=50 rdb=compositor,nodelta
-
-### Terminal reference
-
-- `man terminfo`
-- http://bazaar.launchpad.net/~libvterm/libvterm/trunk/view/head:/doc/seqs.txt
-- http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
-
-Data structures
----------------
-
-Buffer text is stored as a tree of line segments, defined in [memline.c](https://github.com/neovim/neovim/blob/v0.9.5/src/nvim/memline.c#L8-L35).
-The central idea is found in [ml_find_line](https://github.com/neovim/neovim/blob/v0.9.5/src/nvim/memline.c#L2800).
-
-Nvim lifecycle
---------------
-
-Following describes how Nvim processes input.
-
-Consider a typical Vim-like editing session:
-
-01. Vim displays the welcome screen
-02. User types: `:`
-03. Vim enters command-line mode
-04. User types: `edit README.txt<CR>`
-05. Vim opens the file and returns to normal mode
-06. User types: `G`
-07. Vim navigates to the end of the file
-09. User types: `5`
-10. Vim enters count-pending mode
-11. User types: `d`
-12. Vim enters operator-pending mode
-13. User types: `w`
-14. Vim deletes 5 words
-15. User types: `g`
-16. Vim enters the "g command mode"
-17. User types: `g`
-18. Vim goes to the beginning of the file
-19. User types: `i`
-20. Vim enters insert mode
-21. User types: `word<ESC>`
-22. Vim inserts "word" at the beginning and returns to normal mode
-
-Note that we split user actions into sequences of inputs that change the state
-of the editor. While there's no documentation about a "g command mode" (step
-16), internally it is implemented similarly to "operator-pending mode".
-
-From this we can see that Vim has the behavior of an input-driven state machine
-(more specifically, a pushdown automaton since it requires a stack for
-transitioning back from states). Assuming each state has a callback responsible
-for handling keys, this pseudocode represents the main program loop:
-
-```py
-def state_enter(state_callback, data):
- do
- key = readkey() # read a key from the user
- while state_callback(data, key) # invoke the callback for the current state
-```
-
-That is, each state is entered by calling `state_enter` and passing a
-state-specific callback and data. Here is a high-level pseudocode for a program
-that implements something like the workflow described above:
-
-```py
-def main()
- state_enter(normal_state, {}):
-
-def normal_state(data, key):
- if key == ':':
- state_enter(command_line_state, {})
- elif key == 'i':
- state_enter(insert_state, {})
- elif key == 'd':
- state_enter(delete_operator_state, {})
- elif key == 'g':
- state_enter(g_command_state, {})
- elif is_number(key):
- state_enter(get_operator_count_state, {'count': key})
- elif key == 'G'
- jump_to_eof()
- return true
-
-def command_line_state(data, key):
- if key == '<cr>':
- if data['input']:
- execute_ex_command(data['input'])
- return false
- elif key == '<esc>'
- return false
-
- if not data['input']:
- data['input'] = ''
-
- data['input'] += key
- return true
-
-def delete_operator_state(data, key):
- count = data['count'] or 1
- if key == 'w':
- delete_word(count)
- elif key == '$':
- delete_to_eol(count)
- return false # return to normal mode
-
-def g_command_state(data, key):
- if key == 'g':
- go_top()
- elif key == 'v':
- reselect()
- return false # return to normal mode
-
-def get_operator_count_state(data, key):
- if is_number(key):
- data['count'] += key
- return true
- unshift_key(key) # return key to the input buffer
- state_enter(delete_operator_state, data)
- return false
-
-def insert_state(data, key):
- if key == '<esc>':
- return false # exit insert mode
- self_insert(key)
- return true
-```
-
-The above gives an idea of how Nvim is organized internally. Some states like
-the `g_command_state` or `get_operator_count_state` do not have a dedicated
-`state_enter` callback, but are implicitly embedded into other states (this
-will change later as we continue the refactoring effort). To start reading the
-actual code, here's the recommended order:
-
-1. `state_enter()` function (state.c). This is the actual program loop,
- note that a `VimState` structure is used, which contains function pointers
- for the callback and state data.
-2. `main()` function (main.c). After all startup, `normal_enter` is called
- at the end of function to enter normal mode.
-3. `normal_enter()` function (normal.c) is a small wrapper for setting
- up the NormalState structure and calling `state_enter`.
-4. `normal_check()` function (normal.c) is called before each iteration of
- normal mode.
-5. `normal_execute()` function (normal.c) is called when a key is read in normal
- mode.
-
-The basic structure described for normal mode in 3, 4 and 5 is used for other
-modes managed by the `state_enter` loop:
-
-- command-line mode: `command_line_{enter,check,execute}()`(`ex_getln.c`)
-- insert mode: `insert_{enter,check,execute}()`(`edit.c`)
-- terminal mode: `terminal_{enter,execute}()`(`terminal.c`)
-
-## Important variables
-
-The current mode is stored in `State`. The values it can have are `MODE_NORMAL`,
-`MODE_INSERT`, `MODE_CMDLINE`, and a few others.
-
-The current window is `curwin`. The current buffer is `curbuf`. These point
-to structures with the cursor position in the window, option values, the file
-name, etc.
-
-All the global variables are declared in `globals.h`.
-
-### The main event-loop
-
-The main loop is implemented in state_enter. The basic idea is that Vim waits
-for the user to type a character and processes it until another character is
-needed. Thus there are several places where Vim waits for a character to be
-typed. The `vgetc()` function is used for this. It also handles mapping.
-
-What we consider the "Nvim event loop" is actually a wrapper around `uv_run` to
-handle both the `fast_events` queue and possibly (a suitable subset of) deferred
-events. Therefore "raw" `vim.uv.run()` is often not enough to "yield" from Lua
-plugins; instead they can call `vim.wait(0)`.
-
-Updating the screen is mostly postponed until a command or a sequence of
-commands has finished. The work is done by `update_screen()`, which calls
-`win_update()` for every window, which calls `win_line()` for every line.
-See the start of [drawscreen.c](drawscreen.c) for more explanations.
-
-### Command-line mode
-
-When typing a `:`, `normal_cmd()` will call `getcmdline()` to obtain a line with
-an Ex command. `getcmdline()` calls a loop that will handle each typed
-character. It returns when hitting `<CR>` or `<Esc>` or some other character that
-ends the command line mode.
-
-### Ex commands
-
-Ex commands are handled by the function `do_cmdline()`. It does the generic
-parsing of the `:` command line and calls `do_one_cmd()` for each separate
-command. It also takes care of while loops.
-
-`do_one_cmd()` parses the range and generic arguments and puts them in the
-exarg_t and passes it to the function that handles the command.
-
-The `:` commands are listed in [ex_cmds.lua](ex_cmds.lua).
-
-### Normal mode commands
-
-The Normal mode commands are handled by the `normal_cmd()` function. It also
-handles the optional count and an extra character for some commands. These
-are passed in a `cmdarg_T` to the function that handles the command.
-
-There is a table `nv_cmds` in [normal.c](normal.c) which
-lists the first character of every
-command. The second entry of each item is the name of the function that
-handles the command.
-
-### Insert mode commands
-
-When doing an `i` or `a` command, `normal_cmd()` will call the `edit()` function.
-It contains a loop that waits for the next character and handles it. It
-returns when leaving Insert mode.
-
-### Options
-
-There is a list with all option names in [options.lua](options.lua).
-
-Async event support
--------------------
-
-One of the features Nvim added is the support for handling arbitrary
-asynchronous events, which can include:
-
-- RPC requests
-- job control callbacks
-- timers
-
-Nvim implements this functionality by entering another event loop while
-waiting for characters, so instead of:
-
-```py
-def state_enter(state_callback, data):
- do
- key = readkey() # read a key from the user
- while state_callback(data, key) # invoke the callback for the current state
-```
-
-Nvim program loop is more like:
-
-```py
-def state_enter(state_callback, data):
- do
- event = read_next_event() # read an event from the operating system
- while state_callback(data, event) # invoke the callback for the current state
-```
-
-where `event` is something the operating system delivers to us, including (but
-not limited to) user input. The `read_next_event()` part is internally
-implemented by libuv, the platform layer used by Nvim.
-
-Since Nvim inherited its code from Vim, the states are not prepared to receive
-"arbitrary events", so we use a special key to represent those (When a state
-receives an "arbitrary event", it normally doesn't do anything other than
-update the screen).
-
-Main loop
----------
-
-The `Loop` structure (which describes `main_loop`) abstracts multiple queues
-into one loop:
-
- uv_loop_t uv;
- MultiQueue *events;
- MultiQueue *thread_events;
- MultiQueue *fast_events;
-
-`loop_poll_events` checks `Loop.uv` and `Loop.fast_events` whenever Nvim is
-idle, and also at `os_breakcheck` intervals.
-
-MultiQueue is cool because you can attach throw-away "child queues" trivially.
-For example `do_os_system()` does this (for every spawned process!) to
-automatically route events onto the `main_loop`:
-
- Process *proc = &uvproc.process;
- MultiQueue *events = multiqueue_new_child(main_loop.events);
- proc->events = events;
+- [dev_arch.txt](../../runtime/doc/dev_arch.txt)
+- [dev_tools.txt](../../runtime/doc/dev_tools.txt)
+- [develop.txt](../../runtime/doc/develop.txt)
diff --git a/src/nvim/msgpack_rpc/server.c b/src/nvim/msgpack_rpc/server.c
@@ -135,7 +135,7 @@ char *server_address_new(const char *name)
return xstrdup(fmt);
}
-/// Check if this instance owns a pipe address.
+/// Check if this instance owns a pipe address (loopback).
bool server_owns_pipe_address(const char *address)
{
bool result = false;
diff --git a/src/nvim/path.c b/src/nvim/path.c
@@ -46,8 +46,7 @@ enum {
/// Compare two file names.
///
-/// @param s1 First file name. Environment variables in this name will be
-/// expanded.
+/// @param s1 First file name. Environment variables in this name will be expanded.
/// @param s2 Second file name.
/// @param checkname When both files don't exist, only compare their names.
/// @param expandenv Whether to expand environment variables in file names.
@@ -540,7 +539,6 @@ bool path_has_wildcard(const char *p)
return false;
}
-// Unix style wildcard expansion code.
static int pstrcmp(const void *a, const void *b)
{
return pathcmp(*(char **)a, *(char **)b, -1);
@@ -1956,8 +1954,10 @@ bool same_directory(char *f1, char *f2)
}
// Compare path "p[]" to "q[]".
-// If "maxlen" >= 0 compare "p[maxlen]" to "q[maxlen]"
+// If `maxlen` >= 0 compare `p[maxlen]` to `q[maxlen]`
// Return value like strcmp(p, q), but consider path separators.
+//
+// See also `path_full_compare`.
int pathcmp(const char *p, const char *q, int maxlen)
{
int i, j;
@@ -2314,12 +2314,12 @@ int append_path(char *path, const char *to_append, size_t max_len)
return OK;
}
-/// Expand a given file to its absolute path.
+/// Used by `vim_FullName` and `fix_fname` to expand a filename to its full path.
///
-/// @param fname filename which should be expanded.
-/// @param buf buffer to store the absolute path of "fname".
-/// @param len length of "buf".
-/// @param force also expand when "fname" is already absolute.
+/// @param fname Filename to expand.
+/// @param buf Where to store the absolute path of "fname".
+/// @param len Length of `buf`.
+/// @param force Also expand when `fname` is already absolute.
///
/// @return FAIL for failure, OK for success.
static int path_to_absolute(const char *fname, char *buf, size_t len, int force)
diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua
@@ -4616,7 +4616,7 @@ describe('API', function()
},
}, api.nvim_parse_cmd('4,6MyCommand! test it', {}))
end)
- it('works for commands separated by bar', function()
+ it('sets nextcmd for bar-separated commands', function()
eq({
cmd = 'argadd',
args = { 'a.txt' },
@@ -4655,6 +4655,12 @@ describe('API', function()
},
}, api.nvim_parse_cmd('argadd a.txt | argadd b.txt', {}))
end)
+ it('sets nextcmd after expr-arg commands #36029', function()
+ local result = api.nvim_parse_cmd('exe "ls"|edit foo', {})
+ eq({ '"ls"' }, result.args)
+ eq('execute', result.cmd)
+ eq('edit foo', result.nextcmd)
+ end)
it('parses :map commands with space in RHS', function()
eq({
addr = 'none',
@@ -4849,12 +4855,6 @@ describe('API', function()
result = api.nvim_parse_cmd('copen 5', {})
eq(5, result.count)
end)
- it('parses nextcmd for commands #36029', function()
- local result = api.nvim_parse_cmd('exe "ls"|edit foo', {})
- eq({ '"ls"' }, result.args)
- eq('execute', result.cmd)
- eq('edit foo', result.nextcmd)
- end)
end)
describe('nvim_cmd', function()