|
| 1 | +--- |
| 2 | +layout: newsletter |
| 3 | +title: "What Neovim shipped in 2022" |
| 4 | +category: newsletter |
| 5 | +permalink: /news/2022/12 |
| 6 | +--- |
| 7 | + |
| 8 | + |
| 9 | +Neovim is the [world's most-loved editor](https://insights.stackoverflow.com/survey/2021#most-loved-dreaded-and-wanted-new-collab-tools-love-dread). That's just science: |
| 10 | + |
| 11 | + |
| 12 | + |
| 13 | +Here are some highlights from Neovim 2022 (Nvim 0.8) development. |
| 14 | + |
| 15 | +## UI |
| 16 | + |
| 17 | +Eye candy first! |
| 18 | + |
| 19 | +- 'winhighlight' was throughly [reimplemented](https://github.com/neovim/neovim/pull/13457) as window-local highlight namespaces. This is backwards-compatible while enabling many new usecases, like window-local syntax highlighting. |
| 20 | +- [global 'statusline'](https://github.com/neovim/neovim/issues/9342) designates one statusline for all windows. Try it: |
| 21 | + ``` |
| 22 | + :set laststatus=3 |
| 23 | + ``` |
| 24 | +- `'winbar'` is like an extra statusline at the top of each window. It complements `laststatus=3`: |
| 25 | + ``` |
| 26 | + set winbar=%f |
| 27 | + set laststatus=3 |
| 28 | + ``` |
| 29 | +- `'winbar'` and `'statusline'` gained [support for mouse-click regions](https://github.com/neovim/neovim/pull/18650) (as 'tabline' has had since 2016): |
| 30 | + -  |
| 31 | +- _Experimental_ [zero-height command-line](https://github.com/neovim/neovim/pull/16251): |
| 32 | + ``` |
| 33 | + :set cmdheight=0 |
| 34 | + ``` |
| 35 | +- The ['mousescroll' option](https://github.com/neovim/neovim/pull/12355) controls vertical/horizontal mouse scroll behavior. |
| 36 | + ``` |
| 37 | + :set mousescroll=ver:5,hor:2 |
| 38 | + ``` |
| 39 | +- The new ['statuscolumn'](https://github.com/neovim/neovim/pull/20621) 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'. |
| 40 | + - Feature author @luukvbaal also provides a [plugin](https://github.com/luukvbaal/statuscol.nvim) with various pre-packaged 'statuscolumn' configs. |
| 41 | + - Try it! |
| 42 | + ``` |
| 43 | + :set rnu nu |
| 44 | + :let &stc='%#NonText#%{&nu?v:lnum:""}%=%{&rnu&&(v:lnum%2)?"\ ".v:relnum:""}%#LineNr#%{&rnu&&!(v:lnum%2)?"\ ".v:relnum:""}' |
| 45 | + ``` |
| 46 | + - <video height="360" controls><source src="/images/2023/statuscolumn.mp4" type="video/mp4"></video> |
| 47 | +- Marks can [save and restore viewport info](https://github.com/neovim/neovim/pull/15831). |
| 48 | + ``` |
| 49 | + :set jumpoptions=view |
| 50 | + ``` |
| 51 | + - When you jump around, or switch buffers with <kbd>ctrl-^</kbd>, the viewport is restored instead of resetting/recentering vertically. |
| 52 | +- [vim.ui_attach](https://neovim.io/doc/user/lua.html#vim.ui_attach%28%29) (experimental) enables in-process Lua plugins to hook into the same events exposed to all Nvim UIs. [pic.twitter.com/w9U87jGfIL](https://twitter.com/Neovim/status/1578146342991527938/photo/1) |
| 53 | + - [noice.nvim](https://github.com/folke/noice.nvim) was an early adopter (a matter of days!). |
| 54 | + -  |
| 55 | +
|
| 56 | +## LSP |
| 57 | +
|
| 58 | +- [Summary](https://www.vikasraj.dev/blog/lsp-neovim-retrospective) of the history and status of Nvim builtin LSP support. |
| 59 | +- Nvim LSP client now [supports](https://github.com/neovim/neovim/pull/19916) connecting to language servers by TCP. |
| 60 | + ``` |
| 61 | + vim.lsp.start({ name = 'godot', cmd = vim.lsp.rpc.connect('127.0.0.1', 6008) }) |
| 62 | + ``` |
| 63 | +- New [core events for LSP](https://github.com/neovim/neovim/pull/18507): `LspAttach`, `LspDetach`. Example: |
| 64 | + ``` |
| 65 | + vim.api.nvim_create_autocmd('LspAttach', { |
| 66 | + group = yourGroupID, |
| 67 | + callback = function(args) |
| 68 | + local client = vim.lsp.get_client_by_id(args.data.client_id) |
| 69 | + your_callbac_func(client, args.buf) |
| 70 | + end |
| 71 | + } |
| 72 | + ``` |
| 73 | +- `vim.lsp.get_active_clients()` learned to filter (this will be a standard pattern in the Lua stdlib): |
| 74 | + ``` |
| 75 | + get_active_clients({id=42}) |
| 76 | + get_active_clients({bufnr=99}) |
| 77 | + get_active_clients({name='tsserver'}) |
| 78 | + ``` |
| 79 | +
|
| 80 | +## Editor |
| 81 | +
|
| 82 | +- Nvim now [includes](https://github.com/neovim/neovim/pull/15391) 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. |
| 83 | +- [tree-sitter spellcheck](https://github.com/neovim/neovim/pull/19419) constrained to extmark region. |
| 84 | +- The diff-mode ["linematch" feature](https://github.com/neovim/neovim/pull/14537) improves rendering of same-line diff changes: |
| 85 | + ``` |
| 86 | + :set diffopt+=linematch:60 |
| 87 | + ``` |
| 88 | + -  |
| 89 | +- Nvim supports [editorconfig](https://editorconfig.org), and [enables it](https://github.com/neovim/neovim/pull/21633) by default. Nvim detects ".editorconfig" files in your project and applies the settings. |
| 90 | + - To opt-out of this feature, add this to your config: |
| 91 | + ``` |
| 92 | + vim.g.editorconfig_enable = false |
| 93 | + ``` |
| 94 | +- Plugins can provide a [live preview](https://neovim.io/doc/user/map.html#%3Acommand-preview) of user-defined commands. |
| 95 | + - This extends the builtin `'inccommand'` feature (since 2017), which show the effects of `:substitute` (`:s/foo/bar`) as you type. |
| 96 | + - Example: The [live-command.nvim](https://github.com/smjonas/live-command.nvim) plugin adds preview for `:normal` and macros: |
| 97 | + - <video height="360" controls><source src="/images/2023/normal-cmd-preview_a84638.mp4" type="video/mp4"></video> |
| 98 | +- You [can now](https://github.com/neovim/neovim/pull/18194) implement ['inccommand'](https://neovim.io/doc/user/options.html#'inccommand') preview for any user-defined command. This builds a foundation for live preview of `:normal`, [:global](https://github.com/neovim/neovim/pull/18815), etc. |
| 99 | + ``` |
| 100 | + vim.api.nvim_create_user_command( |
| 101 | + 'MyCmd', |
| 102 | + my_cmd, |
| 103 | + { …, preview = my_cmd_preview }) |
| 104 | + ``` |
| 105 | +- The `:write` command [gained](https://github.com/neovim/neovim/issues/19884) the `++p` flag, so this creates parent/dir/ if it doesn't exist: |
| 106 | + ``` |
| 107 | + :edit parent/dir/file.txt |
| 108 | + :write ++p |
| 109 | + ``` |
| 110 | +- Nvim [now stores](https://github.com/neovim/neovim/pull/15583) "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. |
| 111 | +- Plugins can also use `stdpath('log')` to get the recommended location for log files. |
| 112 | +- <kbd>gO</kbd> in the manpage viewer (`:help :Man`) shows an outline (table of contents) in the location list. Now the outline also [lists the flags](https://github.com/neovim/neovim/pull/17558). |
| 113 | + -  |
| 114 | +
|
| 115 | +## Performance |
| 116 | +
|
| 117 | +- [Filetype detection](https://github.com/neovim/neovim/issues/18604) uses Lua (instead of Vimscript) + "on-demand" strategy => 7x speedup vs the old filetype.vim, saves 5+ ms on startup: |
| 118 | + ``` |
| 119 | + before: |
| 120 | + 9.0ms: sourcing …/runtime/filetype.vim |
| 121 | + after: |
| 122 | + 1.3ms: sourcing …/runtime/filetype.lua |
| 123 | + ``` |
| 124 | +- `nvim --startuptime` [now reports](https://github.com/neovim/neovim/pull/19267) Lua `require()` times. |
| 125 | + ``` |
| 126 | + 000.010 000.010: --- NVIM STARTING --- |
| 127 | + 000.198 000.188: event init |
| 128 | + ... |
| 129 | + 026.333 001.109 001.101: require('vim.lsp.protocol') |
| 130 | + 028.144 000.423 000.423: require('vim.lsp._snippet') |
| 131 | + ... |
| 132 | + ``` |
| 133 | +- A brief summary of Nvim 'packpath' improvements: |
| 134 | + -  |
| 135 | +- [Fast, slick folds](https://github.com/kevinhwang91/nvim-ufo) provided by a plugin. |
| 136 | +
|
| 137 | +## Defaults |
| 138 | +
|
| 139 | +- 'mouse' option is [set by default](https://github.com/neovim/neovim/pull/19290) (again). Was disabled since 2017 "until a better approach". Now we have it: |
| 140 | + ``` |
| 141 | + mouse=nvi |
| 142 | + Type ":" (cmdline-mode) to temporarily disable mouse. Right-click shows a popup menu. |
| 143 | + Try it! |
| 144 | + ``` |
| 145 | +
|
| 146 | +## API |
| 147 | +
|
| 148 | +- [nvim_parse_cmd()](https://github.com/neovim/neovim/pull/18231) provides the foundation for `nvim_cmd([list])` and "user cmd-preview"! And super useful for defining custom cmdline (`:`) behavior. |
| 149 | + ``` |
| 150 | + :echo nvim_parse_cmd('.,$g/foo/bar', {}) |
| 151 | + { |
| 152 | + 'cmd': 'global', |
| 153 | + 'args': ['/foo/bar'], |
| 154 | + 'mods': {…}, |
| 155 | + 'magic': {'file': v:false, 'bar': v:false} |
| 156 | + } |
| 157 | + ``` |
| 158 | +- Use `nvim_cmd()` to call any Vim legacy command in a structured way, like `system([...])`. |
| 159 | + - Don't need `fnameescape()`: special chars are controlled by the `magic` param. |
| 160 | + ``` |
| 161 | + nvim_cmd({cmd='vimgrep', args={'/%s/j', '**'}}, {}) |
| 162 | + ``` |
| 163 | +- [nvim-oxi](https://github.com/noib3/nvim-oxi): "first-class Rust bindings (FFI to Nvim C) to the rich API exposed by Neovim." |
| 164 | +
|
| 165 | +## Lua |
| 166 | +
|
| 167 | +- Check out the [vim.fs](https://neovim.io/doc/user/lua.html#vim.fs) module for filesystem operations. |
| 168 | + - `vim.fs.find()` is now the canonical way to find "root files", common for LSP configuration. |
| 169 | +- `vim.cmd` is the Lua `nvim_cmd` wrapper. It supports calling Ex commands as functions instead of strings: |
| 170 | + ``` |
| 171 | + vim.cmd.colorscheme('nightfox') |
| 172 | + ``` |
| 173 | +- Lua plugins [continue to mature](https://zignar.net/2022/11/06/structuring-neovim-lua-plugins/): |
| 174 | + > "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." |
| 175 | + - This elegant interface required lots of careful work, largely thanks to @bfredl! |
| 176 | +
|
| 177 | +## Maintenance |
| 178 | +
|
| 179 | +- Work by @dundargoc closed two refactor epics started in 2014 and 2017: [#567](https://github.com/neovim/neovim/issues/567) [#7401](https://github.com/neovim/neovim/issues/7401) |
| 180 | +- [Progress](https://twitter.com/teej_dv/status/1575450247173738498) on vim9script => Nvim-Lua transpiler from core maintainer [@teej_dv](https://twitter.com/teej_dv) will enable us to continue pulling test coverage from Vim, plus syntax, ftplugins, and even plugins like cfilter. |
| 181 | +- [Nightly + stable releases](https://github.com/neovim/neovim/releases) now [provide](https://github.com/neovim/neovim/pull/19029) a universal binary (ARM/M1, Intel) for macOS 11+. |
| 182 | +
|
| 183 | +## Documentation |
| 184 | +
|
| 185 | +Automated generation of the [online Nvim documentation](https://neovim.io/doc/user/) was rewritten by replacing an old AWK script with Lua + tree-sitter. [We can have nice things.](https://twitter.com/justinmk/status/1577344345736466432) |
| 186 | +
|
| 187 | +- Improved styling |
| 188 | +- Nested lists |
| 189 | +- Soft-wrapped "flow" layout on selected pages ([example](https://neovim.io/doc/user/luaref.html)) |
| 190 | +- Improved parsing of vim :help tokens |
| 191 | +
|
| 192 | +Compare the old layout (left) to the new one (right): |
| 193 | +
|
| 194 | + |
| 195 | +
|
| 196 | +## Job control |
| 197 | +
|
| 198 | +Nvim now [sets](https://github.com/neovim/neovim/pull/11009) 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. |
| 199 | +
|
| 200 | +## RPC |
| 201 | +
|
| 202 | +Nvim UIs are just (inverted) plugins. And now `nvim` itself is a [self-hosting UI](https://github.com/neovim/neovim/pull/18375): when you run `nvim` in a terminal, it starts the TUI as a `nvim --embed` child process. |
| 203 | +
|
| 204 | + |
| 205 | +
|
| 206 | +Just like Nvim GUIs, you can connect the `nvim` TUI to any Nvim server to see its UI! You can try it right now: |
| 207 | +
|
| 208 | +1. Start a server at address `./foo` (creates a `foo` file in the current directory): |
| 209 | + ``` |
| 210 | + nvim --listen ./foo |
| 211 | + ``` |
| 212 | +2. From a different terminal (in the same directory as `./foo`), connect `nvim` to the server: |
| 213 | + ``` |
| 214 | + nvim --remote-ui --server ./foo |
| 215 | + ``` |
| 216 | +
|
| 217 | +## Deprecations |
| 218 | +
|
| 219 | +- [Removed the `'insertmode'` option](https://github.com/neovim/neovim/pull/18547#issuecomment-1134613097), which was used in Vim to implement "easy vim". |
| 220 | + - We're driving towards making the same behavior possible as a plugin. See `:help 'insertmode'`. |
| 221 | +- cscope support was [removed](https://github.com/neovim/neovim/pull/20545), because it is mostly redundant with the LSP client (`:help lsp`). |
| 222 | + - Note: ctags support will *never* be removed, it is far more common and generally useful. |
| 223 | +
|
| 224 | +
|
| 225 | +
|
0 commit comments