Neovim is the world’s most-loved editor. That’s just science:

Here are some highlights from Neovim 2022 (Nvim 0.8) development.
UI
Eye candy first!
- ‘winhighlight’ was throughly reimplemented as window-local highlight namespaces. This is backwards-compatible while enabling many new usecases, like window-local syntax highlighting.
- global ‘statusline’ designates one statusline for all windows. Try it:
:set laststatus=3 'winbar'is like an extra statusline at the top of each window. It complementslaststatus=3:set winbar=%f set laststatus=3'winbar'and'statusline'gained support for mouse-click regions (as ’tabline’ has had since 2016):- Experimental zero-height command-line:
:set cmdheight=0 - The ‘mousescroll’ option controls vertical/horizontal mouse scroll behavior.
:set mousescroll=ver:5,hor:2 - The new ‘statuscolumn’ option gives full control of the “gutter”, with the same familiar format of ‘statusline’. It even supports click events, just like ‘statusline’, ’tabline’, and ‘winbar’.
- Feature author @luukvbaal also provides a plugin with various pre-packaged ‘statuscolumn’ configs.
- Try it!
:set rnu nu :let &stc='%#NonText#%{&nu?v:lnum:""}%=%{&rnu&&(v:lnum%2)?"\ ".v:relnum:""}%#LineNr#%{&rnu&&!(v:lnum%2)?"\ ".v:relnum:""}'
- Marks can save and restore viewport info.
:set jumpoptions=view- When you jump around, or switch buffers with ctrl-^, the viewport is restored instead of resetting/recentering vertically.
- vim.ui_attach (experimental) enables in-process Lua plugins to hook into the same events exposed to all Nvim UIs. pic.twitter.com/w9U87jGfIL
- noice.nvim was an early adopter (a matter of days!).

LSP
- Summary of the history and status of Nvim builtin LSP support.
- Nvim LSP client now supports connecting to language servers by TCP.
vim.lsp.start({ name = 'godot', cmd = vim.lsp.rpc.connect('127.0.0.1', 6008) }) - New core events for LSP:
LspAttach,LspDetach. Example:vim.api.nvim_create_autocmd('LspAttach', { group = yourGroupID, callback = function(args) local client = vim.lsp.get_client_by_id(args.data.client_id) your_callbac_func(client, args.buf) end } vim.lsp.get_active_clients()learned to filter (this will be a standard pattern in the Lua stdlib):get_active_clients({id=42}) get_active_clients({bufnr=99}) get_active_clients({name='tsserver'})
Editor
- Nvim now includes treesitter parsers for C, Lua, and Vimscript. This is a step towards “treesitter by default” for common languages, instead of regex-based vim syntax definitions.
- tree-sitter spellcheck constrained to extmark region.
- The diff-mode “linematch” feature improves rendering of same-line diff changes:
:set diffopt+=linematch:60 - Nvim supports editorconfig, and enables it by default. Nvim detects “.editorconfig” files in your project and applies the settings.
- To opt-out of this feature, add this to your config:
vim.g.editorconfig_enable = false
- To opt-out of this feature, add this to your config:
- Plugins can provide a live preview of user-defined commands.
- This extends the builtin
'inccommand'feature (since 2017), which show the effects of:substitute(:s/foo/bar) as you type. - Example: The live-command.nvim plugin adds preview for
:normaland macros:
- This extends the builtin
- You can now implement ‘inccommand’ preview for any user-defined command. This builds a foundation for live preview of
:normal, :global, etc.vim.api.nvim_create_user_command( 'MyCmd', my_cmd, { …, preview = my_cmd_preview }) - The
:writecommand gained the++pflag, so this creates parent/dir/ if it doesn’t exist::edit parent/dir/file.txt :write ++p - Nvim now stores “session data” (shada, persistent undo, …) in
$XDG_STATE_HOME(/.local/state) instead of/.cache). This change only affects macOS/unix, the Windows locations are unchanged.$XDG_CACHE_HOME( - Plugins can also use
stdpath('log')to get the recommended location for log files. - gO in the manpage viewer (
:help :Man) shows an outline (table of contents) in the location list. Now the outline also lists the flags.
Performance
- Filetype detection uses Lua (instead of Vimscript) + “on-demand” strategy => 7x speedup vs the old filetype.vim, saves 5+ ms on startup:
before: 9.0ms: sourcing …/runtime/filetype.vim after: 1.3ms: sourcing …/runtime/filetype.lua nvim --startuptimenow reports Luarequire()times.000.010 000.010: --- NVIM STARTING --- 000.198 000.188: event init ... 026.333 001.109 001.101: require('vim.lsp.protocol') 028.144 000.423 000.423: require('vim.lsp._snippet') ...- A brief summary of Nvim ‘packpath’ improvements:
- Fast, slick folds provided by a plugin.
Defaults
- ‘mouse’ option is set by default (again). Was disabled since 2017 “until a better approach”. Now we have it:
mouse=nvi Type ":" (cmdline-mode) to temporarily disable mouse. Right-click shows a popup menu. Try it!
API
- nvim_parse_cmd() provides the foundation for
nvim_cmd([list])and “user cmd-preview”! And super useful for defining custom cmdline (:) behavior.:echo nvim_parse_cmd('.,$g/foo/bar', {}) { 'cmd': 'global', 'args': ['/foo/bar'], 'mods': {…}, 'magic': {'file': v:false, 'bar': v:false} } - Use
nvim_cmd()to call any Vim legacy command in a structured way, likesystem([...]).- Don’t need
fnameescape(): special chars are controlled by themagicparam.nvim_cmd({cmd='vimgrep', args={'/%s/j', '**'}}, {})
- Don’t need
- nvim-oxi: “first-class Rust bindings (FFI to Nvim C) to the rich API exposed by Neovim.”
Lua
- Check out the vim.fs module for filesystem operations.
vim.fs.find()is now the canonical way to find “root files”, common for LSP configuration.
vim.cmdis the Luanvim_cmdwrapper. It supports calling Ex commands as functions instead of strings:vim.cmd.colorscheme('nightfox')- Lua plugins continue to mature:
“Lua plugins are basically the same as a vim plugin, except the file extension is
.luainstead of.vimand the file contains Lua code instead of Vimscript.”- This elegant interface required lots of careful work, largely thanks to @bfredl!
Maintenance
- Work by @dundargoc closed two refactor epics started in 2014 and 2017: #567 #7401
- Progress on vim9script => Nvim-Lua transpiler from core maintainer @teej_dv will enable us to continue pulling test coverage from Vim, plus syntax, ftplugins, and even plugins like cfilter.
- Nightly + stable releases now provide a universal binary (ARM/M1, Intel) for macOS 11+.
Documentation
Automated generation of the online Nvim documentation was rewritten by replacing an old AWK script with Lua + tree-sitter. We can have nice things.
- Improved styling
- Nested lists
- Soft-wrapped “flow” layout on selected pages (example)
- Improved parsing of vim :help tokens
Compare the old layout (left) to the new one (right):

Job control
Nvim now sets the $NVIM environment variable in jobstart() and :terminal jobs, so child processes have an unambiguous hint that they are children of Nvim. The old $NVIM_LISTEN_ADDRESS, which had conflicting “dual purposes”, is no longer passed to children.
RPC
Nvim UIs are just (inverted) plugins. And now nvim itself is a self-hosting UI: when you run nvim in a terminal, it starts the TUI as a nvim --embed child process.

Just like Nvim GUIs, you can connect the nvim TUI to any Nvim server to see its UI! You can try it right now:
- Start a server at address
./foo(creates afoofile in the current directory):nvim --listen ./foo - From a different terminal (in the same directory as
./foo), connectnvimto the server:nvim --remote-ui --server ./foo
Deprecations
- Removed the
'insertmode'option, which was used in Vim to implement “easy vim”.- We’re driving towards making the same behavior possible as a plugin. See
:help 'insertmode'.
- We’re driving towards making the same behavior possible as a plugin. See
- cscope support was removed, because it is mostly redundant with the LSP client (
:help lsp).- Note: ctags support will never be removed, it is far more common and generally useful.



