程式化語言功能
程式語言功能是一組由 vscode.languages.* API 支援的智慧編輯功能。在 Visual Studio Code 中提供動態語言功能有兩種常見方式。讓我們以 Hover(游標懸停提示) 為例。
vscode.languages.registerHoverProvider('javascript', {
provideHover(document, position, token) {
return {
contents: ['Hover Content']
};
}
});
如上所示,vscode.languages.registerHoverProvider API 提供了一種簡單的方法,為 JavaScript 檔案提供游標懸停內容。當此擴充功能啟用後,每當您將游標懸停在 JavaScript 程式碼上時,VS Code 會查詢所有 JavaScript 的 HoverProvider,並將結果顯示在 Hover 小工具中。下方的語言功能清單和示意 GIF 為您提供了一種簡單的方法,來定位您的擴充功能需要哪種 VS Code API 或 LSP 方法。
另一種方法是實作一個支援 Language Server Protocol(語言伺服器協定)的語言伺服器。其運作方式如下:
- 擴充功能為 JavaScript 提供語言用戶端 (Language Client) 和語言伺服器 (Language Server)。
- 語言用戶端就像任何其他 VS Code 擴充功能一樣,在 Node.js 擴充功能主機環境中執行。當它被啟用時,它會在另一個處理序中啟動語言伺服器,並透過 Language Server Protocol 與其進行通訊。
- 您在 VS Code 中將游標懸停於 JavaScript 程式碼上。
- VS Code 將懸停事件通知語言用戶端。
- 語言用戶端向語言伺服器查詢懸停結果,並將其傳回給 VS Code。
- VS Code 在 Hover 小工具中顯示懸停結果。
這個過程看起來比較複雜,但它提供了兩個主要好處:
- 語言伺服器可以用任何語言編寫。
- 語言伺服器可以被重複使用,為多個編輯器提供智慧編輯功能。
如需更深入的指南,請前往 語言伺服器擴充功能指南。
語言功能清單
此清單包含每項語言功能的下列項目:
- 該語言功能在 VS Code 中的示意圖。
- 相關的 VS Code API。
- 相關的 LSP 方法。
提供診斷 (Provide Diagnostics)
診斷是用於指出程式碼問題的一種方式。

語言伺服器通訊協定 (Language Server Protocol)
您的語言伺服器會將 textDocument/publishDiagnostics 訊息傳送給語言用戶端。該訊息包含資源 URI 的診斷項目陣列。
注意:用戶端不會主動向伺服器請求診斷。伺服器會主動將診斷資訊推送至用戶端。
直接實作
let diagnosticCollection: vscode.DiagnosticCollection;
export function activate(ctx: vscode.ExtensionContext): void {
...
ctx.subscriptions.push(getDisposable());
diagnosticCollection = vscode.languages.createDiagnosticCollection('go');
ctx.subscriptions.push(diagnosticCollection);
...
}
function onChange() {
let uri = document.uri;
check(uri.fsPath, goConfig).then(errors => {
diagnosticCollection.clear();
let diagnosticMap: Map<string, vscode.Diagnostic[]> = new Map();
errors.forEach(error => {
let canonicalFile = vscode.Uri.file(error.file).toString();
let range = new vscode.Range(error.line-1, error.startColumn, error.line-1, error.endColumn);
let diagnostics = diagnosticMap.get(canonicalFile);
if (!diagnostics) { diagnostics = []; }
diagnostics.push(new vscode.Diagnostic(range, error.msg, error.severity));
diagnosticMap.set(canonicalFile, diagnostics);
});
diagnosticMap.forEach((diags, file) => {
diagnosticCollection.set(vscode.Uri.parse(file), diags);
});
})
}
基本
針對已開啟的編輯器報告診斷。最低限度,這需要在每次儲存時進行。更好的做法是根據編輯器中未儲存的內容來計算診斷。
進階
不僅針對已開啟的編輯器,還要針對已開啟資料夾中的所有資源進行診斷報告,無論它們是否曾在編輯器中開啟過。
顯示程式碼完成建議
程式碼完成功能會為使用者提供內容敏感的建議。

語言伺服器通訊協定 (Language Server Protocol)
在回應 initialize 方法時,您的語言伺服器需要宣告它提供完成功能,以及是否支援 completionItem/resolve 方法,以便為計算出的完成項目提供額外資訊。
{
...
"capabilities" : {
"completionProvider" : {
"resolveProvider": "true",
"triggerCharacters": [ '.' ]
}
...
}
}
直接實作
class GoCompletionItemProvider implements vscode.CompletionItemProvider {
public provideCompletionItems(
document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken):
Thenable<vscode.CompletionItem[]> {
...
}
}
export function activate(ctx: vscode.ExtensionContext): void {
...
ctx.subscriptions.push(getDisposable());
ctx.subscriptions.push(
vscode.languages.registerCompletionItemProvider(
GO_MODE, new GoCompletionItemProvider(), '.', '\"'));
...
}
基本
您不支援解析提供者 (resolve providers)。
進階
您支援解析提供者,可為使用者選取的完成建議計算額外資訊。此資訊將顯示在所選項目的旁邊。
顯示行內完成 (Inline Completions)
行內完成直接在編輯器中呈現多詞彙建議(幽靈文字)。

直接實作
vscode.languages.registerInlineCompletionItemProvider({ language: 'javascript' }, {
provideInlineCompletionItems(document, position, context, token) {
const result: vscode.InlineCompletionList = {
items: [],
commands: [],
};
...
return result;
}
});
您可以在 行內完成範例擴充功能 中探索完整的範例。
基本
僅針對特定語言,根據當前行內容中已知的模式清單傳回行內完成。
進階
根據整個文件或工作區中的內容及更複雜的模式傳回行內完成。
顯示懸停提示 (Show Hovers)
懸停提示會顯示滑鼠游標下方符號/物件的相關資訊。這通常是符號的類型及說明。

語言伺服器通訊協定 (Language Server Protocol)
在回應 initialize 方法時,您的語言伺服器需要宣告它提供懸停功能。
{
...
"capabilities" : {
"hoverProvider" : "true",
...
}
}
此外,您的語言伺服器需要回應 textDocument/hover 請求。
直接實作
class GoHoverProvider implements HoverProvider {
public provideHover(
document: TextDocument, position: Position, token: CancellationToken):
Thenable<Hover> {
...
}
}
export function activate(ctx: vscode.ExtensionContext): void {
...
ctx.subscriptions.push(
vscode.languages.registerHoverProvider(
GO_MODE, new GoHoverProvider()));
...
}
基本
顯示類型資訊,並在可用時包含文件說明。
進階
以與程式碼著色相同的風格為方法簽名著色。
函數與方法簽名協助
當使用者輸入函數或方法時,顯示正在呼叫的函數/方法的資訊。

語言伺服器通訊協定 (Language Server Protocol)
在回應 initialize 方法時,您的語言伺服器需要宣告它提供簽名協助。
{
...
"capabilities" : {
"signatureHelpProvider" : {
"triggerCharacters": [ '(' ]
}
...
}
}
此外,您的語言伺服器需要回應 textDocument/signatureHelp 請求。
直接實作
class GoSignatureHelpProvider implements SignatureHelpProvider {
public provideSignatureHelp(
document: TextDocument, position: Position, token: CancellationToken):
Promise<SignatureHelp> {
...
}
}
export function activate(ctx: vscode.ExtensionContext): void {
...
ctx.subscriptions.push(
vscode.languages.registerSignatureHelpProvider(
GO_MODE, new GoSignatureHelpProvider(), '(', ','));
...
}
基本
確保簽名協助包含該函數或方法的參數說明文件。
進階
無額外內容。
顯示符號定義
允許使用者在變數/函數/方法被使用的地方直接查看其定義。

語言伺服器通訊協定 (Language Server Protocol)
在回應 initialize 方法時,您的語言伺服器需要宣告它提供跳轉至定義 (goto-definition) 的位置。
{
...
"capabilities" : {
"definitionProvider" : "true"
...
}
}
此外,您的語言伺服器需要回應 textDocument/definition 請求。
直接實作
class GoDefinitionProvider implements vscode.DefinitionProvider {
public provideDefinition(
document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken):
Thenable<vscode.Location> {
...
}
}
export function activate(ctx: vscode.ExtensionContext): void {
...
ctx.subscriptions.push(
vscode.languages.registerDefinitionProvider(
GO_MODE, new GoDefinitionProvider()));
...
}
基本
如果符號具歧義,您可以顯示多個定義。
進階
無額外內容。
尋找符號的所有參考
允許使用者查看特定變數/函數/方法/符號在原始程式碼中被使用的所有位置。

語言伺服器通訊協定 (Language Server Protocol)
在回應 initialize 方法時,您的語言伺服器需要宣告它提供符號參考位置。
{
...
"capabilities" : {
"referencesProvider" : "true"
...
}
}
此外,您的語言伺服器需要回應 textDocument/references 請求。
直接實作
class GoReferenceProvider implements vscode.ReferenceProvider {
public provideReferences(
document: vscode.TextDocument, position: vscode.Position,
options: { includeDeclaration: boolean }, token: vscode.CancellationToken):
Thenable<vscode.Location[]> {
...
}
}
export function activate(ctx: vscode.ExtensionContext): void {
...
ctx.subscriptions.push(
vscode.languages.registerReferenceProvider(
GO_MODE, new GoReferenceProvider()));
...
}
基本
傳回所有參考的位置(資源 URI 和範圍)。
進階
無額外內容。
反白顯示文件中符號的所有出現位置
允許使用者查看符號在開啟的編輯器中出現的所有位置。

語言伺服器通訊協定 (Language Server Protocol)
在回應 initialize 方法時,您的語言伺服器需要宣告它提供文件符號位置。
{
...
"capabilities" : {
"documentHighlightProvider" : "true"
...
}
}
此外,您的語言伺服器需要回應 textDocument/documentHighlight 請求。
直接實作
class GoDocumentHighlightProvider implements vscode.DocumentHighlightProvider {
public provideDocumentHighlights(
document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken):
vscode.DocumentHighlight[] | Thenable<vscode.DocumentHighlight[]>;
...
}
}
export function activate(ctx: vscode.ExtensionContext): void {
...
ctx.subscriptions.push(
vscode.languages.registerDocumentHighlightProvider(
GO_MODE, new GoDocumentHighlightProvider()));
...
}
基本
您傳回在編輯器文件中找到參考的範圍。
進階
無額外內容。
顯示文件中所有的符號定義
允許使用者快速導航到開啟編輯器中的任何符號定義。

語言伺服器通訊協定 (Language Server Protocol)
在回應 initialize 方法時,您的語言伺服器需要宣告它提供文件符號位置。
{
...
"capabilities" : {
"documentSymbolProvider" : "true"
...
}
}
此外,您的語言伺服器需要回應 textDocument/documentSymbol 請求。
直接實作
class GoDocumentSymbolProvider implements vscode.DocumentSymbolProvider {
public provideDocumentSymbols(
document: vscode.TextDocument, token: vscode.CancellationToken):
Thenable<vscode.SymbolInformation[]> {
...
}
}
export function activate(ctx: vscode.ExtensionContext): void {
...
ctx.subscriptions.push(
vscode.languages.registerDocumentSymbolProvider(
GO_MODE, new GoDocumentSymbolProvider()));
...
}
基本
傳回文件中的所有符號。定義符號的種類,例如變數、函數、類別、方法等。
進階
無額外內容。
顯示資料夾中所有的符號定義
允許使用者快速導航到 VS Code 中開啟資料夾(工作區)內任何地方的符號定義。

語言伺服器通訊協定 (Language Server Protocol)
在回應 initialize 方法時,您的語言伺服器需要宣告它提供全域符號位置。
{
...
"capabilities" : {
"workspaceSymbolProvider" : "true"
...
}
}
此外,您的語言伺服器需要回應 workspace/symbol 請求。
直接實作
class GoWorkspaceSymbolProvider implements vscode.WorkspaceSymbolProvider {
public provideWorkspaceSymbols(
query: string, token: vscode.CancellationToken):
Thenable<vscode.SymbolInformation[]> {
...
}
}
export function activate(ctx: vscode.ExtensionContext): void {
...
ctx.subscriptions.push(
vscode.languages.registerWorkspaceSymbolProvider(
new GoWorkspaceSymbolProvider()));
...
}
基本
傳回已開啟資料夾內原始程式碼所定義的所有符號。定義符號的種類,例如變數、函數、類別、方法等。
進階
無額外內容。
錯誤或警告的可能動作
在錯誤或警告旁邊為使用者提供可能的修正動作。如果動作可用,錯誤或警告旁邊會出現燈泡圖示。當使用者點擊燈泡時,會顯示可用程式碼動作的清單。

語言伺服器通訊協定 (Language Server Protocol)
在回應 initialize 方法時,您的語言伺服器需要宣告它提供程式碼動作 (Code Actions)。
{
...
"capabilities" : {
"codeActionProvider" : "true"
...
}
}
此外,您的語言伺服器需要回應 textDocument/codeAction 請求。
直接實作
class GoCodeActionProvider implements vscode.CodeActionProvider<vscode.CodeAction> {
public provideCodeActions(
document: vscode.TextDocument, range: vscode.Range | vscode.Selection,
context: vscode.CodeActionContext, token: vscode.CancellationToken):
Thenable<vscode.CodeAction[]> {
...
}
}
export function activate(ctx: vscode.ExtensionContext): void {
...
ctx.subscriptions.push(
vscode.languages.registerCodeActionsProvider(
GO_MODE, new GoCodeActionProvider()));
...
}
基本
為錯誤/警告修正動作提供程式碼動作。
進階
此外,提供原始程式碼操作功能,例如重構。例如:擷取方法 (Extract Method)。
CodeLens - 在原始程式碼中顯示可操作的上下文資訊
為使用者提供穿插在原始程式碼中、可操作且具備上下文的資訊。

語言伺服器通訊協定 (Language Server Protocol)
在回應 initialize 方法時,您的語言伺服器需要宣告它提供 CodeLens 結果,以及是否支援 codeLens/resolve 方法來將 CodeLens 綁定到其指令。
{
...
"capabilities" : {
"codeLensProvider" : {
"resolveProvider": "true"
}
...
}
}
此外,您的語言伺服器需要回應 textDocument/codeLens 請求。
直接實作
class GoCodeLensProvider implements vscode.CodeLensProvider {
public provideCodeLenses(document: TextDocument, token: CancellationToken):
CodeLens[] | Thenable<CodeLens[]> {
...
}
public resolveCodeLens?(codeLens: CodeLens, token: CancellationToken):
CodeLens | Thenable<CodeLens> {
...
}
}
export function activate(ctx: vscode.ExtensionContext): void {
...
ctx.subscriptions.push(
vscode.languages.registerCodeLensProvider(
GO_MODE, new GoCodeLensProvider()));
...
}
基本
定義文件中可用的 CodeLens 結果。
進階
透過回應
codeLens/resolve將 CodeLens 結果綁定到指令。
顯示色彩裝飾器 (Color Decorators)
允許使用者預覽並修改文件中的色彩。

語言伺服器通訊協定 (Language Server Protocol)
在回應 initialize 方法時,您的語言伺服器需要宣告它提供色彩資訊。
{
...
"capabilities" : {
"colorProvider" : "true"
...
}
}
此外,您的語言伺服器需要回應 textDocument/documentColor 和 textDocument/colorPresentation 請求。
直接實作
class GoColorProvider implements vscode.DocumentColorProvider {
public provideDocumentColors(
document: vscode.TextDocument, token: vscode.CancellationToken):
Thenable<vscode.ColorInformation[]> {
...
}
public provideColorPresentations(
color: Color, context: { document: TextDocument, range: Range }, token: vscode.CancellationToken):
Thenable<vscode.ColorPresentation[]> {
...
}
}
export function activate(ctx: vscode.ExtensionContext): void {
...
ctx.subscriptions.push(
vscode.languages.registerColorProvider(
GO_MODE, new GoColorProvider()));
...
}
基本
傳回文件中的所有色彩參考。針對支援的色彩格式(例如 rgb(...)、hsl(...))提供色彩呈現。
進階
無額外內容。
在編輯器中格式化原始程式碼
為使用者提供格式化整個文件的支援。

語言伺服器通訊協定 (Language Server Protocol)
在回應 initialize 方法時,您的語言伺服器需要宣告它提供文件格式化功能。
{
...
"capabilities" : {
"documentFormattingProvider" : "true"
...
}
}
此外,您的語言伺服器需要回應 textDocument/formatting 請求。
直接實作
class GoDocumentFormatter implements vscode.DocumentFormattingEditProvider {
provideDocumentFormattingEdits(
document: vscode.TextDocument, options: vscode.FormattingOptions, token: vscode.CancellationToken)
: vscode.ProviderResult<vscode.TextEdit[]> {
...
}
}
export function activate(ctx: vscode.ExtensionContext): void {
...
ctx.subscriptions.push(
vscode.languages.registerDocumentFormattingEditProvider(
GO_MODE, new GoDocumentFormatter()));
...
}
基本
不提供格式化支援。
進階
您應該始終傳回能達成格式化原始程式碼的最小文字編輯量。這對於確保診斷結果等標記能正確調整且不會丟失至關重要。
在編輯器中格式化所選行
為使用者提供格式化文件中所選行範圍的支援。

語言伺服器通訊協定 (Language Server Protocol)
在回應 initialize 方法時,您的語言伺服器需要宣告它提供行範圍的格式化支援。
{
...
"capabilities" : {
"documentRangeFormattingProvider" : "true"
...
}
}
此外,您的語言伺服器需要回應 textDocument/rangeFormatting 請求。
直接實作
class GoDocumentRangeFormatter implements vscode.DocumentRangeFormattingEditProvider{
public provideDocumentRangeFormattingEdits(
document: vscode.TextDocument, range: vscode.Range,
options: vscode.FormattingOptions, token: vscode.CancellationToken):
vscode.ProviderResult<vscode.TextEdit[]> {
...
}
}
export function activate(ctx: vscode.ExtensionContext): void {
...
ctx.subscriptions.push(
vscode.languages.registerDocumentRangeFormattingEditProvider(
GO_MODE, new GoDocumentRangeFormatter()));
...
}
基本
不提供格式化支援。
進階
您應該始終傳回能達成格式化原始程式碼的最小文字編輯量。這對於確保診斷結果等標記能正確調整且不會丟失至關重要。
使用者輸入時的增量程式碼格式化
為使用者提供輸入時格式化文字的支援。
注意:使用者 設定 editor.formatOnType 控制是否在使用者輸入時格式化原始程式碼。

語言伺服器通訊協定 (Language Server Protocol)
在回應 initialize 方法時,您的語言伺服器需要宣告它提供輸入時格式化功能。它還需要告知用戶端應該在哪個字元上觸發格式化。moreTriggerCharacters 是選填的。
{
...
"capabilities" : {
"documentOnTypeFormattingProvider" : {
"firstTriggerCharacter": "}",
"moreTriggerCharacter": [";", ","]
}
...
}
}
此外,您的語言伺服器需要回應 textDocument/onTypeFormatting 請求。
直接實作
class GoOnTypingFormatter implements vscode.OnTypeFormattingEditProvider{
public provideOnTypeFormattingEdits(
document: vscode.TextDocument, position: vscode.Position,
ch: string, options: vscode.FormattingOptions, token: vscode.CancellationToken):
vscode.ProviderResult<vscode.TextEdit[]> {
...
}
}
export function activate(ctx: vscode.ExtensionContext): void {
...
ctx.subscriptions.push(
vscode.languages.registerOnTypeFormattingEditProvider(
GO_MODE, new GoOnTypingFormatter()));
...
}
基本
不提供格式化支援。
進階
您應該始終傳回能達成格式化原始程式碼的最小文字編輯量。這對於確保診斷結果等標記能正確調整且不會丟失至關重要。
重新命名符號
允許使用者重新命名符號並更新對該符號的所有參考。

語言伺服器通訊協定 (Language Server Protocol)
在回應 initialize 方法時,您的語言伺服器需要宣告它提供重新命名功能。
{
...
"capabilities" : {
"renameProvider" : "true"
...
}
}
此外,您的語言伺服器需要回應 textDocument/rename 請求。
直接實作
class GoRenameProvider implements vscode.RenameProvider {
public provideRenameEdits(
document: vscode.TextDocument, position: vscode.Position,
newName: string, token: vscode.CancellationToken):
Thenable<vscode.WorkspaceEdit> {
...
}
}
export function activate(ctx: vscode.ExtensionContext): void {
...
ctx.subscriptions.push(
vscode.languages.registerRenameProvider(
GO_MODE, new GoRenameProvider()));
...
}
基本
不提供重新命名支援。
進階
傳回需要執行的所有工作區編輯清單,例如所有包含該符號參考的檔案中所需的編輯。