# 35讲插件开发(四):Decorations装饰器
<br>
:-: 
<br>
今天,我们一起来聊一聊 Decorations 装饰器。
<br>
在[专栏第29讲《不错的插件推荐》](https://time.geekbang.org/column/article/68800)里,我介绍过[Pigment](https://marketplace.visualstudio.com/items?itemName=jaspernorth.vscode-pigments)这个插件,有了这个插件,你在代码中书写的颜色,将会以背景色的形式,直接被渲染在代码下面。
<br>
:-: 
<br>
:-: Pigment 插件效果
<br>
这个功能,就是通过 Decorations API 来实现的。同样的,我之前介绍的[Rainbow Brackets](https://marketplace.visualstudio.com/items?itemName=2gua.rainbow-brackets)和[Indent Rainbow](https://marketplace.visualstudio.com/items?itemName=oderwat.indent-rainbow),都是使用的这套 API。
<br>
:-: 
<br>
:-: Rainbow Brackets 插件效果
<br>
:-: 
<br>
:-: Indent Rainbow 插件效果
<br>
**那今天我们就来看看如何使用 Decorations API 来实现类似的效果,以及在这个过程中有哪些注意点。**
<br>
## 样例
<br>
首先,我们依然使用[专栏插件部分第一讲](https://time.geekbang.org/column/article/69768)里使用的 JavaScript 插件模板。这个模板的 extension.js 文件,现在被修改成如下内容:
<br>
~~~
const vscode = require('vscode');
function activate(context) {
vscode.commands.registerCommand('extension.sayHello', () => {
let decorationType = vscode.window.createTextEditorDecorationType({
backgroundColor: '#fff'
});
let editor = vscode.window.activeTextEditor;
editor.setDecorations(decorationType, [new vscode.Range(0, 0, 0, 1)]);
});
}
exports.activate = activate;
function deactivate() {
}
exports.deactivate = deactivate;
~~~
<br>
这段代码依然是注册了一个名为 extension.sayHello 的命令,只不过命令执行的内容变了。这段代码做的第一件事情,就是创建了一个 DecorationType:
<br>
~~~
let decorationType = vscode.window.createTextEditorDecorationType({
backgroundColor: '#fff'
})
~~~
<br>
从中可以看到我们使用了 vscode.window.createTextEditorDecorationType API,同时传入了一个参数对象,对象里添加了属性 backgroundColor,顾名思义,这个参数是用于定义背景色的。
<br>
接着我们就获取了当前的编辑器对象 editor。然后使用了 editor 上的方法 setDecorations,并且传入两个参数,第一个就是我们上面创建的 DecorationType,第二个则是代码范围 Range。通过这个 API,我们在这个代码片段 Range 上使用 decorationType 所代表的装饰器,也就是将背景色调整成`#fff`,即白色。
<br>
下面,我们就运行这个插件看看:
<br>
:-: 
<br>
:-: 运行 Decoration 插件
<br>
无论是Pigment、Rainbow Brackets,还是GitLens,它们修改编辑器内代码颜色和背景色的逻辑,跟上面的这一小段代码基本一致。只不过 VS Code 的 Decoration API,有非常多不同的属性可以设置,这也让 Decoration 效果千差万别。
<br>
下面我们就来看看都有哪些不同的设置。
<br>
## DecorationRenderOptions
<br>
如果我们在 createTextEditorDecorationType 运行 F12,我们就能够跳转到 createTextEditorDecorationType 函数的定义处,接着我们就能看到这个函数的参数类型是 DecorationRenderOptions。
<br>
:-: 
<br>
:-: createTextEditorDecorationType
<br>
而 createTextEditorDecorationType 的结构如下:
<br>
~~~
export interface DecorationRenderOptions extends ThemableDecorationRenderOptions {
isWholeLine?: boolean;
rangeBehavior?: DecorationRangeBehavior;
overviewRulerLane?: OverviewRulerLane;
light?: ThemableDecorationRenderOptions;
dark?: ThemableDecorationRenderOptions;
}
~~~
<br>
createTextEditorDecorationType 继承自 ThemableDecorationRenderOptions ,不过它多加了几个属性。比如是否将这个 decoration 运用在整行代码上,是否要将颜色渲染在滚动条上等。不过比较重要的两个属性其实是 light 和 dark。
<br>
**light**和**dark**的类型,都是 ThemableDecorationRenderOptions,只要设置了这两个值,VS Code 就会根据当前的主题是深色还是浅色,决定是加载 light 还是 dark 的值,如果这两个值没有设置的话,那么就会查看 DecorationRenderOptions 上的其他属性。
<br>
接下来,我们就看看 ThemableDecorationRenderOptions 里有哪些属性:
<br>
~~~
export interface ThemableDecorationRenderOptions {
backgroundColor?: string | ThemeColor;
outline?: string;
outlineColor?: string | ThemeColor;
outlineStyle?: string;
outlineWidth?: string;
border?: string;
borderColor?: string | ThemeColor;
borderRadius?: string;
borderSpacing?: string;
borderStyle?: string;
borderWidth?: string;
fontStyle?: string;
fontWeight?: string;
textDecoration?: string;
cursor?: string;
color?: string | ThemeColor;
opacity?: string;
letterSpacing?: string;
gutterIconPath?: string | Uri;
gutterIconSize?: string;
overviewRulerColor?: string | ThemeColor;
before?: ThemableDecorationAttachmentRenderOptions;
after?: ThemableDecorationAttachmentRenderOptions;
}
~~~
<br>
看到这里你可能会大吃一惊,这也太多了,那应该从哪里学起呢?别着急,我们来给这些属性归归类。
<br>
### 1、Color
<br>
首先,就是跟代码颜色和背景相关的属性。
<br>
~~~
backgroundColor?: string | ThemeColor;
color?: string | ThemeColor;
overviewRulerColor?: string | ThemeColor;
~~~
<br>
我们除了使用类似于 “#fff” 这样的字符串以外,还可以使用 ThemeColor,也就是颜色主题(themes)里的颜色定义,比如:
<br>
~~~
new vscode.ThemeColor('editorWarning.foreground')
~~~
<br>
这样一来,当我们切换主题的时候,这个颜色就会随之改变了。这几个属性的效果,通过文章一开始的例子,相信你已经有所了解,这里不多赘述。
<br>
### 2、Border
<br>
第二类就是 Border 边框,熟悉 CSS 的同学肯定不会觉得陌生。
<br>
~~~
border?: string;
borderColor?: string | ThemeColor;
borderRadius?: string;
borderSpacing?: string;
borderStyle?: string;
borderWidth?: string;
~~~
<br>
比如,我们对上面的样例代码略作修改:
<br>
~~~
vscode.commands.registerCommand('extension.sayHello', () => {
let decorationType = vscode.window.createTextEditorDecorationType({
border: '1px solid red;'
});
let editor = vscode.window.activeTextEditor;
editor.setDecorations(decorationType, [new vscode.Range(0, 0, 0, 1)]);
});
~~~
<br>
然后运行代码,就能够给代码块添加边框了。
<br>
:-: 
<br>
:-: 设置 Border
<br>
### 3、Outline
<br>
在 CSS 中 Outline (轮廓)是用于在 Border 边框的周围画一条线,以突出元素。我们同样可以使用下面这些配置,来分别控制 Outline 的各个属性。
<br>
~~~
outline?: string;
outlineColor?: string | ThemeColor;
outlineStyle?: string;
outlineWidth?: string;
~~~
<br>
比如,我们将样例代码修改成如下:
<br>
~~~
vscode.commands.registerCommand('extension.sayHello', () => {
let decorationType = vscode.window.createTextEditorDecorationType({
outline: '#00FF00 dotted'
});
let editor = vscode.window.activeTextEditor;
editor.setDecorations(decorationType, [new vscode.Range(1, 1, 1, 4)]);
});
~~~
<br>
然后运行,
<br>
:-: 
<br>
:-: 设置 Outline
<br>
这里还请注意,为了更好地看到效果,我把 range 修改成了 new vscode.Range(1, 1, 1, 4)。
<br>
### 4、Font
<br>
下一组属性则是跟文字相关,我们可以通过 fontStyle 和 fontWeight 来控制字体,也可以通过 opacity 来控制透明度,或者使用 letterSpacing 控制文字之间的间距。
<br>
~~~
fontStyle?: string;
fontWeight?: string;
opacity?: string;
letterSpacing?: string;
~~~
<br>
比如我们将代码修改为:
<br>
~~~
vscode.commands.registerCommand('extension.sayHello', () => {
let decorationType = vscode.window.createTextEditorDecorationType({
fontStyle: 'italic',
letterSpacing: '3px'
});
let editor = vscode.window.activeTextEditor;
editor.setDecorations(decorationType, [new vscode.Range(1, 1, 1, 4)]);
});
~~~
<br>
然后运行代码。
<br>
:-: 
<br>
:-: 设置字体
<br>
### 5、其他
<br>
除此之外,我们还可以通过 gutterIconPath 和 gutterIconSize 在行号旁边添加图标。
<br>
~~~
gutterIconPath?: string | Uri;
gutterIconSize?: string;
~~~
<br>
比如说 VS Code 中的断点,就可以通过这个属性在插件中实现。
<br>
:-: 
<br>
:-: 断点
<br>
另外,也可以通过 before 和 after 在某个代码的前面或者后面创建 decorations,
<br>
~~~
before?: ThemableDecorationAttachmentRenderOptions;
after?: ThemableDecorationAttachmentRenderOptions;
~~~
<br>
比如说,CSS 文件里颜色前的 Color Decorator “小方格”,就是使用 before 属性来实现。
<br>
:-: 
<br>
:-: CSS color decorator
<br>
## 小结
<br>
以上就是 Decoration API 的大部分知识了,可能还有部分 API 或者属性,我没有介绍,不过相信你可以自己挖掘出它们的作用。
<br>
最后,我想对 Decoration 的使用讲讲我自己的心得体会。
<br>
DecorationRenderOptions 里的大部分属性,其实就是 CSS 里的各种属性,如果你知道如何使用 CSS 来对元素布局的话,那么使用这些 API 就难不倒你。不过,最难的还是想象力,如何活用这套 API,将重要的信息呈现给用户,而又不会打扰到用户的正常体验,这就体现功力了。
<br>
比如说,我们之前介绍过 Import Cost 插件,这个插件就巧妙地将每个 javascript 模块的大小,渲染在了这一行代码的最后,十分显眼,但又不会影响到你查看代码。
<br>
:-: 
<br>
:-: Import Cost
<br>
GitLens 插件也有类似的设计,它可以把当前这行是谁写的从 Git 中读取出来,然后渲染在本行代码的最后,同时,这些信息的颜色比较浅,从而不会喧宾夺主,但是当你需要的时候,也可以轻松迅速地查看代码的修改信息。
<br>
:-: 
<br>
:-: GitLens Blame 信息
<br>
而文章最开始介绍的 Rainbow Brackets 等,也都是对 Decoration API 的活用。看完这些例子后,不知道你有没有酝酿出什么有趣的想法和技巧,不妨和我们分享分享,一起学习 ;)
- 开篇词讲玩转编辑器,向高效能编程再进一步
- 01讲学编辑器,到底应该学什么
- 02讲VSCode的Why、How和What
- 03讲如何快速上手VSCode?
- 04讲 如何做到双手不离键盘
- 05讲快捷键进阶攻略
- 06讲拒绝重复,你一定要学会的多光标特性
- 07讲如何快速在文件、符号、代码之间跳转
- 08讲玩转鼠标操作
- 09讲代码自动补全、快速修复和重构的二三事
- 10讲拒绝重复,你的代码百宝箱:如何书写codesnippet
- 11讲一定要用好代码折叠、小地图和面包屑特性
- 12讲极速搜索有时候比Intellisense还重要
- 13讲优化你的编辑器设置
- 14讲什么是工作台和命令面板
- 15讲了解文件管理,什么是multi-rootworkspace
- 16讲怎么在编辑器里做好版本管理
- 17讲如何配置终端模拟器,告别系统终端
- 18讲为你的项目打造Workflow(上)
- 19讲为你的项目打造Workflow(下)
- 20讲聊debugger时,我们在聊什么
- 21讲你不知道的工作区快捷键
- 22讲基于自然语言或者纯文本的设置界面,总有一款适合你
- 23讲基础语言支持:JSON、Markdown
- 24讲前端语言支持:JavaScript和Node.js
- 25讲后端语言支持(一):Go、Java
- 26讲后端语言支持(二):Python、C#
- 27讲HTML、CSS以及前端开发神器Emmet介绍与支持
- 28讲如何深度定制自己的主题
- 29讲不错的插件推荐
- 30讲如何在VSCode中配置、部署和调试Docker
- 31讲一些你可能不知道的Tips&Tricks
- 32讲插件开发(一):why、how和what
- 33讲插件开发(二):编写编辑器快捷键及分享快捷键配置、代码片段、主题等
- 34讲插件开发(三):自定义语言支持
- 35讲插件开发(四):Decorations装饰器
- 36讲插件开发(五):工作台相关API
- 37讲插件开发(六):VSCode插件维护和发布要点
- 结束语讲学编辑器,究竟学了什么