LSP в Neovim: умные возможности языка

Рейтинг: 67.2% · 18 голосов
Исчерпывающий курс по Vim и Neovim: модальное редактирование и грамматика (операторы, движения, текстовые объекты, точка-команда), регистры, метки, макросы, поиск и :substitute, :global, буферы/окна/quickfix, визуальный режим, конфигурация на Lua, маппинги, плагины (lazy.nvim), LSP, автодополнение (blink.cmp), Treesitter, fuzzy-поиск, Git, эргономика и антипаттерны. 34 главы, актуально на 2026 (Vim 9.1, Neovim 0.11/0.12).
Ответить
Аватара пользователя
Roman_Vim
Сообщения: 34
Зарегистрирован: 11 май 2026, 05:31

LSP в Neovim: умные возможности языка

Сообщение Roman_Vim »

Оглавление курса (34)
  1. Философия Vim: модальное редактирование и почему это актуально в 2026
  2. Установка и выживание: первый запуск, режимы, как выйти
  3. Перемещение по тексту: движения как основа эффективности
  4. Базовое редактирование: вставка, удаление, копирование
  5. Грамматика Vim: операторы + движения = команды
  6. Текстовые объекты: оперируем структурой, а не символами
  7. Точка-команда и повторяемость: "один штрих, чтобы повторить"
  8. Регистры: продвинутая работа с буфером обмена
  9. Метки и прыжки: навигация по истории перемещений
  10. Поиск: /, ?, *, # и магия паттернов
  11. Замена :substitute и регулярные выражения Vim
  12. Команда :global - оружие массового редактирования
  13. Буферы, окна и вкладки: организация рабочего пространства
  14. Quickfix и location list: пакетная работа по всему проекту
  15. Навигация по файлам: netrw, fuzzy-поиск и проекты
  16. Макросы: автоматизация повторяющихся правок
  17. Визуальный режим и блочное редактирование
  18. Трюки режима вставки
  19. Свёртки, автодополнение и аббревиатуры (встроенные)
  20. Конфигурация с нуля: init.lua и разумные дефолты 2026
  21. Маппинги: leader, which-key и здравые привычки
  22. Скриптинг: основы Vimscript и Lua для Neovim
  23. Менеджеры плагинов: lazy.nvim и lazy-loading
  24. Neovim в 2026: чем отличается и почему выбирают
  25. LSP в Neovim: умные возможности языка (вы здесь)
  26. Автодополнение 2026: blink.cmp против nvim-cmp
  27. Treesitter: точная подсветка и структурное редактирование
  28. Fuzzy-поиск: Telescope, fzf-lua и snacks.picker
  29. Git внутри редактора: fugitive, gitsigns и lazygit
  30. Дистрибутивы, отладка и терминал: быстрый старт и интеграции
  31. Vim повсюду: IDE, браузер и shell
  32. Эргономика и антипаттерны: как не навредить себе и не застрять
  33. Рабочие рецепты, тренажёры и план обучения
  34. Шпаргалка-справочник: все ключевые команды одним списком
До этого момента Neovim был для нас мощным текстовым редактором: мы научились молниеносно перемещаться, оперировать структурой кода через текстовые объекты, гонять макросы и собирать конфигурацию из плагинов. Но современная разработка требует большего, чем редактирование текста как набора символов. Когда вы пишете на Go, Rust, Python или TypeScript, вам нужно, чтобы редактор понимал код: знал, где определена функция, какие у неё параметры, что переменная переименовывается во всех 47 местах разом, а не только там, где совпала строка.

Раньше это означало переход в "настоящую IDE". Сегодня Neovim даёт ровно те же умные возможности через LSP - и, что важно для 2026 года, делает это во многом из коробки, без зоопарка плагинов. Эта глава - про то, как превратить Neovim в редактор, который понимает язык.

Что такое LSP и почему это всё изменило

LSP (Language Server Protocol) - это протокол, придуманный Microsoft для VS Code и затем ставший индустриальным стандартом. Идея проста и гениальна: вместо того чтобы каждый редактор реализовывал поддержку каждого языка заново, мы разделяем ответственность.
  • Языковой сервер (language server) - отдельная программа, которая умеет анализировать конкретный язык. Например, gopls для Go, rust-analyzer для Rust, lua_ls для Lua, pyright/basedpyright для Python, ts_ls для TypeScript. Сервер парсит проект, строит модель кода и знает про него всё.
  • Редактор (LSP-клиент) - в нашем случае Neovim. Он не разбирается в семантике Go или Rust; он просто общается с сервером по стандартному протоколу: "где определение символа под курсором?", "какие тут ошибки?", "переименуй вот это".
Общение идёт через JSON-RPC. Когда вы наводите курсор на функцию и жмёте K, Neovim отправляет серверу запрос textDocument/hover, получает ответ с документацией и показывает его в плавающем окне. Это и есть вся "магия".

Почему это важно понимать, а не просто настроить. Многие проблемы с LSP ("не работает автодополнение", "нет подсветки ошибок", "go-to-definition прыгает не туда") - это либо не установленный/не запущенный сервер, либо неверно определённый корень проекта, либо конфликт двух источников. Когда вы держите в голове схему "клиент Neovim <-> сервер <-> ваш проект", диагностика становится осмысленной.

Разделение ответственности в стеке 2026 года

В Neovim 0.11+ (и тем более 0.12) LSP-клиент стал по-настоящему нативным. Это перекроило всю экосистему. Современный стек состоит из чётко разделённых ролей:

Код: Выделить всё

Компонент              |  Роль                                                                        |  Обязателен?
-----------------------+------------------------------------------------------------------------------+----------------------
Ядро Neovim (vim.lsp)  |  Рантайм LSP-клиента, активация серверов, дефолтные маппинги, диагностика    |  Да, встроено
nvim-lspconfig         |  Каталог готовых дефолтных конфигов серверов (cmd, filetypes, root_markers)  |  Нет, но удобно
mason.nvim             |  Установщик серверов/линтеров/форматтеров одной командой                     |  Нет, но очень удобно
mason-lspconfig.nvim   |  Мост между именами пакетов Mason и именами конфигов + авто-включение        |  Нет
conform.nvim           |  Форматирование (отдельно от LSP, чтобы избежать конфликтов)                 |  Нет, рекомендуется
Vim vs Neovim: важная оговорка. Всё, о чём эта глава, - про Neovim. В классическом Vim нативного vim.lsp не существует вовсе: ядро Vim не содержит LSP-клиента. Чтобы получить LSP в Vim, нужны сторонние плагины - vim-lsp, coc.nvim (тащит за собой Node.js и собственный движок а-ля VS Code) или ALE. То есть нативный из коробки LSP - это эксклюзив Neovim 0.11+; в Vim тот же результат достижим только через внешний слой. Дальше под "редактором-клиентом" мы всегда подразумеваем Neovim.
Ключевой сдвиг: nvim-lspconfig больше не фреймворк, а справочник. Старый паттерн require('lspconfig').gopls.setup{} официально устарел (deprecated) и будет удалён в nvim-lspconfig v3.0.0. Сам плагин жив - но теперь он просто поставляет готовые дефолты поверх нативного API. Для базовой работы LSP он вообще не нужен.

Нативный API: vim.lsp.config() и vim.lsp.enable()

Это центральная тема главы. В Neovim 0.11 появилось разделение конфигурации и активации сервера.
  • vim.lsp.config('имя', { ... }) - задаёт или переопределяет настройки сервера. Ничего не запускает.
  • vim.lsp.enable('имя') - включает сервер: Neovim будет автоматически запускать его для подходящих filetypes.
Минимальный пример в init.lua:

Код: Выделить всё

-- Настраиваем сервер Lua
vim.lsp.config('lua_ls', {
  settings = {
    Lua = {
      runtime = { version = 'LuaJIT' },
      diagnostics = { globals = { 'vim' } }, -- чтобы lua_ls знал про глобал vim
    },
  },
})

-- Включаем нужные серверы
vim.lsp.enable({ 'lua_ls', 'gopls', 'rust_analyzer', 'pyright' })
Каталог lsp/ - конфиг по файлу на сервер

Самая чистая структура 2026 года: один файл на сервер в каталоге ~/.config/nvim/lsp/<server>.lua. Neovim 0.11+ автоматически подхватывает эти файлы из runtimepath - так же, как ftplugin/. Никаких вызовов vim.lsp.config() руками: файл и есть конфиг.

Код: Выделить всё

-- ~/.config/nvim/lsp/lua_ls.lua
return {
  settings = {
    Lua = {
      runtime = { version = 'LuaJIT' },
      diagnostics = { globals = { 'vim' } },
      workspace = { checkThirdParty = false },
    },
  },
}

Код: Выделить всё

-- ~/.config/nvim/lsp/gopls.lua
return {
  settings = {
    gopls = {
      hints = { -- inlay hints для Go
        parameterNames = true,
        assignVariableTypes = true,
      },
    },
  },
}
А в init.lua остаётся только активация:

Код: Выделить всё

vim.lsp.enable({ 'lua_ls', 'gopls', 'rust_analyzer', 'pyright' })
Порядок слияния конфигов (по приоритету): сначала дефолты из nvim-lspconfig (lsp/ в его rtp), затем ваши lsp/*.lua, затем after/lsp/*.lua, затем явные вызовы vim.lsp.config(). Это даёт предсказуемый каскад: вы переопределяете только нужное, а корень проекта, команду запуска и список filetypes берёте из готовых дефолтов.

Общие дефолты через vim.lsp.config('*', ...)

Звёздочка * применяет настройки ко всем серверам - удобно для общих capabilities (например, для интеграции с blink.cmp, см. главу 26) и корневых маркеров:

Код: Выделить всё

vim.lsp.config('*', {
  root_markers = { '.git' },
  capabilities = require('blink.cmp').get_lsp_capabilities(),
})
Важно про root_markers. В нативном API корень проекта надо задавать явно. Старый lspconfig определял его автоматически по хитрым правилам; теперь, если не указать root_markers, сервер может неверно определить корень и, например, не увидеть go.mod или Cargo.toml. Готовые дефолты из nvim-lspconfig обычно уже содержат правильные маркеры для каждого сервера.
Установка серверов: mason.nvim + mason-lspconfig

Языковой сервер - это внешняя программа, которую надо где-то взять. Можно ставить руками через системный пакетный менеджер (brew install gopls), но удобнее - через Mason, который качает серверы в каталог Neovim и не засоряет систему.

Код: Выделить всё

-- через lazy.nvim (см. главу 23)
{
  'mason-org/mason.nvim',
  opts = {},
},
{
  'mason-org/mason-lspconfig.nvim',
  dependencies = { 'mason-org/mason.nvim', 'neovim/nvim-lspconfig' },
  opts = {
    ensure_installed = { 'lua_ls', 'gopls', 'rust_analyzer', 'pyright' },
  },
},
:Mason открывает интерактивный установщик: видно все доступные серверы, линтеры и форматтеры, ставятся клавишей i.

Большое изменение: Mason 2.0 и automatic_enable

В 2025 году вышли Mason 2.0 и mason-lspconfig 2.0 с ломающими изменениями, о которых надо знать:
  • Удалены setup_handlers() и опция handlers. Если вы копируете старый гайд с handlers = { ... } - он не заработает.
  • Появилась опция automatic_enable (включена по умолчанию): mason-lspconfig сам вызывает vim.lsp.enable() для всех установленных серверов.
Это значит, что при использовании mason-lspconfig 2.0 вам не нужно дополнительно вызывать vim.lsp.enable() вручную для установленных через Mason серверов - иначе рискуете запустить сервер дважды. Либо доверьтесь automatic_enable, либо отключите его (automatic_enable = false) и включайте серверы сами. Смешивать оба подхода нельзя.

Что вы получаете: возможности LSP

Теперь - ради чего всё затевалось. Перечислим ключевые умные функции и то, как они вызываются.

Дефолтные маппинги Neovim 0.11+ (без единого плагина!)

Большое нововведение 0.11 - встроенные LSP-маппинги. Они создаются глобально, как только активен хоть один сервер. Раньше каждый гайд вручную биндил gd/gr/<leader>ca - теперь базовый набор уже есть:

Код: Выделить всё

Клавиша         |  Действие                                         |  LSP-метод
----------------+---------------------------------------------------+---------------------------------------------------
K               |  Hover: документация и сигнатура под курсором     |  textDocument/hover
grn             |  Rename: переименовать символ во всём проекте     |  textDocument/rename
gra             |  Code action: быстрые исправления и рефакторинги  |  textDocument/codeAction
grr             |  References: все использования символа            |  textDocument/references
gri             |  Implementation: к реализации интерфейса          |  textDocument/implementation
grt             |  Type definition: к определению типа              |  textDocument/typeDefinition
grx             |  Запустить code lens                              |  vim.lsp.codelens.run() / workspace/executeCommand
gO              |  Document symbol: список символов файла           |  textDocument/documentSymbol
<C-s> (insert)  |  Signature help: подсказка по параметрам          |  textDocument/signatureHelp
[d / ]d         |  Прыжок к предыдущей/следующей диагностике        |  vim.diagnostic
Обратите внимание на префикс gr - это мнемоника "goto + references-семейство". Привычные по другим редакторам gd (go-to-definition) и <leader>rn в дефолты не входят - gd исторически делает в Vim другое (переход к локальному определению по тексту). Многие добавляют свои привычные раскладки поверх; это нормально, но помните, что базовый набор уже работает.

Go-to-definition, hover, references на практике

Код: Выделить всё

// Было: курсор на вызове функции processOrder(o)
//                          ^
// Нажимаем: gd  (если забиндили; или :lua vim.lsp.buf.definition())
// Стало: прыгнули к определению func processOrder(o Order) error { ... }
//        вернуться назад - Ctrl-o (jumplist, см. главу 9)

Код: Выделить всё

// Было: курсор на time.Now
//                    ^
// Нажимаем: K
// Стало: всплыло окно с сигнатурой func Now() Time и документацией.
//        Ещё раз K - фокус переходит в окно, можно скроллить и закрыть q.
Для go-to-definition нет дефолтного маппинга, поэтому типично добавляют:

Код: Выделить всё

vim.keymap.set('n', 'gd', vim.lsp.buf.definition, { desc = 'Go to definition' })
Rename: переименование, которое понимает код

Код: Выделить всё

// Было: переменная userCount используется в 12 местах файла и в 3 других файлах
// Нажимаем: grn, вводим totalUsers, Enter
// Стало: все 15 вхождений переименованы - но только настоящие ссылки,
//        не строка "userCount" в комментарии или в другой области видимости
Это принципиальное отличие от :%s/userCount/totalUsers/g (глава 11): LSP знает семантику, а не просто совпадение строки.

Code actions: рефакторинги и быстрые фиксы

gra показывает контекстное меню действий: импортировать недостающий пакет, убрать неиспользуемую переменную, обернуть в if err != nil, извлечь функцию. Список зависит от сервера и позиции курсора.

Код: Выделить всё

// Было: используется fmt.Println, но import "fmt" отсутствует - ошибка
// Нажимаем: gra -> выбираем "Add import: fmt"
// Стало: в блок import добавлена строка "fmt", ошибка исчезла
Диагностика: vim.diagnostic

Диагностика - это ошибки, предупреждения и подсказки, которые сервер присылает по мере анализа кода. Управляет ими отдельный встроенный модуль vim.diagnostic (он работает не только с LSP, но и с линтерами).
Подводный камень 0.11. После апгрейда virtual_text (текст ошибки прямо в строке) стал opt-in - то есть выключен по умолчанию. Это частая жалоба "диагностика сломалась после обновления". На самом деле её просто надо включить.
Рекомендуемый осознанный конфиг 2026:

Код: Выделить всё

vim.diagnostic.config({
  virtual_text = true,          -- текст ошибки в конце строки
  -- альтернатива: virtual_lines = { current_line = true }
  --   (разворачивает многострочную диагностику под текущей строкой)
  severity_sort = true,         -- сортировать по важности
  underline = true,
  update_in_insert = false,     -- не дёргать диагностику при наборе
  float = { border = 'rounded' },
  signs = {
    text = {
      [vim.diagnostic.severity.ERROR] = 'E',
      [vim.diagnostic.severity.WARN]  = 'W',
      [vim.diagnostic.severity.HINT]  = 'H',
      [vim.diagnostic.severity.INFO]  = 'I',
    },
  },
})
Доступные хендлеры: virtual_text, virtual_lines (новый в 0.11, диагностика отдельными строками), signs (значки в gutter), underline. Полезные функции и клавиши:

Код: Выделить всё

Команда / клавиша            |  Действие
-----------------------------+----------------------------------------------------
[d / ]d                      |  Предыдущая / следующая диагностика
vim.diagnostic.open_float()  |  Показать полный текст ошибки под курсором в окне
vim.diagnostic.setqflist()   |  Сбросить все диагностики в quickfix (см. главу 14)
vim.diagnostic.setloclist()  |  То же в location list текущего окна
Связка с quickfix особенно мощна: :lua vim.diagnostic.setqflist() соберёт все ошибки проекта в один список, по которому можно методично пройтись через :cnext/:cprev.

Форматирование: conform.nvim, а не LSP напрямую

Многие серверы умеют форматировать код (textDocument/formatting). Базовая ручная команда форматирования через LSP - vim.lsp.buf.format() (например, :lua vim.lsp.buf.format() или маппинг на неё); она просит активный сервер отформатировать текущий буфер. Но полагаться на LSP-форматирование напрямую - источник классической боли: двойное форматирование, когда и LSP-сервер, и отдельный форматтер дерутся за файл, переставляя кавычки туда-сюда.

Практика 2026: вынести форматирование в conform.nvim - тонкий слой, на котором сошлась почти вся экосистема (он заменил устаревший null-ls/none-ls). Вы явно назначаете один форматтер на язык, и conform при необходимости глушит LSP-форматтер.

Код: Выделить всё

{
  'stevearc/conform.nvim',
  event = 'BufWritePre',
  opts = {
    formatters_by_ft = {
      lua = { 'stylua' },
      python = { 'ruff_format' },
      javascript = { 'prettierd', 'prettier', stop_after_first = true },
      go = { 'goimports', 'gofmt' },
    },
    format_on_save = {
      -- современный ключ: lsp_format = 'fallback'
      -- (старый lsp_fallback = true ещё работает как deprecated-алиас)
      lsp_format = 'fallback',  -- если форматтера нет - упасть на LSP
      timeout_ms = 1000,
    },
  },
}
Принцип single owner: на каждый язык - ровно один владелец форматирования. Если форматирует conform, отключите documentFormattingProvider у LSP-сервера (это можно сделать в LspAttach, см. ниже), чтобы они не конфликтовали.

Inlay hints: подсказки прямо в коде

Inlay hints - это виртуальные аннотации, которые сервер вставляет в текст: имена параметров в вызовах, выведенные типы переменных. Доступны с Neovim 0.10+.

Код: Выделить всё

// Без hints:                          // С hints (виртуальный текст, серым):
result := compute(10, true)            result := compute(width: 10, verbose: true)
nums := []int{1, 2, 3}                 nums : []int := []int{1, 2, 3}
Включаются так (под проверкой, что сервер поддерживает метод):

Код: Выделить всё

vim.lsp.inlay_hint.enable(true)  -- глобально включить
Хинты визуально шумны при чтении, поэтому хорошая практика - повесить тоггл:

Код: Выделить всё

vim.keymap.set('n', '<leader>uh', function()
  vim.lsp.inlay_hint.enable(not vim.lsp.inlay_hint.is_enabled())
end, { desc = 'Toggle inlay hints' })
Маппинги через LspAttach: правильный паттерн

Где вешать собственные LSP-маппинги и включать фичи вроде inlay hints? Не в on_attach каждого сервера (это легаси-стиль), а в одном autocommand-событии LspAttach, которое срабатывает буфер-локально при подключении любого сервера.

Код: Выделить всё

vim.api.nvim_create_autocmd('LspAttach', {
  group = vim.api.nvim_create_augroup('my.lsp', { clear = true }),
  callback = function(args)
    local client = vim.lsp.get_client_by_id(args.data.client_id)
    local buf = args.buf
    local map = function(keys, fn, desc)
      vim.keymap.set('n', keys, fn, { buffer = buf, desc = desc })
    end

    -- свои привычные раскладки поверх дефолтов 0.11
    map('gd', vim.lsp.buf.definition, 'Go to definition')
    map('gD', vim.lsp.buf.declaration, 'Go to declaration')
    map('<leader>ca', vim.lsp.buf.code_action, 'Code action')

    -- включаем фичи только если сервер их поддерживает
    if client and client:supports_method('textDocument/inlayHint') then
      vim.lsp.inlay_hint.enable(true, { bufnr = buf })
    end

    -- single owner форматирования: глушим LSP-форматтер,
    -- если форматированием владеет conform
    if client then
      client.server_capabilities.documentFormattingProvider = false
    end
  end,
})
Ключевые приёмы здесь:
  • Маппинги буфер-локальны (buffer = buf) - они появляются только там, где есть сервер.
  • Перед включением фичи всегда проверяем client:supports_method(...) - иначе на серверах без поддержки (например, inlay hints) получите ошибки или мусор.
  • augroup с clear = true - чтобы при перечитывании конфига autocommand не дублировался (см. главу 20).
Neovim 0.12: что нового в LSP

Версия 0.12 (29 марта 2026) ещё расширила нативный LSP:
  • Новая интерактивная команда :lsp - нативная команда управления LSP-клиентами с подкомандами (старт, стоп, рестарт клиентов). Важно не путать: одноимённые :LspInfo/:LspRestart/:LspLog/:LspStart/:LspStop встроенными в ядро никогда не были - их предоставлял плагин nvim-lspconfig, а теперь они оттуда удалены. Их функции покрываются так: управление клиентами (старт/стоп/рестарт) - подкомандами нативной :lsp, а :LspInfo сводится к :checkhealth vim.lsp.
  • Событие LspProgress - прогресс индексации сервера можно показать в статусной строке.
  • Встроенная поддержка расширения выделения через selectionRange (сам LSP-метод textDocument/selectionRange не нов, новизна 0.12 - нативная встроенная поддержка умного расширения выделения, в т.ч. через LSP/treesitter). Это альтернатива incremental selection из nvim-treesitter (см. главу 27): она может её заменить, но не автоматически - результат зависит от сервера/конфигурации. Плюс поддержка методов inlineCompletion, linkedEditingRange, documentLink, semantic tokens только для видимой области (быстрее на больших файлах).
  • Нативное автодополнение в insert-режиме (опция 'autocomplete', пока экспериментальная) и встроенный LSP-омникомплит через vim.lsp.completion.enable() - про автодополнение подробно в главе 26.
Лучшие практики 2026
  1. Используйте нативный vim.lsp.config / vim.lsp.enable, а не require('lspconfig').xxx.setup{}. Старый путь выдаёт deprecation-warning и будет удалён в nvim-lspconfig v3.0.0. Не смешивайте подходы - это приводит к дублированию и конфликтам конфигов.
  2. Храните переопределения серверов в ~/.config/nvim/lsp/<server>.lua - один файл на сервер. Чисто, модульно, автоматически подхватывается из runtimepath.
  3. Общие настройки - через vim.lsp.config('*', {...}), а маппинги и фичи - через autocommand LspAttach с проверкой client:supports_method(). Не пишите on_attach в каждом сервере.
  4. Не дублируйте дефолтные маппинги 0.11 (grn, gra, grr, gri, grt, gO, K, <C-s>). Они уже встроены - добавляйте только то, чего не хватает (gd).
  5. Включите virtual_text осознанно - после 0.11 он opt-in. Рассмотрите virtual_lines с current_line = true для разворота многострочных диагностик.
  6. Один владелец форматирования на язык. Вынесите форматирование в conform.nvim и глушите documentFormattingProvider у LSP, чтобы не было двойного форматирования.
  7. С mason-lspconfig 2.0 доверьтесь automatic_enable - не вызывайте vim.lsp.enable() повторно вручную для тех же серверов.
  8. Inlay hints - под тоггл. Они полезны, но шумны; держите клавишу для быстрого включения/выключения.
  9. Задавайте root_markers явно (хотя бы { '.git' }), особенно если не используете дефолты nvim-lspconfig.
Частые ошибки
Первый шаг диагностики: проверить, что вообще прикреплено. Прежде чем чинить "не работает LSP", узнайте, какой сервер привязан к буферу и привязан ли вообще. Способы:
- :checkhealth vim.lsp - главный отчёт о состоянии LSP (на 0.12 сюда же сводится :LspInfo): какие клиенты активны, их cmd, корень проекта, поддерживаемые методы, найден ли исполняемый файл сервера в PATH.
- :lua =vim.lsp.get_clients({ bufnr = 0 }) - показать клиентов, прикреплённых к текущему буферу (пустой список = сервер не стартовал; типичные причины: не установлен сервер, не тот filetype, не совпал root_markers).
- :lsp (0.12) - нативная команда: посмотреть и перезапустить/остановить/запустить клиентов.
- :lua vim.lsp.set_log_level('debug') + :lua vim.cmd('e ' .. vim.lsp.get_log_path()) - заглянуть в лог, если сервер падает на старте.
Этот навык важнее любого конкретного фикса: 90% проблем ("нет автодополнения", "go-to-definition молчит") сводятся к "сервер не прикреплён", и :checkhealth vim.lsp сразу показывает почему.
  • require('lspconfig').gopls.setup{} на 0.11+. Легаси-путь, выдаёт предупреждение и сломается в v3.0.0. Мигрируйте на vim.lsp.config + vim.lsp.enable.
  • Двойной запуск сервера. mason-lspconfig 2.0 сам делает vim.lsp.enable(). Если вы ещё и вручную включаете тот же сервер - он стартует дважды, конфиги конфликтуют.
  • Копирование старого Mason-гайда с setup_handlers()/handlers. В Mason 2.0 эти опции удалены - конфиг тихо не работает.
  • "Пропала подсветка ошибок". На 0.11 virtual_text стал opt-in. Это не баг - добавьте vim.diagnostic.config({ virtual_text = true }).
  • Двойное форматирование. И LSP-сервер, и conform форматируют файл, переставляя код туда-сюда. Назначьте единственного владельца на язык.
  • Inlay hints без проверки поддержки. Вызов vim.lsp.inlay_hint.enable(true) на сервере без textDocument/inlayHint даёт ошибки. Проверяйте client:supports_method(...).
  • Неверный корень проекта. Без root_markers сервер может не увидеть go.mod/Cargo.toml/package.json и работать "наполовину". Задайте маркеры явно.
  • gd ведёт себя странно. Без забинденного vim.lsp.buf.definition клавиша gd делает встроенное Vim-действие (переход к локальному определению по тексту), а не LSP-переход. Это разные вещи.
Упражнения
  1. Минимальный LSP без плагинов. Установите системно один сервер (например, lua-language-server или gopls). В чистом init.lua пропишите только vim.lsp.enable({'lua_ls'}) (или gopls) и убедитесь, что K, grn, grr работают - без nvim-lspconfig и Mason.
  1. Каталог lsp/. Создайте ~/.config/nvim/lsp/lua_ls.lua, возвращающий таблицу с settings.Lua.diagnostics.globals = {'vim'}. Проверьте, что предупреждение "undefined global vim" в вашем конфиге исчезло, а в init.lua остался только vim.lsp.enable.
  1. Свой LspAttach. Напишите autocommand на LspAttach, который вешает буфер-локальные gd (definition) и <leader>ca (code action), и включает inlay hints только при наличии поддержки. Откройте файл с сервером и без - убедитесь, что маппинги появляются лишь там, где есть LSP.
  1. Диагностика в quickfix. В проекте с несколькими ошибками выполните :lua vim.diagnostic.setqflist() и пройдитесь по ошибкам через :copen, :cnext, :cprev. Сравните с прыжками ]d/[d - когда удобнее каждый способ?
  1. Тоггл virtual_lines. Настройте vim.diagnostic.config и сделайте клавишу, которая переключает диагностику между virtual_text = true и virtual_lines = { current_line = true }. Прочувствуйте разницу на длинном сообщении об ошибке.
  1. Single owner форматирования. Подключите conform.nvim с форматтером для одного языка и в LspAttach отключите documentFormattingProvider у LSP. Сохраните файл с намеренно "кривым" отступом и убедитесь, что форматирует именно conform, а не сервер.
Главное из главы
  • LSP разделяет редактор и понимание языка: языковой сервер анализирует код, Neovim как клиент общается с ним по стандартному протоколу.
  • В Neovim 0.11+ LSP-клиент нативный. Канонический способ - vim.lsp.config('сервер', {...}) для настройки и vim.lsp.enable({...}) для активации; конфиги удобно держать пофайлово в ~/.config/nvim/lsp/.
  • nvim-lspconfig теперь каталог дефолтов, а не фреймворк; старый setup{} устарел. mason.nvim ставит серверы, mason-lspconfig 2.0 авто-включает их (automatic_enable).
  • Базовые маппинги (K, grn, gra, grr, gri, grt, gO, <C-s>, [d/]d) встроены - не переизобретайте их, добавляйте только своё через LspAttach.
  • Диагностика живёт в vim.diagnostic; virtual_text стал opt-in - включайте осознанно. Форматирование выносите в conform.nvim (single owner). Inlay hints включайте под проверкой поддержки и под тоггл.
  • Дальше: автодополнение поверх LSP - глава 26; точная подсветка и структурное редактирование через Treesitter - глава 27.
👍1 ❤️1 🔥2 😄 🤔
✔ Лучший ответ сформирован автоматически — nicknut
Roman_Vim писал(а):при использовании mason-lspconfig 2.0 вам не нужно дополнительно вызывать vim.lsp.enable() вручную вот тут и был мой косяк. gopls стартовал дважды, в checkhealth два клиента висели и code action дублировались. убрал свой enable, оставил automatic_enable - все встало на место
Перейти к ответу →
Аватара пользователя
rawdruid
Сообщения: 1
Зарегистрирован: 15 май 2026, 11:27

Re: LSP в Neovim: умные возможности языка

Сообщение rawdruid »

вот про opt-in virtual_text прям в точку. после обновления на 0.11 думал что у меня ts или сам нвим сломался, ошибки перестали показываться в строке. оказалось просто надо vim.diagnostic.config({ virtual_text = true }) дописать. полдня убил пока не дошло
👍1 ❤️3 🔥 😄 🤔
Аватара пользователя
nicknut
Сообщения: 1
Зарегистрирован: 04 июн 2026, 05:13

Re: LSP в Neovim: умные возможности языка

Сообщение nicknut »

✔ Лучший ответ — сформирован автоматически
Roman_Vim писал(а):при использовании mason-lspconfig 2.0 вам не нужно дополнительно вызывать vim.lsp.enable() вручную
вот тут и был мой косяк. gopls стартовал дважды, в checkhealth два клиента висели и code action дублировались. убрал свой enable, оставил automatic_enable - все встало на место
👍 ❤️ 🔥 😄 🤔
Аватара пользователя
popeye00
Сообщения: 1
Зарегистрирован: 07 июн 2026, 01:23

Re: LSP в Neovim: умные возможности языка

Сообщение popeye00 »

а grn это вообще лучшее что есть в нвиме имхо. раньше через :%s переименовывал и постоянно ловил переименованную строку в комментах или в чужой области. теперь grn и спокоен
👍1 ❤️ 🔥1 😄 🤔1
Аватара пользователя
madghost
Сообщения: 1
Зарегистрирован: 13 май 2026, 19:05

Re: LSP в Neovim: умные возможности языка

Сообщение madghost »

Подскажите, а root_markers через звездочку vim.lsp.config('*', { root_markers = {'.git'} }) не перебивает дефолтные маркеры от lspconfig? у меня монорепа, боюсь что gopls перестанет go.mod видеть и схватит корень репы вместо модуля
👍 ❤️2 🔥 😄 🤔2
Аватара пользователя
linuxadmin
Сообщения: 1
Зарегистрирован: 11 май 2026, 13:09

Re: LSP в Neovim: умные возможности языка

Сообщение linuxadmin »

спасибо за таблицу с дефолтными маппингами, наконец понял почему мой gd ведет себя странно - он же не лезет в lsp без бинда, делает старое вимовское. повесил vim.lsp.buf.definition и заработало
👍 ❤️ 🔥 😄 🤔
Аватара пользователя
kafkawhale
Сообщения: 1
Зарегистрирован: 26 май 2026, 05:27

Re: LSP в Neovim: умные возможности языка

Сообщение kafkawhale »

лайфхак закину: вместо virtual_text повесил тоггл на virtual_lines current_line. в обычном режиме чисто, а когда встаю на строку с ошибкой - разворачивается полный текст под ней. на длинных тайпскрипт ошибках просто спасение, они в одну строку не лезут
👍 ❤️ 🔥 😄 🤔
Ответить
← Предыдущая глава
Neovim в 2026: чем отличается и почему выбирают
Следующая глава →
Автодополнение 2026: blink.cmp против nvim-cmp

Все главы курса «Vim и Neovim: модальное редактирование от основ до современного Neovim»

Поделиться темой: ✈ Telegram VK
  • Похожие темы

Вернуться в «Vim и Neovim: модальное редактирование от основ до Neovim 2026»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость