# 前言
背景:项目中预定义了主题样式,在代码编写过程中用到颜色的地方只使用相关变量,然鹅在使用变量时往往记不住各个主题值表示什么颜色,需要反复查阅文档,故希望在coding时能知道当前变量表示的颜色。且支持多套映射,以支持主题切换(如:text_color默认主题下#333,dark主题下#d9d9d9)。
考虑自定义主题值的场景还挺常见,参考项目中使用的插件Color Highlight,最终敲定将插件形式做成高亮自定义字符。
好记性不如烂笔头✏️,写文章记录一下插件开发中用到的知识点。
ps:关于插件项目的初始化、package.json各个配置的作用等,已经很多其他优秀文章介绍过了,可查阅文末的附录参考文献,此处便一笔带过了,本文只介绍实现目标功能用到的核心API
# 插件演示&功能介绍
先看下最终实现的效果,插件支持
- 高亮自定义字符
 - 主题切换
 - 鼠标悬浮到主题变量时显示真实色值
 
按规则配置完成后,编辑器会以指定颜色高亮目标字符
点击右下角切换预定义的主题
鼠标悬浮到主题变量时显示真实色值
# 下载安装
应用商店搜索:Highlight My Word ☘️
# 核心功能API
# 初始化工程
安装脚手架
npm install -g yo generator-code
 初始化工程
yo code
? What type of extension do you want to create? New Extension (TypeScript)
? What's the name of your extension? highlight-my-word-api-demo
? What's the identifier of your extension? highlight-my-word-api-demo
? What's the description of your extension? highlight-my-word-api-demo
? Initialize a git repository? Yes
? Bundle the source code with webpack? No
? Which package manager to use? npm
 2
3
4
5
6
7
8
9
# 在编辑器目标位置设置样式
下例🌰演示了如何高亮编辑器中的第一个目标字段,多主题多映射的情况可以此类推
import * as vscode from 'vscode';
export const highlightTargetStr = (str = 'primary') => {
  // ① 创建装饰器
  const decorator = vscode.window.createTextEditorDecorationType({
    overviewRulerLane: vscode.OverviewRulerLane.Center,
    borderRadius: '2px',
    color: '#fff',
    backgroundColor: '#3072f6',
  });
  
  // ② 获取可见编辑器实例
  const visibleTextEditors = vscode.window.visibleTextEditors;
  visibleTextEditors.forEach((editor) => {
  
    // 获取文档实例
    const { document } = editor;
    
    // ③ 通过文档实例获取目标字符串位置
    const startIndex = document.getText().indexOf(str);
    const startPos = document.positionAt(startIndex);
    const endPos = document.positionAt(startIndex + str.length);
    const range = [new vscode.Range(startPos, endPos)];
    
    // ④ 在目标位置设置装饰器
    editor.setDecorations(decorator, range);
  });
};
 2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
相关代码的作用可见注释,最终效果如下:
注意事项:
①中创建的
decorator对象可存储起来,调用decorator.dispose()可释放资源,释放后用同一decorator重新调用④,样式不会再生效想刷新样式作用的范围,通过
editor.setDecorations第二个参数设置新的range即可。若仅设置一次,该装饰的样式会一直作用于该区域,即使在中间插入新的文本
故需要根据内容的变化(vscode.workspace.onDidChangeTextDocument)来更新装饰器作用的range
# 读写配置
package.json注册
// package.json
{
  ...
  "contributes": {
    "configuration": [
      {
        "title": "%extension-title%",
        "properties": {
          "highlight-my-word-api-demo.themes": {
            "type": "object",
            "description": "%configuration-themes%"
          }
        }
      }
    ]
  }
}
 2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
其中%%包住的变量是在package.nls.json中定义的
// package.nls.json
{
  "extension-title": "highlight my word",
  "configuration-themes": "自定义主题",
}
 2
3
4
5
6
配置完毕后用户即可在setting.json中进行配置,通过下列方式在插件中读取配置
loadConfig = () => {
  const config = vscode.workspace.getConfiguration('highlight-my-word-api-demo').get('themes', {});
  console.log("config", config);
};
 2
3
4
5
监听配置变化
// extension.ts
export function activate(context: vscode.ExtensionContext) {
	context.subscriptions.push(
		vscode.workspace.onDidChangeConfiguration((e) => {
			console.log(e);
		})
	);
}
 2
3
4
5
6
7
8
代码中更新配置
updateConfig = () => {
  vscode.workspace.getConfiguration('highlight-my-word-api-demo').update('themes', { value: '更新后的值' });
};
 2
3
4
# 监听编辑器窗口变化
当有窗口新打开时需要着色新开的窗口,onDidChangeVisibleTextEditors可监听变化后的窗口
// extension.ts
export function activate(context: vscode.ExtensionContext) {
		vscode.window.onDidChangeVisibleTextEditors(editors => { console.log(editors.length); }),
	);
}
 2
3
4
5
6
7
通过前面的api即可实现可配置的自定义高亮内容,不过至此切换主题需要到setting.json中进行配置,不是很友好。为了体验更愉快,再增加快捷切换的功能,用到了下面的api
# 底部状态栏
export const displayStatusBar = () => {
  // 注意保存此对象以更新文案,控制显示与否等
  const statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right);
  statusBar.text = 'Highlight My Word';
  statusBar.tooltip = '点击切换主题';
   // 点击响应事件,绑定对应command的标识
  statusBar.command = 'highlight-my-word-api-demo.changeTheme';
  statusBar.show();
};
 2
3
4
5
6
7
8
9
10
点击状态栏可以响应command, 通过command调用一个快捷选择弹窗即可实现快捷切换主题
# 注册&实现command
packge.json配置
// package.json
{
  ...
  "contributes": {
    "commands": [
      {
        "command": "highlight-my-word-api-demo.changeTheme",
        "title": "切换主题(changeTheme)"
      }
    ]
  }
}
 2
3
4
5
6
7
8
9
10
11
12
注册
// extension.ts 
export function activate(context: vscode.ExtensionContext) {
	context.subscriptions.push(
		vscode.commands.registerCommand('highlight-my-word-api-demo.changeTheme', showQuickPick),
	);
}
 2
3
4
5
6
7
showQuickPick 即下面展示快捷弹窗的方法
# 快捷选择框
const showQuickPick = () => {
  vscode.window.showQuickPick([
    '主题1',
    '主题2',
  ], {
    canPickMany: false,
    placeHolder: "选择您的主题"
  }).then((res) => {
    console.log(res);
  });
};
 2
3
4
5
6
7
8
9
10
11
注意:即使什么都没选择,promise仍会回调,返回undefined
# 鼠标悬浮效果
下例演示鼠标悬停primary单词时候悬浮限制指定内容
// extension.ts
export function activate(context: vscode.ExtensionContext) {
	context.subscriptions.push(
		vscode.languages.registerHoverProvider(['javascript', 'typescript'], {
			provideHover: (document: vscode.TextDocument, position: vscode.Position, _: vscode.CancellationToken): vscode.ProviderResult<vscode.Hover> => {
				// 得到鼠标悬浮处的单词
				const word = document.getText(document.getWordRangeAtPosition(position));
				if (word === 'primary') {
					return new vscode.Hover('悬浮窗');
				}
			},
		})
	);
}
 2
3
4
5
6
7
8
9
10
11
12
13
14
15
最终通过上述api实现了最终的VSCode插件效果,关于详细的API用法可上官网 (opens new window)了解, 欢迎应用商店搜索highlight my word体验使用☘️☘️
# 附录
# 参考资源
[1] 小茗同学-vscode插件开发攻略 (opens new window)
[2] Highlighter-vscode (opens new window)
[3] VS官网 (opens new window)
[4] 少年,我把珍藏的这个 VSCode 插件 API 传给你了 (opens new window)
# 项目地址
[1] 本文demo github地址 (opens new window)
[2] 词语高亮插件 github地址 (opens new window)