參加你附近的 ,瞭解 VS Code 中的 AI 輔助開發。

語義高亮指南

語義高亮是語法高亮指南中描述的語法高亮的補充。Visual Studio Code 使用 TextMate 語法作為主要的標記化引擎。TextMate 語法以單個檔案作為輸入,並根據正則表示式表示的詞法規則將其分解。

語義標記化允許語言伺服器根據語言伺服器對如何在專案上下文中解析符號的知識來提供額外的標記資訊。主題可以選擇使用語義標記來改進和完善語法的語法高亮。編輯器在語法高亮之上應用語義標記的高亮。

以下是語義高亮可以新增的示例

沒有語義高亮

without semantic highlighting

有語義高亮

with semantic highlighting

請注意根據語言服務符號理解的顏色差異

  • 第 10 行:languageModes 被著色為引數
  • 第 11 行:RangePosition 被著色為類,document 被著色為引數。
  • 第 13 行:getFoldingRanges 被著色為函式。

語義標記提供程式

要實現語義高亮,語言擴充套件可以透過文件語言和/或檔名註冊一個語義標記提供程式。當需要語義標記時,編輯器會向提供程式發出請求。

const tokenTypes = ['class', 'interface', 'enum', 'function', 'variable'];
const tokenModifiers = ['declaration', 'documentation'];
const legend = new vscode.SemanticTokensLegend(tokenTypes, tokenModifiers);

const provider: vscode.DocumentSemanticTokensProvider = {
  provideDocumentSemanticTokens(
    document: vscode.TextDocument
  ): vscode.ProviderResult<vscode.SemanticTokens> {
    // analyze the document and return semantic tokens

    const tokensBuilder = new vscode.SemanticTokensBuilder(legend);
    // on line 1, characters 1-5 are a class declaration
    tokensBuilder.push(
      new vscode.Range(new vscode.Position(1, 1), new vscode.Position(1, 5)),
      'class',
      ['declaration']
    );
    return tokensBuilder.build();
  }
};

const selector = { language: 'java', scheme: 'file' }; // register for all Java documents from the local file system

vscode.languages.registerDocumentSemanticTokensProvider(selector, provider, legend);

語義標記提供程式 API 有兩種形式,以適應語言伺服器的功能

  • DocumentSemanticTokensProvider - 始終將完整文件作為輸入。

    • provideDocumentSemanticTokens - 提供文件的所有標記。
    • provideDocumentSemanticTokensEdits- 提供文件的所有標記作為對先前響應的增量。
  • DocumentRangeSemanticTokensProvider - 僅對範圍起作用。

    • provideDocumentRangeSemanticTokens - 提供文件範圍的所有標記。

提供程式返回的每個標記都帶有一個分類,該分類由標記型別、任意數量的標記修飾符和標記語言組成。

如上例所示,提供程式在SemanticTokensLegend中命名它將使用的型別和修飾符。這允許provide API 返回標記型別並將它們修改為圖例的索引。

語義標記分類

語義標記提供程式的輸出由標記組成。每個標記都有一個範圍和一個標記分類,描述了該標記代表哪種語法元素。如果標記是嵌入語言的一部分,則分類還可以可選地命名一種語言。

為了描述語法元素的型別,使用了語義標記型別和修飾符。此資訊類似於語法高亮指南中描述的 TextMate 作用域,但我們希望提出一個專用且更清晰的分類系統。

VS Code 帶有一組標準語義標記型別和修飾符供所有語義標記提供程式使用。儘管如此,語義標記提供程式可以自由定義新的型別和修飾符,並建立標準型別的子型別。

標準標記型別和修飾符

標準型別和修飾符涵蓋了許多語言使用的常見概念。雖然每種語言可能對某些型別和修飾符使用不同的術語,但透過遵守標準分類,主題作者將能夠定義跨語言工作的主題規則。

這些是 VS Code 預定義的標準語義標記型別和語義標記修飾符

標準標記型別

ID 描述
名稱空間 用於宣告或引用名稱空間、模組或包的識別符號。
用於宣告或引用類型別的識別符號。
enum 用於宣告或引用列舉型別的識別符號。
介面 用於宣告或引用介面型別的識別符號。
結構體 用於宣告或引用結構體型別的識別符號。
型別引數 用於宣告或引用型別引數的識別符號。
type 用於宣告或引用上述未涵蓋的型別的識別符號。
引數 用於宣告或引用函式或方法引數的識別符號。
variable 用於宣告或引用區域性或全域性變數的識別符號。
property 用於宣告或引用成員屬性、成員欄位或成員變數的識別符號。
enumMember 用於宣告或引用列舉屬性、常量或成員的識別符號。
裝飾器 用於宣告或引用裝飾器和註解的識別符號。
event 用於宣告事件屬性的識別符號。
函式 用於宣告函式的識別符號。
方法 用於宣告成員函式或方法的識別符號。
用於宣告宏的識別符號。
標籤 用於宣告標籤的識別符號。
註釋 表示註釋的標記。
字串 表示字串字面量的標記。
關鍵字 表示語言關鍵字的標記。
number 表示數字字面量的標記。
正則表示式 表示正則表示式字面量的標記。
運算子 表示運算子的標記。

標準標記修飾符

ID 描述
宣告 用於符號的宣告。
定義 用於符號的定義,例如在標頭檔案中。
只讀 用於只讀變數和成員欄位(常量)。
靜態 用於類成員(靜態成員)。
已棄用 用於不應再使用的符號。
抽象 用於抽象型別和成員函式。
非同步 用於標記為非同步的函式。
修改 用於變數被賦值的變數引用。
文件 用於文件中符號的出現。
預設庫 用於屬於標準庫的符號。

除了標準型別和修飾符,VS Code 還定義了型別和修飾符到類似 TextMate 作用域的對映。這將在語義標記作用域對映部分介紹。

自定義標記型別和修飾符

如有必要,擴充套件可以透過其擴充套件的package.json中的semanticTokenTypessemanticTokenModifiers貢獻點宣告新的型別和修飾符或建立現有型別的子型別。

{
  "contributes": {
    "semanticTokenTypes": [
      {
        "id": "templateType",
        "superType": "type",
        "description": "A template type."
      }
    ],
    "semanticTokenModifiers": [
      {
        "id": "native",
        "description": "Annotates a symbol that is implemented natively"
      }
    ]
  }
}

在上面的示例中,擴充套件聲明瞭一個新型別templateType和一個新修飾符native。透過將type命名為超型別,type的主題樣式規則也將應用於templateType

{
  "name": "Red Theme",
  "semanticTokenColors": {
    "type": "#ff0011"
  }
}

上面顯示的semanticTokenColors"#ff0011"適用於type及其所有子型別,包括templateType

除了自定義標記型別,擴充套件還可以定義這些型別如何對映到 TextMate 作用域。這在自定義對映部分中有所描述。請注意,自定義對映規則不會自動從超型別繼承。相反,子型別需要重新定義對映,最好是更具體的範圍。

語義高亮的啟用

是否計算和高亮語義標記由設定editor.semanticHighlighting.enabled決定。它可以有truefalseconfiguredByTheme值。

  • truefalse為所有主題開啟或關閉語義高亮。
  • configuredByTheme是預設值,並讓每個主題控制是否啟用語義高亮。所有隨 VS Code 附帶的主題(例如,“深色+”預設主題)都預設啟用了語義高亮。

依賴於語義標記的語言擴充套件可以在其package.json中覆蓋其語言的預設值

{
  "configurationDefaults": {
    "[languageId]": {
      "editor.semanticHighlighting.enabled": true
    }
  }
}

主題

主題是為標記分配顏色和樣式。主題規則在顏色主題檔案(JSON 格式)中指定。使用者還可以在使用者設定中自定義主題規則。

顏色主題中的語義著色

為了支援基於語義標記的高亮,顏色主題檔案格式中添加了兩個新屬性。

屬性semanticHighlighting定義主題是否已準備好使用語義標記進行高亮。它預設為 false,但我們鼓勵所有主題啟用它。當設定editor.semanticHighlighting.enabled設定為configuredByTheme時使用此屬性。

屬性semanticTokenColors允許主題定義新的著色規則,這些規則與語義標記提供程式發出的語義標記型別和修飾符匹配。

{
  "name": "Red Theme",
  "tokenColors": [
    {
      "scope": "comment",
      "settings": {
        "foreground": "#dd0000",
        "fontStyle": "italic"
      }
    }
  ],
  "semanticHighlighting": true,
  "semanticTokenColors": {
    "variable.readonly:java": "#ff0011"
  }
}

variable.readonly:java被稱為選擇器,其形式為(*|tokenType)(.tokenModifier)*(:tokenLanguage)?

如果規則匹配,則該值描述樣式。它是一個字串,表示前景色,或者是一個物件,形式為{ foreground: string, bold: boolean, italic: boolean, underline: boolean }{ foreground: string, fontStyle: string },如tokenColors中用於 TextMate 主題規則一樣。

前景需要遵循顏色格式中描述的顏色格式。不支援透明度。

以下是選擇器和樣式的其他示例

  • "*.declaration": { "bold": true } // 所有宣告都加粗
  • "class:java": { "foreground": "#0f0", "italic": true } // Java 中的類

如果沒有規則匹配,或者主題沒有semanticTokenColors部分(但啟用了semanticHighlighting),VS Code 將使用語義標記作用域對映來評估給定語義標記的 TextMate 作用域。該作用域將與主題的tokenColors中的 TextMate 主題規則匹配。

語義標記作用域對映

為了使語義高亮適用於尚未定義任何特定語義規則的主題,並作為自定義標記型別和修飾符的後備,VS Code 維護從語義標記選擇器到 TextMate 作用域的對映。

如果主題啟用了語義高亮,但沒有包含給定語義標記的規則,則將使用這些 TextMate 作用域來查詢 TextMate 主題規則。

預定義的 TextMate 作用域對映

下表列出了當前預定義的對映。

語義標記選擇器 回退 TextMate 作用域
名稱空間 entity.name.namespace
type entity.name.type
type.defaultLibrary support.type
結構體 storage.type.struct
entity.name.type.class
class.defaultLibrary support.class
介面 entity.name.type.interface
enum entity.name.type.enum
函式 entity.name.function
function.defaultLibrary support.function
方法 entity.name.function.member
entity.name.function.preprocessor
variable variable.other.readwrite , entity.name.variable
variable.readonly variable.other.constant
variable.readonly.defaultLibrary support.constant
引數 variable.parameter
property variable.other.property
property.readonly variable.other.constant.property
enumMember variable.other.enummember
event variable.other.event

自定義 TextMate 作用域對映

透過擴充套件在其package.json中的semanticTokenScopes貢獻點,可以擴充套件此對映。

擴充套件這樣做的用例有兩個

  • 定義自定義標記型別和標記修飾符的擴充套件提供 TextMate 作用域作為後備,當主題未為新增的語義標記型別或修飾符定義主題規則時

    {
      "contributes": {
        "semanticTokenScopes": [
          {
            "scopes": {
              "templateType": ["entity.name.type.template"]
            }
          }
        ]
      }
    }
    
  • TextMate 語法的提供者可以描述特定於語言的作用域。這有助於包含特定於語言的主題規則的主題。

    {
      "contributes": {
        "semanticTokenScopes": [
          {
            "language": "typescript",
            "scopes": {
              "property.readonly": ["variable.other.constant.property.ts"]
            }
          }
        ]
      }
    }
    

試試看

我們有一個語義標記示例,它說明了如何建立語義標記提供程式。

作用域檢查器工具允許您探索原始檔中存在哪些語義標記以及它們匹配哪些主題規則。要檢視語義標記,請在 TypeScript 檔案上使用內建主題(例如,深色+)。