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\brepository: 这是一堆键值对形式的规则,可以在文档中使用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: 设置正则匹配到的部分的类型,用来高亮,只能包含nameinclude: 引用其他语言的高亮规则或者引用repository里面的东西
命名规则
为了让主题文件可以通用,name 设置要遵循一定的规则,这样编辑器就知道这块地方是注释,那块是关键字,
从而为不同的部分设置不同的颜色,高亮就是这么来的。名字各部分之间使用 . 连接起来,比如
comment.line.number-sign:
comment设置注释line单行注释,一般使用的有double-slash//double-dash–number-sign#percentage— %- character 其他类型的单行注释
block多行注释,比如/* … */,<!-- … -->documentation
constant常量numeric数字character字符,比如<,\e,\031escape转义字符
language语言支持的常量,true/false/nil等等other比如 css 里面的颜色
entity各种实体,类名,方法名等namefunction方法名type类型名tag标签名section区块名
other其他实体inherited-class继承的类名attribute-name属性名
invalid表示非法内容illegaldeprecated
keyword关键字control流程控制类if/while之类operator运算符,比如orother其他
markup为标记语言使用的,顾名思义即可underlineboldheadingitalicquoteraw比如代码块,无格式other
meta表示不同的部分,比如meta.class,meta.method目的是更好的组织这些规则storage与数据存储相关的type类型class/function/int/var等modifier修饰符static/const/final啥的
string字符串quotedsingle单引号引用的double双引号引用的triple三个引号引用的 比如"""Python"""other另类的,比如$'shell',%{ruby}
unquotedhere-docinterpolated要解析的字符串:`date`,$(pwd)regexp正则表达式other其他类型的字符串
support框架或者库提供的功能function比如C里面的printfclass比如C++里面的vectortypeconstantvariableother
variableparameter函数参数language语言预定于的变量,比如this/super/selfother
实战
有了这些东西就可以开始为一个语言写高亮配置文件了,这里选用一个简单的语言 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"
}
}
}
]
}
}
}
效果如下:
