Cmp
Мы не можем обойтись во время разработки без автокомплитов, которые может предложить нам полноценная IDE. Покрыть эту реализацию поможет нам плагин Cmp
Конфиг будет включать в себя сразу несколько различных пакетов:
lua / plugins / cmp.lua
return {
{ "hrsh7th/cmp-nvim-lsp" },
{ "hrsh7th/cmp-buffer" },
{ "hrsh7th/cmp-path" },
{ "hrsh7th/cmp-cmdline" },
{
"hrsh7th/nvim-cmp",
config = function()
local cmp = require("cmp")
cmp.setup({
snippet = {
expand = function(args)
vim.fn["vsnip#anonymous"](args.body) -- For `vsnip` users.
-- require('luasnip').lsp_expand(args.body) -- For `luasnip` users.
-- require('snippy').expand_snippet(args.body) -- For `snippy` users.
-- vim.fn["UltiSnips#Anon"](args.body) -- For `ultisnips` users.
-- vim.snippet.expand(args.body) -- For native neovim snippets (Neovim v0.10+)
end,
},
window = {
-- completion = cmp.config.window.bordered(),
-- documentation = cmp.config.window.bordered(),
},
mapping = cmp.mapping.preset.insert({
["<C-b>"] = cmp.mapping.scroll_docs(-4),
["<C-f>"] = cmp.mapping.scroll_docs(4),
["<C-Space>"] = cmp.mapping.complete(),
["<C-e>"] = cmp.mapping.abort(),
["<CR>"] = cmp.mapping.confirm({ select = true }), -- Accept currently selected item. Set `select` to `false` to only confirm explicitly selected items.
-- конфигурация маппинга по доступным словам по табу
["<Tab>"] = cmp.mapping(function(fallback)
if cmp.visible() then
cmp.select_next_item()
else
fallback()
end
end, { "i", "s" }),
["<S-Tab>"] = cmp.mapping(function(fallback)
if cmp.visible() then
cmp.select_prev_item()
else
fallback()
end
end, { "i", "s" }),
}),
sources = cmp.config.sources({
{ name = "nvim_lsp" },
{ name = "vsnip" }, -- For vsnip users.
-- { name = 'luasnip' }, -- For luasnip users.
-- { name = 'ultisnips' }, -- For ultisnips users.
-- { name = 'snippy' }, -- For snippy users.
}, {
{ name = "buffer" },
}),
})
end,
},
}
Но пока этот плагин не будет нормально работать, так как у нас не установлены LSP, которые и отвечают за поддержку различных языков
В итоге наш автокомплит будет предлагать нам завершение строк в зависимости от контекста его вызова и доступных вариантов.
LSP + Быстрые переходы
И сейчас для полноценной поддержки наших ЯПов в разработке, нам понадобится подключить Lsp
LSP - это language server protocol, который представляет из себя иснтрумент для взаимодействия с языком (проверка, подсказки и так далее)
Для подключения большого количества различных lsp, мы можем воспользоваться nvim-lspconfig
Тут мы добавили базовые LSP для TS, GO и Lua, а так же клавиши быстрых переходов по коду:
gd
- пройти к определению
K
- сигнатура функции (какие аргументы она принимает)
ctrl + k
- помощь сигнатуры
gi
- имплементация
Тут осуществился переход к компоненту из прошлого скрина
leader
+D
- переход к определнию типаleader
+lr
- переименовывает объектleader
+la
- выводит быстрое действие, которое можно выполнить
leader
+lf
- форматирование кода
lua / plugins / lsp.lua
return {
{
"neovim/nvim-lspconfig",
config = function()
local lspconfig = require("lspconfig")
lspconfig.lua_ls.setup({})
lspconfig.gopls.setup({})
-- поднятие ts-сервера, который будет нужен для работы с его кодом и линтингом
lspconfig.ts_ls.setup({})
-- Быстрые переходы
vim.api.nvim_create_autocmd("LspAttach", {
group = vim.api.nvim_create_augroup("UserLspConfig", {}),
callback = function(ev)
vim.bo[ev.buf].omnifunc = "v:lua.vim.lsp.omnifunc"
local opts = { buffer = ev.buf }
vim.keymap.set("n", "gd", vim.lsp.buf.definition, opts)
vim.keymap.set("n", "K", vim.lsp.buf.hover, opts)
vim.keymap.set("n", "gi", vim.lsp.buf.implementation, opts)
vim.keymap.set("n", "<C-k>", vim.lsp.buf.signature_help, opts)
vim.keymap.set("n", "<Leader>D", vim.lsp.buf.type_definition, opts)
vim.keymap.set("n", "<Leader>lr", vim.lsp.buf.rename, { buffer = ev.buf, desc = "Rename Symbol" })
vim.keymap.set({ "n", "v" }, "<Leader>la", vim.lsp.buf.code_action, opts)
vim.keymap.set("n", "<Leader>lf", function()
vim.lsp.buf.format({ async = true })
end, opts)
end,
})
end,
},
}
Ну и так же нам нужно установить языковые сервера, чтобы протоклы могли с ними общаться
brew install go
npm install -g typescript typescript-language-server
Либо мы можем установить Mason, который упростит установку языковых серверов
Mason + Ensure install
Далее нам понадобится пакетный менеджер Mason, который пзволит нам устанавливать языковые-сервера и связанные с разработкой пакеты в NeoVim
- Первым объектом мы установим сам Mason
- а дальше пакет автоматической установки LSP после установки самого Mason
lua / plugins / mason.lua
return {
{
"williamboman/mason.nvim",
config = function()
require('mason').setup()
end
},
-- Ensure install
{
'williamboman/mason-lspconfig.nvim',
config = function()
require("mason-lspconfig").setup(
{
ensure_installed = { "lua_ls", "rust_analyzer", "gopls" }
})
end
}
}
Командой :Mason
мы вызываем окно, в котором сами ищем и через i
запускаем установку интересующего нас сервера
Так же он сам за нас добавляет сервер в $PATH
И теперь у нас на данном этапе появляется автокомплит
Treesitter
Теперь нам понадобится плагин для того, чтобы подсвечивать синтаксис Treesitter
lua / plugins / treesitter.lua
return {
{
'nvim-treesitter/nvim-treesitter',
config = function()
require('nvim-treesitter.configs').setup({
ensure_installed = { "go", "rust", "lua", "typescript", "javascript", "c", "vim", "vimdoc", "markdown", "markdown_inline" },
auto_install = true,
highlight = {
enable = true,
}
})
end
}
}
В итоге мы из обычной белой подсветки получим полноценную подсветку функций, методов, классов и других конструкций языков
Dressing
Далее было бы удобно открывать быстрые действия с помощью Dressing, которые предоставляет нам LSP в отдельном маленьком попапчике, который будет более удобным отображением, чем окошко в районе поля команд
lua / plugins / dressing.lua
return {
{
'stevearc/dressing.nvim',
config = function()
require('dressing').setup({
input = {
win_options = {
winhighlight = 'Normal:CmpPmenu,FloatBorder:CmpPmenuBorder,CursorLine:PmenuSel,Search:None',
},
}
})
end
}
}
Теперь под каждое действие, которое мы добавили через LSP, у нас открываются попапчики
Trouble
Так же нам очень понадобится плагин, который отобразит более подробно ошибку, которая произошла в коде и в этом нам поможет Trouble
lua / plugins / trouble.lua
return {
{
"folke/trouble.nvim",
opts = {}, -- for default options, refer to the configuration section for custom setup.
cmd = "Trouble",
keys = {
{
"<leader>qq",
"<cmd>Trouble diagnostics toggle focus=true<cr>",
desc = "Diagnostics (Trouble)",
},
{
"<leader>qQ",
"<cmd>Trouble diagnostics toggle filter.buf=0<cr>",
desc = "Buffer Diagnostics (Trouble)",
},
{
"<leader>cs",
"<cmd>Trouble symbols toggle focus=false<cr>",
desc = "Symbols (Trouble)",
},
{
"<leader>cl",
"<cmd>Trouble lsp toggle focus=false win.position=right<cr>",
desc = "LSP Definitions / references / ... (Trouble)",
},
{
"<leader>qL",
"<cmd>Trouble loclist toggle<cr>",
desc = "Location List (Trouble)",
},
{
"<leader>qQ",
"<cmd>Trouble qflist toggle<cr>",
desc = "Quickfix List (Trouble)",
},
},
}
}
leader + qq
- тугл диагностики
Она позволяет сразу переключаться по проблемам в проекте. Закрывается окошко просто через q
(предварительно перейдя в него через ctrl + направление
)
Formatting
Далее нам нужно настроить форматирование кода с помощью плагина Conform
Форматтиер не работает как LSP и мы его должны вызывать будем вызывать ивентом “перед сохранением”
lua / plugins / conform.lua
return {
{
"stevearc/conform.nvim",
opts = {},
config = function()
require("conform").setup({
-- тут мы определяем, какие форматтиеры будут отрабатывать по-умолчанию
formatters_by_ft = {
lua = { "stylua" },
python = { "isort", "black" },
rust = { "rustfmt", lsp_format = "fallback" },
javascript = { "prettier" },
typescript = { "prettier" },
javascriptreact = { "prettier" },
typescriptreact = { "prettier" },
},
})
vim.api.nvim_create_autocmd("BufWritePre", {
pattern = "*",
callback = function(args)
require("conform").format({ bufnr = args.buf })
end,
})
end,
},
}
Далее нам нужно будет запустить команду :MasonInstall stylelua prettier
для установки серверов линтеров
В результате после сохранения файла, у нас будет прогоняться форматтиер, чтобы почистить наш код
Linting
И последним этапом в форматировании кода у нас остаётся специфичный под каждую среду разработки линтинг через nvim-lint
Линтер так же не является LSP, но его мы уже будем вызывать после сохранения
lua / plugins / nvim-lint.lua
return {
{
"mfussenegger/nvim-lint",
config = function()
require("lint").linters_by_ft = {
-- тут мы определяем дефолтные линтеры, которые будут отрабатывать в языках
typescript = { "eslint" },
typescriptreact = { "eslint" },
javascript = { "eslint" },
javascriptreact = { "eslint" },
}
-- тут создаётся команда, которая вызывается перед записью буфера
vim.api.nvim_create_autocmd({ "BufWritePost" }, {
callback = function()
require("lint").try_lint()
end,
})
end,
},
}
Чтобы линтер работал внутри ts, нужно, чтобы в конфигурации LSP была строчка с сетапом сервера языка по типу:
lua / plugins / lsp.lua
...
lspconfig.ts_ls.setup({})
...
Теперь мы всегда будем получать ошибки, которые нарушают наши правила eslint и они будут так же выходить в окно с ошибками leader + qq