What Neovim shipped in 2022

December 2022

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

Here are some highlights from Neovim 2022 (Nvim 0.8) development.


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 complements laststatus=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!).


  • 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('', 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)
  • vim.lsp.get_active_clients() learned to filter (this will be a standard pattern in the Lua stdlib):


  • 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
  • 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 :normal and macros:
  • You can now implement ‘inccommand’ preview for any user-defined command. This builds a foundation for live preview of :normal, :global, etc.
      { …, preview = my_cmd_preview })
  • The :write command gained the ++p flag, 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 $XDG_CACHE_HOME (~/.cache). This change only affects macOS/unix, the Windows locations are unchanged.
  • 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.


  • Filetype detection uses Lua (instead of Vimscript) + “on-demand” strategy => 7x speedup vs the old filetype.vim, saves 5+ ms on startup:
      9.0ms: sourcing …/runtime/filetype.vim
      1.3ms: sourcing …/runtime/filetype.lua
  • nvim --startuptime now reports Lua require() 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.


  • ‘mouse’ option is set by default (again). Was disabled since 2017 “until a better approach”. Now we have it:
    Type ":" (cmdline-mode) to temporarily disable mouse. Right-click shows a popup menu.
    Try it!


  • 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, like system([...]).
    • Don’t need fnameescape(): special chars are controlled by the magic param.
      nvim_cmd({cmd='vimgrep', args={'/%s/j', '**'}}, {})
  • nvim-oxi: “first-class Rust bindings (FFI to Nvim C) to the rich API exposed by Neovim.”


  • 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.cmd is the Lua nvim_cmd wrapper. It supports calling Ex commands as functions instead of strings:
  • Lua plugins continue to mature:

    “Lua plugins are basically the same as a vim plugin, except the file extension is .lua instead of .vim and the file contains Lua code instead of Vimscript.”

    • This elegant interface required lots of careful work, largely thanks to @bfredl!


  • 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+.


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.


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:

  1. Start a server at address ./foo (creates a foo file in the current directory):
    nvim --listen ./foo
  2. From a different terminal (in the same directory as ./foo), connect nvim to the server:
    nvim --remote-ui --server ./foo


  • 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'.
  • 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.


Find more updates in the news archive.

What is Neovim?

Neovim is a Vim-based text editor engineered for extensibility and usability, to encourage new applications and contributions.

Visit #neovim:matrix.org or #neovim on irc.libera.chat to chat with the team.



RSS clients can follow the RSS feed.