如何开发一个提示颜色代码的VSCode插件
今天小编给大家分享一下如何开发一个提示颜色代码的VS Code插件的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。
为企业提供做网站、网站制作、网站优化、成都全网营销推广、竞价托管、品牌运营等营销获客服务。成都创新互联公司拥有网络营销运营团队,以丰富的互联网营销经验助力企业精准获客,真正落地解决中小企业营销获客难题,做到“让获客更简单”。自创立至今,成功用技术实力解决了企业“网站建设、网络品牌塑造、网络营销”三大难题,同时降低了营销成本,提高了有效客户转化率,获得了众多企业客户的高度认可!
需求
我在写css时,经常会有颜色选择困难症,虽然VS Code内置的插件提供了取色器,但在256^3的颜色中去选取,未必能找到符合期望的颜色。于是我想要是有个颜色提示插件就好了,只要我输入# + 颜色名
,就能以代码提示的方式,将对应的颜色列出来供我选择。
获取颜色
首先第一件事就是要有现成的颜色代码,很快我就找到了这个网站:中国色
这个网站提供了500多种颜色的rgb值以及hex值,打开浏览器控制台,输入colorsArray就能全部拿到,这就是我想要的。
从网站底部的信息来看,这个网站是山寨自日本色,颜色据称来自中科院科技情报编委会名词室编写、科学出版社1957年出版的《色谱》。
这个颜色来源是否可信我无从考证,随便百度一下“中国传统色”,就可以找到很多版本的所谓中国色,我在github上还找到了另一个接近2k star的中国色项目:中国传统颜色手册,这个网站使用的颜色与前者完全不同,是来自于一篇现在已经无法查看的新浪博客,颜色数量我没有统计,粗略估计在200以内。
初始化项目
安装开发工具
npm i -g yo generator-code
新建项目
yo code
Hello World
初始项目中有个Hello World,用VS Code打开项目,然后按F5(或者点击“运行-->启动调试”)可以开启调试窗口。
然后在调试窗口下 Ctrl + Shift + P (或者点击“设置-->命令面板”),输入并选择 Hello World 命令,就会在编辑器右下角弹出一个消息提示。
extension.ts
是插件的入口文件:
import * as vscode from 'vscode';
// activate方法会在插件被激活时调用
export function activate(context: vscode.ExtensionContext) {
// 注册命令,第一个参数是命令名称,第二参数是回调
let disposable = vscode.commands.registerCommand('chinese-colors.helloWorld', () => {
// 弹出消息提示
vscode.window.showInformationMessage('Hello World from Chinese Colors!');
});
// 添加到插件上下文
context.subscriptions.push(disposable);
}
// deactivate方法会在插件失活时调用
export function deactivate() {}
package.json
查看package.json
,其中比较重要的两项:
{
"activationEvents": [
"onCommand:chinese-colors.helloWorld"
],
"contributes": {
"commands": [
{
"command": "chinese-colors.helloWorld",
"title": "Hello World"
}
]
},
}
activationEvents是插件的激活配置,它是一个数组,每一项对应一个激活插件的条件,格式为“<类型>:<名称>”,onCommand是调用命令(也就是上面的输入Hello World)。
contributes:一般翻译为贡献点,配置了一个“chinese-colors.helloWorld”,与activationEvents配置项对应。
其他packege.json配置见下表:
名称 | 必要 | 类型 | 说明 |
---|---|---|---|
name | 是 | string | 插件名称,必须为小写且不能有空格。 |
version | 是 | string | 插件版本 |
publisher | 是 | string | 发布者 |
engines | 是 | object | 一个至少包含vscode 键值对的对象,该键表示的是本插件可兼容的VS Code的版本,其值不能为* 。比如 ^0.10.5 表示插件兼容VS Code的最低版本是0.10.5 。 |
license | 否 | string | 授权。如果有授权文档LICENSE.md,可以把license 值设为"SEE LICENSE IN LICENSE.md" 。 |
displayName | 否 | string | 插件市场中显示的名字。 |
description | 否 | string | 描述,说明本插件是什么以及做什么。 |
categories | 否 | string[] | 插件类型:[Languages, Snippets, Linters, Themes, Debuggers, Other] |
keywords | 否 | array | 一组 关键字或者 标记,方便在插件市场中查找。 |
galleryBanner | 否 | object | 插件市场中横幅的样式。 |
preview | 否 | boolean | 在市场中把本插件标记为预览版本。 |
main | 否 | string | 插件的入口文件。 |
contributes | 否 | object | 一个描述插件 贡献点 的对象。 |
activationEvents | 否 | array | 一组用于本插件的激活事件。 |
dependencies | 否 | object | 生产环境Node.js依赖项。 |
devDependencies | 否 | object | 开发环境Node.js依赖项。 |
extensionDependencies | 否 | array | 一组本插件所需的其他插件的ID值。格式 ${publisher}.${name} 。比如:vscode.csharp 。 |
scripts | 否 | object | 和 npm的 scripts 一样,但还有一些额外VS Code特定字段。 |
icon | 否 | string | 一个128x128像素图标的路径。 |
用户自定配置项
颜色代码有多种表示方式,比较常用的是16进制(#ffffff)和rgb(255,255,255)这两种,因此我需要让用户自己选择采用哪种方式。
在contributes中有个configuration,允许用户对插件进行一些自定义配置。
package.json
:
{
// ...
"contributes": {
"configuration": [{
"title": "color mode",// 配置项名称
"properties": {
// 配置属性
"RGB": {
"type": "boolean", // 属性值类型
"default": false, // 属性默认值
"description": "控制预设的中国色采用RGB格式" // 属性描述
}
}
}]
},
}
这样就可以在扩展设置中进行一些自定义的设置:
我们可以通过workspace.getConfiguration()获取用户的配置。
import { workspace } from "vscode";
const configuration = workspace.getConfiguration();
const isRGB = configuration.RGB;
代码补全
API
代码补全API:
vscode.languages.registerCompletionItemProvider(selector, provider, …triggerCharacters)
该方法有三个参数:
参数 | Description |
---|---|
selector: string/string[] | 选择编程语言,比如python |
provider | 供应者配置对象 |
triggerCharacters: string/string[] | 触发字符, 比如 . 或 : |
register completion item provider(注册完成件供应者),这个provider也是比较费解的一个词,直译是供应者,我猜:代码补全就相当于插件给我们供应了代码,所以叫provider。
provider是一个对象,要求必须包含一个叫provideCompletionItems
的方法,该方法需要返回一个数组,数组的每一项是一个CompletionItem对象,规定了代码提示和补全的规则。
官方示例
import * as vscode from 'vscode';
export function activate(context: vscode.ExtensionContext) {
// 注册供应者:languages.registerCompletionItemProvider
const provider2 = vscode.languages.registerCompletionItemProvider(
'plaintext',// plaintext,表示对txt文档激活该插件
{
// 实现provideCompletionItems方法
// document的内容见下文,position为当前光标的位置
provideCompletionItems(document: vscode.TextDocument, position: vscode.Position) {
// 获取当前这行代码
const linePrefix = document.lineAt(position).text.substr(0, position.character);
// 如果这行代码不是以console.结尾,返回undefined,表示不会弹出代码提示
if (!linePrefix.endsWith('console.')) {
return undefined;
}
// 返回CompletionItem对象组成的数组,补全代码列表:log、warn、error
// CompletionItem对象可以自己创建,也可以像下面这样new vscode.CompletionItem的方式创建
// vscode.CompletionItem()有两个参数:
// 第一个是补全的代码,第二个是代码类型,用于控制显示在每一行提示前的图标
// vscode.CompletionItemKind.Method表示该代码是一个方法
return [
new vscode.CompletionItem('log', vscode.CompletionItemKind.Method),
new vscode.CompletionItem('warn', vscode.CompletionItemKind.Method),
new vscode.CompletionItem('error', vscode.CompletionItemKind.Method),
];
}
},
'.' // 以.作为触发
);
context.subscriptions.push(provider2);
}
provideCompletionItems
参数:
position
:当前光标所处的位置。
document
:用于获取、控制文档的内容或状态,这里列举几个常用的方法和属性:
方法:
getWordRangeAtPosition(position): Range:获取指定位置单词的范围(起始位置)
getText(Range):string:获取指定范围的文本
lineAt(position):string:获取指定位置的文本
validatePosition(position):Position:获取鼠标停留的位置
属性
lineCount:总代码行数
languageId:语言名称
isClosed:当前文件是否关闭
isDirty:当前文件的代码是否更改未保存
CompletionItem对象
CompletionItem对象可以通过new vscode.CompletionItem()的方式创建,但它默认只能补全代码,不能自定义替换,并不能满足我的需求,因此需要自己创建。
CompletionItem对象包含的属性:
属性 | 说明 |
---|---|
detail: string | 语义化描述 |
documentation: string | 语义化描述 |
filterText: string | 代码过滤。匹配输入的内容,没有设置时,使用label |
insertText: string | 插入、补全的代码。没有设置时,使用label |
label: string | 默认的匹配代码、补全代码 |
kind | 代码类型,控制显示代码提示前的图标 |
sortText: string | 排序文本,与sortText匹配的提示代码会排在靠前的位置 |
textEdit | 对补全代码进行编辑,如果设置了textEdit,insertText会失效 |
kind的取值:
Class
Color
Constructor
Enum
Field
File
Function
Interface
Keyword
Method
Module
Property
Reference
Snippet
Text
Unit
Value
Variable
简单的示例
import * as vscode from "vscode";
import { CompletionItemKind } from "vscode";
export function activate(context: vscode.ExtensionContext) {
const cc = vscode.languages.registerCompletionItemProvider(
"css",
{
provideCompletionItems() {
return [
{
detail: '#66ccff',
documentation: '天依蓝',
kind: CompletionItemKind.Color,
filterText: `#66ccff天依蓝`,
label: '天依蓝',
insertText: '#66ccff'
},
{
detail: '#39c5bb',
documentation: '初音绿',
kind: CompletionItemKind.Color,
filterText: `#39c5bb初音绿`,
label: '初音绿',
insertText: '#39c5bb'
}
];
},
},
"#"
);
context.subscriptions.push(cc);
}
export function deactivate() {}
记得要在package.json里配置激活:
"activationEvents": [
"onLanguage:css"
]
中国色插件
package.json关键配置:
{
"activationEvents": [
"onLanguage:css",
"onLanguage:scss",
"onLanguage:sass",
"onLanguage:less",
"onLanguage:stylus",
"onLanguage:html",
"onLanguage:xml",
"onLanguage:json",
"onLanguage:javascript",
"onLanguage:typescript",
"onLanguage:javascriptreact",
"onLanguage:typescriptreact",
"onLanguage:vue",
"onLanguage:vue-html"
],
"contributes": {
"configuration": [{
"title": "Chinese Colors",
"properties": {
"RGB": {
"type": "boolean",
"default": false,
"description": "控制预设的中国色采用RGB格式"
}
}
}]
},
}
颜色列表colors.ts
:
// 声明Color类型
export type Color = {
rgb: number[];
hex: string;
name: string;
phonics: string;
};
// 这里只列两个颜色
export const colors: Color[] = [
{
rgb: [92, 34, 35],
hex: "#5c2223",
name: "暗玉紫",
phonics: "anyuzi",
},
{
rgb: [238, 162, 164],
hex: "#eea2a4",
name: "牡丹粉红",
phonics: "mudanfenhong",
},
// ...
]
extensions.ts
import * as vscode from "vscode";
import { workspace, CompletionItemKind } from "vscode";
import { colors, Color } from "./colors";
const isRgb = workspace.getConfiguration().RGB;
export function activate(context: vscode.ExtensionContext) {
const cc = vscode.languages.registerCompletionItemProvider(
[
"css",
"scss",
"sass",
"less",
"stylus",
"html",
"xml",
"json",
"javascript",
"typescript",
"javascriptreact",
"typescriptreact",
"vue",
"vue-html",
],// activationEvents
{
provideCompletionItems() {
const list = [] as CompletionItemKind[];
colors.forEach((color: Color) => {
list.push({
detail: isRgb ? rgb : hex,
documentation: color.name,
kind: CompletionItemKind.Color,
filterText: "#" + color.name + color.phonics,
label: color.name,
insertText: isRgb ? rgb : hex,
});
});
return list;
},
},
"#"
);
context.subscriptions.push(cc);
}
export function deactivate() {}
如此,代码补全的功能已经基本实现,实际开发时,为了便于维护,需要将这部分逻辑抽离出来。
颜色预览
接下来,需要实现颜色的预览,虽然VS Code内置的插件已经实现了这项功能,但我的需求是:不仅能预览颜色,还得显示颜色名称。
API
实现颜色预览需要用到装饰效果,涉及以下这些API:
window.createTextEditorDecorationType(options)
:创建装饰效果的类型
window.activeTextEditor.setDecorations(decorationType, decorations)
:添加装饰效果至文档
window.onDidChangeActiveTextEditor
:文档内容变化事件
workspace.onDidChangeTextDocument
:切换文档事件
官方示例
首先来看一下官方提供的示例片段
import * as vscode from 'vscode';
// 插件激活时调用
export function activate(context: vscode.ExtensionContext) {
console.log('decorator sample is activated');
let timeout: NodeJS.Timer | undefined = undefined;
// 为small numbers创建装饰效果类型
const smallNumberDecorationType = vscode.window.createTextEditorDecorationType({
// 以下是装饰效果的样式
borderWidth: '1px',
borderStyle: 'solid',
overviewRulerColor: 'blue',
overviewRulerLane: vscode.OverviewRulerLane.Right,
light: {
// 亮色主题下的边框颜色
borderColor: 'darkblue'
},
dark: {
// 暗色主题下的边框颜色
borderColor: 'lightblue'
}
});
// 为large numbers创建装饰效果类型
const largeNumberDecorationType = vscode.window.createTextEditorDecorationType({
cursor: 'crosshair',
// 设置装饰的背景颜色, 在package.json中可以配置该名称对应的颜色
backgroundColor: { id: 'myextension.largeNumberBackground' }
});
// activeEditor是当前活跃(展示)的文档编辑器实例
let activeEditor = vscode.window.activeTextEditor;
// updateDecorations方法,在每次文档被更新或切换文档时调用。
function updateDecorations() {
if (!activeEditor) {
return;
}
// 匹配数字的正则
const regEx = /\d+/g;
// 获取文档的文本
const text = activeEditor.document.getText();
// 装饰效果数组,用于归集每一个Decoration对象
const smallNumbers: vscode.DecorationOptions[] = [];
const largeNumbers: vscode.DecorationOptions[] = [];
let match;
while ((match = regEx.exec(text))) {
// 获取匹配结果的起始位置
const startPos = activeEditor.document.positionAt(match.index);// 开始位置
const endPos = activeEditor.document.positionAt(match.index + match[0].length);// 结束位置
// Decoration对象
const decoration = {
// 装饰效果的位置
range: new vscode.Range(startPos, endPos),
// 鼠标悬停(hover)的提示信息
hoverMessage: 'Number **' + match[0] + '**'
};
// 将符合的结果归集
if (match[0].length < 3) {
smallNumbers.push(decoration);
} else {
largeNumbers.push(decoration);
}
}
// 添加装饰效果
activeEditor.setDecorations(smallNumberDecorationType, smallNumbers);
activeEditor.setDecorations(largeNumberDecorationType, largeNumbers);
}
// 给方法节流
function triggerUpdateDecorations(throttle = false) {
if (timeout) {
clearTimeout(timeout);
timeout = undefined;
}
if (throttle) {
timeout = setTimeout(updateDecorations, 500);
} else {
updateDecorations();
}
}
// 打开文档时调用一次
if (activeEditor) {
triggerUpdateDecorations();
}
// 切换文档时调用
vscode.window.onDidChangeActiveTextEditor(editor => {
// 这一步赋值是必须的,确保activeEditor是当前打开的文档编辑器实例
activeEditor = editor;
if (editor) {
triggerUpdateDecorations();
}
}, null, context.subscriptions);
// 文档内容发送改变时调用
vscode.workspace.onDidChangeTextDocument(event => {
if (activeEditor && event.document === activeEditor.document) {
triggerUpdateDecorations(true);
}
}, null, context.subscriptions);
}
DecorationType
DecorationType是通过window.createTextEditorDecorationType(options)创建的对象,它主要用来设置装饰效果的样式,其实就是css样式,比如border、color、backgroundColor等等。
如果要在匹配结果之前或之后添加装饰,可以添加before/after字段进行设置,还可以分别给dark、light模式配置不同的样式。
const decorationType = window.createTextEditorDecorationType({
// 在匹配位置之前添加装饰效果:
before: {
color: '#eee',
backgroundColor: '#fff',
width: 'fit-content'
}
})
由于该方法支持的样式字段有限,有些样式(比如line-height)无法在options里直接添加,但我们可以在任意字段后添加分号,将这些样式写在后面,比如:
const decorationType = window.createTextEditorDecorationType({
// 在匹配位置之后添加装饰效果:
after: {
color: '#333',
backgroundColor: '#fff',
width: 'fit-content',
height: '0.8em',
// fontSize: '0.6em', 这么设置是无效的,因为并不支持fontSize字段,
// 但我们可以将其添加在任意字段后面
fontStyle: 'normal;font-size:0.6em;line-height:0.8em'
}
})
具体支持哪些字段,可以查看此API的官方文档:
VS Code API | Visual Studio Code Extension API
Decoration对象
Decoration对象有三个属性:
range
:装饰效果的位置,range对象可以通过new vscode.Range(start, end)创建hoverMessage
:鼠标悬停时的提示信息renderOptions
:和decorationType类似,可以单独对每一个装饰效果设置样式。但只支持before、after、dark、light四个字段,也就是说,无法再对匹配的内容本身设置样式。
示例
由于实现的代码比较长,和上述官方示例其实差不多,这里就不再贴出来了,感兴趣的可以我去文章开头的仓库地址查看。
值得一提的是,为了颜色的名称在不同的颜色背景下都能清晰的显现,我这里用到了一个计算对比色的方法,贴出来供参考:
// 通过hex值计算应该使用的字体颜色
function getContrastColor(hexcolor: string) {
const r = parseInt(hexcolor.substring(1, 2), 16)
const g = parseInt(hexcolor.substring(3, 4), 16)
const b = parseInt(hexcolor.substring(5, 6), 16)
const yiq = (r * 299 + g * 587 + b * 114) / 1000
return yiq >= 8 ? 'black' : 'white'
}
插件打包
打包命令:
vsce package
如果打包失败,可能的原因:
packege.json缺少上文表格中必要的配置项
VS Code版本与packege.json里设置的版本不兼容
根目录下缺少README.md文件
根目录下缺少LICENSE.md文件
以上就是“如何开发一个提示颜色代码的VS Code插件”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注创新互联行业资讯频道。
当前题目:如何开发一个提示颜色代码的VSCode插件
本文地址:http://scyanting.com/article/ipdcop.html