毕业到现在一直用的是 Vim 来开发 Go 项目。之前用的是 vim + vim-go,最近刚切换到 neovim。本篇文章,来介绍下基于 neovim,我是如何配置一个易用的 Vim IDE 的。
什么是 Neovim?
neovim 从名称来看:新星的vim。按照官方说明:nvim 是一个 vim 的 fork,主要关注了扩展性和易用性。大量的 vim 用户迁移到 nvim,而 vim 的魅力出了经典的快捷键还有丰富的插件系统,这些 nvim 都继承了下来,同时内置了 LSP,增加了 异步 IO 等新特性。
为什么要转 Neovim?
Neovim 是 Vim7 的一个 fork,我选择 Neovim 代替 Vim 的主要原因如下:
- 内置LSP Client,和 VSCode一样通过标准协议和LSP服务器交互;
- Neovim 属于较新的项目,在项目活跃度、Star 数、代码架构等方面,要优于 Vim,如下图所示。
- Treesitter,支持增量的高效语法树解析,轻松应对大文件
- Neovim 支持插件异步运行,在处理大型项目或复杂文件时带来更好的性能。另外 NeoVim 支持Lua配置,支持更灵活的插件配置;
- Neovim 具有更好的性能。
Neovim 和 Vim 的差异
Neovim 和 Vim 差异如下:
- 配置文件位置:
- Vim 的配置文件通常是
.vimrc
,位于用户的主目录下; - Neovim 的配置文件是
init.lua
,位于~/.config/nvim/
目录下。(Neovim 也支持init.vim
,这里只介绍更加原生、标准的配置方式init.lua
)
- Vim 的配置文件通常是
- 配置文件格式:
- Vim 的
.vimrc
可以使用 Vim 脚本语言(也称为 VimL)编写。 - Neovim 的
init.lua
支持Lua作为其配置语言,以支持更加灵活、强大的配置;
- Vim 的
- 插件管理:
- Vim通常使用Vim插件管理器,如Vundle、Pathogen或vim-plug;
- Neovim可以使用相同的插件管理器,但由于对Lua的支持,Neovim 也可以使用如lazy.nvim 这样的Lua插件管理;
相较于 Vim,Neovim 还新增了很多新的特性,以下是这些特性说明:
- 启动性能:Neovim设计了更快的启动时间和更低的内存占用;
- 异步API:Neovim提供了异步API,允许插件执行非阻塞操作,这在Vim中不是原生支持的
- 终端支持:Neovim对内置终端的支持更加完善,提供了更好的集成和用户体验。
- 树状结构的目录:Neovim推荐使用树状结构的目录来组织配置文件和插件,这与Vim的传统单文件配置方式不同;
- 远程插件:Neovim支持远程插件,允许你通过RPC调用远程服务
- 状态栏和UI:Neovim提供了更灵活的状态栏和UI定制选项,如通过Lua可以更简单实现;
- 兼容性选项:Neovim提供了一个compatible选项,当设置为false时,可以关闭与Vim的兼容性模式,以使用Neovim的特定功能
- 窗口支持:Neovim原生支持浮动窗口、弹出菜单。Vim需插件模拟;
Neovim 安装
Neovim 提供了不同的安装方式,例如:通过包管理器安装、通过源码安装。本文选择,更加通用的源码安装方式。
bash
$ git clone https://github.com/neovim/neovim /tmp/neovim
$ cd /tmp/neovim
$ make CMAKE_BUILD_TYPE=RelWithDebInfo # 提示:这里需要 cmake 工具正确安装
$ sudo make install
$ nvim --version
NVIM v0.11.0-dev-2083+g6b00c9acfd
Build type: RelWithDebInfo
LuaJIT 2.1.1741730670
Run "nvim -V1 -v" for more info
CMAKE_BUILD_TYPE
是 CMake 构建系统中用于指定编译模式的参数,以下是具体说明和典型应用场景:
- Debug 模式:优化等级
-O0
,用于开发调试(可断点、变量检查); - Release 模式:优化等级
-O3
,用于生产环境(最高性能); - RelWithDebInfo 模式:优化等级
-O2
,用于生产调试(平衡性能与可调试性); - MinSizeRel 模式:优化等级
-Os
,用于最小体积发布。
安装完之后,为了方便后面的使用,需要进行以下 bash 配置:
bash
$ tee -a $HOME/.bashrc <<'EOF'
alias vi='nvim' # 将 "vi" 命令别名指向 "nvim"(NeoVim)
alias vim='nvim' # 将 "vim" 命令别名也指向 "nvim"
# 设置默认命令行编辑器为 "nvim"
# 影响 git 等工具的行为:`git commit` 会使用此处设置的编辑器
export EDITOR=nvim
EOF
Neovim 配置
Neovim 安装简单,重点在 Neovim 配置。这里,先来看下 Neovim 是如何配置的。
neovim 中配置可以通过 init.vim 或者 init.lua 进行配置,当前大部分的配置都采用了 lua,本文也将会通过 lua 进行配置 nvim。如果你还不会使用 lua 也不许需要担心,lua 可以快速上手。你可以直接通过 :h lua-guide
进行查看 lua 教程。
Neovim 配置结构介绍
类似 oh-my-zsh 相对于zsh,Neovim 也有很多优秀的开箱即用配置项目帮你快速上手,例如以下四个(按Star数量排序):NvChad、LazyVim、LunarVim、AstroNvim。
但 Neovim 的配置其实非常简单,你完全可以配置自己独一无二的 Neovim。自定义 Neovim 配置可以带来以下好处:
- 根据个人的喜好配置 Neovim,使用起来更顺手;
- 可以根据需要去处臃肿、不需要的配置,使整个 Neovim 的配置更加轻量级;
- 有助于学习如何配置 Neovim,未来使用的过程中,可以根据需要随时更改配置。例如:修改快捷键、设置一些配置项等;
如果你想学习如何配置 Neovim,推荐一个简单的入门配置示例:kickstart.nvim。这个项目教你如何开始配置Neovim,还配了视频教程。
Neovim 支持结构化的配置方式,其默认配置位于 $HOME/.config/nvim/
目录中,遵守 XDG规范。配置结构如下:
bash
# Neovim 配置目录结构解析(基于 LazyVim 风格)
.
├── init.lua # 主入口文件,负责加载核心配置和插件管理器
├── lazy-lock.json # 插件版本锁定文件(由 Lazy.nvim 自动生成维护)
├── LICENSE # 许可证文件(若配置开源)
├── lua/ # Lua 配置模块目录(Neovim 标准配置结构)
│ ├── configs/ # 基础功能配置模块
│ │ ├── basic.lua # 基础设置(行号/缩进/颜色等)
│ │ ├── keymaps.lua # 快捷键映射配置
│ │ └── lazy.lua # 插件管理器 Lazy.nvim 的配置
│ └── plugins/ # 各插件独立配置文件
│ ├── alpha.lua # 启动页插件 (alpha-nvim)
│ ├── autopairs.lua # 自动括号补全 (nvim-autopairs)
│ ├── avante.lua # AI 编程
│ ├── catppuccin.lua # Catppuccin 主题插件
│ ├── cmp.lua # 代码补全引擎 (nvim-cmp)
│ ├── comment.lua # 注释插件 (Comment.nvim)
│ ├── conform.lua # 代码格式化插件 (conform.nvim)
│ ├── fzf.lua # 模糊搜索插件 (fzf-lua)
│ ├── gitsigns.lua # Git 状态标记 (gitsigns.nvim)
│ ├── go-vim.lua # Go 语言开发插件(如 go.nvim)
│ ├── gruvbox.lua # Gruvbox 主题插件
│ ├── guess-indent.lua # 自动检测缩进插件
│ ├── indent-blankline.lua # 缩进参考线插件
│ ├── lsp.lua # LSP 客户端核心配置
│ ├── lualine.lua # 状态栏插件 (lualine.nvim)
│ ├── markdown.lua # Markdown 增强支持
│ ├── neo-tree.lua # 文件树插件 (neo-tree.nvim)
│ ├── notify.lua # 通知系统插件 (nvim-notify)
│ ├── root.lua # 根目录检测插件(可能结合 LSP),可自动切换至根目录
│ ├── toggleterm.lua # 内嵌终端插件
│ ├── tokyonight.lua # Tokyo Night 主题插件
│ ├── treesitter.lua # 语法高亮 (nvim-treesitter)
│ └── which-key.lua # 快捷键提示插件
└── README.md # 项目说明文档(配置说明/快捷键备忘等)
# 备注:
# 1. 此结构采用模块化设计,符合现代 NeoVim 配置最佳实践
# 2. 插件配置分离到独立文件便于维护(如更新/禁用插件)
# 3. 实际插件名可能与文件名略有差异(如 lsp.lua 可能对应 nvim-lspconfig)
其中init.lua
是 Neovim 的入口文件,加载所有的配置文件:
lua
require("configs.basic") -- 加载全局配置
require("configs.lazy") -- 加载插件管理器
require("configs.keymaps") -- 加载全局快捷键
-- -- 必须设置在 init.lua 的最外层(非函数内部)--
vim.opt.termguicolors = true -- 启用真彩色支持--
vim.o.background = "dark" -- or "light" for light mode
vim.cmd.colorscheme("tokyonight") -- 应用主题
配置之后的 Vim IDE 长这样:
Neovim 配置:基础配置
lua/configs/basic.lua
设置了一些基础的配置。因为 Neovim 理地修改了很多默认配置,相较于 Vim,我们只需要配置非常少量的配置项。<font style="color:rgb(25, 27, 31);">basic.lua</font>
配置内容如下:
lua
------------------------------------------------------------------------------
-- 1. Leader 键
------------------------------------------------------------------------------
vim.g.mapleader = " " -- 设置全局 leader 键为空格
vim.g.maplocalleader = " " -- 设置本地 leader 键为空格
------------------------------------------------------------------------------
-- 2. 文件与编码
------------------------------------------------------------------------------
vim.g.encoding = "UTF-8" -- Vim 内部使用 UTF-8 编码
vim.o.fileencoding = "utf-8" -- 文件默认保存编码为 UTF-8
------------------------------------------------------------------------------
-- 3. 光标与滚动
------------------------------------------------------------------------------
vim.o.scrolloff = 8 -- 光标上下保留 8 行可见区域
vim.o.sidescrolloff = 8 -- 光标左右滚动时保留 8 列可见区域
------------------------------------------------------------------------------
-- 4. 行号与指示列
------------------------------------------------------------------------------
vim.wo.number = false -- 不显示绝对行号
vim.wo.relativenumber = false -- 不显示相对行号
vim.wo.cursorline = false -- 不高亮当前行
vim.wo.signcolumn = "no" -- 不显示左侧指示符符号列
------------------------------------------------------------------------------
-- 5. 折叠 (Folding)
------------------------------------------------------------------------------
vim.opt.foldenable = true -- 默认开启文件折叠
vim.opt.foldnestmax = 1 -- 最大折叠层数为 1
vim.wo.foldmethod = 'expr' -- 使用表达式进行折叠
vim.wo.foldexpr = 'nvim_treesitter#foldexpr()' -- 使用 treesitter 进行折叠
vim.wo.foldlevel = 1 -- 打开文件时折叠层级为 1
------------------------------------------------------------------------------
-- 6. 缩进与 Tab
------------------------------------------------------------------------------
vim.o.tabstop = 4 -- Tab 显示为 4 个空格宽度
vim.bo.tabstop = 4
vim.o.softtabstop = 4 -- 插入模式下 Tab 的软宽度
vim.o.shiftround = true -- >> << 时对齐到 shiftwidth 的倍数
vim.o.shiftwidth = 4 -- 自动缩进时每级缩进为 4 个空格
vim.bo.shiftwidth = 4
vim.o.expandtab = true -- 将 Tab 转为空格
vim.bo.expandtab = true
vim.o.autoindent = true -- 自动继承上一行缩进
vim.bo.autoindent = true
vim.o.smartindent = true -- 根据语法自动缩进
------------------------------------------------------------------------------
-- 7. 文件自动保存与读取
------------------------------------------------------------------------------
vim.o.autowrite = true -- 切换 buffer 时自动保存
vim.o.autoread = true -- 外部修改文件后自动重新加载
vim.bo.autoread = true
------------------------------------------------------------------------------
-- 8. 搜索
------------------------------------------------------------------------------
vim.o.ignorecase = true -- 搜索时忽略大小写
vim.o.smartcase = true -- 若有大写字母,则开启智能大小写搜索
vim.o.hlsearch = true -- 高亮搜索结果
vim.o.incsearch = true -- 边输入边搜索
------------------------------------------------------------------------------
-- 9. 历史记录与命令行
------------------------------------------------------------------------------
vim.o.cmdheight = 1 -- 命令行高度为 1
vim.o.history = 1000 -- 历史记录数量
vim.o.backspace = "indent,eol,start"
vim.o.whichwrap = 'b,s,<,>,[,],~' -- 允许在行首尾使用 <Left>/<Right> 跨行移动
------------------------------------------------------------------------------
-- 10. 延迟与交互
------------------------------------------------------------------------------
vim.o.updatetime = 300 -- 触发自动保存及 CursorHold 事件的时间
vim.o.timeoutlen = 500 -- 等待映射连击的时间(毫秒)
------------------------------------------------------------------------------
-- 11. 窗口拆分与折行
------------------------------------------------------------------------------
vim.o.splitbelow = true -- 水平分割窗口时,新窗口显示在下方
vim.o.splitright = true -- 垂直分割窗口时,新窗口显示在右侧
vim.wo.wrap = true -- 自动折行
vim.o.whichwrap = "<,>,[,]" -- 光标在行首尾时允许向上一行或下一行移动
------------------------------------------------------------------------------
-- 12. 缓冲区与鼠标支持
------------------------------------------------------------------------------
vim.o.hidden = true -- 允许切换未经保存的 buffer
vim.o.mouse = "a" -- 启用鼠标支持
------------------------------------------------------------------------------
-- 13. 备份与 Undo
------------------------------------------------------------------------------
vim.o.backup = false -- 禁用备份文件
vim.o.writebackup = false -- 禁用写入时备份
vim.opt.undofile = true -- 启用持久化 Undo
vim.opt.swapfile = false -- 禁用交换文件
------------------------------------------------------------------------------
-- 14. 自动补全与提示
------------------------------------------------------------------------------
vim.g.completeopt = "menu,menuone,noselect,noinsert"
-- 设定自动补全选项
vim.o.shortmess = vim.o.shortmess .. "c"
-- 不将某些消息显示到补全菜单
vim.o.pumheight = 10 -- 自动补全弹出菜单最多显示 10 行
vim.o.showtabline = 2 -- 始终显示标签页
vim.o.showmode = false -- 不在状态栏显示当前模式(由插件代替)
------------------------------------------------------------------------------
-- 15. 终端颜色与字符显示
------------------------------------------------------------------------------
vim.o.termguicolors = true -- 启用 24 位色
vim.opt.termguicolors = true
vim.o.list = false -- 不显示不可见字符
vim.o.listchars = "space:·,tab:··"
-- 定义空格和 Tab 的可见字符
vim.o.wildmenu = true -- 命令行补全时显示菜单
------------------------------------------------------------------------------
-- 16. 系统剪切板
------------------------------------------------------------------------------
vim.opt.clipboard = "unnamedplus" -- 使用系统剪贴板
colin@dev nvim $
lua/configs/basic.lua 配置文件中,中文注释介绍的很详细,这里不再一一介绍各个配置项的作用。
在 basic.lua 中有以下 2 行:
bash
vim.g.mapleader = " " -- 设置全局 leader 键为空格
vim.g.maplocalleader = " " -- 设置本地 leader 键为空格
在 Neovim(以及较新的 Vim 版本)使用 Lua 配置时,常见的 vim.g
、vim.o
、vim.bo
、vim.wo
等 API 能让我们分别访问或修改全局变量、全局选项、Buffer 专属选项以及 Window 专属选项。
Neovim 配置:全局快捷键设置
lua/configs/keymaps.lua
设置了全局快捷键映射,不包括插件特定快捷键。
lua
-- 复用 opt 参数
local opt = {noremap = true, silent = true }
vim.keymap.set("n", "<leader>i", "gg=G", opt) -- 格式化文件中所有代码行(nvim-treesitter 代码格式化)
-- 窗口操作
-- 取消 s 默认功能
vim.keymap.set("n", "s", "", opt)
-- windows 分屏快捷键
vim.keymap.set("n", "sv", ":vsp<CR>", opt)
vim.keymap.set("n", "sh", ":sp<CR>", opt)
vim.keymap.set("n", "sc", "<C-w>c", opt) -- 关闭当前
vim.keymap.set("n", "so", "<C-w>o", opt) -- 关闭其他
....
Neovim 配置:插件管理器
启动速度是Neovim/Vim相较于IDE最大的优势之一。lazy 是Neovim最流行的插件管理器,可以只在需要的时候加载相关插件,大大提升加载速度。
lua/configs/lazy.lua
中是Lazy官方推荐的配置方式,这里不做过多讲解。lazy.lua
内容如下:
lua
-- Bootstrap lazy.nvim
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
if not (vim.uv or vim.loop).fs_stat(lazypath) then
local lazyrepo = "https://github.com/folke/lazy.nvim.git"
local out = vim.fn.system({ "git", "clone", "--filter=blob:none", "--branch=stable", lazyrepo, lazypath })
if vim.v.shell_error ~= 0 then
vim.api.nvim_echo({
{ "Failed to clone lazy.nvim:\n", "ErrorMsg" },
{ out, "WarningMsg" },
{ "\nPress any key to exit..." },
}, true, {})
vim.fn.getchar()
os.exit(1)
end
end
vim.opt.rtp:prepend(lazypath)
-- Make sure to setup `mapleader` and `maplocalleader` before
-- loading lazy.nvim so that mappings are correct.
-- This is also a good place to setup other settings (vim.opt)
vim.g.mapleader = " "
vim.g.maplocalleader = "\\"
-- Setup lazy.nvim
require("lazy").setup({
spec = {
-- import your plugins
-- { import = "plugins" },
{ import = "plugins/alpha" },
-- { import = "plugins/catppuccin" },
-- { import = "plugins/gruvbox" },
{ import = "plugins/conform" },
{ import = "plugins/gitsigns" },
{ import = "plugins/indent-blankline" },
{ import = "plugins/lualine" },
{ import = "plugins/toggleterm" },
{ import = "plugins/treesitter" },
{ import = "plugins/autopairs" },
{ import = "plugins/cmp" },
{ import = "plugins/markdown" },
-- { import = "plugins/neo-tree" },
{ import = "plugins/tokyonight" },
{ import = "plugins/which-key" },
{ import = "plugins/guess-indent" },
--{ import = "plugins/lspconfig" },
-- { import = "plugins/mason" },
{ import = "plugins/lsp" },
{ import = "plugins/fzf" },
{ import = "plugins/go-vim" },
{ import = "plugins/comment" },
{ import = "plugins/notify" },
{ import = "plugins/avante" },
{ import = "plugins/root" },
},
-- Configure any other settings here. See the documentation for more details.
-- colorscheme that will be used when installing plugins.
install = { colorscheme = { "tokyonight" } },
-- automatically check for plugin updates
checker = {
enabled = false, -- 完全禁用更新检查
notify = false -- 关闭所有通知
-- frequency = 604800 -- 检查间隔改为每周一次(单位:秒)
},
ui = {
icons = {
ft = "",
lazy = " ",
loaded = "",
not_loaded = "",
},
},
performance = {
rtp = {
disabled_plugins = {
"2html_plugin",
"tohtml",
"getscript",
"getscriptPlugin",
"gzip",
"logipat",
"netrw",
"netrwPlugin",
"netrwSettings",
"netrwFileHandlers",
"matchit",
"tar",
"tarPlugin",
"rrhelper",
"spellfile_plugin",
"vimball",
"vimballPlugin",
"zip",
"zipPlugin",
"tutor",
"rplugin",
"syntax",
"synmenu",
"optwin",
"compiler",
"bugreport",
"ftplugin",
},
},
},
})
在实际开发中,我喜欢根据需要加载 Neovim 插件。所以在lua/configs/lazy.lua 文件中,我添加了disabled_plugins
配置项,用来根据需要禁用不需要的插件。另外,在 spec
配置项中,指定插件来加载。
Neovim 常用插件
我根据需要荆条细选了以下 Neovim 插件,这些插件可以完全满足 Go 项目开发。所有的插件配置均位于 lua/plugins
目录下,并且根据需要加载。
UI
alpha
alpha插件可以让你在Neovim启动时展示你喜欢的图形和快捷方式。
neo-tree
强大的文件树,可以查看/修改文件树、展示git信息、查看当前Buffer或有Git改动的相关文件等。
lualine
漂亮的状态栏,可以展示当前模式、文件信息、行号、文件类型、文件编码等。
notify
优化Neovim的通知体验,可以在右上角展示通知的标题、等级、内容,还可以通过命令查看所有历史通知、清除通知。
colorschemes
目前 Neovim最火的主题应该是以下 3 个:
你可以根据需要选择喜欢的主题。我用的是 tokyonight-night 主题:
我同时安装了 tokyonight、gruvbox 2 个主题。日常开发主要用 tokyonight。偶尔也会切 gruvbox。
LSP
lspconfig
配置Neovim的LSP功能,除了官方的配置,我自定义了一些配置:
- 依赖了Mason插件来安装需要的LSP服务器以及额外的格式化工具
- 大部分LSP功能Neovim已经内置了快捷键,所以只配置了缺失的Hover和Definition的快捷键
- 自动在LocalList展示LSP Diagnastic
- 在保存Go文件时,利用gopls的organizeImports功能自动添加缺失的imports,删除多余的imports
代码展示
treesitter
通过语法树解析能力,提供语法高亮、textobjects、折叠等功能。
indent-blankline.nvim
展示缩进线,代码层次更加清晰,感觉Golang的Tab在Neovim中已经比较清晰,主要是为了lua、yaml等其他类型文件配置。
代码编辑
cmp
nvim-cmp不仅支持代码的自动补全,还支持文件路径、命令行的自动补全、展示函数签名等功能。
autopairs
自动添加配对的括号。
conform
格式化插件,支持LSP格式化和非LSP格式化,支持保存时自动格式化。
- 目前我为lua文件指定了更流行的stylua
- Golang则用默认的LSP格式化
codeium
免费AI助手,支持代码补全、代码生成、聊天等功能。AI真的能大幅提升生产力,其实我这篇文章很多是Codeium帮我生成的。
guess-indent
自动缩进插件,通常Neovim需要为不同的语言配置不同的缩进配置,比如golang用tab,lua用2个space。 guess-indent可以自动根据当前缩进猜测缩进配置,免去为每种语言配置缩进的麻烦。
查找
fzf-lua
fzf-lua 提供了很强大的查找功能,支持查找文件、字符串、命令、主题、引用、快捷键、帮助等。
还有一个 telescope 插件跟 fzf-lua 插件功能类似。但经过 Google 和试用,感觉 fzf-lua 从功能、性能等方面是一个更好的选择。
fzf-lua 查找界面如下:
Git
gitsigns
展示当前文件的改动信息:
查看Diff:
blame
用来查看文件的修改历史。
Go
go.nvim
go.nvim是一个专门为Golang语言开发的Neovim插件,它集成了nvim-lsp(Neovim的内置语言服务器协议客户端)、treesitter(用于语法高亮和代码分析)以及Lua(一种轻量级脚本语言),旨在提供一个现代化且高效的编程环境。
另外,GitHub 上也有其他一些很受欢迎的 Go 插件,例如:
- vim-go:最初为 Vim 开发的 Go 插件,功能插件。切换到 NeoVim 后,没有再使用;
- gopher:另一个 NeoVim 领域受欢迎的 Go 插件。
注意,安装完 go.nvim 插件之后,可以执行 :<font style="color:rgb(31, 35, 40);">GoInstallBinaries</font>
来自定安装需要的 Go 工具。
其他
toggleterm
可以直接在 Neovim 中打开终端,临时执行一些命令不需要切换窗口。
markdown-preview
Vim 用户一般都希望能用纯文本的方式编写文档,Markdown是最佳选择。markdown-preview可以自动在浏览器中打开markdown预览,实时预览Neovim中的改动。
which-key
好多快捷键记不住怎么办?Which Key!不仅可以查看当前有哪些快捷键可以用,在按下快捷键的前置按键后,还能提示剩余匹配的快捷键,解放记忆力!
nvim-rooter
在使用 fzf 的过程中,我希望 live_grep 是从项目根目录开始查找。所以需要安装 nvim-rooter,让 fzf-lua 自动切换到项目根目录,并基于根目录进行查询。
我的 Neovim 配置
可以关注我的公众号:令飞编程,输入:「neovim」,获取我的 Neovim 配置下载地址。