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.

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 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!).

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
      
  • 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.
    vim.api.nvim_create_user_command(
      'MyCmd',
      my_cmd,
      { …, 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.

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

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, 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.”

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.cmd is the Lua nvim_cmd wrapper. 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 .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!

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:

  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
    

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

News

Find more updates in the news archive. There's also an RSS feed.

What is Neovim?

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

Discuss

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