Neovim is een opensource terminalteksteditor die sinds 2014 bestaat. Het is een fork van Vim en kan in zekere zin worden beschouwd als de spirituele opvolger daarvan. Neovim heeft extra functies, zoals ondersteuning voor Lua-scripting, LSP en asynchrone i/o. Verder bevat het een terminalemulator en kan de functionaliteit verder worden uitgebreid met plug-ins. Kort geleden is versie 0.12.0 uitgekomen en hierin zijn de volgende veranderingen en verbeteringen aangebracht:
Breaking Changes
These changes may require adaptations in your config or plugins.
APIDiagnostics
- |nvim_get_commands()| returns `complete` as a Lua function, if it was defined as such.
Editor
- |diagnostic-signs| can no longer be configured with |:sign-define| or |sign_define()| (deprecated in Nvim 0.10 |deprecated-0.10|).
- Removed |vim.diagnostic.disable()| and |vim.diagnostic.is_disabled()| (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.
Events
- |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 `=@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|.
LSP
- |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.
LUA
- 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()`.
- |vim.lsp.util.convert_signature_help_to_markdown_lines()| activeParameter handling updated:
- 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`
Options
- Renamed `vim.diff` to `vim.text.diff`.
Plugins
- 'shelltemp' defaults to "false".
treesitter
- 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
- |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.
APIBuild
- |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.
Defaults
- 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.
Diagnostics
- '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:
- |vim.diagnostic.status()|
- |vim.ui.progress_status()|
- :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.
Editor
- |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.
Events
- |: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.
Highlights
- 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.
LSP
- |hl-DiffTextAdd| highlights added text within a changed line.
- |hl-OkMsg| |hl-StderrMsg| |hl-StdoutMsg|
- |hl-SnippetTabstopActive| highlights the currently active tabstop.
- |hl-PmenuBorder| |hl-PmenuShadow| |hl-PmenuShadowThrough| see 'pumborder'.
- |nvim_set_hl()| and |nvim_get_hl()| support the SGR attributes "dim", "blink", "conceal", and "overline".
LUA
- |lsp-completion|:
- |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".
- Support for `textDocument/inlineCompletion` |lsp-inline_completion| See |lsp-inline_completion| for quickstart instructions.
- |: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/codeLens` |lsp-codelens| was reimplemented.
- `textDocument/colorPresentation` |lsp-document_color|
- `textDocument/diagnostic`
- `textDocument/documentColor` |lsp-document_color|
- `textDocument/documentLink`: |gx| opens "documentLink" items at cursor.
- `textDocument/inlineCompletion`
- `textDocument/linkedEditingRange` |lsp-linked_editing_range|
- `textDocument/onTypeFormatting` |lsp-on_type_formatting|
- `textDocument/selectionRange` Incremental selection. |v_an| selects outwards, |v_in| selects inwards.
- `textDocument/semanticTokens/range`
- `workspace/codeLens/refresh`
- `workspace/diagnostic/refresh`
- `workspace/diagnostic` |vim.lsp.buf.workspace_diagnostics()|
- 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.
- Support for related documents in pull diagnostics: more info
- |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
Options
- |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.
Performance
- 'autocomplete' enables |ins-autocompletion|.
- '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}^".
- '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').
Plugins
- |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.
Startup
- 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.
Terminal
- |v:argf| provides file arguments given at startup.
- Nvim shows a warning if the log file path is inaccessible.
Treesitter
- |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|.
TUI
- |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.
UI
- |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.
Vimscript
- |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 the current UI.
- |: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-message|s.
- |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
See |deprecated-0.12|.