Neovim配置——从入门到放弃

发布时间 2023-12-18 13:56:07作者: lavateinn

前言

本来这个教程想分成十几篇来写的,但实在是懒,就放在这一篇里吧,有什么更新也会直接添加到文章后面。

本篇博文声明:

  1. 本篇博客不以完整的教程为目的,仅作为一个提纲性的参考
  2. 默认读者对vim/neovim有一定的了解,或者已经用了一段时间了,但是想系统性的调整自己的配置文件
  3. 任何第三方的博客都是二手资料,一般都是不如官方文档的,除非实在写的太烂,比如luasnip:),如果你看这篇博客看不懂,直接去翻插件的文档,如果英文看不懂,就算翻译一下总能看懂的,总比到处问强
  4. 不要盲目添加插件,没有完美的配置,只有适合自己的配置,在使用的过程中添加/删除插件,修改配置
  5. 天天改配置不如多写几行代码:(

关于用现成的配置比如LazyVim, LunarVim,还是完全自己配,这个完全看个人

  • 不想折腾就用现成的,开箱即用,然后加上一些自定义配置,缺点是出了问题不知道在哪
  • 自己配,知根知底,相对麻烦一些,但实际上也没那么麻烦

我的配置在github,个人使用,仅供参考。
放几张效果图:

启动页 文件搜索
image image
定义/引用查找 目录树/大纲
image image

我的neovim配置结构

我的配置没有完全放弃对vim的支持,这部分用viml来设置,主要是一些基础的配置,比如高亮行,设置行号等等,还有一些基础的按键设置,目的是保留对部分服务器的简单支持,直接copy就行,当然,如果是自己的开发机的话,也可以通过rsync同步的方式把配置上传到开发机上。

配置的基本目录结构如下:

~/.config/nvim/
├── debug.lua
├── init.lua            neovim配置入口
├── lazy-lock.json        插件版本信息
├── lua
│   ├── autoload/        自己写的自动加载的脚本(插件)
│   ├── helper/            一些工具函数
│   └── plugins            插件目录
│       ├── dap/        调试
│       ├── edit/        编辑类
│       ├── lang/        特定语言类,例如tex, c/cpp, python这样分类
│       ├── lsp/        lsp相关
│       ├── tools/        工具类插件
│       ├── ui/            ui美化类插件
│       └── unused/        暂时不用的插件,不加载
├── my-snippets/        我的代码片段
├── README.md
├── stylua.toml            lua格式化
├── tasks.ini            代码运行全局配置
├── test/                各种乱七八糟的文件,测试效果用的
└── vimrc                基础配置

配置文件入口为 ~/.config/nvim/init.lua,里面先加载vimrc,然后才是用lua写的插件配置。
插件管理器用的是folke大神写的lazy.nvim,目前主流的Neovim预配置项目都采用了这个管理器,推荐,具体用法在后面介绍。

vim.cmd.source(vim.fn.stdpath("config") .. "/vimrc")

require("helper.path")

require("helper.lazy").setup({
    spec = {
        -- 经过这种import 方式导入插件的lua 文件必须返回一个table
        { import = "plugins.ui" },
        { import = "plugins.edit" },
        { import = "plugins.lsp" },
        { import = "plugins.dap" },
        { import = "plugins.tools" },
        { import = "plugins.lang" },
        { import = "autoload" },
    },
    dev = {
        path = "~/Projects/neovim/",
    },
})

同步配置

服务器连接github比较困难的情况下,可以用rsync把本地配置同步到远程,享受几乎一样的体验

sync_nvim() {
    local server=$1
    rsync ~/.vimrc $server:~/.vimrc
    rsync -av --progress --delete --exclude test/ ~/.config/nvim/ $server:~/.config/nvim/
    rsync -av --progress --exclude .git/ ~/.local/share/nvim/lazy/ $server:~/.local/share/nvim/lazy/
}

用法

sync_nvim ubuntu@192.168.1.2
# 或者
sync_nvim server_alias

基础配置

基础配置在~/.config/nvim/vimrc,neovim会先加载这个文件,vim如果使用的话通过软链接的方式ln -s ~/.config/nvim/vimrc ~/.vimrc

这个文件大概分为这几个部分

  • options 常用设置选项
  • keymaps 无插件按键映射
  • autocmd 设置了几个自动命令
  • gui config 主要是字体设置(不常用)
  • vim only config 主要是vim内置的目录树netrw和apt安装的vim-airline
    image

由于这些配置具有一定的个人喜好,所以仅列出部分,详情可以去翻我的仓库

options

" 编码
set encoding=utf-8
set fileencodings=utf-8,gb2312,gbk,gb18030,latin1
set fileformat=unix
set fileformats=unix,dos

" 缩进与格式
filetype indent on
set autoindent
set smarttab
set cindent
set shiftwidth=4
set tabstop=4
set expandtab
set softtabstop=4
set backspace=eol,start,indent

" 搜索
set hlsearch
set incsearch
set ignorecase
set smartcase

keymaps

这里先祭出一张忘了从哪抄来的表格

Mode           | Norm | Ins | Cmd | Vis | Sel | Opr | Term | Lang | ~
Command        +------+-----+-----+-----+-----+-----+------+------+ ~
[nore]map      | yes  |  -  |  -  | yes | yes | yes |  -   |  -   |
n[nore]map     | yes  |  -  |  -  |  -  |  -  |  -  |  -   |  -   |
[nore]map!     |  -   | yes | yes |  -  |  -  |  -  |  -   |  -   |
i[nore]map     |  -   | yes |  -  |  -  |  -  |  -  |  -   |  -   |
c[nore]map     |  -   |  -  | yes |  -  |  -  |  -  |  -   |  -   |
v[nore]map     |  -   |  -  |  -  | yes | yes |  -  |  -   |  -   |
x[nore]map     |  -   |  -  |  -  | yes |  -  |  -  |  -   |  -   |
s[nore]map     |  -   |  -  |  -  |  -  | yes |  -  |  -   |  -   |
o[nore]map     |  -   |  -  |  -  |  -  |  -  | yes |  -   |  -   |
t[nore]map     |  -   |  -  |  -  |  -  |  -  |  -  | yes  |  -   |
l[nore]map     |  -   | yes | yes |  -  |  -  |  -  |  -   | yes  |
Modes
normal_mode = "n",
insert_mode = "i",
visual_mode = "v",
visual_block_mode = "x",
term_mode = "t",
command_mode = "c",

下面列出部分映射

" 优化jk设置
nnoremap j gj
nnoremap k gk
vnoremap j gj
vnoremap k gk

" alt+hjkl移动行
" mini.move
nnoremap <M-j> :m +1<CR>==
vnoremap <M-j> :m '>+1<CR>gv=gv
nnoremap <M-k> :m -2<CR>==
vnoremap <M-k> :m '<-2<CR>gv=gv
nnoremap <M-h> <<
vnoremap <M-h> <gv
nnoremap <M-l> >>
vnoremap <M-l> >gv

" H, L jump to line home / end
nnoremap H ^
nnoremap L $
vnoremap H ^
vnoremap L $
onoremap H ^
onoremap L $

" 切换buffer
nnoremap <C-n> <cmd>bnext<CR>
nnoremap <C-p> <cmd>bprevious<CR>

" 简单的自动括号实现,给vim用的
if !has('nvim')
    inoremap ( ()<Left>
    inoremap <expr> ) getline(line('.'))[col('.')-1]==')' ? '<Right>' : ')'

    inoremap [ []<Left>
    inoremap <expr> ] getline(line('.'))[col('.')-1]==']' ? '<Right>' : ']'

    inoremap { {}<Left>
    inoremap <expr> } getline(line('.'))[col('.')-1]=='}' ? '<Right>' : '}'

    inoremap < <><Left>
    inoremap <expr> > getline(line('.'))[col('.')-1]=='>' ? '<Right>' : '>'

    " inoremap ' ''<Left>
    " inoremap <expr> ' getline(line('.'))[col('.')-1]=="'" ? '<Right>' : "'"
    " inoremap " ""<Left>
    " inoremap <expr> " getline(line('.'))[col('.')-1]=='"' ? '<Right>' : '"'
    " inoremap ` ``<Left>
    " inoremap <expr> ` getline(line('.'))[col('.')-1]=='`' ? '<Right>' : '`'
endif

autocmd

augroup _general_settings
    autocmd!
    "这些文件类型按q退出
    autocmd FileType qf,help,man,checkhealth,startuptime nnoremap <silent><buffer> q <cmd>close<CR>
    " json等文件tab设置为2,并高亮所在列
    autocmd FileType json,json5,yaml setlocal shiftwidth=2 tabstop=2 softtabstop=2 cursorcolumn
    " neovim复制文本后高亮
    if has('nvim')
        autocmd TextYankPost * silent!lua require('vim.highlight').on_yank({ timeout = 500 })
    endif
    autocmd BufWinEnter * set formatoptions-=cro
    autocmd CursorHold * set nohlsearch
augroup end

" 剪贴板设置
" wsl用户,在vim中复制后同步到系统剪贴板
" 从系统剪贴板复制到vim中用终端的Ctrl-Shift-V
if has('wsl')
    let s:clip = '/mnt/c/Windows/System32/clip.exe'
    if executable(s:clip)
        augroup WSLYank
            autocmd!
            autocmd TextYankPost * if v:event.operator ==# 'y' | call system(s:clip, @0) | endif
        augroup end
    endif
else
    set clipboard=unnamedplus
endif

gui font

这里主要是针对gvim字体设置

if has('gui_running')
    " 去掉gvim的标题栏
    set guioptions-=m
    set guioptions-=T
    " 设置字体,注意不同系统的分隔符还不一样
    if has('win32') || has('mac') || has('nvim')
        set guifont=JetBrainsMono\ Nerd\ Font:10,Consolas:10
    else
        set guifont=JetBrainsMono\ Nerd\ Font\ 10,Consolas\ 10,DejaVu\ Sans\ Mono\ 10
    endif
endif

插件管理器 Lazy.nvim

Lazy.nvim是一个非常方便,模块化管理的插件管理器,现在主流的neovim配置都是用的这个。

自己配置neovim,第一个设置的肯定是插件管理器。还是强调一下无论什么插件,基本用法在官方文档里都是有的。

Lazy.nvim 文档

lazy.nvim有一段自动安装的脚本,这个你放在配置的开头,然后在启动lazy.nvim,我自己呢是做了一个简单的包装

    local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
    if not vim.loop.fs_stat(lazypath) then
        vim.fn.system(
            "git clone --filter=blob:none --branch=stable https://github.com/folke/lazy.nvim.git " .. lazypath
        )
    end
    vim.opt.rtp:prepend(lazypath)

设置lazy.nvim

require("helper.lazy").setup({
    spec = {
        -- 经过这种import 方式导入插件的lua 文件必须返回一个table
        { import = "plugins.ui" },  -- 对应~/.config/nvim/lua/plugins/ui 目录
        { import = "plugins.edit" },-- 对应~/.config/nvim/lua/plugins/edit目录
        { import = "plugins.lsp" },
        { import = "plugins.dap" },
        { import = "plugins.tools" },
        { import = "plugins.lang" },
        { import = "autoload" },   -- 对应~/.config/nvim/lua/autoload 目录
    },
})

然后把插件文件放进这些目录里就行,lazy.nvim会自动加载,不过每个插件文件需要满足一定的格式,每个文件必须返回一个table,例如

return {
    "folke/lazy.nvim", version = "*"
}

一个文件也可以包含多个插件

return {
    { "folke/lazy.nvim", version = "*" },
    { "williamboman/mason.nvim", version = "*", config = true },
    ...
}

常用的字段:

  • dependencies 依赖插件,会先加载
  • version 选择的插件版本(tag)常用version="*",即只使用打tag的release版本,相对稳定些
  • commit 插件的某个版本commit id,用于某些更新频繁,不太稳定的插件
  • event 触发event之后加载
  • keys 快捷键映射,同时也作为插件加载的依据
  • cmd 需要执行命令时加载
  • opts 插件的opts,会自动传给require('...').setup(opts)
  • config 与opts类似
    如果同时使用config字段和opts字段,opts字段会不生效,需要改成:
    opts = { ... },
    config = function(_, opts)
        require('plugin').setup(opts) -- 上面的opts也可以直接放到这里
        -- other setttings
    end,

设置event, keys, cmd之后默认是懒加载模式,如果需要在启动的时候加载,可以指定lazy=false

模糊搜索 fzf-lua/Telescope/Leaderf/vim-clap...

插件管理器之后,我认为最重要的插件应该是模糊搜索类插件,这类插件在我心中的地位,甚至超过了输入补全和lsp
这类插件可以非常方便的进行文件搜索和跳转,全项目范围的字符模糊搜索,同时一般也集成了内置比如查看按键映射,高亮,最近打开的文件等等功能,还有集成了lsp/dap等扩展功能,非常强大,非常方便

文件搜索 mru
image image
字符串搜索 keymap查询
image image

我把这类插件放在第二个来介绍,还不仅仅是因为上面这些强大的功能,主要是因为可以非常方便的搜索文档。
image

不知道某个插件怎么用?搜一下文档
不知道某个内置函数怎么用?搜一下文档
不知道neovim有什么内置函数可以用?搜一下文档
有这个功能之后,可以节省你很多的时间。

vim/neovim生态下的模糊搜索插件主要有以下几个:

  • telescope.nvim 纯neovim,使用人数最多,插件比较多
  • fzf-lua,和telescope差不多,但我感觉好用一点
  • LeaderF,同时支持vim/neovim,优势在于支持gtags,缺点是不支持lsp,gtags可以作为lsp以外的补充。(依赖python,模糊搜索算法是作者自己设计的,不输fzf)
  • vim-clap,和leaderf类似,同样是中国人开发,支持vim/neovim,这个插件我了解不多

这些插件在功能性上应该都差不多,选一个自己用的顺手的就行。我现在用的是fzf-lua

return {
    "ibhagwan/fzf-lua",
    dependencies = {
        "nvim-tree/nvim-web-devicons",
    },
    event = { "VeryLazy" },
    enabled = vim.pathlib.executable("fzf"),
    opts = {
        "default",
        winopts = {
            preview = {
                border = "noborder",
                vertical = "up:50%",
                horizontal = "right:50%",
                delay = 50,
            },
        },
        files = {
            path_shorten = 3,
        },
        diagnostics = {
            split = "belowright new",
        },
        previewers = {
            bat = {
                cmd = vim.pathlib.executable("batcat") and "batcat" or "bat",
            },
        },
    },
    keys = {
        { "<leader>f/", "<cmd>FzfLua <CR>", desc = "FzfLua self" },
        { "<leader>ff", "<cmd>FzfLua files<CR>", desc = "files" },
        { "<leader>fb", "<cmd>FzfLua buffers<CR>", desc = "buffers" },
        { "<leader>fl", "<cmd>FzfLua live_grep<CR>", desc = "live grep" },
        { "<leader>fh", "<cmd>FzfLua help_tags<CR>", desc = "help" },
        { "<leader>fH", "<cmd>FzfLua highlights<CR>", desc = "highlights" },
        { "<leader>fm", "<cmd>FzfLua oldfiles<CR>", desc = "mru" }, -- mru: most recent used
        { "<leader>fc", "<cmd>FzfLua commands<CR>", desc = "commands" },
        { "<leader>fj", "<cmd>FzfLua jumps<CR>", desc = "jumplist" },
        { "<leader>fk", "<cmd>FzfLua keymaps<CR>", desc = "keymaps" },
        { "<leader>fq", "<cmd>FzfLua quickfix<CR>", desc = "quickfix" },
        { "<leader>fw", "<cmd>FzfLua grep_cword<CR>", desc = "cword" },
        { "<leader>fa", "<cmd>lua require('helper.asynctask').fzf_select()<CR>", desc = "asynctask" },

        { "<leader>d", "<cmd>FzfLua lsp_document_diagnostics<CR>", desc = "lsp_document_diagnostics" },
        { "<leader>fd", "<cmd>FzfLua lsp_definitions<CR>", desc = "lsp_definition" },
        { "<leader>fr", "<cmd>FzfLua lsp_references<CR>", desc = "lsp_references" },
        { "<leader>fi", "<cmd>FzfLua lsp_implementations<CR>", desc = "lsp_implementations" },
        { "<leader>fs", "<cmd>FzfLua lsp_document_symbols<CR>", desc = "lsp_document_symbols" },
        { "<leader>fS", "<cmd>FzfLua lsp_workspace_symbols<CR>", desc = "lsp_workspace_symbols" },

        { "<C-f>", "<cmd>FzfLua grep_curbuf<CR>", desc = "lines" },
    },
}

在进行各个插件的按键映射的时候最好遵循一套自己的逻辑,在模糊搜索功能下主要以<leader>f作为前缀(我的leader键是空格),然后有些用的非常频繁的可以作为个例,比如我这里的<C-f>,算是使用windows留下的习惯吧。

输入补全 cmp

cmp是neovim中的一个补全框架,说时候配置比较繁琐,如果追求省事儿,可以选用coc.nvim,老牌插件了,也是国人开发的,开箱即用

cmp比较轻量级,但是文档冗长,经常出现意义不明的选项=_=

cmp插件本身只是一个框架,需要source来配合,例如:

return {
    "hrsh7th/nvim-cmp",
    dependencies = {
        -- cmp-nvim-lsp in lsp/init.lua
        -- cmp-luasnip in edit/luasnip.lua
        "hrsh7th/cmp-cmdline",
        "hrsh7th/cmp-buffer",
        "hrsh7th/cmp-path",
    },
    config = function()
        --
    end,
}

配置及说明

--我在cmp配置文件开头有一个CMP_SOURCES 的表
CMP_SOURCES = {
    luasnip = { name = "luasnip", menu = "[Snip]" },
    nvim_lsp = {
        name = "nvim_lsp",
        menu = "[LSP]",
        entry_filter = function(entry)
            return require("cmp").lsp.CompletionItemKind.Snippet ~= entry:get_kind()
        end,
    },
    path = { name = "path", menu = "[Path]" },
    buffer = { name = "buffer", menu = "[Buf]" },
    cmdline = { name = "cmdline", menu = "[Cmd]" },
}
    -- cmp的配置
    config = function()
        local cmp = require("cmp")
        local compare = require("cmp.config.compare")

        -- 这里设置的是插入模式下的补全source
        cmp.setup({
        -- 补全菜单和文档框,是否要有边框,以及高亮组等
            window = {
                completion = cmp.config.window.bordered({
                    border = "none",
                    winhighlight = "Normal:Normal,FloatBorder:Normal,CursorLine:MyCmpSel", -- 重点是CursorLine
                }),
                documentation = cmp.config.window.bordered({
                    border = "none",
                }),
            },
            -- 补全菜单的格式,见下面的效果图
            formatting = {
                fields = { "abbr", "kind", "menu" },
                expandable_indicator = false,
                format = function(entry, vim_item)
                    vim_item.menu = CMP_SOURCES[entry.source.name].menu
                    return vim_item
                end,
            },

            -- global setting and can be overwritten in sources
            experimental = { ghost_text = false },
            sources = {
                CMP_SOURCES.nvim_lsp,
                CMP_SOURCES.luasnip,
                CMP_SOURCES.buffer,
                CMP_SOURCES.path,
            },

            -- 补全项的排序算法权重,我也比较迷惑
            sorting = {
                comparators = {
                    compare.score,
                    compare.kind,
                    compare.exact,
                    compare.length,
                    compare.offset,
                    compare.sort_text,
                },
            },

            -- snippet settting in luasnip
            mapping = cmp.mapping.preset.insert({
                -- expand snippet setting in luasnip
                ["<C-u>"] = cmp.mapping.scroll_docs(-4),
                ["<C-d>"] = cmp.mapping.scroll_docs(4),

                -- ["<C-n>"] = require("cmp_rime").mapping.select_next_item,
                -- ["<C-p>"] = require("cmp_rime").mapping.select_prev_item,
                -- toggle cmp 菜单
                ["<C-Space>"] = cmp.mapping(function(fallback)
                    if cmp.visible() then
                        cmp.abort()
                    else
                        cmp.complete()
                    end
                end),
                -- 回车选中
                ["<CR>"] = cmp.mapping.confirm({ select = true, behavior = cmp.ConfirmBehavior.Replace }),
            }),
        })

        -- 搜索模式
        for _, cmd_type in ipairs({ "/", "?" }) do
            cmp.setup.cmdline(cmd_type, {
                mapping = cmp.mapping.preset.cmdline(),
                sources = {
                    CMP_SOURCES.buffer,
                },
            })
        end
        -- 命令行模式
        cmp.setup.cmdline(":", {
            mapping = cmp.mapping.preset.cmdline(),
            sources = {
                -- 有path 的时候屏蔽cmd
                vim.tbl_extend("force", CMP_SOURCES.path, { group_index = 1 }),
                vim.tbl_extend("force", CMP_SOURCES.cmdline, { group_index = 2 }),
            },
        })
    end,

效果:

image image
image image

LSP

在这里不解释LSP是什么,只介绍怎么配置。

如果使用的是coc,基本开箱即用,易用性也挺好的,如果是用的neovim官方的lsp,那还需要少量的配置。

用到的插件有

  • neovim/nvim-lspconfig:neovim官方lsp插件
  • hrsh7th/cmp-nvim-lsp:用于cmp补全的source
  • williamboman/mason.nvimwilliamboman/mason-lspconfig.nvim:管理下载的插件
  • folke/neodev.nvim:这个可能
  • nvimdev/lspsaga.nvim:基于lsp协议实现查找定义,引用等的插件
  • 其他lsp应用类的插件

管理lsp的部分基本照抄就行了

-- ~/.config/nvim/lua/plugins/lsp/init.lua

local on_attach = function(client, bufnr)
    vim.api.nvim_buf_set_option(bufnr, "omnifunc", "v:lua.vim.lsp.omnifunc")
    -- 禁用lsp 语义高亮
    -- client.server_capabilities.semanticTokensProvider = nil
end

local capabilities = vim.lsp.protocol.make_client_capabilities()
capabilities.textDocument.completion.completionItem = {
    documentationFormat = { "markdown", "plaintext" },
    -- snippet禁用无效,要在cmp里设置
    snippetSupport = false,
}

return {
    "neovim/nvim-lspconfig",
    dependencies = {
        { "folke/neodev.nvim", version = "*", config = true, lazy = true },
        "hrsh7th/cmp-nvim-lsp",
        { "williamboman/mason-lspconfig.nvim", version = "*", config = true },
    },
    event = { "BufReadPre", "BufNewFile" },
    config = function()
        require("mason-lspconfig").setup_handlers({
            function(server_name)
                local configs = {
                    on_attach = on_attach,
                    capabilities = capabilities,
                    root_dir = require("lspconfig").util.root_pattern(vim.g.ROOT_MARKERS),
                }

                if vim.pathlib.file_exist(("~/.config/nvim/lua/plugins/lsp/settings/%s.lua"):format(server_name)) then
                    local spec_configs = require(("plugins.lsp.settings.%s"):format(server_name))
                    configs = vim.tbl_deep_extend("force", configs, spec_configs)
                end

                require("lspconfig")[server_name].setup(configs)
            end,
        })
    end,
}

mason.nvim是一个用于下载neovim下第三方工具的一个插件,可以用于下载安装lsp、dap、语法检查工具linter、格式化工具等等,相比于手动apt下载,管理更加方便。与其配套的有

  • mason-lspconfig.nvim
  • mason-nvim-dap.nvim
  • mason-null-ls.nvim
    我都用到了,除了方便安装,还可以通过配置做到即装即用,不用再手动的vim.lsp.start

上面这段配置做到了全局和局部的结合,用mason-lspconfig.nvim启动会带上默认的配置,如果需要修改,将配置写到~/.config/nvim/lua/plugins/lsp/settings/这个目录下,从这里读取的配置会覆盖全局设置和lsp默认设置,比如clangd:

-- ~/.config/nvim/lua/plugins/lsp/settings/clangd.lua
return {
    capabilities = {
        offsetEncoding = { "utf-16" }, -- 解决全局的utf8编码问题
    },
    cmd = {
        "clangd",
        -- 同时开启的任务数量
        "-j 8",
        -- 开启clang-tidy
        "--clang-tidy",

        -- xxxxxxxxx其他设置
    },
    -- 有些lsp可以用过这个字段来进行设置
    settings = {

    }
}

大部分lsp的默认设置已经可以用了,只需要少量的需要进行调整

nvimdev这个插件是用于写lua配置和插件用的,主要功能是设置了lua_ls这个lsp和runtimepath,使得写lua配置的时候可以对neovim配置的lua的api和lua插件进行补全和提示,需要在lua_ls启动之前加载,所以这个插件作为lspconfig的依赖了

lspsaga.nvim是lsp应用类的插件,基于lsp协议实现的定义/引用查找,查看文档等功能
模糊查找的插件比如telescopefzf-lua也都内置了这些功能

查看error/warning信息的插件trouble.nvim,用的人也比较多。

代码运行、调试、测试

代码运行 asynctask.vim

代码运行类的插件只推荐asynctask.vim这个插件,非常的优雅。

调试 dap

这个比较坑

测试 neotest

编辑类插件

注释 Comment.nvim

注释类插件我用的是Comment.nvim,我习惯用<leader>c/<leader>C前缀。

return {
    "numToStr/Comment.nvim",
    event = { "BufRead" },
    version = "*",
    opts = {
        padding = true,
        sticky = true,
        ignore = "^$",

        toggler = {
            line = "<leader>cc",
            block = "<leader>CC",
        },
        opleader = {
            line = "<leader>c",
            block = "<leader>C",
        },
        extra = {
            above = "<leader>cO",
            below = "<leader>co",
            eol = "<leader>cA",
        },
        mappings = {
            basic = true,
            extra = true,
        },
    },
}

nvim-autopair

nvim-surround

格式化 null-ls

代码片段 luasnip

其他

工具类插件

大纲解析 aerial

目录树 nvim-tree

悬浮终端 toggleterm

gitsigns

diffview.nvim

flash.nvim

mini.nvim

美化类插件

主题

dashboard

noice

lualine

dressing

indent-blankline

其他

luasnip

vimtex

弃用的插件