Featured image of post 解决Neovim中denols与tsserver冲突的问题

解决Neovim中denols与tsserver冲突的问题

针对不同项目进行细化的 lsp 配置

最近在neovim中配置deno的开发环境的时候,遇到了一个问题,那就是在此之前我一直使用的JavaScript和TypeScript的LSP——tsserver,会和deno的LSP(denols)有冲突。

按照官方文档的说法,我们可以对LSP的root_dir进行任何配置:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
nvim_lsp.denols.setup {
  on_attach = on_attach,
  root_dir = nvim_lsp.util.root_pattern("deno.json", "deno.jsonc"),
}

nvim_lsp.tsserver.setup {
  on_attach = on_attach,
  root_dir = nvim_lsp.util.root_pattern("package.json"),
  single_file_support = false
}

按说,这种情况下neovim的LSP会根据项目中不同的文件判断该启动tsserver还是denols,但是这样同样存在问题,那就是如果我们当前的文件夹中有一个deno.json,但是在上级文件夹中又存在package.json,就会导致tsserver和denols都被启动。例如,我的~文件夹中存在一个package.json文件,此时如果我想要在桌面(~/Desktop)新建一个deno项目,就会导致同一个js / ts文件的buffer中同时挂载tsserver和denols。

而这还不算完,此前我使用prettier对代码进行整理,而deno则使用自带的deno fmt进行格式化,如果同时启动两个server,可能会出现deno项目使用了prettier进行美化的问题。

因此,我最终的解决方案是,设置tsserver / denols在on_attach事件中对已经启动的server进行检测,如果在应该使用denols的情况下已经启动了tsserver,则停止tsserver。

tsserver:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
local opts = {
	single_file_support = false,
	on_attach = function(client, bufnr)
        if #vim.lsp.get_active_clients({name = 'denols'}) > 0 then
            client.stop()
        else
            -- common是我的配置文件中自己定义的模块
            -- disableFormat是禁用neovim自带的格式化,使用null-ls
            -- keyAttach是快捷键配置,其中 <leader>fm 是使用null-ls进行格式化
            common.disableFormat(client)
            common.keyAttach(bufnr)
        end
	end,
}

denols:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
local opts = {
	root_dir = require("lspconfig").util.root_pattern("deno.json", "deno.jsonc"),
    single_file_support = true,
	on_attach = function(client, bufnr)
        local active_client = vim.lsp.get_active_clients({name = 'tsserver'})
        if #active_client > 0 then
            active_client[1].stop()
        end
		common.disableFormat(client)
		common.keyAttach(bufnr)
        
        -- 不使用null-ls,而是使用 deno fmt
        -- 格式化的命令是 !deno fmt %,! 表示执行命令,%指代当前文件
		vim.keymap.del("n", "<leader>fm", { buffer = bufnr })
		vim.keymap.set(
			"n",
			"<leader>fm",
			"<cmd>w<CR><cmd>!deno fmt %<CR><CR>",
			{ noremap = true, silent = true, buffer = bufnr }
		)
	end,
}
使用 Hugo + Stack 主题构建