News-0.12

Nvim :help pages, generated from source using the tree-sitter-vimdoc parser.


Notable changes since Nvim 0.11
For changes in the previous release, see news-0.11.

BREAKING CHANGES

These changes may require adaptations in your config or plugins.

API

nvim_get_commands() returns complete as a Lua function, if it was defined as such.

DIAGNOSTICS

diagnostic-signs can no longer be configured with :sign-define or sign_define() (deprecated in Nvim 0.10 deprecated-0.10).
The legacy signature of vim.diagnostic.enable() (deprecated in Nvim 0.10 deprecated-0.10) is no longer supported.

EDITOR

i_CTRL-R inserts named/clipboard registers (A-Z,a-z,0-9+) literally, like pasting instead of like user input. Improves performance, avoids broken formatting. To get the old behavior you can use <C-R>=@x.
Parsing of URI-like buffer names more closely follows RFC3986, so for example "svn+ssh:", "ed2k:", and "iris.xpc:" are recognized as URI schemes.
Security: Nvim on Windows no longer searches the current directory for external command executables; prefix a relative or absolute path if you want the old behavior $NoDefaultCurrentDirectoryInExePath.

EVENTS

ui-messages no longer emits the msg_show.return_prompt, and msg_history_clear events. The msg_clear event was repurposed and is now emitted after the screen is cleared. These events arbitrarily assumed a 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.

LSP

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.
Renamed vim.lsp.semantic_tokens start()/stop() to enable().
Values < 0 are now treated as nil instead of 0.
Values outside the range of signatures[activeSignature].parameters are now treated as nil instead of #signatures[activeSignature].parameters

LUA

Renamed vim.diff to vim.text.diff.

OPTIONS

'shelltemp' defaults to "false".

PLUGINS

Removed "shellmenu" plugin, an old menu-based quasi-snippet plugin for shell scripts.
package-tohtml is now an "opt-in" plugin. Use :packadd to activate it:
:packadd nvim.tohtml
TREESITTER
ft-query-plugin no longer enables vim.treesitter.query.lint() by default.
treesitter-directive-offset! can now be applied to quantified captures. It no longer sets metadata[capture_id].range; it instead sets 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.
The "all" option to Query:iter_matches(), which was introduced in Nvim 0.11 to aid in transitioning to the new behavior, has been removed.

NEW FEATURES

The following new features were added.

API

api-contract allows existing functions to change return-type from void => non-void.
nvim_win_text_height() can limit the lines checked when a certain max_height is reached, and returns the end_row and end_vcol for which max_height or the calculated height is reached.
vim.secure.read() now returns true for trusted directories. Previously it would return nil, thus impossible to tell if the directory was actually trusted.
nvim_ui_send() writes arbitrary data to a UI's stdout. Use this to write escape sequences to the terminal when Nvim is running in the TUI.
nvim_echo() can set the ui-messages kind with which to emit the message.
nvim_echo() can create Progress messages
nvim_get_commands() returns preview and callback as Lua functions if they were so specified in nvim_create_user_command().
nvim_open_tabpage() can open a new tab-page.
nvim_open_win() floating windows can show a 'statusline'. Plugins can use style='minimal' or :setlocal statusline= to hide the statusline.
nvim_win_set_config() can move floating-windows to other tabpages.
EXPERIMENTAL: nvim__exec_lua_fast() allows remote API clients to execute Lua while Nvim is blocking for input. api-fast
Decoration provider gained an on_range callback (deprecates on_line).
vim.secure.trust() accepts path for the allow action.
nvim_get_chan_info() includes exitcode field for :terminal buffers.
nvim_set_hl() supports updating specified attributes only.

BUILD

EXPERIMENTAL: Zig-based build is available as an alternative to CMake. It is currently limited in functionality, and CMake remains the recommended option for the time being.
Nvim can be built without Unibilium (terminfo implementation), in which case the user's terminfo database won't be loaded and only internal definitions for the most common terminals are used:
make distclean && make CMAKE_EXTRA_FLAGS="-DENABLE_UNIBILIUM=0" DEPS_CMAKE_FLAGS="-DUSE_BUNDLED_UNIBILIUM=0"
On Windows, tee.exe is included with nvim.exe by default so that commands like :make, :grep work out of the box.

DEFAULTS

'diffopt' default value now includes "indent-heuristic" and "inline:char".
'statusline' default is exposed as a statusline expression (previously it was implemented as an internal C routine).
Default 'statusline' shows:
:terminal exit code
Project-local configuration ('exrc') is also loaded from parent directories. Unset 'exrc' to stop further search.
Mappings:
grt in Normal mode maps to vim.lsp.buf.type_definition()
grx in Normal mode maps to vim.lsp.codelens.run()
'shada' default now excludes "/tmp/" and "/private/" paths to reduce clutter in :oldfiles.
Enabled treesitter highlighting for Markdown files.

DIAGNOSTICS

vim.diagnostic.setloclist() and vim.diagnostic.setqflist() now support a format function to modify (or filter) diagnostics before being set in the location/quickfix list.
vim.diagnostic.get() now accepts an enabled filter to only return enabled or disabled diagnostics.
vim.diagnostic.status() returns a status description of current buffer diagnostics.
vim.diagnostic.fromqflist() accepts opts.merge_lines to merge multiline compiler messages.

EDITOR

:iput works like :put but adjusts indent.
:retab accepts new optional parameter -indentonly to only change leading whitespace in indented lines.
:uniq deduplicates text in the current buffer.
omnicompletion is available when editing help buffers. ft-help-omni
:help! has DWIM ("Do What I Mean") behavior: it tries to guess the help tag at cursor. In help buffers, 'keywordprg' defaults to ":help!". For example, try "K" anywhere in this code:
local v = vim.version.parse(vim.system({'foo'}):wait().stdout)
Setting "'0" in 'shada' prevents storing the jumplist in the shada file.
'shada' now correctly respects "/0" and "f0".
prompt-buffer supports multiline input/paste, undo/redo, and o/O normal commands.
'wildchar' now enables completion in search contexts using /, ?, :g, :v and :vimgrep commands.
Security: 'exrc' no longer shows "(a)llow". Instead you must "(v)iew", then run :trust (or :trust [file], but that has a TOCTOU risk).
gx in help buffers opens the online documentation for the tag at cursor.
:source with a range in non-Lua files (e.g., vimdoc) now detects Lua codeblocks via treesitter and executes them as Lua instead of Vimscript. (Or use :{range}lua to skip the detection.)
:wall with ++p auto-creates missing parent directories.

EVENTS

In the ui-protocol, message kind empty is emitted for empty messages (e.g. :echo "").
CmdlineLeave sets v:char to the character that stops the Cmdline mode.
CmdlineLeavePre triggered before preparing to leave the command line.
New append, id and trigger parameter for ui-messages msg_show event.
'rulerformat' is emitted as msg_ruler when not part of the statusline.
Creating or updating a progress message with nvim_echo() triggers a Progress event.
MarkSet is triggered after a mark is set by the user (currently doesn't support implicit marks like '[ or '<, …).
SessionLoadPre is triggered before loading a Session file.
TabClosedPre is triggered before closing a tabpage.
TermRequest event gained a terminator parameter.

HIGHLIGHTS

hl-DiffTextAdd highlights added text within a changed line.
hl-SnippetTabstopActive highlights the currently active tabstop.
nvim_set_hl() and nvim_get_hl() support the SGR attributes "dim", "blink", "conceal", and "overline".

LSP

vim.lsp.completion.enable() gained a cmp option for custom ordering.
Supports colored symbol preview for color items.
Shows a preview ("completionItem/resolve") if 'completeopt' has "popup".
:lsp can be used to interactively manage LSP clients.
vim.lsp.ClientConfig gained workspace_required.
You can control the priority of vim.lsp.Config root_markers.
LSP capabilities:
textDocument/diagnostic
textDocument/documentLink: gx opens "documentLink" items at cursor.
textDocument/inlineCompletion
textDocument/selectionRange Incremental selection. v_an selects outwards, v_in selects inwards.
textDocument/semanticTokens/range
Support for dynamic registration:
textDocument/diagnostic
The textDocument/diagnostic request now includes the previous id in its parameters.
vim.lsp.enable() start/stops clients as necessary and detaches non-applicable LSP clients.
vim.lsp.is_enabled() checks if a LSP config is enabled (without "resolving" it).
vim.lsp.get_configs() gets all LSP configs matching an optional filter.
Support for multiline semantic tokens.
Support for the disabled field on code actions.
The function form of cmd in a vim.lsp.Config or vim.lsp.ClientConfig receives the resolved config as the second arg: cmd(dispatchers, config).
Support for annotated text edits.
:checkhealth vim.lsp is now available to check which buffers the active LSP features are attached to.
LSP DiagnosticRelatedInformation is now shown in vim.diagnostic.open_float(). It is read from the LSP diagnostic object stored in the user_data field.
When inside the float created by vim.diagnostic.open_float() and the cursor is on a line with DiagnosticRelatedInformation, gf can be used to jump to the problematic location.
vim.lsp.buf.signature_help() supports "noActiveParameterSupport".
The filter option of vim.lsp.buf.code_action() now receives the client ID as an argument.
vim.lsp.ClientConfig exit_timeout decides the time waited before "stop" escalates to "force-stop" for vim.lsp.enable(), Client:stop(), and during Nvim shutdown.
exit_timeout graduated from "experimental" flags.exit_timeout to a top-level field. Defaults to false.
Client:stop() accepts force as an integer, which is treated as the time to wait before before stop escalates to force-stop.
vim.lsp.buf.rename() now highlights the symbol being renamed using the hl-LspReferenceTarget highlight group.
Code lenses now display as virtual lines

LUA

vim.net.request() can fetch/download HTTP content.
vim.wait() returns the callback results.
Lua type annotations for vim.uv.
vim.hl.range() now allows multiple timed highlights.
vim.tbl_extend(), vim.tbl_deep_extend() behavior argument can be a function.
vim.fs.root() can define "equal priority" via nested lists.
vim.fs.ext() returns the last extension of a file.
vim.version.range() can output human-readable string via tostring().
vim.version.intersect() computes intersection of two version ranges.
Iter:take() and Iter:skip() now optionally accept predicates.
Iter:peek() now works for all iterator types, not just list-iterator.
vim.list.unique() and Iter:unique() to deduplicate lists and iterators, respectively.
vim.list.bisect() performs binary search.
vim.json.encode() indent option performs pretty-formatting.
vim.json.encode() sort_keys option sorts by key.
vim.json.decode() skip_comments option allows comments in JSON data.
EXPERIMENTAL: vim.pos, vim.range provide Position/Range abstraction.

OPTIONS

'autowriteall' writes all buffers upon receiving SIGHUP, SIGQUIT or SIGTSTP.
'chistory' and 'lhistory' set size of the quickfix-stack.
'complete' new flags:
"F{func}" complete using given function
"F" complete using 'completefunc'
"o" complete using 'omnifunc'
'complete' allows limiting matches for sources using "{flag}^<limit>".
'completeopt' flag "nearest" sorts completion results by distance to cursor.
'diffanchors' specifies addresses to anchor a diff.
'diffopt' inline: configures diff highlighting for changes within a line.
'diffopt' with inline:word now automatically merges adjacent diff blocks separated by gaps and punctuation by 5 bytes to improve readability.
'fillchars' has new flag "foldinner".
'fsync' and 'grepformat' are now global-local options.
'listchars' has new flag "leadtab".
'jumpoptions' flag "view" now applies when popping the tagstack.
'maxsearchcount' sets maximum value for searchcount() and defaults to 999.
'pummaxwidth' sets maximum width for the completion popup menu.
'winborder' "bold" style, custom border style.
'busy' sets a buffer "busy" status. Indicated in the default statusline.
'pumborder' adds a border to the popup menu.
g:clipboard accepts a string name to force any builtin clipboard tool.
g:clipboard autodetection selects tmux only when running inside tmux.
'statusline' allows "stacking" highlight groups (groups inherit from previous highlight attributes)
'messagesopt' "progress:c" flag controls whether progress messages are shown in the cmdline message area.
Improved :set+=, :set^= and :set-= handling of comma-separated "key:value" pairs (e.g. 'listchars', 'fillchars', 'diffopt').

PERFORMANCE

vim.glob.to_lpeg() uses a new LPeg-based implementation (Peglob) that provides ~50% speedup for complex patterns. The implementation restores support for nested braces and follows LSP 3.17 specification with additional constraints for improved correctness and resistance to backtracking edge cases.
i_CTRL-R inserts named/clipboard registers literally, 10x speedup.
LSP textDocument/semanticTokens/range is supported, which requests tokens for the viewport (visible screen) only.
:packadd doesn't invalidate the cached Lua package path. Instead the cache gets updated in place. This might make a big startuptime difference for certain init.lua patterns where multiple :packadd or vim.pack.add() calls are interspersed with other code.

PLUGINS

Built-in plugin manager: vim.pack
:DiffTool compares directories (and files).
:Undotree lets you visually navigate the undo-tree.
Customize :checkhealth by handling a FileType checkhealth event. health-usage
Simplify Python provider setup to a single step: uv tool install pynvim Nvim will detect the plugin's location without user configuration, even if unrelated Python virtual environments are activated. provider-python
:checkhealth now checks for an available vim.ui.open() handler.
spellfile.vim : Replaced by package-spellfile.

STARTUP

v:argf provides file arguments given at startup.
Nvim shows a warning if the log file path is inaccessible.

TERMINAL

nvim_open_term() can be called with a non-empty buffer. The buffer contents are piped to the PTY and displayed as terminal output.
CSI 3 J (the sequence to clear terminal scrollback) is now supported.
DEC private mode 2026 (synchronized output) is now supported. Applications running in :terminal can batch screen updates to avoid tearing.
A suspended PTY process is now indicated by "[Process suspended]" at the bottom-left of the buffer and can be resumed by pressing a key.
On terminal exit, "[Process exited]" is shown as virtual text (instead of modifying buffer contents), and exit code is shown in statusline.
You can disable "[Process exited]" entirely, see terminal-config.

TREESITTER

Query:iter_captures() supports specifying starting and ending columns.
:EditQuery command gained tab-completion, works with injected languages.
LanguageTree:parse() now accepts a list of ranges.
v_an v_in v_]n v_[n incremental selection of treesitter nodes.

TUI

TermResponse now supports DA1 and APC query responses.
Native progress bars are displayed for Progress events using the OSC 9;4 sequence.
The TUI now renders the SGR dim (faint), blink, conceal, and overline attributes.

UI

ui2 is a redesign of the core messages and commandline UI, which will replace the legacy message grid in the TUI.
Avoids "Press ENTER" interruptions.
Avoids delays from W10 "Changing a readonly file" and other warnings.
Highlights the cmdline as you type.
Provides the pager as a buffer + window.
Currently experimental. To enable it: require('vim._core.ui2').enable()
:restart restarts Nvim and reattaches all UIs.
:connect dynamically connects the current UI to the server at the given address.
:checkhealth shows a summary in the header for every healthcheck.
ui-multigrid provides composition information and absolute coordinates.
Error messages are more concise:
"Error detected while processing:" changed to "Error in:".
"Error executing Lua:" changed to "Lua:".
'busy' status is shown in default statusline with symbol ◐
Cursor shape indicates when it is behind an unfocused floating window.
Improved LSP signature help rendering.
Multigrid UIs can call nvim_input_mouse with grid 0 to let Nvim decide the grid.
vim.ui.progress_status() returns a status description of currently running progress-messages.

VIMSCRIPT

chdir() allows optionally specifying a scope argument.
cmdcomplete_info() gets current cmdline completion info.
getcompletiontype() gets command-line completion type for any string.
has() gained two new system dependent feature flags, android and termux.
prompt_getinput() gets current user-input in prompt-buffer.
wildtrigger() triggers command-line expansion.
v:vim_did_init is set after sourcing init.vim but before load-plugins.
prompt_appendbuf() appends text to prompt-buffer.

CHANGED FEATURES

These existing features changed their behavior.
'pumblend' does not apply special attributes (bold, underline) from the background layer to the foreground layer.
gv works in operator pending mode and does not abort.
'smartcase' applies to completion filtering.
'spellfile' location defaults to stdpath("data").."/site/spell/" instead of the first writable directory in 'runtimepath'.
vim.version.range() doesn't exclude to if it is equal to from.
$VIM and $VIMRUNTIME no longer check for Vim version-specific runtime directory vim{number} (e.g. vim82).
'scrollback' maximum value increased from 100000 to 1000000
matchfuzzy() and matchfuzzypos() use an improved fuzzy matching algorithm (same as fzy).
Windows: Paths like "\Windows" and "/Windows" are now considered to be absolute paths (to the current drive) and no longer relative.
When 'shelltemp' is off, shell commands now use pipe() and not socketpair() for input and output. This matters mostly for Linux where some command lines using "/dev/stdin" and similar would break as these special files can be reopened when backed by pipes but not when backed by socket pairs.

REMOVED FEATURES

These deprecated features were removed.
vim.treesitter.get_parser() instead of throwing an error get_parser() now always returns nil when it fails to create a parser.

DEPRECATIONS

Main
Commands index
Quick reference