Gopls: Реализация

Последнее крупное обновление: 16 января 2024

В данном документе представлена высокоуровневая структура gopls, чтобы помочь новым участникам ориентироваться в проекте. Он не предназначен для полного описания реализации, а также даже ключевых компонентов; для этого лучше обратиться к документации пакетов (ссылки ниже) и другим комментариям внутри кода.

Диаграмма ниже показывает выбранные компоненты модуля gopls и их взаимосвязи согласно графу импортов Go. Тесты и инфраструктура тестов не показаны, а также вспомогательные пакеты и пакеты из модуля x/tools. Для краткости пакеты обозначены последним сегментом их названия, который обычно является однозначным.

Высота каждого блока соответствует его технической глубине. Некоторые блоки широкие и мелкие, такие как protocol, который определяет стандартный протокол; он в основном генерируется механически из схемы, предоставленной Microsoft. Самый важный тип — DocumentURI, который представляет file: URL, идентифицирующий документ в клиентском редакторе. Также предоставляется Mapper, который отображает между различными системами координат, используемыми для позиций в исходном коде: UTF-8, UTF-16 и token.Pos.

Далее идут важные и широко используемые структуры данных:

  • Пакет file определяет основные абстракции клиента файла: его Identity (URI и хэш содержимого), а также Handle (который дополнительно предоставляет версию и содержимое конкретного снимка файла).

  • Пакет parsego определяет File — разобранную форму Go-файла, включая его содержимое, синтаксическое дерево и отображения координат (Mapper и token.File). Пакет выполняет различные виды восстановления дерева, чтобы компенсировать недостатки обработки ошибок парсера Go.

  • Пакет metadata определяет Package — абстракцию метаданных Go-пакета, аналогичную выводу go list -json. Метаданные создаются из go/packages, который заботится о вызове go list. (Пользователи сообщают, что он работает в какой-то степени с GOPACKAGESDRIVER для Bazel, хотя мы не поддерживаем тесты для этой сценарии.)

    Пакет также предоставляет Graph — полный граф импортов для рабочей области; каждый узел графа — это Package.

Слой settings определяет структуру данных (по сути, большой деревянный объект) для параметров конфигурации gopls, а также его JSON-кодирование.

Слой cache является самым большим и сложным компонентом gopls. Он отвечает за управление состоянием, анализ зависимостей и инвалидацию: Session — сеанс связи с клиентом; Folder — папки, открытые клиентом; View — представление конкретного дерева рабочей области с определёнными параметрами сборки; Snapshot — состояние всех файлов в рабочей области после определённой операции редактирования; содержимое всех файлов, будь то сохранённые на диск (DiskFile) или отредактированные и несохранённые (Overlay); Cache — кэш вычислений в памяти с мемоизацией, например, разбор go.mod файлов или построение индекса символов; и Package, который содержит результаты проверки типов пакета из синтаксиса Go.

Слой кэша зависит от различных вспомогательных пакетов, включая:

Кэш также определяет драйвер go/analysis gopls, который выполняет модульный анализ (похожий на go vet) по всей рабочей области. gopls также включает несколько анализов, которые не являются частью go vet.

Следующий слой определяет четыре пакета, каждый из которых обрабатывает файлы определённого языка: mod для go.mod файлов; work для go.work файлов; template для файлов в синтаксисе text/template; и golang, для файлов на самом Go. Этот пакет, безусловно, самый большой, предоставляет основные функции gopls: навигацию, анализ и рефакторинг Go-кода. Как представляют себе большинство пользователей, этот пакет и есть gopls.

Пакет server определяет реализацию службы LSP, при этом для каждого типа запроса LSP предусмотрен свой метод-обработчик. Каждый обработчик переключается по типу файла и передаёт управление одному из четырёх языковых специфичных пакетов.

Пакет lsprpc обеспечивает связь между интерфейсом службы и нашим сервером jsonrpc2.

Следует учитывать, что диаграмма представляет собой граф зависимостей — «статическую» точку зрения на структуру программы. Более динамическая точка зрения упорядочила бы пакеты по последовательности их обнаружения во время обработки конкретного запроса; в таком представлении нижний уровень представлял бы «канал» (протокол и команда), следующий уровень включал бы пакеты, связанные с RPC (lsprpc и server), а функциональные возможности (например, golang, mod, work, template) находились бы на верхнем уровне.

Пакет cmd определяет интерфейс командной строки команды gopls, вокруг которого основной пакет gopls является всего лишь тривиальной обёрткой. Обычно команда запускается без аргументов, что приводит к запуску сервера и его постоянному ожиданию подключений. Также она предоставляет ряд субкоманд, которые запускают сервер, выполняют один запрос к нему и завершаются, обеспечивая традиционный пакетный доступ к функциональности сервера. Эти субкоманды в основном предоставляются в качестве средства отладки; однако см. https://go.dev/issue/63693.


Исходные файлы этой документации можно найти в golang.org/x/tools/gopls/doc.

GoRu.dev Golang на русском

На сайте представлена адаптированная под русский язык документация языка программирования Golang