Colorize Language in VSCode
微软大法好
VSCode 是个好编辑器,虽然插件挫了点,但是跑得比 Atom 快,调试功能特别赞,对 JavaScript 和 Go 的代码提示简直不能再好,将来插件生态再好一点,这就是一个全能的 IDE 了。
VSCode 在很早就开放了插件系统, 这里主要介绍一下语法高亮插件的部分。
VSCode 的语法高亮配置和 Atom 一样,使用的是 textmate 的配置语法。
例子
来看一个例子:
{
"scopeName": "source.untitled",
"fileTypes": [],
"foldingStartMarker": "\{\s*$",
"foldingStopMarker": "^\s*\}'",
"patterns": [
{
"name": "keyword.control.untitled",
"match": "\b(if|while|for|return)\b"
},
{
"name": "string.quoted.double.untitled",
"begin": "\"",
"end": "\"",
"patterns": [
{
"name": "constant.character.escape.untitled",
"match": "\\."
}
]
}
]
}
主要配置有几部分:
scopeName
: 这个是用来标识语言的,必须独一无二,一般使用.
分割成两个部分, 前半部分一般是text
/source
,后面是具体的语言名字fileTypes
: 这个用来指定配置适用的文件扩展名foldingStartMarker
/foldingStopMarker
: 用来控制折叠patterns
: 这才是真正用来识别高亮的规则
另外还有两个不在例子里面的配置:
firstLineMatch
: 如果匹配了文档第一行,这个文档就适用这个高亮规则,比如^#!/.*\bruby\b
repository
: 这是一堆键值对形式的规则,可以在文档中使用include
引用这些规则
规则
规则使用键值对形式,键可以是:
name
: 指定规则的名字,是用来高亮的依据,需要遵循一定的命名规则来让编辑器知道该高亮成什么类型match
: 匹配文本的正则表达式begin
,end
: 匹配多行文本的规则,和match
不能共存,begin
是匹配开头的正则,end
是匹配结尾的正则,begin
里面 capture 到内容可以在end
里面引用,比如匹配 heredoc 的时候:{ "name": "string.unquoted.here-doc", "begin": "<<(\w+)", "end": "^\1$" }
contentName
: 类似name
,但是是设置begin
和end
中间文本的类型的captures
,beginCaptures
,endCaptures
: 设置正则匹配到的部分的类型,用来高亮,只能包含name
include
: 引用其他语言的高亮规则或者引用repository
里面的东西
命名规则
为了让主题文件可以通用,name
设置要遵循一定的规则,这样编辑器就知道这块地方是注释,那块是关键字,
从而为不同的部分设置不同的颜色,高亮就是这么来的。名字各部分之间使用 .
连接起来,比如
comment.line.number-sign
:
comment
设置注释line
单行注释,一般使用的有double-slash
//double-dash
–number-sign
#percentage
— %- character 其他类型的单行注释
block
多行注释,比如/* … */
,<!-- … -->
documentation
constant
常量numeric
数字character
字符,比如<
,\e
,\031
escape
转义字符
language
语言支持的常量,true
/false
/nil
等等other
比如 css 里面的颜色
entity
各种实体,类名,方法名等name
function
方法名type
类型名tag
标签名section
区块名
other
其他实体inherited-class
继承的类名attribute-name
属性名
invalid
表示非法内容illegal
deprecated
keyword
关键字control
流程控制类if
/while
之类operator
运算符,比如or
other
其他
markup
为标记语言使用的,顾名思义即可underline
bold
heading
italic
quote
raw
比如代码块,无格式other
meta
表示不同的部分,比如meta.class
,meta.method
目的是更好的组织这些规则storage
与数据存储相关的type
类型class
/function
/int
/var
等modifier
修饰符static
/const
/final
啥的
string
字符串quoted
single
单引号引用的double
双引号引用的triple
三个引号引用的 比如"""Python"""
other
另类的,比如$'shell'
,%{ruby}
unquoted
here-docinterpolated
要解析的字符串:`date`
,$(pwd)
regexp
正则表达式other
其他类型的字符串
support
框架或者库提供的功能function
比如C
里面的printf
class
比如C++
里面的vector
type
constant
variable
other
variable
parameter
函数参数language
语言预定于的变量,比如this
/super
/self
other
实战
有了这些东西就可以开始为一个语言写高亮配置文件了,这里选用一个简单的语言 Cool, Cool (Classroom Object Oriented Language) 是 Stanford 编译器课程的教学语言,语法比较简单
具体语法可以查看 http://theory.stanford.edu/~aiken/software/cool/cool.html
具体例子可参考 https://github.com/maogm12/language-cool
在 VSCode 中安装的命令 ext install cool
{
"scopeName": "source.cool",
"name": "COOL",
"fileTypes": [
"cl"
],
"patterns": [
{
"include": "#code"
}
],
"repository": {
"block": {
"patterns": [
{
"begin": "{",
"end": "}",
"name": "meta.block.cool",
"patterns": [
{
"include": "#code"
}
]
}
]
},
"builtins": {
"patterns": [
{
"match": "(Int|String|Bool|IO|Object)",
"name": "support.class.cool"
},
{
"match": "(abort|type_name|copy|out_string|out_int|in_string|in_int|length|concat|substr)",
"name": "support.function.cool"
},
{
"match": "(self|SELF_TYPE)",
"name": "variable.language.cool"
}
]
},
"class": {
"begin": "((?i:class))\\s+([A-Z][A-Za-z0-9_]*)(\\s+((?i:inherits))\\s+([A-Z][A-Za-z0-9_]*))?\\b",
"beginCaptures": {
"1": {
"name": "storage.type.cool"
},
"2": {
"name": "entity.name.type.class.cool"
},
"4": {
"name": "keyword.operator.cool"
},
"5": {
"name": "entity.name.type.class.cool"
}
},
"end": "}",
"name": "meta.class.cool",
"patterns": [
{
"begin": "{",
"end": "(?=})",
"name": "meta.class.body.cs",
"patterns": [
{
"include": "#method"
},
{
"include": "#code"
}
]
}
]
},
"code": {
"patterns": [
{
"include": "#block"
},
{
"include": "#builtins"
},
{
"include": "#class"
},
{
"include": "#comments"
},
{
"include": "#constants"
},
{
"include": "#keywords"
},
{
"include": "#method"
}
]
},
"line_comment": {
"begin": "--",
"end": "$\\n?",
"name": "comment.line.double-dash.cool"
},
"block_comment": {
"begin": "\\(\\*",
"end": "\\*\\)\\n?",
"name": "comment.block.documentation.cool",
"patterns": [
{
"include": "#block_comment"
}
]
},
"comments": {
"patterns": [
{
"include": "#line_comment"
},
{
"include": "#block_comment"
}
]
},
"constants": {
"patterns": [
{
"match": "\\b(true|false)\\b",
"name": "constant.language.cool"
},
{
"match": "\\b([1-9][0-9]*)\\b",
"name": "constant.numeric.cool"
},
{
"begin": "(?<!\\\\)\"",
"end": "(?<!\\\\)\"",
"name": "string.quoted.double.cool",
"patterns": [
{
"match": "\\\\(n|t)",
"name": "constant.character.escape.cool"
}
]
}
]
},
"keywords": {
"patterns": [
{
"match": "\\b(if|then|else|fi|while|loop|pool|case|esac)\\b",
"name": "keyword.control.cool"
},
{
"match": "\\b(in|inherits|isvoid|let|new|of|new|not)\\b",
"name": "keyword.operator.cool"
}
]
},
"method": {
"patterns": [
{
"match": "\\b([a-z][A-Za-z0-9_]*)\\s*\\(\\s*(?:([a-z][A-Za-z0-9_]*)\\s*:\\s*([A-Z][A-Za-z0-9_]*))?(?:\\s*,\\s*([a-z][A-Za-z0-9_]*)\\s*:\\s*([A-Z][A-Za-z0-9_]*))*\\s*\\)\\s*:\\s*([A-Z][A-Za-z0-9_]*)\\b",
"name": "meta.method.cool",
"captures": {
"1": {
"name": "entity.name.function.cool"
},
"2": {
"name": "variable.parameter.cool"
},
"3": {
"name": "storage.type.cool"
},
"4": {
"name": "variable.parameter.cool"
},
"5": {
"name": "storage.type.cool"
},
"6": {
"name": "storage.type.cool"
}
}
}
]
}
}
}
效果如下: