Files
qode/docs/lsp.md
T
2026-10-31 15:33:00 +03:00

5.9 KiB

LSP-серверы — api.editor

Запуск серверов целиком настраивается Lua-сценарием. Редактор предоставляет только клиент по stdio, синхронизацию документов и доставку диагностики.

Запуск сервера

api.editor:run_lsp({
  name = "gopls",                  -- условное имя для stop/restart
  cmd = "gopls",                   -- путь к бинарнику или имя в PATH
  args = { "serve" },              -- аргументы процесса
  env = { GOFLAGS = "-mod=mod" },  -- переменные окружения
  languages = { "go" },            -- какие languageId обслуживает
  watcher = "**/*.go",             -- шаблон файлового вотчера
  root = ".",                      -- корень workspace (по умолчанию cwd)
  initialization_options = {},     -- initializationOptions сервера
})
Метод Описание
api.editor:run_lsp(config) Запустить сервер по описанию
api.editor:lsp_servers() Имена запущенных серверов: { "gopls", ... }
api.editor:stop_lsp("gopls") Остановить сервер; true, если сервер был запущен
api.editor:restart_lsp("gopls") Перезапустить сервер с прежними настройками
api.editor:on_lsp_diagnostics(delay_ms, fn) Обработчик диагностики всех серверов; nil вместо fn удаляет его

cmd обязателен. Если root не задан или относителен, он отсчитывается от текущего рабочего каталога процесса. Поле watcher принимает строку, таблицу или boolean:

watcher = "**/*.go"
watcher = { pattern = "**/*.go", ignore = { "vendor/**" } }
watcher = true   -- все файлы, игнорируя только стандартные каталоги сборки

--config меняет только каталог init.lua, поэтому root = "." указывает на текущий каталог запуска — проект должен быть текущим рабочим каталогом.

Автодополнение и подсказки

Автодополнение включается само при вводе идентификатора; Ctrl/Cmd+Space открывает список вручную. Поведение клавиш описано в keymap.md и может быть переопределено через api.keymap:map_completion_key. Документация выбранного элемента показывается второй всплывающей панелью справа от списка. Наведение мыши показывает Markdown-документацию символа.

Диагностику, которую сервер присылает после правок, редактор подчёркивает волнистой линией: ошибки — красной, предупреждения и остальные сообщения — жёлтой. Подчёркивание работает и при выключенной подсветке синтаксиса.

Обработчик диагностики

api.editor:on_lsp_diagnostics(delay_ms, fn) регистрирует один обработчик на все LSP-серверы. delay_ms — пауза тишины: если сообщения приходят чаще, вызовы пропускаются, а обработчик получает последний снимок после того, как обновления прекратились. Если зарегистрировать обработчик, когда диагностика уже накоплена, он сработает сразу после этой паузы.

api.editor:on_lsp_diagnostics(1000, function(servers)
  for _, entry in ipairs(servers) do
    print(entry.server, entry.path, #entry.diagnostics)
  end
end)

servers — массив записей по одной на пару «документ, сервер»:

{
  server = "gopls",                  -- имя сервера, приславшего диагностику
  uri = "file:///project/main.go",    -- URI документа
  path = "/project/main.go",         -- путь файла; nil для не-file URI
  diagnostics = {
    {
      line = 0, character = 2,        -- начало (с нуля, как в LSP)
      end_line = 0, end_character = 8,
      severity = 1,                   -- 1 ошибка, 2 предупреждение, 3 info, 4 hint
      severity_name = "error",        -- error | warning | information | hint
      message = "undefined: foo",
      source = "gopls",
      code = "UndeclaredName",
      tags = {},                      -- unnecessary, deprecated
    },
  },
}

Позиции нумеруются с нуля; для отображения прибавляйте единицу к line и character. Остановка сервера удаляет его сообщения из следующих снимков.

Пример из init.lua с защитой от ошибки запуска:

local gopls_ok, gopls_err = pcall(function()
  api.editor:run_lsp({
    name = "gopls",
    cmd = "gopls",
    args = { "serve" },
    root = ".",
    languages = { "go" },
    watcher = { pattern = "**/*.go", ignore = { "vendor/**" } },
    initialization_options = {
      usePlaceholders = true,
      completeUnimported = true,
    },
  })
end)
if not gopls_ok then
  print("[lsp] gopls не запущен: " .. tostring(gopls_err))
end