Gopls: Дизайн
Заметка от будущего
Ниже приведён оригинальный документ по дизайну gopls, собранный из различных источников, охватывающих 2018 и 2019 годы. С тех пор все перечисленные ниже функции были реализованы, а также добавлены многие другие. Две первые цели были достигнуты: gopls стал полноценной реализацией LSP и является стандартной backend-системой для VS Code Go и многих других редакторов. Третья цель была реализована лишь частично: хотя gopls получил множество новых возможностей, он не является расширяемым в том смысле, в котором это описано в данном документе: единственным способом расширить gopls остаётся изменение исходного кода gopls. Четвёртая цель не достигнута: хотя некоторые крупные компании способны использовать gopls с Bazel, опыт при этом не идеален, и официально поддерживается только сборочная система Go command.
С другой стороны, две из явно указанных неподдерживаемых целей были переосмыслены. Одна из них — мелкая: подсветка синтаксиса теперь поддерживается в LSP благодаря семантическим токенам. Вторая — более серьёзная: по мере роста популярности gopls стало очевидно, что его использование памяти представляет собой проблему. Размер рабочих пространств разработчиков рос быстрее, чем объём доступной оперативной памяти в типичных средах разработки (особенно при использовании контейнеризованной разработки). В настоящее время gopls использует гибридный подход, сочетающий индексы на диске и кэши в памяти, который подробнее описан в нашей записи в блоге о масштабируемости.
Заметно, что предвидя трудности, описанные в этом документе, оказалось правильным. gopls действительно столкнулся с трудностями, связанными с основными пакетами стандартной библиотеки, на которых он построен, и его пользовательский опыт всё ещё ограничен возможностями LSP. Тем не менее, выбор стандартной библиотеки и LSP был правильным решением, поскольку, несмотря на небольшую команду, эти решения помогли gopls оставаться актуальным по отношению к развивающемуся языку Go (например, дженерикам) и интегрироваться с новыми текстовыми редакторами.
Разработка gopls продолжается, более чем через четыре года, с акцентом на простоту, надёжность и расширяемость. Новый, опциональный Go telemetry поможет нам достичь более высокого уровня стабильности в наших релизах, чем это было возможно только через GitHub issues. Более того, телеметрия позволит нам сосредоточиться на функциях с высоким приоритетом и устаревших обходных путях, которые нагружают кодовую базу. С более высокой скоростью мы с нетерпением ждём возможности работать с сообществом над улучшением рефакторинга, статического анализа и прочего, что принесёт будущее.
- Rob Findley (rfindley@google.com), 2023
Цели
goplsдолжен становиться стандартной backend-системой редакторов для основных редакторов, используемых программистами на Go, полностью поддерживаемых командой Go.goplsбудет полноценной реализацией LSP, как описано в спецификации LSP, чтобы стандартизировать как можно больше его возможностей.goplsбудет чистым и расширяемым, чтобы в будущем можно было добавлять дополнительные функции, позволяя инструментам Go снова стать лучшими в своём классе.goplsбудет поддерживать альтернативные системы сборки и структуры файлов, позволяя разработке на Go быть проще и мощнее в любой среде.
Контекст
Хотя у Go есть множество отличных и полезных инструментов командной строки, которые улучшают опыт разработки, стало ясно, что интеграция этих инструментов с IDE может вызывать сложности.
Поддержка этих инструментов зависела от добровольности членов сообщества, и они часто несли большую нагрузку по поддержке по мере развития языка, инструментария и среды выполнения. В результате многие инструменты перестали работать, возникли проблемы с поддержкой, появлялись форки и замены, или же предоставляли опыт, который мог быть лучше.
См. раздел ниже о существующих решениях для получения дополнительных проблем и деталей.
Это приемлемо для инструментов, используемых время от времени, но для основных возможностей IDE это неприемлемо.
Автозавершение, переход к определению, форматирование и другие подобные функции должны всегда работать, поскольку они являются ключевыми для разработки на Go.
Команда Go создаст бэкенд редактора, который будет работать в любой системе сборки.
Он также сможет улучшить задержки работы инструментов Go, поскольку каждый инструмент больше не будет отдельно запускать проверку типов при каждом вызове. Вместо этого будет существовать длительно работающий процесс, и данные смогут быть общими между определениями, автозавершением, диагностикой и другими функциями.
Приняв на себя ответственность за эти инструменты и объединив их в виде gopls, команда Go обеспечит, чтобы опыт разработки на Go не был ненужно усложнённым для пользователей Go.
Наличие одного бэкенда редактора упростит жизнь разработчиков Go, команды Go и поддерживаемых плагинов редакторов Go.
См. выступление Ребекки на GopherCon talk и слайды для получения дополнительного контекста.
Нецели
-
Скорость командной строки
Хотя gopls будет иметь режим командной строки, он будет оптимизирован для длительной работы, а не для быстрого отклика, поэтому он может быть не самым подходящим инструментом для таких вещей, как системы CI. Для таких случаев потребуется альтернативный инструмент, использующий те же самые базовые библиотеки для согласованности.
-
Среды с низким объёмом памяти
Чтобы эффективно обрабатывать большие проекты с очень низкой задержкой, gopls будет хранить множество данных в памяти. Предполагается, что разработчики обычно работают на системах с достаточным объёмом оперативной памяти, и это не будет проблемой. В целом это соответствует большому потреблению памяти существующих решений IDE (например, IntelliJ)
-
Подсветка синтаксиса
На данный момент нет редактора, который делегировал бы эту функциональность отдельному двоичному файлу, и нет стандартного способа её реализации.
Существующие решения
Каждый год команда Go проводит опрос, в котором спрашивают разработчиков о их опыте работы с языком.
Одним из вопросов является «Как вы оцениваете свой редактор?».
Ответы рассказали очень негативную историю. Примеры категоризированных цитат:
- Установка
- «Сложно установить и настроить»
- «Недостаточная документация»
- Производительность
- «Производительность очень низкая»
- «Довольно медленно в больших проектах»
- Надёжность
- «Функции работают один день, а на следующий перестают»
- «Инструментарий не обновляется вместе с новыми возможностями языка»
Каждый редактор имеет собственный плагин, который вызывает различные инструменты, многие из которых ломаются при новых релизах Go или потому, что больше не поддерживаются.
Каждый отдельный инструмент должен выполнять работу по пониманию кода и всех его транзитивных зависимостей.
Каждая функция — это отдельный инструмент, с разным набором паттернов для командной строки, разным способом принятия входных данных и разбора вывода, разным способом указания местоположения исходного кода. Чтобы поддерживать существующий набор функций, VSCode установил 24 различных командных инструмента, многие из которых имеют параметры или форки для настройки. При рассмотрении набора инструментов, которые нужно было перенести в модули, во всех редакторах, их оказалось 63 отдельных инструмента.
Все эти инструменты должны понимать код, и они используют одни и те же стандартные библиотеки для этого. Эти библиотеки оптимизированы под такие инструменты, но даже так обработка такого объёма кода занимает много времени. Почти ни один из инструментов не способен возвращать результаты за 100 мс. Пока разработчики печатаются в своём редакторе, активируются несколько из этих функций, что означает, что они не просто платят стоимость один раз, а много раз. В результате общее впечатление от работы в редакторе кажется медлительным, а функции либо не включены, либо иногда выдают результаты настолько медленно, что они становятся бесполезными к моменту их появления. Эта проблема усиливается с увеличением размера кодовой базы, то есть она становится всё хуже со временем, и особенно плохо для крупных кодовых баз, с которыми сталкиваются компании при использовании Go для более важных задач.
Требования
Полный набор функций
Чтобы gopls можно было считать успешным, он должен реализовать полный набор функций, обсужденных ниже. Это набор функций, необходимых пользователям, чтобы чувствовать себя таким же продуктивно, как и раньше, с использованием заменяемого инструментария. Он не включает все функции предыдущих реализаций: некоторые функции почти никогда не используются и должны быть удалены (например, анализ указателей guru), а другие функции не удаётся легко интегрировать и будут решаться обходными путями (замена save hook/linter).
Эквивалентный или лучший опыт
Для всех этих функций пользовательский опыт должен соответствовать или превосходить текущий опыт, доступный во всех редакторах. Это легко сказать, но сложно проверить или измерить. Многие возможные показатели не способны передать опыт.
Например, если была попытка измерить задержку вызова перехода к определению, результаты, скорее всего, были бы довольно стабильными в старом инструменте godef. В реализации gopls же может наблюдаться гораздо более широкий диапазон задержек: лучший случай может быть на порядки быстрее, а худший — лишь немного хуже, поскольку gopls старается выполнять гораздо больше работы, но при этом эффективно кэширует её между вызовами.
Или для вызова автозавершения, оно может быть медленнее, но давать лучшее первое совпадение, что приведёт к тому, что пользователи чаще будут принимать его, в результате чего общее впечатление от использования станет лучше.
В основном всё это должно опираться на отзывы пользователей. Если пользователи отказываются переключаться, потому что опыт не стал лучше, значит, это ещё не сделано. Если же пользователи переходят, но большинство жалуется, то, вероятно, есть достаточно областей, где всё улучшилось, чтобы сделать переход убедительным, но есть и те, где всё хуже. Если же большинство людей переходят и либо молчат, либо остаются довольны, значит, это уже сделано. При создании инструментов, пользователь — это всё.
Надёжное сообщество участников
Объём и масштаб проблемы, которую пытается решить gopls, невозможны для решения командой разработчиков Go в одиночку. Для этого потребуется сильное сообщество, которое сможет реализовать всё это.
Это означает, что код должен быть простым для участия, а также удобным для параллельной работы многих разработчиков. Функциональность должна быть хорошо декомпозирована и иметь полноценную систему тестирования.
Задержки, соответствующие допустимому уровню для пользователя
Существует множество исследований, посвящённых допустимым задержкам для действий пользователя.
Основной вывод, который влияет на gopls, заключается в том, что обратная связь, немедленно реагирующая на непрерывные действия пользователя, должна быть менее 100 мс, чтобы она была незаметной, а всё, что превышает 200 мс, вызывает раздражение у пользователя. Это означает, что в целом цель должна быть установлена на уровне <100 мс для всего, что происходит во время ввода разработчиком. Всегда будут случаи, когда gopls не сможет соответствовать этому сроку, и нужно будет предусмотреть способы сделать пользовательский опыт приемлемым в таких случаях, но в целом цель этого срока — направлять базовый дизайн архитектуры. Любое решение, которое теоретически не сможет соответствовать этой цели в долгосрочной перспективе, является неправильным.
Простота настройки
Разработчики очень требовательны и имеют очень разные предпочтения в своей кодовой среде. gopls должен поддерживать значительную степень гибкости, чтобы удовлетворить эти потребности. Однако, настройки по умолчанию без какой-либо конфигурации должны обеспечивать наилучший опыт для большинства пользователей, и где это возможно, функции должны быть гибкими без необходимости настройки, чтобы клиент мог легко принимать решения о том, как обрабатывать запросы, не меняя способ связи с gopls.
Сложности
Объём данных
- Маленький:
- Средний:
- Большой:
- Корпоративный монорепозиторий: гораздо больше
Анализ и проверка типов большого количества кода довольно затратна, а преобразованные формы занимают много места. Так как gopls должен постоянно обновлять эту информацию во время ввода разработчиком, он должен очень аккуратно управлять кэшированием преобразованных форм, чтобы сбалансировать использование памяти и скорость.
Неверное кэширование
Базовой единицей операции для проверки типов является пакет, но базовой единицей операции для редактора является файл. gopls должен уметь эффективно сопоставлять файлы с пакетами, чтобы при изменении файлов знать, какие пакеты нужно обновить (а также любые другие пакеты, которые зависят от них транзитивно). Это особенно затруднено тем, что изменение содержимого файла может изменить, к каким пакетам он считается принадлежащим (изменяя объявление пакета или build-теги), файл может находиться в нескольких пакетах, а изменения могут быть внесены в файлы без использования редактора, в этом случае редактор не будет уведомлять нас об изменениях.
Неподходящая базовая функциональность
Базовые библиотеки Go (включая go/token, go/ast и go/types) спроектированы для приложений, подобных компилятору. Они больше заботятся о пропускной способности, чем о потреблении памяти, имеют структуры, предназначенные для роста, а затем уничтожения при завершении программы, и не предназначены для работы в случае ошибок в обрабатываемом исходном коде. Также они не имеют возможностей выполнять инкрементальные изменения.
Создание долгосрочной службы, работающей хорошо с этими библиотеками, представляет собой очень большую задачу, но написание новых библиотек потребовало бы гораздо больше усилий и привело бы к значительным долгосрочным затратам, поскольку обе группы библиотек должны были бы поддерживаться. В настоящее время более важно предоставить рабочий инструмент пользователям. В долгосрочной перспективе это решение может потребовать повторного рассмотрения, и новые низкоуровневые библиотеки могут быть единственным способом продолжать продвижение возможностей вперёд.
Возможности системы сборки
gopls должен быть независимым от системы сборки, но он должен использовать систему сборки для выяснения, как файлы сопоставляются с пакетами. При попытке сделать это, даже если функциональность одинакова, затраты (по времени, CPU и памяти) очень различаются и могут значительно повлиять на пользовательский опыт. Разработка того, как gopls взаимодействует с системой сборки, чтобы минимизировать или скрыть эти различия, является сложной задачей.
Build-теги
Система build-тегов в Go довольно мощная и имеет множество вариантов использования. Исходные файлы могут исключать сами себя, используя мощную булеву логику над набором активных тегов. Однако она предназначена для указания набора активных тегов в командной строке, а библиотеки спроектированы так, чтобы справляться только с одной допустимой комбинацией за раз. Также нет способа вычислить набор допустимых комбинаций.
Проверка типов файла требует знания всех других файлов в том же пакете, и этот набор файлов изменяется с помощью build-тегов. Набор экспортируемых идентификаторов пакета также зависит от того, какие файлы входят в пакет, а значит, и от его build-тегов.
Это означает, что даже для файлов или пакетов, у которых нет управления через build-теги, невозможно получить корректные результаты без знания набора build-тегов, которые следует учитывать. Это делает очень трудным получение полезных результатов при просмотре файла.
Возможности, не поддерживаемые LSP
Существуют некоторые вещи, которые было бы хорошо уметь делать, но они не укладываются легко в существующий протокол LSP. Например, отображение информации о потоке управления, автоматические struct-теги, сложные рефакторинги…
Каждая из таких возможностей должна быть тщательно рассмотрена, и либо предложено изменение протокола LSP, либо добавлен способ добавления специфичных для gopls расширений протокола, которые остаются простыми в использовании во всех плагинах редакторов.
Чтобы избежать этого на старте, будут реализованы только основные возможности LSP, поскольку они уже достаточны для выполнения базовых требований, но потенциальные функции должны быть учтены при проектировании основной архитектуры.
Распространение
Обеспечение того, чтобы пользователи использовали правильную версию gopls, станет проблемой. Каждый плагин редактора, вероятно, будет устанавливать инструменты своим способом: некоторые выберут глобальную установку, другие будут хранить свою собственную копию.
Поскольку это новый инструмент, он будет активно развиваться. Если пользователи не будут информированы о том, что они используют устаревшую версию, они столкнутся с проблемами, которые уже были исправлены, что хуже для них, а затем, возможно, будут сообщать об этих проблемах, что будет тратить время у команды gopls. Необходимо создать механизм, позволяющий gopls проверять актуальность версии, а также рекомендовать способ установки актуальной версии.
Отладка проблем пользователей
gopls по сути представляет собой очень состоятельный сервер, работающий на машине разработчика. Его базовая работа затрагивает множество факторов — от среды пользователя до содержимого локального кэша сборки. Данные, над которыми он работает, часто являются конфиденциальными кодовыми базами, которые нельзя делиться.
Все эти обстоятельства делают трудным для пользователей полезное сообщение об ошибке или создание минимального примера воспроизведения.
Нужно обеспечить простые способы для пользователей сообщать доступную информацию, а также способы попытки воспроизведения проблем без использования всего их состояния. Это также необходимо для создания тестов на регрессию.
Основные решения по архитектуре
Существуют некоторые фундаментальные архитектурные решения, которые влияют на большую часть остальной части дизайна инструмента, включая фундаментальные компромиссы, которые влияют на пользовательский опыт.
Время жизни процесса: управляется редактором
Обработка большого кода для полной проверки типов и последующего анализа в рамках требуемых временных рамок невозможна, и это одна из основных проблем существующих решений. Это остается справедливым даже в том случае, если вычисленная информация кэшируется на диске, поскольку запуск анализаторов и проверяющих программ все равно требует полного AST всех файлов в графе зависимостей. Теоретически можно добиться лучшего результата, но только при значительной переработке существующих библиотек парсинга и проверки типов, что в настоящее время невозможно.
Это означает, что gopls должен быть долгоживущим процессом, способным кэшировать и предварительно вычислять результаты в памяти, чтобы при поступлении запроса он мог быстро предоставить ответ.
Он может работать как демон на машине пользователя, но при этом возникает множество проблем с управлением демоном. Возможно, это и правильный выбор в долгосрочной перспективе, и в архитектуре следует учитывать такую возможность, но на начальном этапе будет использоваться процесс, который работает столько же, сколько и редактор, запустивший его, и который может быть легко перезапущен.
Кэширование: в памяти
Постоянные дисковые кэши очень трудно поддерживать и требуют решения множества дополнительных задач. Хотя создание необходимой информации дорогостоящее по сравнению с задержками, необходимыми для обработки запросов, оно довольно незначительно по сравнению со временем запуска редактора, поэтому ожидается, что перестроение информации при перезапуске gopls будет приемлемым.
Преимущество, получаемое от этого, заключается в том, что gopls становится безсостоятельным между перезапусками, то есть если у него возникают проблемы или оно путается в своём состоянии, простой перезапуск часто решает проблему. Это также означает, что при сообщении пользователем о проблемах не требуется вся информация из кэша на диске для диагностики и воспроизведения проблемы.
Обмен данными: stdin/stdout JSON
Спецификация LSP определяет JSON-сообщения, которые обычно используются, но она не определяет, как должны передаваться эти сообщения, и существуют реализации LSP, которые не используют JSON (например, в качестве альтернативы можно использовать Protocol buffers).
Ограничения для gopls заключаются в том, что он должен быть легко интегрируемым в любой редактор на всех операционных системах, и не должен иметь больших внешних зависимостей.
JSON входит в стандартную библиотеку Go и является родным языком LSP, поэтому он наиболее логичен. Безусловно, лучшей поддерживаемой механикой обмена является стандартный ввод и вывод процесса, и все распространённые клиентские реализации имеют способы использования JSON rpc 2 в этом режиме. В Go не было полных реализаций протокола с низкой зависимостью, но он представляет собой довольно простой протокол поверх библиотеки JSON, который можно реализовать с умеренными усилиями и который в любом случае будет полезной библиотекой.
В будущем планируется запускать gopls в отдельном клиент-серверном режиме, поэтому написание его таким образом, чтобы он мог использовать сокеты вместо stdin/stdout с самого начала, было лучшим способом обеспечить возможность такого перехода. Это также оказалось очень полезным при отладке: можно было запускать сервер gopls вручную и отлаживать его вне редактора.
Запуск других инструментов: нет
Возможности
Существует набор возможностей, которые gopls должен предоставлять, чтобы стать полноценным IDE-решением. Ниже приведён минимальный набор возможностей, а также существующие решения и то, как они должны отображаться в LSP.
Инспекция
Возможности инспекции предоставляют разработчикам информацию о коде во время его написания. Они не вносят и не предлагают изменения.
| Диагностика | Результаты статического анализа кода, включая ошибки компиляции и lint |
|---|---|
| Требования | Полный запуск go/analysis, который требует полной AST, информации о типах и SSA |
| LSP | textDocument/publishDiagnostics |
| Предыдущие решения | go build, go vet, golint, errcheck, staticcheck |
| Это одна из самых важных возможностей IDE, позволяющая быстро получать обратную связь, не запуская компиляторы и проверяющие утилиты в терминале. Часто используется для отображения списков проблем, маркеров в обрамлении и подчеркивания ошибок в IDE. Для пользователей необходимо предусмотреть возможность настройки набора проверок, желательно без необходимости перекомпиляции основного двоичного файла LSP. |
| Hover | Информация о коде под курсором |
|---|---|
| Требования | AST и информация о типах для файла и всех зависимостях |
| LSP | textDocument/hover |
| Предыдущие решения | godoc, gogetdoc |
| Используется при чтении кода для отображения информации, известной компилятору, но не всегда очевидной из самого кода. Например, может возвращать типы идентификаторов или документацию. |
| Помощь по сигнатуре | Информация о параметрах функции и документация |
|---|---|
| Требования | AST и информация о типах для файла и всех зависимостях |
| LSP | textDocument/signatureHelp |
| Предыдущие решения | gogetdoc |
| При вводе вызова функции в коде полезно знать параметры этого вызова, чтобы разработчик мог корректно его вызвать. |
Навигация
Возможности навигации предназначены для того, чтобы облегчить разработчику ориентацию в кодовой базе.
| Определение | Выберите идентификатор и перейдите к коду, в котором был определён этот идентификатор. |
|---|---|
| Требования | Полная информация о типах для файла и всех зависимостях |
| LSP | textDocument/declaration |
textDocument/definition |
|
textDocument/typeDefinition |
|
| Предыдущее решение | godef |
| Запрос на открытие места, где был определён символ, является одним из самых часто используемых инструментов навигации по коду внутри IDE. Особенно это полезно при изучении не знакомой кодовой базы. Из-за ограничений выходных данных компилятора, невозможно использовать бинарные данные для выполнения этой задачи (конкретно, они не содержат информацию о столбцах), поэтому необходимо производить разбор исходного кода. |
| Реализация | Сообщает типы, реализующие интерфейс |
|---|---|
| Требования | Полное знание типов в рабочей области |
| LSP | textDocument/implementation |
| Предыдущее решение | impl |
| Эта функция сложно масштабируется на большие кодовые базы и требует тщательного подхода к реализации. Возможно, временно будет осуществимо реализовать более ограниченную форму этой функции. |
| Символы документа | Предоставляет набор символов верхнего уровня в текущем файле. |
|---|---|
| Требования | Только AST текущего файла |
| LSP | textDocument/documentSymbol |
| Предыдущее решение | go-outline, go-symbols |
| Используется для работы таких функций, как режим структуры документа. |
| Ссылки | Найти все ссылки на символ под курсором. |
|---|---|
| Требования | AST и информация о типах для обратной транзитивной оболочки |
| LSP | textDocument/references |
| Предыдущий инструмент | guru |
| Для этого требуется знание всех пакетов, которые могут зависеть от любых пакетов, частью которых является текущий файл. Ранее это реализовывалось либо с использованием глобальных знаний, что не масштабируется, либо путем указания "области видимости", что вводило пользователей в заблуждение до такой степени, что они просто не использовали инструменты. gopls, вероятно, в долгосрочной перспективе потребует более мощного решения, но для начала автоматическое ограничение области может дать приемлемые результаты. Это, вероятно, будет модуль, если он известен, или какой-то разумный родительский каталог в противном случае. |
| Сворачивание | Сообщить логические иерархии блоков |
|---|---|
| Требования | Только AST текущего файла |
| LSP | textDocument/foldingRange |
| Предыдущий инструмент | go-outline |
| Обычно используется для предоставления функциональности раскрытия и сворачивания в редакторах. |
| Выделение | Сообщить области логического выделения вокруг курсора |
|---|---|
| Требования | Только AST текущего файла |
| LSP | textDocument/selectionRange |
| Предыдущий инструмент | guru |
| Используется в функциях редактора, таких как расширение выделения. |
Помощь при редактировании
Эти функции предлагают или применяют правки к коду для пользователя, включая функции рефакторинга, для которых существует множество возможных вариантов использования. Рефакторинг — одно из мест, где инструменты Go могут быть потенциально очень сильными, но до сих пор не были таковыми, и, следовательно, существует огромный потенциал для улучшения пользовательского опыта. Однако пока еще нет четкого понимания того, какие виды рефакторинга нужны пользователям, и как они должны выражаться, а также существуют слабые места в протоколе LSP в этой области. Это означает, что это может быть больше исследовательским проектом.
| Форматирование | Исправить форматирование файла |
|---|---|
| Требования | AST текущего файла |
| LSP | textDocument/formatting |
textDocument/rangeFormatting |
|
textDocument/onTypeFormatting |
|
| Предыдущие решения | gofmt, goimports, goreturns |
| Будет использоваться стандартный пакет format. Текущие ограничения заключаются в том, что он не работает с некорректным кодом. Возможно, потребуются очень осторожные изменения в форматировщике, чтобы позволить форматирование невалидного AST или изменения, которые принудительно переведут AST в валидное состояние. Эти изменения также улучшат работу в режимах диапазона и файла, но они в основном необходимы для onTypeFormatting |
| Импорты | Автоматически переписать блок импортов, чтобы соответствовать используемым символам. |
|---|---|
| Требования | AST текущего файла и полная информация о символах всех возможных пакетов. |
| LSP | textDocument/codeAction |
| Предыдущие решения | goimports, goreturns |
| Для реализации требуется знание пакетов, которые ещё не используются, а также способность находить эти пакеты по их имени. Также необходимо знать экспортируемые символы всех обнаруженных пакетов. Реализация должна использовать стандартный пакет imports, но может потребоваться более детальный API, чем просто перезапись файла, для некоторых взаимодействий. |
| Автозавершение | Предлагает варианты завершения вводимой сущности. |
|---|---|
| Требования | AST и информация о типах файла и всех зависимостях Также полная информация об экспортируемых символах всех пакетов. |
| LSP | textDocument/completion |
completionItem/resolve |
|
| Предыдущие решения | gocode |
| Автозавершение — одна из самых сложных функций, и чем больше она знает, тем точнее будут её предложения. Например, она может завершать код в пакеты, которые ещё не импортированы, если у неё есть их публичные символы. Она может давать лучшие варианты, если знает, какой тип программы вы пишете. Она может предлагать лучшие аргументы, если знает, как вы обычно вызываете функцию. Она может предлагать целые шаблоны кода, если знает, что они часто используются. В отличие от многих других функций, которые имеют конкретную задачу и завершаются после её выполнения, автозавершение никогда не будет завершено. Балансировка и улучшение как кандидатов, так и их ранжирования будет проблемой исследования на протяжении долгого времени. |
| Переименование | Переименование идентификатора |
|---|---|
| Требования | AST и информация о типах для обратного транзитивного замыкания |
| LSP | textDocument/rename |
textDocument/prepareRename |
|
| Предыдущая реализация | golang.org/x/tools/cmd/gorename |
| Этот инструмент использует те же данные, что и функция поиска ссылок, со всеми теми же проблемами и ограничениями. Он немного хуже, потому что предлагаемые изменения делают его чувствительным к некорректным результатам. Также он опасен при использовании для изменения публичного API пакета. |
| Предлагаемые исправления | Предложения, которые можно принять вручную или автоматически для изменения кода |
|---|---|
| Требования | Полный запуск go/analysis, который требует полной информации AST, типов и SSA |
| LSP | textDocument/codeAction |
| Предыдущая реализация | Нет |
| Это совершенно новая функция, работающая на новом движке go/analysis, и она должна позволить осуществить огромное количество автоматизированных рефакторингов. |
Исходные файлы этой документации можно найти в golang.org/x/tools/gopls/doc.