
coc.nvimからnvim-lspconfigへ移行した
- 日本語
- Neovim
- coc.nvim
- nvim-lspconfig
- blink.cmp
移行理由
coc.nvim はとても素晴しいプラグイン。不満は無いが、 nvim-lspconfig に興味があったので移行した。
Neovimを使い始めた当初は nvim-lspconfig と ddc.vim を利用してLSPの補完を実装していた。
「VimとNeovim両方のプラグインを開発出来る!」 という画期的なエコシステム denops.vim は、プログラミング初心者だった当時の私にとって 「実装出来たらかっこいい!!」 プラグインだった。
その頃は仕事やプライベート含め、dotfiles盆栽だけに集中出来る環境だったので必死に最新の状態を追いかけていたが、仕事でプログラミングを書くことになりメンテナンスを続けることが困難になっていった。
denops.vim が依存している Deno も活発に開発が行われており、いよいよ難しくなってきたタイミングで VS Code の Vim拡張 環境に移行することを決断した。
「いろいろなプラグインを使って便利にコーディングする!」よりも、「VimキーバインドとLSPで満足」の状態になった私は、 Neovim ではなく VS CodeのVim拡張機能 に定住することとなった。
そして仕事も落ち付き始めた頃に、dotfiles のメンテナンスを再開したい気持ちが芽生えた。
【余談】私の dotfiles 歴史を語りたい
ちなみに私の dotfiles は2回作り直している。1つ目は macDotfiles だ。
{{ card(title=“macDotfiles | GitHub”, url=“https://github.com/Daiki48/macDotfiles”) }}
初めて dotfiles という文化を知って作ったリポジトリ。懐しい。
この頃に ddc.vim や ddu.vim 、いわゆる Shougo ware を愛用していた。
Shougo Ware はデフォルトで何もしないという設計になっているため、自分で設定した通りに動作する。
この思想自体がとても好きだったため、かなり背伸びして利用していた。おかげで Neovim の設定をするためにドキュメントを隅々まで確認する習慣が出来た。
また環境に関しても、当時は Mac mini を利用していたので Unix 環境限定になっている。
macDotfilesは現在管理していない。
2つ目に作ったのが windowsDotfiles だ。
{{ card(title=“windowsDotfiles | GitHub”, url=“https://github.com/Daiki48/windowsDotfiles”) }}
これは Windows 環境を対象に作ったリポジトリ。懐しい。
当時の私は、 dotfiles のファイル構成が実際の配置とイコールにならなければシンボリックが設定出来ないという認識だったため Windows は分けたんだと思う。
Neovim の設定はかなり薄いものになっている。なぜならこの時期が VS Code 時代だからだ。
Neovim は適当なメモを書く時にさっと利用するぐらいだったため、 LSP の設定やファイラの設定なども排除していた。
windowsDotfilesは現在管理していない。
そして現在メンテナンスしながら利用している dotfiles だ。
{{ card(title=“dotfiles | GitHub”, url=“https://github.com/Daiki48/dotfiles”) }}
シンボリックをスクリプトで生成するようにしているため、どの環境でも利用出来るはず。
手元にあった Mac mini はもう無い上に、現在は Windows の PowerShell をメインに開発しているため他の環境で試せていないが、このリポジトリで管理していくつもりだ。
Manjaro 環境もあるが、今はデスクトップ Windows 環境が楽なのでまた今後使おう…
私のプラグイン管理方法
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",
"https://github.com/folke/lazy.nvim.git",
"--branch=stable", -- latest stable release
lazypath,
})
end
vim.opt.rtp:prepend(lazypath)
local plugins = require("plugins")
local opts = {
defaults = {
lazy = true,
},
performance = {
cache = {
enabled = true,
},
},
dev = {
path = "D:/dev/vim-plugins/",
},
}
require("lazy").setup(plugins, opts)
そして、 lua/plugins 配下にプラグインの設定ファイルを配置している。
lua/plugins/init.lua で require している。
return {
require("plugins.snacks"),
require("plugins.sakurajima"),
require("plugins.editorconfig-vim"),
require("plugins.lualine"),
require("plugins.gitsigns"),
require("plugins.oil"),
require("plugins.oil-vcs-status"),
require("plugins.nvim-autopairs"),
require("plugins.vim-startuptime"),
-- require("plugins.telescope"),
-- require("plugins.coc"),
require("plugins.vim-svelte-plugin"),
require("plugins.treesitter"),
require("plugins.nvim-ts-autotag"),
require("plugins.codesnap"),
require("plugins.flash"),
require("plugins.which-key"),
require("plugins.blink-cmp"),
require("plugins.nvim-lspconfig"),
require("plugins.trouble"),
require("plugins.fidget"),
}
このような感じで不要なものはコメントアウトしている。 コメントアウトしてしばらく経過し、それでも再度利用する気配が無ければ削除する。また必要になった時に設定すれば良い。
coc.nvim を無効にした
なので、一旦 lua/plugins/init.lua で require("plugins.coc) を無効にした。
ちなみに lua/plugins/coc.lua に設定を書いていた。ほぼ公式のコピペ。
return {
"neoclide/coc.nvim",
branch = "release",
event = { "BufReadPre", "BufNewFile" },
-- lazy = false,
config = function()
-- This config is official example.
-- Some servers have issues with backup files, see #649
vim.opt.backup = false
vim.opt.writebackup = false
-- Having longer updatetime (default is 4000 ms = 4s) leads to noticeable
-- delays and poor user experience
vim.opt.updatetime = 300
-- Always show the signcolumn, otherwise it would shift the text each time
-- diagnostics appeared/became resolved
vim.opt.signcolumn = "yes"
local keyset = vim.keymap.set
-- Autocomplete
function _G.check_back_space()
local col = vim.fn.col(".") - 1
return col == 0 or vim.fn.getline("."):sub(col, col):match("%s") ~= nil
end
-- Use Tab for trigger completion with characters ahead and navigate
-- NOTE: There's always a completion item selected by default, you may want to enable
-- no select by setting `"suggest.noselect": true` in your configuration file
-- NOTE: Use command ':verbose imap <tab>' to make sure Tab is not mapped by
-- other plugins before putting this into your config
local opts = { silent = true, noremap = true, expr = true, replace_keycodes = false }
keyset(
"i",
"<TAB>",
'coc#pum#visible() ? coc#pum#next(1) : v:lua.check_back_space() ? "<TAB>" : coc#refresh()',
opts
)
keyset("i", "<S-TAB>", [[coc#pum#visible() ? coc#pum#prev(1) : "\<C-h>"]], opts)
-- Make <CR> to accept selected completion item or notify coc.nvim to format
-- <C-g>u breaks current undo, please make your own choice
keyset("i", "<cr>", [[coc#pum#visible() ? coc#pum#confirm() : "\<C-g>u\<CR>\<c-r>=coc#on_enter()\<CR>"]], opts)
-- Use <c-j> to trigger snippets
keyset("i", "<c-j>", "<Plug>(coc-snippets-expand-jump)")
-- Use <c-space> to trigger completion
keyset("i", "<c-space>", "coc#refresh()", { silent = true, expr = true })
-- Use `[g` and `]g` to navigate diagnostics
-- Use `:CocDiagnostics` to get all diagnostics of current buffer in location list
keyset("n", "[g", "<Plug>(coc-diagnostic-prev)", { silent = true })
keyset("n", "]g", "<Plug>(coc-diagnostic-next)", { silent = true })
-- GoTo code navigation
keyset("n", "gd", "<Plug>(coc-definition)", { silent = true })
keyset("n", "gy", "<Plug>(coc-type-definition)", { silent = true })
keyset("n", "gi", "<Plug>(coc-implementation)", { silent = true })
keyset("n", "gr", "<Plug>(coc-references)", { silent = true })
-- Use K to show documentation in preview window
function _G.show_docs()
local cw = vim.fn.expand("<cword>")
if vim.fn.index({ "vim", "help" }, vim.bo.filetype) >= 0 then
vim.api.nvim_command("h " .. cw)
elseif vim.api.nvim_eval("coc#rpc#ready()") then
vim.fn.CocActionAsync("doHover")
else
vim.api.nvim_command("!" .. vim.o.keywordprg .. " " .. cw)
end
end
keyset("n", "K", "<CMD>lua _G.show_docs()<CR>", { silent = true })
-- Highlight the symbol and its references on a CursorHold event(cursor is idle)
vim.api.nvim_create_augroup("CocGroup", {})
vim.api.nvim_create_autocmd("CursorHold", {
group = "CocGroup",
command = "silent call CocActionAsync('highlight')",
desc = "Highlight symbol under cursor on CursorHold",
})
-- Symbol renaming
keyset("n", "<leader>rn", "<Plug>(coc-rename)", { silent = true })
-- Formatting selected code
keyset("x", "<leader>f", "<Plug>(coc-format-selected)", { silent = true })
keyset("n", "<leader>f", "<Plug>(coc-format-selected)", { silent = true })
-- Setup formatexpr specified filetype(s)
vim.api.nvim_create_autocmd("FileType", {
group = "CocGroup",
pattern = "typescript,json",
command = "setl formatexpr=CocAction('formatSelected')",
desc = "Setup formatexpr specified filetype(s).",
})
-- Update signature help on jump placeholder
vim.api.nvim_create_autocmd("User", {
group = "CocGroup",
pattern = "CocJumpPlaceholder",
command = "call CocActionAsync('showSignatureHelp')",
desc = "Update signature help on jump placeholder",
})
-- Apply codeAction to the selected region
-- Example: `<leader>aap` for current paragraph
local opts = { silent = true, nowait = true }
keyset("x", "<leader>a", "<Plug>(coc-codeaction-selected)", opts)
keyset("n", "<leader>a", "<Plug>(coc-codeaction-selected)", opts)
-- Remap keys for apply code actions at the cursor position.
keyset("n", "<leader>ac", "<Plug>(coc-codeaction-cursor)", opts)
-- Remap keys for apply source code actions for current file.
keyset("n", "<leader>as", "<Plug>(coc-codeaction-source)", opts)
-- Apply the most preferred quickfix action on the current line.
keyset("n", "<leader>qf", "<Plug>(coc-fix-current)", opts)
-- Remap keys for apply refactor code actions.
keyset("n", "<leader>re", "<Plug>(coc-codeaction-refactor)", { silent = true })
keyset("x", "<leader>r", "<Plug>(coc-codeaction-refactor-selected)", { silent = true })
keyset("n", "<leader>r", "<Plug>(coc-codeaction-refactor-selected)", { silent = true })
-- Run the Code Lens actions on the current line
keyset("n", "<leader>cl", "<Plug>(coc-codelens-action)", opts)
-- Map function and class text objects
-- NOTE: Requires 'textDocument.documentSymbol' support from the language server
keyset("x", "if", "<Plug>(coc-funcobj-i)", opts)
keyset("o", "if", "<Plug>(coc-funcobj-i)", opts)
keyset("x", "af", "<Plug>(coc-funcobj-a)", opts)
keyset("o", "af", "<Plug>(coc-funcobj-a)", opts)
keyset("x", "ic", "<Plug>(coc-classobj-i)", opts)
keyset("o", "ic", "<Plug>(coc-classobj-i)", opts)
keyset("x", "ac", "<Plug>(coc-classobj-a)", opts)
keyset("o", "ac", "<Plug>(coc-classobj-a)", opts)
-- Remap <C-f> and <C-b> to scroll float windows/popups
---@diagnostic disable-next-line: redefined-local
-- local opts = {silent = true, nowait = true, expr = true}
-- keyset("n", "<C-f>", 'coc#float#has_scroll() ? coc#float#scroll(1) : "<C-f>"', opts)
-- keyset("n", "<C-b>", 'coc#float#has_scroll() ? coc#float#scroll(0) : "<C-b>"', opts)
-- keyset("i", "<C-f>",
-- 'coc#float#has_scroll() ? "<c-r>=coc#float#scroll(1)<cr>" : "<Right>"', opts)
-- keyset("i", "<C-b>",
-- 'coc#float#has_scroll() ? "<c-r>=coc#float#scroll(0)<cr>" : "<Left>"', opts)
-- keyset("v", "<C-f>", 'coc#float#has_scroll() ? coc#float#scroll(1) : "<C-f>"', opts)
-- keyset("v", "<C-b>", 'coc#float#has_scroll() ? coc#float#scroll(0) : "<C-b>"', opts)
-- Use CTRL-S for selections ranges
-- Requires 'textDocument/selectionRange' support of language server
keyset("n", "<C-s>", "<Plug>(coc-range-select)", { silent = true })
keyset("x", "<C-s>", "<Plug>(coc-range-select)", { silent = true })
-- Add `:Format` command to format current buffer
vim.api.nvim_create_user_command("Format", "call CocAction('format')", {})
-- " Add `:Fold` command to fold current buffer
vim.api.nvim_create_user_command("Fold", "call CocAction('fold', <f-args>)", { nargs = "?" })
-- Add `:OR` command for organize imports of the current buffer
vim.api.nvim_create_user_command("OR", "call CocActionAsync('runCommand', 'editor.action.organizeImport')", {})
-- Add (Neo)Vim's native statusline support
-- NOTE: Please see `:h coc-status` for integrations with external plugins that
-- provide custom statusline: lightline.vim, vim-airline
vim.opt.statusline:prepend("%{coc#status()}%{get(b:,'coc_current_function','')}")
-- Mappings for CoCList
-- code actions and coc stuff
---@diagnostic disable-next-line: redefined-local
local opts = { silent = true, nowait = true }
-- Show all diagnostics
keyset("n", "<space>a", ":<C-u>CocList diagnostics<cr>", opts)
-- Manage extensions
keyset("n", "<space>l", ":<C-u>CocList extensions<cr>", opts)
-- Show commands
keyset("n", "<space>c", ":<C-u>CocList commands<cr>", opts)
-- Find symbol of current document
keyset("n", "<space>o", ":<C-u>CocList outline<cr>", opts)
-- Search workspace symbols
keyset("n", "<space>s", ":<C-u>CocList -I symbols<cr>", opts)
-- Do default action for next item
keyset("n", "<space>j", ":<C-u>CocNext<cr>", opts)
-- Do default action for previous item
keyset("n", "<space>k", ":<C-u>CocPrev<cr>", opts)
-- Resume latest coc list
keyset("n", "<space>p", ":<C-u>CocListResume<cr>", opts)
local function switch_coc_ts()
local path = vim.fn.expand("%:p:h")
if path == "" then
path = "."
end
if vim.fn.empty(vim.fn.finddir("node_modules", path .. ";")) == 1 then
vim.fn["coc#config"]("deno.enable", true)
vim.fn["coc#config"]("tsserver.enable", false)
else
vim.fn["coc#config"]("deno.enable", false)
vim.fn["coc#config"]("tsserver.enable", true)
end
end
vim.api.nvim_create_autocmd("FileType", {
pattern = { "typescript", "typescript.tsx" },
callback = switch_coc_ts,
once = true,
})
-- Show diagnostics in a floating window
vim.keymap.set(
"n",
"<space>e",
":<C-u>CocCommand document.showIncomingCalls<CR>",
{ silent = true, noremap = true }
)
-- coc-prettier
vim.api.nvim_create_user_command("Prettier", function()
vim.fn.CocAction("runCommand", "prettier.formatFile")
end, {})
-- coc-htmldjango
vim.api.nvim_create_user_command("Djlint", function()
vim.fn.CocAction("runCommand", "htmldjango.djlint.format")
end, {})
end,
}
nvim-lspconfig をインストールする
nvim-lspconfig は Neovim 用の LSPクライアント で基本的なデフォルト設定を提供してくれる。(とREADMEに書いてあった)
nvim-lspconfig is a “data only” repo, providing basic, default Nvim LSP client configurations for various LSP servers.
View the documentation for all configs or :help lspconfig-all from Nvim.
まずは最小構成で書いた。他人の設定をコピペしたり、公式READMEのコピペで動作しなくて断念した苦い思い出がある。(Neovim初心者はみんなそうだと信じてる)
return {
"neovim/nvim-lspconfig",
event = { "BufReadPre", "BufNewFile" },
}
blink.cmp をインストールする
blink.cmp をLSPの補完プラグインとして利用するためインストールする。結構高速に動作するらしい。(README調べ)
blink.cmp is a completion plugin with support for LSPs and external sources that updates on every keystroke with minimal overhead (0.5-4ms async). It use a custom fuzzy matcher to easily handle 20k+ items. It provides extensibility via pluggable sources (LSP, snippets, etc), component based rendering and scripting for the configuration.
まさかのドキュメントサイトが存在する。
{{ card(title=“Blink Completion (blink.cmp)”, url=“https://cmp.saghen.dev/”) }}
これもまずは最小構成で設定した。
return {
"saghen/blink.cmp",
dependencies = "rafamadriz/friendly-snippets",
event = "InsertEnter",
version = "*",
}
nvim-lspconfig と blink.cmp の設定
最小構成でプラグインを読み込めてエラーが出なかったとして作業を進める。
まずは blink.cmp の設定をした。
そもそも、 coc.nvim から移行するモチベーションはこのプラグインを使ってみたいというのがある。
nvim-cmp という素晴しい補完プラグインが地位を確立している中、突如現われたプラグインだから興味があった。
この設定はドキュメントサイトを確認すれば細かく書いてあるので説明は割愛する。
return {
"saghen/blink.cmp",
dependencies = "rafamadriz/friendly-snippets",
event = "InsertEnter",
version = "*",
opts = {
keymap = {
preset = "default",
["<C-u>"] = { "scroll_documentation_up", "fallback" },
["<C-d>"] = { "scroll_documentation_down", "fallback" },
["<S-Tab>"] = { "select_prev", "fallback" },
["<Tab>"] = { "select_next", "fallback" },
["<C-y>"] = { "select_and_accept" },
},
appearance = {
use_nvim_cmp_as_default = false,
nerd_font_variant = "mono",
},
sources = {
default = { "lsp", "path", "snippets", "buffer" },
},
completion = {
keyword = {
range = "full",
},
list = {
selection = {
preselect = true,
auto_insert = true,
},
},
menu = {
border = "single",
auto_show = true,
draw = {
columns = { { "kind_icon" }, { "label", "label_description", gap = 1 }, { "kind_icon", "kind" } },
},
},
documentation = {
window = {
border = "single",
},
auto_show = true,
auto_show_delay_ms = 500,
},
ghost_text = { enabled = true },
},
signature = {
window = {
border = "single",
},
},
cmdline = {
enabled = false,
},
snippets = {
preset = "default",
},
},
opts_extend = { "sources.default" },
}
公式ドキュメントサイトも分かりやすいし、Youtubeにも動画がいくつかあった。注目されているプラグインなのかもしれない。
次に nvim-lspconfig の設定もする。まずは lua_ls の設定から。
return {
"neovim/nvim-lspconfig",
dependencies = { "saghen/blink.cmp" },
event = { "BufReadPre", "BufNewFile" },
opts = {
servers = {
lua_ls = {
settings = {
Lua = {
runtime = {
version = "LuaJIT",
},
diagnostics = {
globals = { "vim" },
},
},
},
},
},
},
config = function(_, opts)
local lspconfig = require("lspconfig")
local root_pattern = require("lspconfig").util.root_pattern
for server, config in pairs(opts.servers) do
config.capabilities = require("blink.cmp").get_lsp_capabilities(config.capabilities)
lspconfig[server].setup(config)
end
end,
}
これは blink.cmp の公式ドキュメントサイトに書いてあった。
{{ card(title=“Installation | Blink Completion(blink.cmp)”, url=“https://cmp.saghen.dev/installation.html#lazy-nvim”) }}
設定は一旦書き終わった。
lua-language-server をインストールする
しかし、このままNeovimを再起動して Lua ファイルを開いてもエラーが発生するだろう。
nvim-lspconfig のドキュメントを確認すると lua-language-server のインストールが必要だ。
{{ card(title=“lua_ls | GitHub”, url=“https://github.com/neovim/nvim-lspconfig/blob/master/doc/configs.md#lua_ls”) }}
私は Scoop を利用してインストールした。
scoop install lua-language-server
この状態でNeovimを再起動後、Lua ファイルを開くとLSPと blink.cmp によるコードの補完が有効になっているだろう。
かなりシンプルな設定でコード補完までを実現出来た。
これも ddc.vim や nvim-cmp で挫折した経験が生かされているのだろう。
他の言語も設定する
Lua 以外に Rust や Go の設定もしている。
言語の設定は nvim-lspconfig で行う。これもドキュメントが親切なので確認しながら。
return {
"neovim/nvim-lspconfig",
dependencies = { "saghen/blink.cmp", "j-hui/fidget.nvim" },
event = { "BufReadPre", "BufNewFile" },
opts = {
servers = {
lua_ls = {
settings = {
Lua = {
runtime = {
version = "LuaJIT",
},
diagnostics = {
globals = { "vim" },
},
},
},
},
rust_analyzer = {
settings = {
["rust-analyzer"] = {
check = {
command = "clippy",
},
imports = {
granularity = {
group = "module",
},
prefix = "self",
},
cargo = {
buildScripts = {
enable = true,
},
},
procMacro = {
enable = true,
},
},
},
},
taplo = {
settings = {
["taplo"] = {
cmd = {
"taplo",
"lsp",
"stdio",
},
filetypes = {
"toml",
},
single_file_support = true,
},
},
},
svelte = {
settings = {
["svelte"] = {
cmd = {
"svelteserver",
"--stdio",
},
filetypes = {
"svelte",
},
},
},
},
html = {
settings = {
["html"] = {
cmd = {
"vscode-html-language-server",
"--stdio",
},
filetypes = {
"html",
"templ",
},
},
},
},
cssls = {
settings = {
["cssls"] = {
cmd = {
"vscode-css-language-server",
"--stdio",
},
filetypes = {
"css",
"scss",
"less",
},
init_options = {
provideFormatter = true,
},
},
},
},
gopls = {
settings = {
["gopls"] = {
cmd = {
"gopls",
},
filetypes = {
"go",
"gomod",
"gowork",
"gotmpl",
},
single_file_support = true,
},
},
},
tailwindcss = {
settings = {
["tailwindcss"] = {
cmd = {
"tailwindcss-language-server",
"--stdio",
},
filetypes = {
"javascript",
"javascriptreact",
"typescript",
"typescriptreact",
"vue",
"svelte",
},
classAttributes = { "class", "className", "class:list", "classList", "ngClass" },
includeLanguages = {
eelixir = "html-eex",
eruby = "erb",
htmlangular = "html",
templ = "html",
},
lint = {
cssConflict = "warning",
invalidApply = "error",
invalidConfigPath = "error",
invalidScreen = "error",
invalidTailwindDirective = "error",
invalidVariant = "error",
recommendedVariantOrder = "warning",
},
validate = true,
},
},
},
},
},
config = function(_, opts)
local lspconfig = require("lspconfig")
local root_pattern = require("lspconfig").util.root_pattern
for server, config in pairs(opts.servers) do
config.capabilities = require("blink.cmp").get_lsp_capabilities(config.capabilities)
lspconfig[server].setup(config)
end
end,
}
ts_ls と denols の設定
coc.nvim であれば coc-settings.json で有効無効の切り替えが出来ていたので良かったが、 nvim-lspconfig は設定ファイルが存在しないので package.json や deno.json など、それぞれのプロジェクト固有ファイルで識別するようにした。
結構難しかった。
return {
"neovim/nvim-lspconfig",
dependencies = { "saghen/blink.cmp", "j-hui/fidget.nvim" },
event = { "BufReadPre", "BufNewFile" },
opts = {
servers = {
-- 割愛
ts_ls = {
settings = {
["ts_ls"] = {
cmd = {
"typescript-language-server",
"--stdio",
},
filetypes = {
"javascript",
"javascriptreact",
"javascript.jsx",
"typescript",
"typescriptreact",
"typescript.tsx",
},
init_options = {
hostInfo = "neovim",
},
single_file_support = true,
},
},
},
denols = {
settings = {
["denols"] = {},
},
},
-- 割愛
},
},
config = function(_, opts)
local lspconfig = require("lspconfig")
local root_pattern = require("lspconfig").util.root_pattern
for server, config in pairs(opts.servers) do
config.capabilities = require("blink.cmp").get_lsp_capabilities(config.capabilities)
local is_ts = root_pattern("package.json", "tsconfig.json")()
local is_deno = root_pattern("deno.json", "deno.jsonc")()
if server == "ts_ls" and is_ts then
config.root_dir = root_pattern("package.json", "tsconfig.json")
lspconfig[server].setup(config)
elseif server == "denols" and is_deno then
config.root_dir = root_pattern("deno.json", "deno.jsonc")
lspconfig[server].setup(config)
elseif server ~= "ts_ls" and server ~= "denols" then
lspconfig[server].setup(config)
end
end
end,
}
opts はそれぞれの言語で必要な設定をドキュメントを参考にしながら書く。
{{ card(title=“ts_ls | GitHub”, url=“https://github.com/neovim/nvim-lspconfig/blob/master/doc/configs.md#ts_ls”) }}
{{ card(title=“denols | GitHub”, url=“https://github.com/neovim/nvim-lspconfig/blob/master/doc/configs.md#denols”) }}
そして、サーバー名で root_pattern を区別するようにした。
この設定で望む動作を実現出来た。良かった。
どのLSPがアクティブか lualine に表示する
coc.nvim でも設定していたが、ステータスラインにアクティブなLSPを表示すると分かりやすくて良かったため、こっちでも設定する。
clients_lsp を定義する。
local clients_lsp = function()
local bufnr = vim.api.nvim_get_current_buf()
local clients = vim.lsp.buf_get_clients(bufnr)
if next(clients) == nil then
return ""
end
local c = {}
for _, client in pairs(clients) do
table.insert(c, client.name)
end
return "\u{f085} " .. table.concat(c, "|")
end
あとは sections の好きな位置で表示する。私は a の位置に coc.nvim の g:coc_status を表示していたので同じ場所にした。
...
local config = {
options = {
icons_enabled = true,
theme = "sakurajima",
component_separators = { left = "", right = "" },
section_separators = { left = "", right = "" },
disabled_filetypes = {},
},
sections = {
lualine_a = {
{ vim_mode },
"g:coc_status",
clients_lsp,
},
...
これで現在アクティブなLSPをステータスラインに表示することが出来た。
lualine 以外のプラグインは利用したことが無いので分からない。
LSP起動中の確認
rust-analyzer などは、LSPが完全に起動するまで時間がかかる。 coc.nvim では右下に起動中の表示があったので分かりやすかった。これと同じようなものを実装してみる。
fidget.nvim がドンピシャだ。
設定はシンプル。
return {
"j-hui/fidget.nvim",
tag = "v1.6.0",
opts = {},
}
あとは nvim-lspconfig の依存に追加する。
return {
"neovim/nvim-lspconfig",
dependencies = { "saghen/blink.cmp", "j-hui/fidget.nvim" },
event = { "BufReadPre", "BufNewFile" },
opts = {
servers = {
lua_ls = {
...
試しに Rust プロジェクトを作成して確認すると右下にビルドしている様子が表示されるだろう。
終わりに
ひとまず coc.nvim で便利だった機能を実現することが出来た。これら全てをデフォルト設定で実現出来ていた coc.nvim はやはり素晴しいプラグインだと思う。
coc-settings.json での管理も VS Code みたいなので抵抗は少ないだろう。
coc.nvim が便利過ぎてなかなか実行に移せなかったが、遂に nvim-lspconfig でコーディング出来る環境を構築出来たので良かった。
最近 telescope.nvim から snacks.nvim の picker に移行したりと folke ware の勢いに乗りたい自分がいるので他で記事を書きたいと思う。