语义高亮指南
语义高亮是 语法高亮指南 中描述的语法高亮的补充。Visual Studio Code 使用 TextMate 语法作为主要的标记化引擎。TextMate 语法将单个文件作为输入,并根据正则表达式中表达的词法规则将其分解。
语义标记化允许语言服务器根据语言服务器在项目上下文中解析符号的知识提供额外的标记信息。主题可以选择使用语义令牌来改进和细化来自语法的语法高亮。编辑器将来自语义令牌的高亮应用在来自语法的高亮之上。
这是一个语义高亮可以添加的示例
没有语义高亮
有语义高亮
请注意基于语言服务符号理解的颜色差异
- 第 10 行:
languageModes
被着色为参数 - 第 11 行:
Range
和Position
被着色为类,document
被着色为参数。 - 第 13 行:
getFoldingRanges
被着色为函数。
语义令牌提供程序
要实现语义高亮,语言扩展可以按文档语言和/或文件名注册一个 semantic token provider
(语义令牌提供程序)。当需要语义令牌时,编辑器将向提供程序发出请求。
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 | 描述 |
---|---|
namespace |
对于声明或引用命名空间、模块或包的标识符。 |
class |
对于声明或引用类类型的标识符。 |
enum |
对于声明或引用枚举类型的标识符。 |
interface |
对于声明或引用接口类型的标识符。 |
struct |
对于声明或引用结构类型的标识符。 |
typeParameter |
对于声明或引用类型参数的标识符。 |
type |
对于声明或引用上面未涵盖的类型的标识符。 |
parameter |
对于声明或引用函数或方法参数的标识符。 |
variable |
对于声明或引用局部或全局变量的标识符。 |
property |
对于声明或引用成员属性、成员字段或成员变量的标识符。 |
enumMember |
对于声明或引用枚举属性、常量或成员的标识符。 |
decorator |
对于声明或引用装饰器和注释的标识符。 |
event |
对于声明事件属性的标识符。 |
function |
对于声明函数的标识符。 |
method |
对于声明成员函数或方法的标识符。 |
macro |
对于声明宏的标识符。 |
label |
对于声明标签的标识符。 |
comment |
对于表示注释的令牌。 |
string |
对于表示字符串字面量的令牌。 |
keyword |
对于表示语言关键字的令牌。 |
number |
对于表示数字字面量的令牌。 |
regexp |
对于表示正则表达式字面量的令牌。 |
operator |
对于表示运算符的令牌。 |
标准令牌修饰符
ID | 描述 |
---|---|
declaration |
对于符号的声明。 |
definition |
对于符号的定义,例如,在头文件中。 |
readonly |
对于只读变量和成员字段(常量)。 |
static |
对于类成员(静态成员)。 |
deprecated |
对于不应再使用的符号。 |
abstract |
对于抽象的类型和成员函数。 |
async |
对于标记为 async 的函数。 |
modification |
对于变量被赋值到的变量引用。 |
documentation |
对于文档中符号的出现。 |
defaultLibrary |
对于标准库中的符号。 |
除了标准类型和修饰符之外,VS Code 还定义了类型和修饰符到类似 TextMate 范围的映射。这将在 语义令牌范围映射 部分中介绍。
自定义令牌类型和修饰符
如有必要,扩展可以通过其扩展的 package.json
中的 semanticTokenTypes
和 semanticTokenModifiers
贡献点声明新的类型和修饰符,或创建现有类型的子类型
{
"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
决定。它可以具有值 true
、false
和 configuredByTheme
。
true
和false
为所有主题打开或关闭语义高亮。configuredByTheme
是默认值,并允许每个主题控制是否启用语义高亮。所有随 VS Code 附带的主题(例如,“Dark+”默认主题)默认启用语义高亮。
依赖于语义令牌的语言扩展可以在其 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 范围。该范围将与主题的 TextMate 主题规则(在 tokenColors
中)进行匹配。
语义令牌范围映射
为了使语义高亮显示适用于未定义任何特定语义规则的主题,并作为自定义令牌类型和修饰符的回退,VS Code 维护一个从语义令牌选择器到 TextMate 范围的映射。
如果主题启用了语义高亮显示,但没有包含给定语义令牌的规则,则将使用这些 TextMate 范围来查找 TextMate 主题规则。
预定义的 TextMate 范围映射
下表列出了当前预定义的映射。
语义令牌选择器 | 回退 TextMate 范围 |
---|---|
namespace |
entity.name.namespace |
type |
entity.name.type |
type.defaultLibrary |
support.type |
struct |
storage.type.struct |
class |
entity.name.type.class |
class.defaultLibrary |
support.class |
interface |
entity.name.type.interface |
enum |
entity.name.type.enum |
function |
entity.name.function |
function.defaultLibrary |
support.function |
method |
entity.name.function.member |
macro |
entity.name.function.preprocessor |
variable |
variable.other.readwrite , entity.name.variable |
variable.readonly |
variable.other.constant |
variable.readonly.defaultLibrary |
support.constant |
parameter |
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 文件上使用内置主题(例如,Dark+)。