重新配置NeoVim IDE
我之前 NeoVim IDE 参考 从零开始配置 Neovim(Nvim) ,原作者更新了博客,配置更为精简。正好我遇到了在 FreeBSD平台配置NeoVim IDE ,所以再次参考这篇博客进行配置。
配置文件路径
nvim
配置目录 ~/.config/nvim
,默认读取 ~/.config/nvim/init.lua
,为方便维护,从 init.lua
划分出不同目标的配置:
nvim
配置目录 ~/.config/nvim
结构.
├── init.lua
└── lua
├── colorscheme.lua
├── keymaps.lua
├── lsp.lua
├── options.lua
└── plugins.lua
选项配置
~/.config/nvim/lua/options.lua
配置实现功能:默认采用系统剪贴板,同时支持鼠标操控 Nvim
Tab 和空格的换算
UI 界面
“智能”搜索
~/.config/nvim/lua/options.lua
-- Hint: 如果需要,使用 `:h <option>` 来查找配置含义
vim.opt.clipboard = 'unnamedplus' -- 使用系统剪贴板
vim.opt.completeopt = {'menu', 'menuone', 'noselect'}
vim.opt.mouse = 'r' -- 允许在Nvim中使用鼠标,原文使用 'a' ,不过这样只能在vim内部使用,退出vim就丢失
-- 我修改为 'r' 这样退出vim依然保留剪贴板内容;如果 'r' 无效,则可以尝试 'v' ,实际取决于 vimrc
-- 参考 https://unix.stackexchange.com/questions/139578/copy-paste-for-vim-is-not-working-when-mouse-set-mouse-a-is-on
-- Tab
vim.opt.tabstop = 4 -- 每个Tab代表的虚拟空格数量
vim.opt.softtabstop = 4 -- 当编辑时空间tab(spacesin tab)代表的空格数量
vim.opt.shiftwidth = 4 -- 在一个tab中插入4个空格
vim.opt.expandtab = true -- 将tabs转换为空格,这在python有用
-- UI config
vim.opt.number = true -- 显示绝对数值(也就是行号)
vim.opt.relativenumber = true -- 在左边显示没一行的行号
vim.opt.cursorline = true -- 高亮光标水平行下方显示横线
vim.opt.splitbelow = true -- 打开新的垂直分割底部
vim.opt.splitright = true -- 在水平分割右方打开
-- vim.opt.termguicolors = true -- 在TUI激活24位RGB颜色
vim.opt.showmode = false -- 根据经验,我们不需要 "-- INSERT --" 模式提示
-- Searching
vim.opt.incsearch = true -- 在输入字符时搜索
vim.opt.hlsearch = false -- 不要高亮匹配项
vim.opt.ignorecase = true -- 默认搜索时不区分大小写
vim.opt.smartcase = true -- 如果搜索时输入一个大写字母则表示搜索区分大小写
在
init.lua
中添加以下配置激活使用options.lua
:
~/.config/nvim/lua/init.lua
中激活 options.lua
require('options')
require('keymaps')
require('plugins')
require('colorscheme')
require('lsp')
键盘映射配置
以下配置
~/.config/nvim/lua/keymaps.lua
实现如下键盘映射:使用
<C-h/j/k/l>
在窗口间移动光标使用
Ctrl + 方向键
来调整窗口大小在select选择模式,可以使用
Tab
或者Shift-Tab
来更改连续缩排(indentation repeatedly)
~/.config/nvim/lua/keymaps.lua
-- 定义常用选项
local opts = {
noremap = true, -- 非递归
silent = true, -- 不显示消息
}
---------------------------
-- 常规模式(Normal mode) --
---------------------------
-- 提示: 查看 `:h vim.map.set()`
-- 最佳窗口导航
vim.keymap.set('n', '<C-h>', '<C-w>h', opts)
vim.keymap.set('n', '<C-j>', '<C-w>j', opts)
vim.keymap.set('n', '<C-k>', '<C-w>k', opts)
vim.keymap.set('n', '<C-l>', '<C-w>l', opts)
-- 通过箭头调整窗口大小
-- 变量: 2 行
vim.keymap.set('n', '<C-Up>', ':resize -2<CR>', opts)
vim.keymap.set('n', '<C-Down>', ':resize +2<CR>', opts)
vim.keymap.set('n', '<C-Left>', ':vertical resize -2<CR>', opts)
vim.keymap.set('n', '<C-Right>', ':vertical resize +2<CR>', opts)
---------------------------
-- 可视模式(Visual mode) --
---------------------------
-- 提示: 以之前区域和相同模式启动相同区域的可视模式
vim.keymap.set('v', '<', '<gv', opts)
vim.keymap.set('v', '>', '>gv', opts)
同样在
init.lua
中添加以下配置激活使用keymaps.lua
:
~/.config/nvim/lua/init.lua
中激活 keymaps.lua
require('options')
require('keymaps')
require('plugins')
require('colorscheme')
require('lsp')
安装插件管理器
nvim
通过第三方插件提供了强大的能力。有多种插件管理器,其中 lazy.nvim 非常受欢迎,提供了很多神奇功能:
修正以来顺序
锁文件
lazy-lock.json
跟踪安装的插件...
创建
~/.config/nvim/lua/plugins.lua
(这里的案例只完成lazy.nvim
自身安装,没有指定其他第三方插件)):
~/.config/nvim/lua/plugins.lua
管理插件local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
if not (vim.uv or vim.loop).fs_stat(lazypath) then
vim.fn.system({
"git",
"clone",
"--filter=blob:none",
"https://github.com/folke/lazy.nvim.git",
"--branch=stable", -- latest stable release
lazypath,
})
end
vim.opt.rtp:prepend(lazypath)
require("lazy").setup({})
同样在
init.lua
中添加以下配置激活使用plugins.lua
:
~/.config/nvim/lua/init.lua
中激活 plugins.lua
require('options')
require('keymaps')
require('plugins')
require('colorscheme')
require('lsp')
主题配置
备注
Monokai Pro 开发的 Monokai
color scheme 是开发IDE中最流行的语法高亮配色,在 THE HISTORY OF Monokai 一文中有详细的介绍:
2006年荷兰设计师兼开发者Wimer Hazenberg开发出最初的Monokai,主要是TextMate on macOS上暗黑背景的活泼色彩
随后被各个主要IDE所接纳,并且用于终端色彩
2017年发布了Monokai Pro,进一步采用了现代色彩系列,并且包含了用户接口设计和定制图标,提供了色彩过滤器,例如
Spectrum
,Ristretto
和Monokai Classic
2024年发布了Monokai Pro Light,采用了新的
Sun
filter,适配了明亮环境,也就是说经过多年发展,Monokai已经完成了主流的 dark 和 light 两种环境适配
在完成了上文 lazy.nvim 配置之后,就可以安装配色插件,这里参考原文使用了 monokai.nvim 插件,并且选择了我对比之后认为较为美观的 monokai
风格:
修订
~/.config/nvim/lua/plugins.lua
,增加安装monokai.nvim
的配置行:
~/.config/nvim/lua/plugins.lua
增加 monokai.nvim
插件管理配色local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
if not (vim.uv or vim.loop).fs_stat(lazypath) then
vim.fn.system({
"git",
"clone",
"--filter=blob:none",
"https://github.com/folke/lazy.nvim.git",
"--branch=stable", -- latest stable release
lazypath,
})
end
vim.opt.rtp:prepend(lazypath)
require("lazy").setup({
"tanvirtin/monokai.nvim",
})
创建一个
~/.config/nvim/lua/colorscheme.lua
来定制monokai.nvim
插件:
~/.config/nvim/lua/colorscheme.lua
定制 monokai.nvim
插件-- define your colorscheme here
local colorscheme = 'monokai'
-- local colorscheme = 'monokai_pro'
-- local colorscheme = 'monokai_soda'
-- local colorscheme = 'monokai_ristretto'
local is_ok, _ = pcall(vim.cmd, "colorscheme " .. colorscheme)
if not is_ok then
vim.notify('colorscheme ' .. colorscheme .. ' not found!')
return
end
最后在
~/.config/nvim/init.lua
激活配置
~/.config/nvim/lua/init.lua
中激活 colorscheme.lua
require('options')
require('keymaps')
require('plugins')
require('colorscheme')
require('lsp')
自动代码补全(Auto-completion)
备注
2024年之后 从零开始配置 Neovim(Nvim) 采用了 blink.cmp 替代了之前使用的自动补全插件 nvim-cmp 。配置更为简单且自动补全快(Rust代码)。
警告
blink.cmp 混合了部分Rust程序代码,所以安装是有平台要求的。如果不是常用平台Linux(x86和arm)/macOS/Windows,那么安装会比较麻烦,需要从源代码编译安装。
之前使用的 nvim-cmp 由于是纯Lua代码,就没有这个困难。
另外, blink.cmp
官方发布的release实际上对 nvim
版本要求很高,我在ARM平台的 Raspberry Pi 系统上安装就遇到 nvim
版本过低无法config的问题。
总之,有利有弊
备注
在FreeBSD平台,我还是继续使用 nvim-cmp (纯Lua跨平台)
在Raspberry Pi平台,我重新构建了 Debian镜像(tini进程管理器) (包含了编译 neovim 步骤),以获得最新的nvim版本来适配
blink.cmp
修订
~/.config/nvim/lua/plugins.lua
添加:
~/.config/nvim/lua/plugins.lua
添加 blink.cmp
插件配置... -- 省略其他行
require("lazy").setup({
... -- 省略其他行
{
"saghen/blink.cmp",
-- optional: provides snippets for the snippet source
dependencies = { "rafamadriz/friendly-snippets" },
-- use a release tag to download pre-built binaries
version = "*",
-- AND/OR build from source, requires nightly: https://rust-lang.github.io/rustup/concepts/channels.html#working-with-nightly-rust
-- build = 'cargo build --release',
-- If you use nix, you can build from source using the latest nightly rust with:
-- build = 'nix run .#build-plugin',
opts = {
-- 'default' (recommended) for mappings similar to built-in completions (C-y to accept)
-- 'super-tab' for mappings similar to VSCode (tab to accept)
-- 'enter' for enter to accept
-- 'none' for no mappings
--
-- All presets have the following mappings:
-- C-space: Open menu or open docs if already open
-- C-n/C-p or Up/Down: Select next/previous item
-- C-e: Hide menu
-- C-k: Toggle signature help (if signature.enabled = true)
--
-- See :h blink-cmp-config-keymap for defining your own keymap
keymap = {
-- Each keymap may be a list of commands and/or functions
preset = "enter",
-- Select completions
["<Up>"] = { "select_prev", "fallback" },
["<Down>"] = { "select_next", "fallback" },
["<Tab>"] = { "select_next", "fallback" },
["<S-Tab>"] = { "select_prev", "fallback" },
-- Scroll documentation
["<C-b>"] = { "scroll_documentation_up", "fallback" },
["<C-f>"] = { "scroll_documentation_down", "fallback" },
-- Show/hide signature
["<C-k>"] = { "show_signature", "hide_signature", "fallback" },
},
appearance = {
-- 'mono' (default) for 'Nerd Font Mono' or 'normal' for 'Nerd Font'
-- Adjusts spacing to ensure icons are aligned
nerd_font_variant = "mono",
},
sources = {
-- `lsp`, `buffer`, `snippets`, `path`, and `omni` are built-in
-- so you don't need to define them in `sources.providers`
default = { "lsp", "path", "snippets", "buffer" },
-- Sources are configured via the sources.providers table
},
-- (Default) Rust fuzzy matcher for typo resistance and significantly better performance
-- You may use a lua implementation instead by using `implementation = "lua"` or fallback to the lua implementation,
-- when the Rust fuzzy matcher is not available, by using `implementation = "prefer_rust"`
--
-- See the fuzzy documentation for more information
fuzzy = { implementation = "prefer_rust_with_warning" },
completion = {
-- The keyword should only match against the text before
keyword = { range = "prefix" },
menu = {
-- Use treesitter to highlight the label text for the given list of sources
draw = {
treesitter = { "lsp" },
},
},
-- Show completions after typing a trigger character, defined by the source
trigger = { show_on_trigger_character = true },
documentation = {
-- Show documentation automatically
auto_show = true,
},
},
-- Signature help when tying
signature = { enabled = true },
},
opts_extend = { "sources.default" },
}
})
重启
nvim
后就会自动安装插件并得到初步的自动补全功能
异常排查
我在配置了 blink.cmp
之后,启动遇到一个报错
blink.cmp
报错Failed to run `config` for blink.cmp
...share/nvim/lazy/blink.cmp/lua/blink/cmp/config/utils.lua:16: present: expected function: 0x7ffecef73a38, got string (enter)
# stacktrace:
- vim/shared.lua:0 _in_ **validate**
- /blink.cmp/lua/blink/cmp/config/utils.lua:16 _in_ **_validate**
- /blink.cmp/lua/blink/cmp/config/keymap.lua:224 _in_ **validate**
- /blink.cmp/lua/blink/cmp/config/init.lua:51 _in_ **validate**
- /blink.cmp/lua/blink/cmp/config/init.lua:116 _in_ **merge_with**
- /blink.cmp/lua/blink/cmp/init.lua:20 _in_ **setup**
- plugins.lua:14
- ~/.config/nvim/init.lua:3
这个问题似乎和 Config failing - preset: expected function: 0x7ff7cc3683b8, got string (default) #881 类似,issue中说明要升级nvim。报告issue的nvim是 NVIM v0.11.0-dev-979+g84623dbe9
,比我的发行版使用的 NVIM v0.11.0-dev-790+g0fe4362e2
还要新一些,报告升级到 NVIM v0.11.0-dev-1479+g548f19ccc3
解决。
我重新构建了 Debian镜像(tini进程管理器) (包含了编译 neovim 步骤),获得了最新的 NVIM v0.12.0-dev-695+g63a7b92e58
解决了这个异常问题。
LSP
要将 Nvim
作为IDE,需要依赖LSP实现。但是手动安装和配置LSP很麻烦,因为不同的LSP有不同的安装步骤,对后期的管理来说很不方便。所以就有了 mason.nvim 和 mason-ispconfig.nvim 来简化配置:
mason.nvim : LSP 管理器,可以实现 LSP 的下载、更新等
mason-ispconfig.nvim : 主要功能是处理 mason.nvim 和 nvim-lspconfig 之间名字不一致的问题; mason-lspconfig.nvim 还会自动调用 vim.lsp.enable 启动安装好的 LSP
修改
plugins.lua
添加如下行:
~/.config/nvim/lua/plugins.lua
增加 nason.nvim
相关设置... -- 省略其他行
require("lazy").setup({
-- LSP manager
{ "mason-org/mason.nvim", opts = {} },
{
"mason-org/mason-lspconfig.nvim",
dependencies = {
"mason-org/mason.nvim",
"neovim/nvim-lspconfig",
config = function()
local lspconfig = require("lspconfig")
lspconfig.pylsp.setup({})
end,
},
opts = {
ensure_installed = { "pylsp", "lua_ls", "bashls", "ruby_lsp", "clangd" },
},
},
... -- 省略其他行
})
说明:
mason.nvim
采用默认配置即可,所以用的是opts = {}
mason-lspconfig.nvim
配置项使用ensure_installed
确保pylsp
会被自动安装(pylsp 是 Python 语言的一个 LSP)通过
nvim-lspconfig
对pylsp
进行配置
这里没有采用
opts = { ... }
进行插件配置,而是使用config = function() ... end
自定义一个配置函数,该函数会被自动执行主要的功能是调用
lspconfig.pylsp.setup({})
,这里的{}
表示采用该LSP
的默认行为
完成上面的配置之后,LSP 已经可用了: 默认安装了 pylsp
编辑
~/.config/nvim/lua/lsp.lua
,添加一些Mason的特定配置:
~/.config/nvim/lua/lsp.lua
-- Note: The order matters: mason -> mason-lspconfig -> lspconfig
require("mason").setup({
ui = {
icons = {
package_installed = "✓",
package_pending = "➜",
package_uninstalled = "✗",
},
},
})
typescript LSP
警告
Mason的LSP支持列表实际上比 nvim-lspconfig
少,所以有些LSP无法通过Mason安装。此外 Mason 是强Linux绑定,对FreeBSD支持不佳,所以在 FreeBSD编程工具 ,我后续将尝试直接使用 nvim-lspconfig
。或者改为使用 helix
编辑器。
要支持更多的LSP,则参考 nvim-lspconfig/doc/configs.md
现在配置非常简单,只需要只需要修订
opts
配置段,在ensure_installed
加入对应LSP名字就可以了支持 JavaScript 和 TypeScript 可以使用 typescript-tools.nvim ,修订
lua/plugins.lua
:
typescript-tools.nvim
require("lazy").setup({
{
"pmizio/typescript-tools.nvim",
dependencies = { "nvim-lua/plenary.nvim", "neovim/nvim-lspconfig" },
opts = {},
},
})