Skip to main content

Migrate from Vim to Neovim

·481 words·3 mins
Table of Contents

整理了一下环境,把 Vim 切换到 Neovim 了。首先如果想体验 Neovim,并不意味着你的 vimrc 要重新写,大部分是兼容的。只需要参考 Transitioning from Vim 中的步骤就可以基于原本在 Vim 中的配置使用 Neovim 了。我这里选择通过 Lua 重写,一是 Vimscript 这个每次要改点什么就要查语法很头疼,二是 Neovim 在当下的生态已经远比几年前好了,基本上各种 Vimscript 编写的插件都可以找到使用 Lua 重写的替代版本了

说几个奇怪的地方

  • 以前保存一个没有权限的文件的时候,vim 是不能保存的。需要添加 cmap w!! w !sudo tee > /dev/null % 这种快捷命令。但是 Neovim 不用配置就可以做到,这个可能引起误伤
  • :shell 没了,取而代之的是 :terminal。这个可能和你的 Zsh 之类的配置有冲突

Builtin Settings #

将内建的配置项和三方插件的分开后。你可以通过执行 source 来直接载入 VimScript 的配置,也就是说原来的基本不用动

vim.cmd('source ' ..  'the path of VimScript')```

也可以重写成 Lua 版本的,这里列举几个例子

  • VimScript 中的 g 改写成 Lua 中的 vim.g。比如 let g:mapleader = ',' => vim.g.mapleader = ","
  • 大部分的 set x 改写成 vim.opt.x = value 的形式。比如 set ruler => vim.opt.ruler = true。这里所有的选项可以通过 :help option-list 得到
  • autocmd 替换成函数。比如 au FocusLost * :set norelativenumber number => vim.api.nvim_create_autocmd("FocusLost", { pattern = "*", command = ":set norelativenumber number" })。这里所用到的 vim.api 是用来和 vim 进行交互的。这条命令也可以进一步 Lua 化
  • 按键映射方面直接使用 vim.keymap.set 取代,nmap/vmap/nnoremap 这些都被变成参数了。比如 vim.keymap.set("n", "<leader>w", ":w<CR>", { silent = false, noremap = true, desc = "write to file" })
  • 原先的自定义函数可以重写成 Lua 版本的,然后通过 vim.api.nvim_create_user_command 注册成命令,这个函数的第二个参数可以为 Lua 的函数,也可以为 String 用来外部插件中的原生 VimScript 函数。比如 vim.api.nvim_create_user_command("Inflection", "call inflection#inflect_current_word()", {})

另外如果有问题,可能除 Help 以外, r/neovim 是一个不错的选择,里面关于 Neovim 的解答可能比 stackoverflow 还多。还有一点就是可以先搜一下有没有插件实现了这个功能,Neovim 的插件极多,哪怕是一个小功能都有插件,比如高亮 TODO 的 todo-comments

Plugin Ecosystem #

主要以 Lua 编写的插件为主。搜索的时候可以使用 Google 的搜索语法,通过双引号括起来 Neovim,来避免匹配到很多 Vim 的插件

Plugin Manager #

目前流行的应该就这两个

体验了一下感觉 lazy.nvim 更方便友好。Neovim 的默认配置目录,在 ~/.config/nvim 中。如果使用 lazy.nvim 可以通过配置来自动载入 ~/.config/nvim/lua/plugins.lua 或者 ~/.config/nvim/lua/plugins/*.lua 中的内容。所以你可以将配置目录整理成这样

.
├── init.lua
├── lazy-lock.json
├── lua
│   └── plugins
│       ├── completion.lua
│       ├── finder.lua
│       ├── lsp.lua
│       ├── misc.lua
│       ├── operation.lua
│       ├── syntax.lua
│       └── ui.lua

init.lua 写入包管理器所需的必要代码

local _M = {}

function _M.setup()
  -- load plugin manager
  local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
  if not vim.loop.fs_stat(lazypath) then
    print('installing lazy.nvim...')
    vim.fn.system({
      "git",
      "clone",
      "--filter=blob:none",
      "https://github.com/folke/lazy.nvim.git",
      "--branch=stable", -- latest stable release
      lazypath,
    })
    print('installing lazy.nvim...done')
  end
  vim.opt.rtp:prepend(lazypath)

  -- load plugins, auto import lua/plugins files
  require("lazy").setup({ { import = "plugins" } })
end

_M.setup()

~/.config/nvim/lua/plugins/*.lua 的每个文件中,返回一个配置插件的 table 就可以了。参考如下

-- ~/.config/nvim/lua/plugins/completion.lua`
return {
  -- https://github.com/windwp/nvim-autopairs
  -- A super powerful autopair plugin for Neovim that supports multiple characters.
  {
    "windwp/nvim-autopairs",
    config = function()
      require("nvim-autopairs").setup()
    end,
  },
}

上面代码中的 config 用于配置插件,需要视插件本身而定。lazy.nvim 本身也提供了很多配置参数,但用下来基本只需要关注 event 参数,用来控制载入的时机

Some Useful Plugins #

这一节主要列举一些可以替换的插件。首先可以先装 neodev.nvim 这个插件,可以为编写 Neovim 配置提供环境,支持文档,跳转

Language Server #

依旧可以选择 coc.nvim 一套带走。我这里则是基于原生的生态来改

首先是 Language Server Manager,可以帮助我们对 LS 进行管理

另外还推荐

这可以使用额外的工具作为数据源来做一些代码重命名,格式化之类的,弥补 Neovim 内置的 LSP 的不足

Fuzzy Finder #

用于模糊查找,可以用于替换 LeaderF

这一个系列也有好几个插件需要安装,可以自行 Google

Syntax Enhanced #

用处之一是可以增强高亮显示,不再需要像 Vim 那样去装 rust-lang/rust.vim 这种东西了。除此之外还可以为其他的插件提供语义支持,比如可以 block 级别的跳转

可以考虑以下插件进行配合

Snippets #

看个人喜好,我这里使用的是当前 star 数最多的 LuaSnip

Ohters #

一些其他的插件,用于增强体验

关于插件启动速度,可以使用 Lazy.nvim 的中提供的 Profile 功能。如果遇到插件安装后没有反应,可以试着执行 :checkhealth 这个命令,里面会有详细信息,前提插件实现了健康检查的接口