VSCode создавался с прицелом на возможность расширения функционала с помощью плагинов. От UI интерфейса до своих AI агентов — почти каждую часть VS Code можно настроить и улучшить с помощью VSCode API. Многие части самого VSCode фактически являются плагинами.
Есть подробная документация по созданию своего плагина, а большое количество "мини-плагинов" с демонстрацией возможностей можно найти в репозитории vscode-extension-samples. Сама dts-ка с описанием API есть в основной репе microsoft/vscode вот тут. Кроме src/vscode-dts/vscode.d.ts
в директории еще много других файлов в формате vscode.proposed.*.d.ts
. Это экспериментальное API. О нем и пойдет речь в данной статье.
Что и как?
Плагин github-copilot (для inline-подсказок) использует следующие proposed API
// package.json плагина github-copilot
{
...
"enabledApiProposals": [
"inlineCompletionsAdditions"
],
...
}
Это почти все необходимое, чтобы ваш плагин использовал какое-нибудь proposed API. Еще к сорцам плагина необходимо добавить dts-ку соответствующего API. Это удобно делать с помощью пакета @vscode-dts.
Microsoft рекомендует использовать такие расширения только в VSCode Insiders - специальной dev версии VSCode. Это связано с тем, что proposed API не стабильно и может кардинально измениться в следующем релизе VSCode (в статье будет пример).
Использование в привычном VSCode тоже возможно, но есть одно ограничение - ваш VSCode, если его не попросить, не сможет использовать функционал плагина, основанный на proposed API (так не всегда, но об этом позже). Попросить можно так: отредактировать аргументы загрузки самого VSCode, т.е. выполнить команду Preferences: Configure Runtime Arguments и добавить туда
// file .vscode/argv.json
{
...
"enable-proposed-api": ["<YOUR-EXTENSION-ID>"]
}
Ну и главное - расширение, которое использует proposed API, нельзя публиковать в официальный Extensions Marketplace. Придется устанавливать через команду Install from VSIX.
Генерация commit message
Рассмотрим пример того, как расширение github-copilot-chat генерит commit message. Для этого оно использует proposed API под названием contribSourceControlInputBoxMenu. Это API позволяет добавлять кнопку к input блоку в Source Control меню и что-то туда записывать. Выглядит это следующим образом
Фактически это API позволяет работать с scm/inputBox (который скоро будет полностью заменен на SourceControl интерфейс). Использование выглядит очень просто
const repo: git.Repository = ...;
repo.inputBox.value = 'My awesome commit message';
В плагине задается следующим образом
// package.json плагина github-copilot-chat
{
"enabledApiProposals": [
"contribSourceControlInputBoxMenu"
],
"contributes": {
"commands": [
{
"command": "github.copilot.git.generateCommitMessage",
"title": "%github.copilot.git.generateCommitMessage%",
"icon": "$(sparkle)",
"enablement": "!github.copilot.interactiveSession.disabled",
"category": "GitHub Copilot"
},
...
],
...
},
...
}
Сама кнопка с иконкой $(sparkle) , а при нажатии просто вызывается команда github.copilot.git.generateCommitMessage.
Стабильность
Proposed API - штука не стабильная. Хороший пример - это proposed API под названием interactive. Proposal довольный старый и до версии 1.89.0 позволял добавлять в свой плагин inline чат. Выглядело так
Но теперь этот proposal (как и все чатовые proposals) доступны только с авторизованным github copilot и только как интеграция в github-copilot-chat.
Пример
Напишем игрушечный плагин, который показывает cwd shell-integration терминала при запуске команды. Для этого используем proposed API под названием terminalShellIntegration.
Создадим свой awesome sample проект через yo
Разбирать детально структуру не будем, разберем только package.json и src/extension.ts
// package.json
{
"name": "awesomesample",
"displayName": "awesomeSample",
"publisher": "awesomePublisher",
...
"activationEvents": [
"onStartupFinished"
],
"enabledApiProposals": [
"terminalShellIntegration"
],
...
}
Чтобы использовать proposed API сначала установим @vscode/dts
> npm i @vscode/dts
, а затем запустим
> npx vscode-dts dev
Downloading vscode.proposed.terminalShellIntegration.d.ts
To: /Users/d.artyushin/Documents/habr/github-copilot-proposed-api/awesomesample/vscode.proposed.terminalShellIntegration.d.ts
From: https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.terminalShellIntegration.d.ts
Read more about proposed API at: https://code.visualstudio.com/api/advanced-topics/using-proposed-api
В корне проекта должен появиться файл vscode.proposed.terminalShellIntegration.d.ts с описанием доступного API. Используем его
// src/extension.ts
import * as vscode from 'vscode';
export function activate(context: vscode.ExtensionContext) {
// подписываемся на запуск команды в терминале
const terminalCwd = vscode.window.onDidStartTerminalShellExecution((event) => {
// event имеет тип vscode.TerminalShellExecutionStartEvent
// если shellIntegration есть, то у него берем поле cwd
const currentCwd = event.terminal.shellIntegration?.cwd;
if (currentCwd === undefined) {
vscode.window.showInformationMessage('No found cwd :(');
} else {
vscode.window.showInformationMessage(`Cwd is ${currentCwd}`);
}
});
context.subscriptions.push(terminalCwd);
}
export function deactivate() {}
Нужно не забыть добавить в argv.json строку (попробуйте сначала запустить плагин без этого)
// .vscode/argv.json
{
...
// Enable proposed API features.
"enable-proposed-api": ["awesomePublisher.awesomesample"],
}
Наконец, запускаем плагин и пробуем команду ls в zsh и bash:
Proposed API в плагинах Copilot
Обычно github тестирует свои новые API на плагине github-copilot-chat. Вот пример
// package.json плагина github-copilot-chat
{
...
"enabledApiProposals": [
"interactive",
"terminalDataWriteEvent",
"terminalExecuteCommandEvent",
"terminalSelection",
"terminalQuickFixProvider",
"chatParticipantAdditions",
"defaultChatParticipant",
"embeddings",
"chatVariableResolver",
"chatProvider",
"mappedEditsProvider",
"aiRelatedInformation",
"codeActionAI",
"findTextInFiles",
"textSearchProvider",
"commentReveal",
"contribSourceControlInputBoxMenu",
"contribCommentEditorActionsMenu",
"contribCommentThreadAdditionalMenu",
"contribCommentsViewThreadMenus",
"newSymbolNamesProvider",
"findFiles2",
"extensionsAny",
"authLearnMore",
"testObserver",
"aiTextSearchProvider",
"documentFiltersExclusive",
"chatParticipantPrivate",
"lmTools"
],
...
}
Справедливый вопрос: "Как тогда github публикует свои плагины в Extension Marketplace?". В исходном коде VSCode можно найти следующий код
...
// NEW world - product.json spells out what proposals each extension can use
if (productService.extensionEnabledApiProposals) {
for (const [k, value] of Object.entries(productService.extensionEnabledApiProposals)) {
const key = ExtensionIdentifier.toKey(k);
const proposalNames = value.filter(name => {
if (!allApiProposals[<ApiProposalName>name]) {
_logService.warn(`Via 'product.json#extensionEnabledApiProposals' extension '${key}' wants API proposal '${name}' but that proposal DOES NOT EXIST. Likely, the proposal has been finalized (check 'vscode.d.ts') or was abandoned.`);
return false;
}
return true;
});
this._productEnabledExtensions.set(key, proposalNames);
}
}
}
updateEnabledApiProposals(extensions: IExtensionDescription[]): void {
for (const extension of extensions) {
this.doUpdateEnabledApiProposals(extension);
}
}
...
Коммент в коде говорит сам за себя. Файл product.json после установки VSCode находится по пути (для MacOS) /Applications/Visual Studio Code.app/Contents/Resources/app/product.json . Там для "важных" расширений как раз указаны доступные proposal API
{
...
"extensionEnabledApiProposals": {
...
"GitHub.copilot": [
"inlineCompletionsAdditions"
],
"GitHub.copilot-nightly": [
"inlineCompletionsAdditions"
],
"GitHub.copilot-chat": [
"interactive",
"terminalDataWriteEvent",
"terminalExecuteCommandEvent",
"terminalSelection",
"terminalQuickFixProvider",
"chatParticipantAdditions",
"defaultChatParticipant",
"embeddings",
"chatVariableResolver",
"chatProvider",
"mappedEditsProvider",
"aiRelatedInformation",
"codeActionAI",
"findTextInFiles",
"textSearchProvider",
"commentReveal",
"contribSourceControlInputBoxMenu",
"contribCommentEditorActionsMenu",
"contribCommentThreadAdditionalMenu",
"contribCommentsViewThreadMenus",
"newSymbolNamesProvider",
"findFiles2",
"extensionsAny",
"authLearnMore",
"testObserver",
"aiTextSearchProvider",
"documentFiltersExclusive",
"chatParticipantPrivate",
"lmTools"
],
...
}
Себе (или пользователям) вы тоже можете обновлять этот файл, чтобы избегать манипуляций с argv.
Заключение
Заключение очень простое - учитывайте нюансы и используйте VSCode proposed API, там много клевого и полезного :) Так же призываю следить за Release Notes новых версий VSCode - там всегда есть раздел Proposed APIs.
gudvinr
VSCode создавался с прицелом на внедрение проприетарных плагинов Microsoft под браваду о приверженности опенсорсу
Pylance с опенсорсной сборкой не работает.
OmniSharp почти закрыли, но поднялась шумиха.
Практически все крупные плагины разрабатываются MS для MS практически без возможности внести изменения. Да и вносить изменения в код, написанный энтерпрайзом для энтерпрайза с отпратительным процессом принятия PR, уже итак не хочется