Start from scratch: Neovim

2024 年初发现 WSL 竟然无法更新 VSCode, 后发现其官网也被墙了, 为了愉快的在 Linux 环境写代码还是选择重回 nvim

nvim
├── init.lua
├── lazy-lock.json
└── lua
    ├── core
    │   ├── autocmds.lua
    │   ├── crisp.lua
    │   ├── keybindings.lua
    │   └── options.lua
    ├── lazy-init.lua
    └── plugins
        ├── common
        │   ├── leetcode.lua
        │   └── rustaceanvim.lua
        ├── debug
        │   ├── neotest.lua
        │   ├── nvim-dap-ui.lua
        │   ├── nvim-dap-vtxt.lua
        │   └── nvim-dap.lua
        ├── editor
        │   ├── flash.lua
        │   ├── nvim-spider.lua
        │   └── vim-surround.lua
        ├── file
        │   ├── comment.lua
        │   ├── goto-preview.lua
        │   ├── indent-blankline.lua
        │   ├── markdown-preview.lua
        │   ├── nvim-autopairs.lua
        │   ├── nvim-bqf.lua
        │   ├── todo-comments.lua
        │   ├── vim-doge.lua
        │   └── wrapping.lua
        ├── git
        │   ├── gitsigns.lua
        │   └── lazygit.lua
        ├── highlight
        │   ├── nvim-treesitter-context.lua
        │   ├── nvim-treesitter.lua
        │   └── nvim-ts-rainbow.lua
        ├── init.lua
        ├── lsp
        │   ├── auto-complete.lua
        │   ├── formatting.lua
        │   ├── lsp.lua
        │   ├── navic.lua
        │   ├── neodev.lua
        │   ├── nvim-lint.lua
        │   ├── server
        │   │   ├── bash.lua
        │   │   ├── clangd.lua
        │   │   ├── cmake.lua
        │   │   ├── common.lua
        │   │   ├── lua.lua
        │   │   └── markdown.lua
        │   └── signature.lua
        ├── manager
        │   ├── bufferline.lua
        │   ├── lualine.lua
        │   ├── navigation.lua
        │   ├── startup.lua
        │   └── yazi.lua
        ├── system
        │   ├── clipboard.lua
        │   ├── filetype.lua
        │   ├── nvim-notify.lua
        │   └── startuptime.lua
        ├── theme
        │   └── onedark.lua
        └── tools
            ├── cscope_maps.lua
            ├── symbols-outline.lua
            ├── telescope.lua
            ├── toggleterm.lua
            ├── trouble.lua
            └── which-key.lua

15 directories, 60 files

需要安装 neovim 0.9 以上版本, 配置文件可以在 dotfiles repo 下查看。

0. 初期参考

1. 安装 Neovim

直接使用 Nvim Github 提供的二进制文件省心省力。

wget https://github.com/neovim/neovim/releases/download/stable/nvim-linux64.tar.gz
tar -xvf nvim-linux64.tar.gz
sudo mv nvim-linux64 /usr/local

# edit the .bashrc file to add 'nvim-linux64' system path
vim ~/.bashrc
# .bashrc
export PATH=/usr/local/nvim-linux64/bin:$PATH

# back to cli
source ~/.bashrc

2. vim 选项配置

3. vim 快捷键配置

4. 插件安装

最近在群上看到 lazy.nvim 真香的言论特地搜索了一番, 竟然比 Packer 效率提高了将近 10 倍, 而且 Packer 的作者也不再维护 Packer 的仓库了, 是时候全面转向 lazy 了!

Zwlin98/nvim LSP 配置要疯, 这个仓库简直救我狗命!
使用Lazy.nvim插件管理器,让你的Nvim懒惰起来(从Packer迁移到Lazy记录) - CSDN

4.1 Common

LeetCode: leetcode.nvim
用 neovim 刷 LeetCode 的必备工具。
Rust: rust-analyzer
rust-analyzer 基于 LSP 实现, 它为许多代码编辑器 (包括 VS Code、 Emacs 和 Vim) 提供了补全和跳转定义等特性, 交给 nvim-lspconfig.rust_analyzer 安装配置即可。
Enhanced Rust Tool: mrcjkb/rustaceanvim
Rust 语言的非标准化的扩展组件, 提供了一些基于 rust-analyzer 的额外的功能。
Image: image.nvim
给 LeetCode 插件提供显示图片支持, 但需要安装额外的软件提供支持, 而且还会影响 Leetcode 的 wrapper 功能, 一般不用它。

Leetcode Image Display

# image magick
sudo apt-get install imagemagick
# magick luarock
sudo apt-get install luarocks
luarocks --local install magick
# kitty
sudo apt-get install kitty
# ueberzugpp Ubuntu 20.04
echo 'deb http://download.opensuse.org/repositories/home:/justkidding/xUbuntu_22.04/ /' | sudo tee /etc/apt/sources.list.d/home:justkidding.list
curl -fsSL https://download.opensuse.org/repositories/home:justkidding/xUbuntu_22.04/Release.key | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/home_justkidding.gpg > /dev/null
sudo apt update
sudo apt install ueberzugpp
# use following command to sign in LeetCode
nvim leetcode.nvim
# search `graphql` to acquire cookies

4.2 Debug

Debug Adapter Protocol: nvim-dap
Nvim-dap 是基于 Neovim 的 Debug Adapter Protocol 客户端实现的, 能够进行基本的断点、 步进等操作, 并监视应用的状态。
Debug UI: ​​nvim-dap-ui
我们需要提供一个可用的界面用来显示调试过程中的各种信息,包括变量值和调用栈。
Debug Variable Value: ​nvim-dap-virtual-text​​​
用以显示 debug 过程中一些变量的值, 类似 vscode 中的 watch。
Tests: neotest
类似 VSCode 中的测试插件功能, 方便进行测试内容的可视化和快捷操作。

配置 cpp 调试需要参考 DAP configuration for C++

从零开始配置vim(28)——代码的编译、运行与调试
从零开始配置vim(29)——DAP 配置
从零开始配置vim(30)——DAP的其他配置

4.3 Editor

Easy Jump: flash.nvim
EasyMotion 在 neovim 中的平替款, 还对原生 vim 功能的 fFtT, 这几个快捷键进行了增强。
Quick Punctuation Operate: vim-surround
不太会用但确实很有用的插件, 能对括号, 标点等进行快速更改。
CamelCase Motion: nvim-spider
CamelCase Motion 的 lua 实现版本, 按照说明配置快捷键可实现相同功能。

4.4 File

Smart Comment: Comment.nvim
能够方便的对代码进行注释, 这个插件的配置更灵活也更强大, 用 gccgbc 等指令就能方便的进行行注释和块注释。
Goto Preview: goto-preview
Goto 指令使用时类似 vscode 的选择界面, 以浮动窗口的形式预览符号的定义、实现等信息。
Indent Display: indent-blankline.nvim
方便显示 Indent 距离, 而且能够对代码块进行分隔。
Markdown Preview: markdown-preview.nvim
实现类似 VSCode 的 Markdown Preview 的功能
AutoPair: nvim-autopairs
自动补全括号的插件, 具体作用之后用了补充。
QuickFix Enhance: nvim-bqf
quick fix 的增强插件, 配置的时候直接再装个 fzf。
Like TODO: todo-comments.nvim
高亮注释中的关键词, HACK, NOTE, TODO, WARN, WARNING, BUG, FIX, PREF
Doxygen: kkoomen/vim-doge
提供 doxygen 相关的支持, 当然 vim 本身也有多 doxygen 支持的选项需要在 options 中进行配置。
Text Wrapping: andrewferrier/wrapping.nvim
提升 Markdown 的使用体验, neovim 中 Markdown 文件一行如果太长不会自动折叠, 需要这个插件进行支持。

4.5 Git

LazyGit: lazygit.nvim
Git 相关组件, 实现 commit, push 等操作的可视化。
Git Signs: gitsigns.nvim
提供了和 Git 相关的功能, 例如查看 git diff, last commit, status bar 等, 类似 vscode 中的 GitLen。

对于 LazyGit 还需要相应得安装其二进制包, 一种通过下述方式将 lazygit 编译好的二进制文件拷贝到目录下, 另一种就通过增加 ppa 源的方式, 我在配置文件中写了自动安装的脚本。

curl -Lo lazygit.tar.gz "https://github.com/jesseduffield/lazygit/releases/latest/download/lazygit_0.40.2_Linux_x86_64.tar.gz"
sudo tar xf lazygit.tar.gz -C /usr/local/bin lazygit

4.6 Highlight

Code Highlighting: nvim-treesitter.nvim
nvim-treesitter 插件提供基于 tree-sitter 的多个基础功能, 它可以让你在 nvim 中高效的实现 代码高亮, 增量选择 等功能。
Code Context: nvim-treesitter-context
它可以将当前函数的函数头固定在 neovim 界面的前几行,让你知道当前在编辑的是什么类、函数或方法。
Parentheses Highlighting: nvim-ts-rainbow
对配对的括号进行彩色标注。

注意 treesitter 无法渲染 .h 文件, 需要强制转换 set ft=cpp 同样可以通过 filetype.nvim 解决

4.7 LSP

Language Server Protocol: nvim-lspconfig
Language Server Protocol (LSP) 是微软为开发工具提出的一个协议, 它将编程工具解耦成了Language Server 与 Language Client 两部分。 Client 专注于页面样式实现, Server 负责提供语言支持, 包括常见的自动补全, 跳转到定义, 查找引用, 悬停文档提示等功能。
Portable Package Manager: mason.nvim
mason.nvim 是下一代 nvim-lsp-installer, 能够方便地安装和管理 LSP servers, DAP servers, linters, 以及 formatters.
Packer: mason-lspconfig.nvim
mason-lspconfig.nvim 为 mason.nvim 以及 nvim-lspconfig 建立了桥梁, 方便两个插件的协同工作和配置。
Linter: nvim-lint
Linter 的配置插件, 配合 rshkarin/mason-nvim-lint 进行自动化包管理和安装。
Formatter: stevearc/conform.nvim
null-ls 的替代品, 非常好用的 formatter!
Completion: nvim-cmp
自动补全的引擎, 支持 LSP 以及自定义灵活配置, 我们需要安装如下插件 neovim/nvim-lspconfig, hrsh7th/cmp-nvim-lsp, hrsh7th/cmp-buffer, hrsh7th/cmp-path, hrsh7th/cmp-cmdline, hrsh7th/nvim-cmp, hrsh7th/cmp-vsnip, hrsh7th/vim-vsnip, saadparwaiz1/cmp_luasnip
Friendly Snippets: friendly-snippets
更够为不同语言提供 Snippets 支持。
Neovim Lua API LSP: folke/neodev.nvim
folke 大神的又一杰作, 方便对 neovim 的 Lua 配置文件的开发与修改, 能够提供函数签名提示, 自动补全等功能。
Code Content Render: SmiteshP/nvim-navic
把函数签名, 代码等信息显示在 Statusline 或者 WinBar 上, 需要 LSP 支持并且需要用户自定义格式, 我参考了 Waylon Walker - Nvim Navic 的配置, 但是保留 navic 的 auto-attach 功能, 这样就不需要每次增加一个 LSP Server 就配置一次了。
Function Signature Display: lsp_signature.nvim
非常好用的 LSP 提示插件, 之前给函数输入参数的时候忘了得用 lspsaga 去重新提示声明, 这个直接自动化了。

配置 clangd 可以参考 neovim Mason配置LSP相关 - 知乎 以及 lspconfig-clangd, 且需要注意对 build 中的 compile_commands.json 进行软连接。

ln -s /path/to/myproject/build/compile_commands.json /path/to/myproject/

如需使用 clang-format 还要进行相应的软件包安装, 相应的其他的 formatter 也是需要安装的。

# install clang-format
sudo apt-get install -y clang-format
# install lua-language-server
# check <https://github.com/LuaLS/lua-language-server/releases> to download release file
mkdir lua_ls
mv lua-language-server-3.7.4-linux-x64.tar.gz lua_ls
tar -xvf lua-language-server-3.7.4-linux-x64.tar.gz
sudo mv lus_ls /usr/local
# add lus_ls/bin into .bashrc
export PATH=/usr/local/lus_ls/bin:$PATH

建议安装 python 虚拟环境组件以供支持其他 LSP 安装。

sudo apt-get install python3.10-venv

How To Setup Linting And Formatting In Neovim To Replace null-ls 介绍了新的 format 的插件, 我参考 Blog 配置了 stevearc/conform.nvim

Packer 版本的 LSP 整体参考 jiaxinaoliao/neovimBeginCpp 后 Lazy 版本参考 Zwlin98/nvim
Neovim 内置 LSP 配置 (一):基础配置 - 知乎
从零开始配置vim(24)——自动补全

4.8 Manager

Status Line: lualine.nvim
neovim 的状态栏配置插件。
File Explorer: nvim-tree.nvim
提供了便捷的文件管理树的功能, 所有的文件操作可以通过键盘实现。
Tmux Navigator: vim-tmux-navigator.nvim
tmux (terminal multiplexer) 是一个终端复用器, 主要可以用于分屏和保持会话。 保持会话的意思是, 即使关闭终端窗口, 或者 SSH 由于各种原因连接中断, 在服务器端 tmux 中的会话和对应的进程仍然不会终止。 tmux 能够创建多个会话 (session), 每个会话能够创建多个窗口 (window), 每个窗口又可以分为多个窗格 (pane)。
Buffer Line: bufferline.nvim
这个插件提供了类似 vscode 的标签页的功能
File Manager: Yazi
Terminal file manager, 适用于终端的文件管理器。
Startup: startup-nvim/startup.nvim
neovim 启动界面的个性化定制。

当然还有一些依赖插件, nvim-lua/plenary.nvimnvim-lua/popup.nvimnvim-tree/nvim-web-deviconsMunifTanjim/nui.nvim 都是为了增强以上插件的使用体验, 具体可参考我的配置文件。

从零开始配置 vim(13)——标签页插件 - jesssic
从零开始配置vim(26)——LSP UI 美化 - jesssic

4.9 System

FileType: filetype.nvim
filetype.nvim 是为了替代 nvim 启动时引用的 filetype.vim 文件, 该文件的目的是创建一系列自动命令, 根据文件名设置 filetype 变量, 但该文件的载入耗费了大量的时间, filetype.nvim 能优化这一载入过程, 对启动过程进行加速。
Lua Loader: impatient.nvim
该插件在 neovim 0.9 后就不需要了, 只用开启 vim.loader.enable() 即可对 lua 模块以及文件的载入进行加速。
Notification: nvim-notify
优化了原来的 vim 通知的风格, 用弹窗的形式进行展示, 不会打乱原有窗口的排布且该通知是异步操作的, 速度更快。
Startup Time Measurement: vim-startuptime
用来监测 neovim 启动时间的, 不过 Lazy.nvim 表示它的更准确一些, 这个在我优化配置的时候会用到。
Clipboard: deferred-clipboard.nvim
打通操作系统与 nvim 之间的桥梁, 二者能共用剪贴板的缓存。

Clipboard Configuration

Copy into system clipboard from neovim - StackOverflow 则介绍了另外一种办法, 不过推荐用上述插件更为便捷, 但仍需保证提供一种 clipboard 组件, 例如在 wsl 上需要安装 wl-clipboard

WSL - WSLg (Fast) Make sure wl-clipboard is installed on your system and WSLg is enabled.

sudo apt-get install wl-clipboard
if vim.fn.has("wsl") == 1 then
    if vim.fn.executable("wl-copy") == 0 then
        print("wl-clipboard not found, clipboard integration won't work")
    else
        vim.g.clipboard = {
            name = "wl-clipboard (wsl)",
            copy = {
                ["+"] = 'wl-copy --foreground --type text/plain',
                ["*"] = 'wl-copy --foreground --primary --type text/plain',
            },
            paste = {
                ["+"] = (function()
                    return vim.fn.systemlist('wl-paste --no-newline|sed -e "s/\r$//"', {''}, 1) -- '1' keeps empty lines
                end),
                ["*"] = (function()
                    return vim.fn.systemlist('wl-paste --primary --no-newline|sed -e "s/\r$//"', {''}, 1)
                end),
            },
            cache_enabled = true
        }
    end
end

4.10 Theme

个人比较喜欢 OneDark 系列, 主要参考 onedark.nvim, 加入插件后自定义配置即可。

-- Lazy, theme/onedark.lua
return {
    {
        'navarasu/onedark.nvim',
        lazy = false, -- make sure we load this during startup if it is your main colorscheme
        priority = 1000, -- make sure to load this before all the other start plugins
        config = function()
          -- load the colorscheme here
          vim.cmd([[colorscheme onedark]])
        end,
    }
}

4.11 Tools

Cscope: cscope_maps.nvim
对于有 Linux 源码阅读需求的人而言 neovim 移除 cscope 支持实在无法接受, 这个插件对原生 cscope 进行封装和功能增强, 可自选 cscope 引擎, 我的在脚本中配置的是 gtags-cscopeludovicchabant/vim-gutentags 可用 cscope_maps.nvim 作为 ctags 引擎自动生成所需要的 tags 并进行存档。
Terminal: toggleterm.nvim
虽然用 nvim 默认的指令可以在编辑文档时打开 Terminal, 但是 toggleterm.nvim 提供了更为便捷以及功能更强大的 Terminal 管理方案。
Basic Component: popup.nvim
plenary.nvim 的必要组件, 能够提供与 vim popup_* 兼容的 API 接口。
Basic Component: plenary.nvim
telescope.nvim 的必要组件, 能够提供异步编程, 目录扫描等基础功能。
Which Key: which-key.nvim
提示当前的 keybinding, 对记不住快捷键的人简直是神器!
Trouble Shooter: trouble.nvim
trouble.nvim可以让你快速查看你的工作区、文件中的LSP警告列表。 但是 Lspsaga 有内置的检查器倒是不必要安装。
Symbols Outline: symbols-outline.nvim
类似 vscode 中的 Outline, 基于 LSP 实现的函数与符号树, 方便查看代码实现的整体结构。
Fuzzy Finder: telescope.nvim
telescope.nvim 能在 neovim 中提供文件名模糊搜索和文本内容搜索的功能, 以及更多复杂的功能。
fzf: telescope-fzf-native.nvim
fzf 的集成插件, 拓展 telescope 功能。

Telescope Usage

telescope 常用的指令如下:

  • find_files​​: 查找文件
  • ​​live_grep​​: 使用正则表达式来进行内容的搜索,它可以跨文件搜索
  • ​​buffers​​: 查看当前打开的缓冲区,并且可以预览缓冲区的内容
  • ​​grep_string​​: 以当前光标所在单词进行搜索
  • ​​oldfile​​: 打开历史文件列表
  • ​​marks​​: 打开书签表
  • ​​jumplist​​: 打开跳转列表

如果我们希望能够使用 ​​live_grep​​​ 和 ​​grep_string​​ 的功能需要提前在系统上安装 ripgrep, 另外用 checkhealth 指令提示可以安装 sharkdp/fd 获取更多拓展功能, 我已添加自动化脚本方便安装和配置。

sudo apt-get install ripgrep
sudo apt-get install fd-find

Vim/Neovim 全文检索插件 – telescope.nvim - 知乎
Neovim - Toggleterm | Open terminal programs in Neovim - Youtube
从零开始配置vim(19)——终端配置 - jesssic

5. 配置问题

5.1 Mason fails checkhealth

运行 :checkhealth mason 遇到如下问题:

mason: require("mason.health").check()

- ERROR Failed to run healthcheck for "mason" plugin. Exception:
  function health#check, line 25
  Vim(eval):E5108: Error executing lua ...r/.local/share/nvim/lazy/mason.nvim/lua/mason/health.lua:315: function health#check[25]..health#report_error[2]..<SNR>66_format_report_message, line 7: a:1: expected String or List
  stack traceback:
  [C]: in function 'error'
  ...share/nvim/lazy/mason.nvim/lua/mason-core/async/init.lua:131: in function 'run_blocking'
  ...r/.local/share/nvim/lazy/mason.nvim/lua/mason/health.lua:315: in function 'check'
  [string "luaeval()"]:1: in main chunk

Failed to run healthcheck for “mason” plugin #1323 也有人提示了这个问题, PhilRunninger 的回答表示是 rust 版本太老需要升级, 但根据下述方法进行组件安装后未解决问题。

# 安装
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source "$HOME/.cargo/env"
rustc --version
cargo --version
# 帮助
curl https://sh.rustup.rs -sSf | sh -s -- --help
# 升级
rustup update

另外尝试删除缓存也没有解决问题:

rm -rf ~/.local/share/nvim ~/.cache/nvim ~/.local/state/nvim

后在 mason-lspconfig.nvim 主页看到这么一句意识到自己的配置顺序有问题。

Warning

It’s important that you set up the plugins in the following order:

  1. mason.nvim
  2. mason-lspconfig.nvim
  3. Setup servers via lspconfig

但最终问题是检查配置的时候发现 bufferline 这个插件多配置了一次发生了冲突, 处理之后 mason 该问题似乎解决了但重启 nvim 后又出现了。

5.2 UNKNOW PLUGIN

打开 nvim 出现 (UNKNOWN PLUGIN): Error excuting lua: attempt to call a nil value 的报错。 估摸着是某些插件有先后运行顺序, 但这个问题很难找, 不过后来在使用的过程中又折腾了一段时间, 发现是 telescope 中的插件配置问题, 导致 neovim 无法识别到相关的插件。