Написать свой Language Server с нуля на Go сложно. Нужно разобраться с JSON-RPC фреймингом, маршрутизацией сообщений, типами LSP, управлением жизненным циклом соединения. И всё это до того, как начнёшь писать саму языковую логику.
go-lsp берёт всё это на себя. Библиотека реализует LSP 3.17 и даёт чистый интерфейс, где вы просто описываете, что ваш сервер умеет делать.
go-lsp состоит из трёх пакетов. jsonrpc отвечает за JSON-RPC 2.0 поверх io.ReadWriteCloser. lsp содержит Go-типы для всех структур протокола, без логики. server связывает всё вместе: принимает хендлер, смотрит какие интерфейсы он реализует и автоматически регистрирует соответствующие LSP-методы.
Устанавливаем:
go get github.com/owenrumney/go-lsp
Минимальный сервер с поддержкой hover:
package main
import (
"context"
"os"
"github.com/owenrumney/go-lsp/lsp"
"github.com/owenrumney/go-lsp/server"
)
type Handler struct{}
func (h *Handler) Initialize(ctx context.Context, params *lsp.InitializeParams) (*lsp.InitializeResult, error) {
return &lsp.InitializeResult{
Capabilities: lsp.ServerCapabilities{
HoverProvider: &lsp.HoverOptions{},
},
}, nil
}
func (h *Handler) Shutdown(ctx context.Context) error {
return nil
}
func (h *Handler) Hover(ctx context.Context, params *lsp.HoverParams) (*lsp.Hover, error) {
return &lsp.Hover{
Contents: lsp.MarkupContent{
Kind: lsp.MarkupKindMarkdown,
Value: "Hello from the server",
},
}, nil
}
func main() {
srv := server.NewServer(&Handler{})
if err := srv.Run(context.Background(), server.RunStdio()); err != nil {
os.Exit(1)
}
}
Сервер сам понимает, что хендлер поддерживает hover, потому что он реализует интерфейс HoverHandler. Вручную регистрировать методы не нужно. Хотите добавить completion — реализуйте CompletionHandler.
Обязательный интерфейс только один — LifecycleHandler с методами Initialize и Shutdown. Всё остальное реализуете по мере необходимости.
➡️ Репозиторий
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека Go-разработчика