neovim入门指南(四):LSP配置(下)

neovim入门指南(三):LSP配置 上 中说了 lsp 是什么如何配置和启动。那么接下来就完成 lsp 的其他配置。本章节主要介绍下面几个方面的介绍:代码高亮,文件格式化,lsp 相关的 UI 美化。

在有了 lsp 之后,当我们编写代码发生错误的时候,就会有相应的提醒。如图下提示

https://island-hexo.oss-cn-beijing.aliyuncs.com/neovim_lsp/lsp%20error.png

目前的错误还是字母,例如警告是W 。不太美观。对于这个来说,vim 开放了相关的接口,可以通过接口进行设置, neovim-diagnostic

仍旧在 lsp 的文件夹下建立 ui.lua 目录。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
-- lsp/ui.lua
-- 对错误警告的图标
vim.diagnostic.config({
        virtual_text = true,
        signs = true,
 -- 在输入模式下也更新提示,设置为 true 也许会影响性能
 update_in_insert = true,
})
local signs = { Error = "󰅙", Info = "󰋼", Hint = "󰌵", Warn = "" }
for type, icon in pairs(signs) do
 local hl = "DiagnosticSign" .. type
 vim.fn.sign_define(hl, { text = icon, texthl = hl, numhl = hl })
end

其中 vim.diagnostic.config 是在配置提示文本,virtual_text 为错误信息提示.

目前的设置中,对于代码的高亮并不完美,需要采用一个插件了完成。tree-sitter 是一个用 rust 编写的高性能代码高亮的渲染工具,很多编辑器会采用它作为高亮功能的实现,比如说 Zed 。基于 tree sitter ,可以让我们的 neovim 的高亮更加完美。

https://user-images.githubusercontent.com/2361214/202753610-e923bf4e-e88f-494b-bb1e-d22a7688446f.png

这是来源于 nvim-treesitter 的一张图,图中左侧为未启用 treesitter 的代码高亮,右侧为启用后的效果。启用后的效果还是很明显的。

安装 tree-sitter 后,可以通过 TSInstall 来安装具体的语言高亮,例如 Rust 的高亮,可以直接使用 TSInstall rust 命令,或者使用 TSUpdate rust 命令进行更新。整体安装和配置还是比较简单的,这里不过多的解释。

代码格式化是一个很重要的功能,也是我们使用频率很高的功能。针对 Neovim 的代码格式化有很多种方式。这里主要介绍 null-ls。不幸的是,null-ls 已经归档来,不再进行维护,万幸的是,它的 fork 项目 none-ls 重新维护起来,而且目前还兼容 null-ls 的配置,如果你之前使用的是 null-ls,那么只需要将依赖地址由 jose-elias-alvarez/null-ls.nvim 改为 nvimtools/none-ls.nvim 即可。

安装好 none-ls,后可以通过 Mason 安装相关的 formatter,例如安装 lua 的 formatter。通过命令 :Mason 打开安装界面。

https://island-hexo.oss-cn-beijing.aliyuncs.com/stylua%20install.png

选择 stylua,进行安装。安装完成后就可以进行配置,在 lua/lsp 下新建文件,命名为 nonels.lua

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
-- lsp/nonels.lua
-- 即使是采用了 none-ls, 这里也是获取 null-ls
local status, null_ls = pcall(require, "null-ls")
if not status then
	vim.notify("没有找到 null-ls")
	return
end

local formatters = null.builtins.format

null_ls.setup({
    sources = {
        -- Stylua
        formatters.stylua,
        -- 其他 formatter 方式
    },
})

这样在我们进行编写代码的时候,进行相关格式化。在上一文中也进行了介绍,对快捷键进行了绑定。使用 <Leader>= 进行格式化。

关于前面,介绍了通过 cmp 插件进行了自动补全,通过 cmp 可以补充不同来源的代码。

我们使用一些 IDE 或者编辑器的时候,在补全的选项中是会展示一些图标,用来标识补全项的类型,例如变量、类名、方法或是接口等。

RustRover 自动补充样式。

https://resources.jetbrains.com/help/img/idea/2023.3/ri_macros_completion.png

VS Code 自动补全样式。

https://code.visualstudio.com/assets/docs/editor/intellisense/intellisense_icons.png

通过配置,也可以让 neovim 的提示实现上图效果。

当前自动补全的效果如图,前面为补全的字段,后面通过文字来标识补全的类型。

https://island-hexo.oss-cn-beijing.aliyuncs.com/202402221538274.png

有一个插件叫做 lspkind ,可以通过安装该插件结合我们的 cmp 完成上述的样式。

在 lsp 下新建文件 kind.lua,配置 kind,这个可以在 lspkind,找到相关配置。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
-- lsp/kind.lua
local lspkind = require("lspkind")
lspkind.init({
	mode = "symbol_text",
	preset = "codicons",
	symbol_map = {
		Text = "󰉿",
		Method = "󰆧",
		Function = "󰊕",
		Constructor = "",
		Field = "󰜢",
		Variable = "󰀫",
		Class = "󰠱",
		Interface = "",
		Module = "",
		Property = "󰜢",
		Unit = "󰑭",
		Value = "󰎠",
		Enum = "",
		Keyword = "󰌋",
		Snippet = "",
		Color = "󰏘",
		File = "󰈙",
		Reference = "󰈇",
		Folder = "󰉋",
		EnumMember = "",
		Constant = "󰏿",
		Struct = "󰙅",
		Event = "",
		Operator = "󰆕",
		TypeParameter = ""
	},
})

这里可以配置每个类别的图标,配置完成后在 cmp 中进行配置。主要是修改提示的样式。这里主要参考了 Github 上的一个样式,。在 formatting 中进行配置。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
-- cmp.lua
cmp.setup({
    -- 省略其他代码
    formatting = {
        		completion = { border = { "╭", "─", "╮", "│", "╯", "─", "╰", "│" }, scrollbar = "║" },
		documentation = {
			border = { "╭", "─", "╮", "│", "╯", "─", "╰", "│" },
			scrollbar = "║",
		},
		format = lspkind.cmp_format({
			mode = "symbol",
			maxwidth = 20,
			ellipsis_char = "...",
			before = function(entry, vim_item)
				-- Get the full snippet (and only keep first line)
				local word = entry:get_insert_text()
				if entry.completion_item.insertTextFormat == types.lsp.InsertTextFormat.Snippet then
					word = vim.lsp.util.parse_snippet(word)
				end
				word = str.oneline(word)
				if
					entry.completion_item.insertTextFormat == types.lsp.InsertTextFormat.Snippet
					and string.sub(vim_item.abbr, -1, -1) == "~"
				then
					word = word .. "~"
				end
				vim_item.abbr = word
				return vim_item
			end,
		}),
    }
    -- 省略其他代码
})

完成后的样式如图,基本和 VS Code 一样。

https://island-hexo.oss-cn-beijing.aliyuncs.com/202403011511658.png

lspsage 可以极大的提高 nvim lsp 的体验。lspsage 的功能基本都是在增强和美化原有的 lsp 。具体的文档可以查看 nvimdev

lspsage 主要功能:

Finder: 用于高级 LSP 符号搜索的 UI
Diagnostic: 在诊断之间跳转并在漂亮的浮动窗口中显示它们
Peek Definition / Type Definition:查看定义/类型定义
悬停: 更漂亮的悬停操作
重命名: LSP 重命名和异步项目搜索和替换
调用层次传入/传出调用
Code Action: 具有实时预览的漂亮代码操作 UI
LightBulb: 类似 VSCode 的灯泡,指示可能的代码操作
面包屑: 类似于 WinBar 上的 IDE 符号纲要
大纲: 类似于 IDE 的符号纲要 实现: 轻松查看实现数量并快速跳转到它们
浮动终端: 一个简单的浮动终端
杂项: 适用于所有模块的选项

上面来自于官方文档的介绍。

Finder 的功能是一个类似 VS Code 的变量/函数 查看的界面,可以在界面上看到这个变量/函数的定义和调用地方。

https://island-hexo.oss-cn-beijing.aliyuncs.com/202403011526955.png

1
2
3
4
5
6
7
-- keybindings.lua
-- 其他代码
pluginKeys.mapLSP = function(mapbuf) {
    -- 其他代码
    mapbuf("n", "gf", ":Lspsaga lsp_finder<CR>", opt) -- 新增
    -- 其他代码
}

这样在 normal 情况下按下 gf 就会出现上面的 finder 窗口。

Code Action 是一个非常重要的功能,可以根据代码上下文给出相关的提示或者代码改进。例如这块代码,Code Action 提醒我们可以直接转换为字面量的拼接。

https://island-hexo.oss-cn-beijing.aliyuncs.com/202403011541203.png

Code Action 并不是 lspsaga 提供的,但是 lspsaga 给提供了一个漂亮的界面。在有 Code Action 的地方,会有一个黄色灯泡 💡 的提示。

下面绑定我们的快捷键。

1
2
3
4
5
6
7
-- keybindings.lua
pluginKeys.lspKeybinding = function(mapbuf)
 -- 省略其他代码
 -- code action
 -- mapbuf("n", "<leader>ca", ":lua vim.lsp.buf.code_action()<CR>", opt) -- 原有的
 mapbuf("n", "<leader>ca", ":Lspsaga code_action<CR>", opt) -- 替换为这个
end

lspsaga 提供了一个浮动终端窗口,可以在终端上执行任何命令。可以在 keybindings 中绑定这个快捷键,或者直接使用默认的快捷键 t ,来进行终端的打开和关闭。

lspsaga 还提供了很多功能,基本每个功能对我们都有帮助,这里就不做过多介绍了,大家可以看官方文档。

这里基本介绍完了 lsp 的常见功能和配置,剩下的大家可以通过需要进行安装和配置。

这里是我的配置 youngxhui/nvim 大家可以适当参考。

vim/neovim 使用的时候,的确是有一个较高的上手成本,尤其是方向键的习惯,当完全习惯了 h,j,kl 进行光标移动的时候,其实就离入门 vim/neovim 不远了。

当习惯了 vim 这一套风格之后,就会尝试把手头的编辑器/IDE 的快捷键都采用 vim ,而且在熟悉 vim 的快捷键后,真正的感觉到了手指在键盘上飞舞。

无论是 neovim 还是相关插件,更新迭代是很快的,也许当你看到这篇文章的时候,上述的很多配置都已经失效,或者相关插件已经停止维护,文章只是抛砖引玉,我相信你会找到合适自己的 nvim 配置。

我相信喜欢 vim/neovim 的人都是有一颗专研,喜欢折腾的心。正是这样的心才陪伴这个你我一步一步前进。

写到这里有感而发,下一篇我们将会介绍 DAP 。

相关内容