如何打造一款属于自己的 Visual Studio Code 颜色主题

Visual Studio Code 是我在最近一年中最喜欢的一款编辑器,微软每一次的更新都会给大家带来惊喜,更是令人愈加喜欢。之前一直使用内置的颜色主题 Light+ 和 Dark+ ,但近来突然觉得前者颜色区分度不高,一眼看上去就密密麻麻的一对代码,而后者则是被选中的文本背景色太浅,跟编辑器的背景颜色很相似,很难区分出来,于是萌生了要制作一款自己的颜色主题的想法。经过几天的研究,终于捣鼓出来了 Lei Theme 系列颜色主题。

先来看看其中两款主题的效果:

一般来说,我们并不需要重头来制作一款颜色主题,首先需要选择一款自己最喜欢的颜色主题(或者说先找一款与自己的想法最相似的颜色主题),然后在此基础上进行些许调整即可。另外如果想将颜色主题发布到微软的 Visual Studio Code 扩展商店上,还需要注册一个微软开发者账号,并通过 vsce 工具来发布出去,下文会对此进行详细说明。

tmTheme 格式的颜色主题

TextMate 曾是多年前最流行的代码编辑器之一,其颜色主题的文件后缀为 .tmTheme ,在本文中我们将其简称为 tmTheme 格式。Visual Studio Studio 的颜色主题采用的是标准的 TextMate 主题格式,我们可以参考这篇文章 Writing a TextMate Grammar: Some Lessons Learned ,大概可以理解为这样: 编辑器对代码进行解析后,会为每个元素指定一个 scope ,这个 scope 即表明此元素是一个关键字还是一个常量,又或者是一个标点符号,通过 tmTheme 格式的文件来定义相应 scope 的文字样式。

根据该文章可知道以下是常见的 scope 列表:

comment

constant

constant.character.escape

constant.language

constant.numeric

declaration.section entity.name.section

declaration.tag

deco.folding

entity.name.function

entity.name.tag

entity.name.type

entity.other.attribute-name

entity.other.inherited-class

invalid

invalid.deprecated.trailing-whitespace

keyword

keyword.control.import

keyword.operator.js

markup.heading

markup.list

markup.quote

meta.embedded

meta.preprocessor

meta.section entity.name.section

meta.tag

storage

storage.type.method

string

string source

string.unquoted

support.class

support.constant

support.function

support.type

support.variable

text source

variable

variable.language

variable.other

variable.parameter

以下是一个 tmTheme 格式文件的代码片段:

<dict>

<key>name</key>

<string>Keyword</string>

<key>scope</key>

<string>keyword.control,keyword.other,variable.language,storage.type,storage.modifier,keyword.function</string>

<key>settings</key>

<dict>

<key>foreground</key>

<string>#0808D1</string>

</dict>

</dict>

<dict>

<key>name</key>

<string>Invalid</string>

<key>scope</key>

<string>invalid</string>

<key>settings</key>

<dict>

<key>foreground</key>

<string>#cd3131</string>

</dict>

</dict>

从上面的代码可以看出,其实这个 tmTheme 格式的文件似乎也挺简单的,然而初学者而言,难的是 不知道 scope 怎么写 ,下文会循序渐进地对此进行说明。

创建颜色主题项目

根据官方文档,我们先执行以下命令安装 Yeoman 代码生成工具来创建一个默认的颜色主题项目:

$ npm install -g yo generator-code

安装完毕之后,进入 ~/.vscode/extensions 目录执行以下命令启动生成器:

$ yo code

说明: ~/.vscode/extensions 表示用户根目录下的 .vscode/extensions 目录,之所以在此处新建项目主要是为了不用发布到扩展商店也可以在本地进行使用,并且方便调试。

选择 New Color Theme 创建颜色主题项目:

_-----_ ╭——————————————————————————╮

| | │ Welcome to the Visual │

|--(o)--| │ Studio Code Extension │

`---------? │ generator! │

( _?U`_ ) ╰——————————————————————————╯

/___A___\ /

| ~ |

__'.___.'__

? ` |° ? Y `

What type of extension do you want to create?

New Extension (TypeScript)

New Extension (JavaScript)

New Color Theme

New Language Support

New Code Snippets

接着需要在命令行下交互式地填写一些问题,以下是我在执行过程中填写的内容:

What type of extension do you want to create? New Color Theme

URL (/app/?23C4FA</string>

</dict>

</dict>

其中第一项 name 表示的是我们给该规则起的名称; scope 则是适用的 scope ,如果多个可以用逗号分隔,比如 User-defined constant 的 scope 值就为 constant.character, constant.other ; settings 则是具体的样式信息,比如颜色值。

从源码中可以看出,支持的样式只有 foreground 和 fontStyle ,而 background 则从注释中可以看出由于某原因导致 Visual Studio Code 暂时不支持。

scope 值为 template.expression 则可被认为是 CSS 类选择器 token.template.expression ,在前文的 Developer Tools 的演示视频中,模板字符串的变量名在渲染时其 HTML 为 <span class="token block ts meta variable other readwrite string function arrow new expr template expression">...</span> ,如果我们熟悉 CSS 的话应该能一眼就看出来 .token.template.expression 是会匹配到该标签的。所以,我们可以简单地把 scope 当作是 CSS 的类选择器。

需要注意的是,如果我们在定义 scope 时写得不够详细,可能会错误地匹配到其他元素,致使调好了一部分,另一部分却被调坏了,所以要做得完美也并非易事。

发布到扩展商店

要将扩展发布到扩展商店以便让更多人可以使用到,我们需要借助 vsce 命令行工具,可以参考文档 vsce - Publishing Tool Reference 。以下是其基本步骤:

安装 vsce 命令行工具。执行命令 npm install -g vsce

注册 Visual Studio Team Services 账号,并获取到 Access Token

创建 Publisher。执行命令 vsce create-publisher

登录到 Publisher。执行命令 vsce login

发布扩展。执行命令 vsce publish

详细操作步骤建议参考相应的官方文档。

本文并没有详细到手把手教地去讲解如何打造一款 Visual Studio Code 颜色主题,仅仅是提到了几个我在折腾过程中认为比较关键,而又很难通过文档去查到的要点。爱折腾是程序员的天性,希望本文能让爱折腾的你少走一些弯路,把喜爱的 Visual Studio Code 玩出花来。