本站点文档内容均翻译自code.visualstudio.com,仅供个人学习,如有差异请以官网为准。

语义突出指南

语义高亮是语法高亮的补充,如在语法高亮指南中所述。Visual Studio Code 使用 TextMate 语法作为主要的标记引擎。TextMate 语法以单个文件为输入,并根据用正则表达式表示的词法规则将其分解。

语义分词允许语言服务器根据语言服务器在项目上下文中如何解析符号的知识,提供额外的分词信息。主题可以选择使用语义分词来改进和优化语法的语法高亮显示。编辑器将语义分词的高亮显示应用在语法的高亮显示之上。

以下是语义突出显示可以添加的示例:

没有语义突出显示:

没有语义突出显示

带有语义突出显示:

带有语义突出显示

请注意基于语言服务符号理解的颜色差异:

  • 第10行:语言模式被参数化为一种颜色
  • 第11行:范围职位被标记为类,并且文档作为参数。
  • 第13行:获取折叠范围被用作函数的着色。

语义令牌提供者

为了实现语义突出显示,语言扩展可以注册一个语义令牌提供者根据文档语言和/或文件名。编辑器将在需要语义标记时向提供商提出请求。

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' }; // 从本地文件系统注册所有Java文档

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

语义标记提供程序 API 有多种形式,以适应语言服务器的能力:

  • 文档语义令牌提供者- 始终以完整的文档作为输入。

    • 提供文档语义令牌- 提供文档中的所有标记。
    • 提供文档语义标记编辑- 作为对先前响应的增量,提供文档中的所有标记。
  • 文档范围语义标记提供者- 仅在范围内工作。

    • 提供文档范围语义标记- 提供文档范围内所有标记。

每个由提供者返回的代币都具有一个分类,该分类由代币类型、任意数量的代币修饰符和代币语言组成。

如上面的例子所示,提供者在其声明中指定了将使用的类型和修饰符语义令牌图例. 那允许提供API 用于返回标记类型并作为图例的索引进行修改。

语义标记分类

语义标记提供者的输出由标记组成。每个标记都有一个范围和一个标记分类,描述该标记代表什么类型的语法元素。可选地,分类还可以命名一种语言,如果该标记是嵌入语言的一部分。

为了描述语法元素、语义标记类型和修饰符,使用了这些信息。这类似于在《语法突出显示指南》中描述的 TextMate 范围,但我们希望制定一个专用且更简洁的分类系统。

VS Code 附带了一组标准的语义标记类型和修饰符,供所有语义标记提供者使用。然而,语义标记提供者仍然可以定义新的类型和修饰符,并创建标准类型的子类型。

标准代币类型和修饰符

标准类型和修饰符涵盖了多种语言中使用的常见概念。虽然每种语言可能对某些类型和修饰符使用不同的术语,但通过遵循标准分类,主题作者可以定义适用于多种语言的主题规则。

这些是 VS Code 预定义的标准语义标记类型和语义标记修饰符:

标准代币类型:

身份证 描述
命名空间 对于声明或引用命名空间、模块或包的标识符。
用于声明或引用类类型的标识符。
枚举 用于声明或引用枚举类型标识符。
接口 用于声明或引用接口类型的标识符。
结构体 对于声明或引用结构体类型的标识符。
类型参数 对于声明或引用类型参数的标识符。
类型 对于声明或引用上述内容未涵盖的类型的标识符。
参数 对于声明或引用函数或方法参数的标识符。
变量 用于声明或引用局部或全局变量的标识符。
财产 对于声明或引用成员属性、成员字段或成员变量的标识符。
枚举成员 对于声明或引用枚举属性、常量或成员的标识符。
装饰器 用于声明或引用装饰器和注释的标识符。
事件 用于声明事件属性的标识符。
函数 对于声明函数的标识符。
方法 对于声明成员函数或方法的标识符。
宏观 对于声明宏的标识符。
Tab 用于声明标签的标识符。
评论 对于代表评论的代币。
字符串 对于表示字符串字面值的标记。
关键词 对于代表语言关键字的代币。
数字 对于表示数字字面量的标记。
正则表达式 对于表示正则表达式字面量的标记。
操作员 对于代表操作符的代币。

标准代币修饰符:

身份证 描述
声明 用于符号声明。
定义 符号定义,例如,在头文件中。
只读 对于只读变量和成员字段(常量)。
静态 对于类成员(静态成员)。
已弃用 对于不再使用的符号。
摘要 对于抽象类型和成员函数。
异步 对于标记为 async 的函数。
修改 对于变量引用,该变量被分配。
文档 对于文档中符号的出现。
默认库 对于标准库的一部分符号。

除了标准类型和修饰符,VS Code 还定义了类型和修饰符到类似 TextMate 范围的映射。这在 语义标记范围映射 部分中有所涵盖。

自定义代币类型和修饰符

如果需要,扩展可以通过该接口声明新的类型和修饰符或创建现有类型的子类型语义标记类型语义标记修饰符他们在扩展中的贡献点package.json输入:

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

在上面的示例中,一个扩展声明了一种新类型模板类型和一个新的修饰符本地通过命名类型作为超级类型,主题样式规则为类型也将适用于模板类型输入:

{
  "name": "红色主题",
  "semanticTokenColors": {
    "类型": "#ff0011"
  }
}

语义标记颜色"#ff0011"如上所述,适用于两者类型及其所有子类型,包括模板类型输入:.

除了自定义的令牌类型,扩展可以定义这些类型如何映射到 TextMate 范围。这在自定义映射部分中描述。请注意,自定义映射规则不会自动从父类型继承。相反,子类型需要重新定义映射,最好映射到更具体的范围。

语义突出显示的启用

是否计算和突出显示语义标记由设置决定编辑器.语义高亮.启用. 它可以有值,和按主题配置输入:.

  • 将所有主题的语义突出显示打开或关闭。
  • 按主题配置是默认设置,允许每个主题控制是否启用语义高亮。所有 VS Code 自带的主题(例如,"Dark+"默认主题)默认启用语义高亮。

依赖语义标记的语言扩展可以在其 中覆盖其语言的默认设置package.json输入:

{
  "配置默认值": {
    "[语言ID]": {
      "编辑器语义高亮启用": true
    }
  }
}

主题化

主题化是将颜色和样式分配给标记的过程。主题化规则在颜色主题文件(JSON格式)中指定。用户还可以在用户设置中自定义主题化规则。

语义着色在颜色主题中

为了支持基于语义标记的突出显示,Color Theme文件格式中添加了两个新属性。

属性语义突出显示定义主题是否准备好使用语义标记进行突出显示。默认情况下,它为假,但我们鼓励所有主题启用它。该属性在设置中使用编辑器.语义高亮.启用设置为按主题配置输入:.

属性语义标记颜色允许主题定义新的着色规则,这些规则与语义标记提供程序发出的语义标记类型和修饰符进行匹配。

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

variable.readonly:java被称为选择器,并具有形式(*|标记类型)(.标记修饰符)*(:Markdown)?输入:.

该值描述了规则匹配时的样式。它要么是一个字符串,表示前景色,要么是一个对象,形式为{ 前景色: 字符串, 加粗: 布尔值, 斜体: 布尔值, 下划线: 布尔值 }{ 前景色: 字符串, 字体样式: 字符串 }作为用于 TextMate 主题规则代币颜色输入:.

前景需要遵循在颜色格式中描述的颜色格式。不支持透明度。

以下是其他选择器和样式的示例:

  • "*.declaration": { "bold": true } // 所有声明都是粗体
  • "类:java": { "前景": "#0f0", "斜体": true } // java中的类

如果没有任何规则匹配或主题没有语义标记颜色部分(但是语义突出显示 启用),VS Code 使用 语义标记范围映射 来评估给定的语义标记的 TextMate 范围。该范围与 中的 TextMate 主题规则进行匹配代币颜色输入:.

语义标记作用域映射

为了使语义突出显示能够适用于没有定义任何特定语义规则的主题,并作为自定义标记类型和修改符的备用方案,VS Code 维护了一个从语义标记选择器到 TextMate 范围的映射。

如果一个主题启用了语义突出显示,但不包含给定的语义标记的规则,则会使用这些 TextMate 范围来查找 TextMate 主题规则。

预定义的 TextMate 范围映射

以下表格列出了当前预定义的映射。

语义标记选择器 回退 TextMate 作用域
命名空间 实体名称命名空间
类型 实体名称类型
类型.默认库 支持类型
结构体 存储类型.结构体
实体名称类型类
类.默认库 支持类
接口 实体名称类型接口
枚举 实体名称类型枚举
函数 实体.名称.功能
function.defaultLibrary 支持功能
方法 实体.名称.函数.成员
宏观 实体.名称.函数.预处理器
变量 变量.其他.读写实体名称变量
变量.只读 变量.其他.常量
变量.只读.默认库 支持.常量
参数 变量.参数
财产 变量.其他.属性
属性.只读 变量.其他.常量.属性
枚举成员 变量.其他.枚举成员
事件 变量.其他.事件

自定义 TextMate 范围映射

此地图可以通过扩展通过语义标记范围贡献点在他们的package.json输入:.

对扩展进行此操作有两个用例:

  • 定义自定义令牌类型和令牌修饰符的扩展在主题未定义为添加的语义令牌类型或修饰符的着色规则时,提供 TextMate 范围作为回退:

    {
      "contributes": {
        "semanticTokenScopes": [
          {
            "scopes": {
              "templateType": ["entity.name.type.template"]
            }
          }
        ]
      }
    }
    
  • TextMate语法的提供者可以描述特定语言的范围。这对于包含特定语言主题规则的主题很有帮助。

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

试试看

我们有一个语义令牌示例,它展示了如何创建一个语义令牌提供者。

作用域检查器工具允许您探索源文件中存在哪些语义令牌以及它们匹配哪些主题规则。要查看语义令牌,请在TypeScript文件上使用内置主题(例如,Dark+)。