Token 着色与语义着色
代码高亮由两套系统协作:TextMate 语法着色(基于语法规则)与语义着色(基于语言服务理解)。理解两者关系是主题配色的关键。
两套着色系统对比
| 维度 | tokenColors | semanticTokenColors |
|---|---|---|
| 数据来源 | TextMate 语法(正则匹配) | 语言服务(编译/解析结果) |
| 理解粒度 | 词法层面 | 语义层面(变量/参数/类型) |
| 覆盖范围 | 所有语言 | 依赖语言服务支持 |
| 准确度 | 静态规则 | 动态精确 |
语义着色通常覆盖在语法着色之上:同一个 token 先按语法规则着色,若语言服务标注了语义类型且有对应规则,则用语义颜色覆盖。
tokenColors 规则结构
tokenColors 是规则数组,每条规则由 scope 与 settings 构成:
{
"tokenColors": [
{
"name": "注释",
"scope": "comment",
"settings": {
"foreground": "#8b949e",
"fontStyle": "italic"
}
}
]
}settings 支持
| 字段 | 值 | 作用 |
|---|---|---|
foreground | 十六进制颜色 | 前景色 |
background | 十六进制颜色 | 背景色(少见,用于高亮块) |
fontStyle | 空格分隔的关键字 | 字体样式 |
fontWeight | 如 bold | 字重 |
fontStyle 组合
{
"scope": "keyword",
"settings": {
"fontStyle": "italic bold underline"
}
}fontStyle 取值:italic、bold、underline、strikethrough,可空格组合。空字符串表示取消继承的样式。
scope 选择器语法
scope 是分层命名的,选择器按层级匹配。
单个 scope 匹配
{
"scope": "keyword",
"settings": { "foreground": "#ff7b72" }
}数组匹配多个 scope
{
"scope": ["keyword", "storage", "constant.language"],
"settings": { "foreground": "#ff7b72" }
}嵌套选择器(用空格)
TextMate scope 是点分隔的层级链,选择器中用空格表示嵌套关系:
{
"scope": "source.js keyword.operator",
"settings": { "foreground": "#79c0ff" }
}这条规则匹配"JavaScript 源文件中的运算符关键字",只对 keyword.operator 且在 source.js 内部的 token 生效。
选择器优先级
嵌套选择器比单独 scope 优先级更高:
{
"tokenColors": [
{
"name": "通用运算符",
"scope": "keyword.operator",
"settings": { "foreground": "#79c0ff" }
},
{
"name": "仅 JS 的运算符",
"scope": "source.js keyword.operator",
"settings": { "foreground": "#ffa657" }
}
]
}JS 文件中的运算符会命中第二条规则(更精确),其他语言命中第一条。
常用 scope 速查
| scope | 含义 |
|---|---|
comment | 注释 |
string | 字符串 |
string.quoted.double | 双引号字符串 |
keyword | 关键字 |
keyword.control | 控制流关键字 |
keyword.operator | 运算符 |
storage.type | 类型声明(int/const/let) |
constant.numeric | 数字 |
constant.language | 语言常量(this/null/true) |
entity.name.function | 函数定义名 |
entity.name.type | 类型定义名 |
variable | 变量 |
variable.parameter | 函数参数 |
support.function | 内置函数(console.log 的 log) |
punctuation.definition | 标点定义 |
示例:完整的基础高亮规则
{
"tokenColors": [
{ "scope": "comment", "settings": { "foreground": "#8b949e", "fontStyle": "italic" } },
{ "scope": "string", "settings": { "foreground": "#a5d6ff" } },
{ "scope": "keyword", "settings": { "foreground": "#ff7b72" } },
{ "scope": "keyword.operator", "settings": { "foreground": "#79c0ff" } },
{ "scope": "constant.numeric", "settings": { "foreground": "#79c0ff" } },
{ "scope": "constant.language", "settings": { "foreground": "#ff7b72" } },
{ "scope": "storage.type", "settings": { "foreground": "#ff7b72" } },
{ "scope": "entity.name.function", "settings": { "foreground": "#d2a8ff" } },
{ "scope": "variable", "settings": { "foreground": "#ffa657" } },
{ "scope": "variable.parameter", "settings": { "foreground": "#79c0ff" } },
{ "scope": "support.function", "settings": { "foreground": "#d2a8ff" } },
{ "scope": "punctuation", "settings": { "foreground": "#8b949e" } }
]
}language-specific 语言特定着色
用嵌套选择器限定语言,为特定语言覆盖配色:
{
"tokenColors": [
{
"name": "Python 装饰器",
"scope": "source.python meta.function.decorator",
"settings": { "foreground": "#79c0ff" }
},
{
"name": "HTML 标签",
"scope": "text.html.basic meta.tag",
"settings": { "foreground": "#7ee787" }
},
{
"name": "CSS 属性名",
"scope": "source.css property-name",
"settings": { "foreground": "#79c0ff" }
}
]
}语言 scope 前缀参考:
| 语言 | 顶层 scope |
|---|---|
| JavaScript | source.js |
| TypeScript | source.ts |
| Python | source.python |
| Java | source.java |
| HTML | text.html.basic |
| CSS | source.css |
| JSON | source.json |
semanticTokenColors 语义着色
语义 token 类型由语言服务声明,主题为其分配颜色:
{
"semanticTokenColors": {
"namespace": "#d2a8ff",
"type": "#d2a8ff",
"class": "#d2a8ff",
"enum": "#d2a8ff",
"interface": "#d2a8ff",
"typeParameter": "#ffa657",
"parameter": "#79c0ff",
"variable": "#ffa657",
"property": "#79c0ff",
"enumMember": "#ffa657",
"event": "#ff7b72",
"function": "#d2a8ff",
"method": "#d2a8ff",
"macro": "#ff7b72",
"keyword": "#ff7b72",
"modifier": "#ff7b72",
"comment": "#8b949e",
"string": "#a5d6ff",
"number": "#79c0ff",
"boolean": "#ff7b72",
"operator": "#79c0ff",
"decorator": "#d2a8ff"
}
}语义修饰符
修饰符表达附加语义,如 readonly、defaultLibrary、declaration:
{
"semanticTokenColors": {
"variable.readonly": "#ffa657",
"variable.defaultLibrary": "#8b949e",
"parameter.declaration": "#79c0ff",
"type.defaultLibrary": "#8b949e"
}
}语义着色的语法着色回退
语言服务的语义 token 未命中任何 semanticTokenColors 规则时,颜色回退到语法着色结果。为语义 token 单独配色的效果:
{
"semanticTokenColors": {
"parameter": "#79c0ff"
}
}所有语言服务标注为参数的 token 都会变成蓝色,即使语法着色原本给了别的颜色。
语义 token 的编辑器控制
用户可细化语义着色:设置 editor.semanticTokenColorCustomizations 可覆盖语义颜色、开关特定类型:
{
"editor.semanticTokenColorCustomizations": {
"enabled": true,
"rules": {
"parameter": "#9cdcfe",
"variable.readonly": "#4fc1ff"
}
}
}主题侧开关
{
"semanticTokenColors": {},
"semanticHighlighting": false
}semanticHighlighting: false 关闭整主题的语义着色;semanticTokenColors 为空对象则只关闭默认语义配色。
着色调试
Inspect Editor Tokens and Scopes
命令面板运行 Developer: Inspect Editor Tokens and Scopes,查看 token 的完整信息:
------ Inspect Token at 6:10 -----
Text: user
Foreground: #ffa657
Scope: source.ts variable.other.readwrite
source.ts meta.object-literal.key
Meta: Meta 信息...
Semantic token type: variable, modifier: readonly语义 token 调试
同一命令会显示语义信息(Semantic token type 部分),标注语义类型与修饰符,以及是否命中 semanticTokenColors 规则。
完整示例:暗色主题的着色系统
{
"name": "Ocean Dark",
"type": "dark",
"tokenColors": [
{ "scope": "comment", "settings": { "foreground": "#8b949e", "fontStyle": "italic" } },
{ "scope": "string", "settings": { "foreground": "#a5d6ff" } },
{ "scope": "keyword, storage.type, constant.language", "settings": { "foreground": "#ff7b72" } },
{ "scope": "keyword.operator", "settings": { "foreground": "#79c0ff" } },
{ "scope": "constant.numeric", "settings": { "foreground": "#79c0ff" } },
{ "scope": "entity.name.function, support.function", "settings": { "foreground": "#d2a8ff" } },
{ "scope": "variable", "settings": { "foreground": "#ffa657" } },
{ "scope": "variable.parameter", "settings": { "foreground": "#79c0ff" } },
{ "scope": "source.js keyword.operator", "settings": { "foreground": "#ff7b72" } }
],
"semanticTokenColors": {
"parameter": "#79c0ff",
"variable": "#ffa657",
"variable.readonly": "#8b949e",
"function": "#d2a8ff",
"type": "#d2a8ff"
}
}语法着色 + 语义着色构成了完整的代码高亮体系。下一步把配色延伸到文件图标,让资源管理器同样有主题感。