相信大家对vscode应该都不陌生,VSCode是微软出的一款轻量级代码编辑器,免费而且功能强大,以功能强大、提示友好、不错的性能和颜值俘获了大量开发者的青睐,对JavaScript和NodeJS的支持非常好,自带很多功能,例如代码格式化,代码智能提示补全、颜色高亮插件等。
再强大的IDE那也不可能面面俱到什么功能都塞进去,那样只会导致IDE本身太臃肿。功能嘛,按需索取,所以,vscode的很多强大功能都是基于插件实现的,IDE只提供一个最基本的框子和最基本功能,由插件来丰富和扩展它的功能。
vscode插件可以很轻松的在应用商店搜索并下载到,应用商店官网是:https://marketplace.visualstudio.com/vscode ,vscode推出时间本身并不长,但生态发展得非常好,应用商店已经有各种各样丰富的插件供大家使用了。
官方脚手架
安装脚手架:
npm install -g yo generator-code
然后cd到你的工作目录,运行yo code
项目结构其实很简单,主要是清单文件package.json以及extension.js这个插件入口文件:
package.json部分关键内容如下(已省略其它)
{
// 扩展的激活事件
"activationEvents": [
"onCommand:extension.sayHello"
],
// 入口文件
"main": "./src/extension",
// 贡献点,vscode插件大部分功能配置都在这里
"contributes": {
"commands": [
{
"command": "extension.sayHello",
"title": "Hello World"
}
]
}
}
src/extension.js内容如下:
const vscode = require('vscode');
/**
* 插件被激活时触发,所有代码总入口
* @param {*} context 插件上下文
*/
exports.activate = function(context) {
console.log('恭喜,您的扩展“vscode-plugin-demo”已被激活!');
// 注册命令
context.subscriptions.push(vscode.commands.registerCommand('extension.sayHello', function () {
vscode.window.showInformationMessage('Hello World!');
}));
};
/**
* 插件被释放时触发
*/
exports.deactivate = function() {
console.log('您的扩展“vscode-plugin-demo”已被释放!')
};
解读
extension.sayHello
的命令,并在src/extension.js中去实现了它(弹出一个Hello World的提示);activationEvents
添加上onCommand:extension.sayHello
用来告诉vscode,当用户执行了这个命令操作时去执行前面我们定义的内容;onCommand
之外,还有onView
、onUri
、onLanguage
等等运行调试
按下F5
就会弹出一个新的vscode窗口:
这个新窗口已经加载了我们的插件,窗口标题会注明扩展开发主机,对于只有单显示器的同学来说,很容易写着写着就忘了哪个是主窗口,哪个是新窗口,所以可以通过这个来区分。
为了描述方便,我们约定,后续把新弹出来的那个窗口叫新窗口,之前老的那个叫旧窗口。
然后按下Ctrl+Shift+P
,输入HelloWorld
执行对应命令,当你发现右下角弹出了HelloWorld的提示时,恭喜你,你已经掌握了插件开发基本技巧。
{
// 插件的名字,应全部小写,不能有空格
"name": "vscode-plugin-demo",
// 插件的友好显示名称,用于显示在应用市场,支持中文
"displayName": "VSCode插件demo",
// 描述
"description": "VSCode插件demo集锦",
// 关键字,用于应用市场搜索
"keywords": ["vscode", "plugin", "demo"],
// 版本号
"version": "1.0.0",
// 发布者,如果要发布到应用市场的话,这个名字必须与发布者一致
"publisher": "sxei",
// 表示插件最低支持的vscode版本
"engines": {
"vscode": "^1.27.0"
},
// 插件应用市场分类,可选值: [Programming Languages, Snippets, Linters, Themes, Debuggers, Formatters, Keymaps, SCM Providers, Other, Extension Packs, Language Packs]
"categories": [
"Other"
],
// 插件图标,至少128x128像素
"icon": "images/icon.png",
// 扩展的激活事件数组,可以被哪些事件激活扩展,后文有详细介绍
"activationEvents": [
"onCommand:extension.sayHello"
],
// 插件的主入口
"main": "./src/extension",
// 贡献点,整个插件最重要最多的配置项
"contributes": {
// 插件配置项
"configuration": {
"type": "object",
// 配置项标题,会显示在vscode的设置页
"title": "vscode-plugin-demo",
"properties": {
// 这里我随便写了2个设置,配置你的昵称
"vscodePluginDemo.yourName": {
"type": "string",
"default": "guest",
"description": "你的名字"
},
// 是否在启动时显示提示
"vscodePluginDemo.showTip": {
"type": "boolean",
"default": true,
"description": "是否在每次启动时显示欢迎提示!"
}
}
},
// 命令
"commands": [
{
"command": "extension.sayHello",
"title": "Hello World"
}
],
// 快捷键绑定
"keybindings": [
{
"command": "extension.sayHello",
"key": "ctrl+f10",
"mac": "cmd+f10",
"when": "editorTextFocus"
}
],
// 菜单
"menus": {
// 编辑器右键菜单
"editor/context": [
{
// 表示只有编辑器具有焦点时才会在菜单中出现
"when": "editorFocus",
"command": "extension.sayHello",
// navigation是一个永远置顶的分组,后面的@6是人工进行组内排序
"group": "navigation@6"
},
{
"when": "editorFocus",
"command": "extension.demo.getCurrentFilePath",
"group": "navigation@5"
},
{
// 只有编辑器具有焦点,并且打开的是JS文件才会出现
"when": "editorFocus && resourceLangId == javascript",
"command": "extension.demo.testMenuShow",
"group": "z_commands"
},
{
"command": "extension.demo.openWebview",
"group": "navigation"
}
],
// 编辑器右上角图标,不配置图片就显示文字
"editor/title": [
{
"when": "editorFocus && resourceLangId == javascript",
"command": "extension.demo.testMenuShow",
"group": "navigation"
}
],
// 编辑器标题右键菜单
"editor/title/context": [
{
"when": "resourceLangId == javascript",
"command": "extension.demo.testMenuShow",
"group": "navigation"
}
],
// 资源管理器右键菜单
"explorer/context": [
{
"command": "extension.demo.getCurrentFilePath",
"group": "navigation"
},
{
"command": "extension.demo.openWebview",
"group": "navigation"
}
]
},
// 代码片段
"snippets": [
{
"language": "javascript",
"path": "./snippets/javascript.json"
},
{
"language": "html",
"path": "./snippets/html.json"
}
],
// 自定义新的activitybar图标,也就是左侧侧边栏大的图标
"viewsContainers": {
"activitybar": [
{
"id": "beautifulGirl",
"title": "美女",
"icon": "images/beautifulGirl.svg"
}
]
},
// 自定义侧边栏内view的实现
"views": {
// 和 viewsContainers 的id对应
"beautifulGirl": [
{
"id": "beautifulGirl1",
"name": "国内美女"
},
{
"id": "beautifulGirl2",
"name": "国外美女"
},
{
"id": "beautifulGirl3",
"name": "人妖"
}
]
},
// 图标主题
"iconThemes": [
{
"id": "testIconTheme",
"label": "测试图标主题",
"path": "./theme/icon-theme.json"
}
]
},
// 同 npm scripts
"scripts": {
"postinstall": "node ./node_modules/vscode/bin/install",
"test": "node ./node_modules/vscode/bin/test"
},
// 开发依赖
"devDependencies": {
"typescript": "^2.6.1",
"vscode": "^1.1.6",
"eslint": "^4.11.0",
"@types/node": "^7.0.43",
"@types/mocha": "^2.2.42"
},
// 后面这几个应该不用介绍了
"license": "SEE LICENSE IN LICENSE.txt",
"bugs": {
"url": "https://github.com/sxei/vscode-plugin-demo/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/sxei/vscode-plugin-demo"
},
// 主页
"homepage": "https://github.com/sxei/vscode-plugin-demo/blob/master/README.md"
}
插件在VS Code中默认是没有被激活的,哪什么时候才被激活呢?就是通过activationEvents来配置,目前支持一下8种配置:
*
都比较好懂,我就不做一一介绍了,举个例子,如果我配置了`onLanguage:javascript``,那么只要我打开了JS类型的文件,插件就会被激活。
重点说一下*
,如果配置了*
,只要一启动vscode,插件就会被激活,为了出色的用户体验,官方不推荐这么做。看到这里相信大家知道了我们前面HelloWord里面为啥要配置onCommand了吧。
https://code.visualstudio.com/api/references/extension-manifest
https://code.visualstudio.com/api/references/activation-events
https://code.visualstudio.com/api/references/contribution-points
我们在前面HelloWord章节中已经提到了命令写法,这里再重温一下。
context.subscriptions.push(vscode.commands.registerCommand('extension.sayHello', () => {
vscode.window.showInformationMessage('您执行了extension.sayHello命令!');
}));
然后在清单文件声明:
"commands": [
{
"command": "extension.sayHello",
"title": "Hello World"
},
]
vscode.commands.registerCommand
是注册命令的API,执行后会返回一个Disposable
对象,所有注册类的API执行后都需要将返回结果放到context.subscriptions
中去。
回调函数接收一个可选参数uri
:
示例:
context.subscriptions.push(vscode.commands.registerCommand('extension.demo.getCurrentFilePath', (uri) => {
vscode.window.showInformationMessage(`当前文件(夹)路径是:${uri ? uri.path : '空'}`);
}));
package.json
如下:
"menus": {
"editor/context": [
{
"when": "editorFocus",
"command": "extension.demo.getCurrentFilePath",
"group": "navigation"
}
],
"explorer/context": [
{
"command": "extension.demo.getCurrentFilePath",
"group": "navigation"
}
]
}
}
最终效果:
除了上面的注册普通命令之外,还有一个vscode.commands.registerTextEditorCommand
命令,文本编辑器命令与普通命令不同,它们仅在有被编辑器被激活时调用才生效,此外,这个命令可以访问到当前活动编辑器textEditor
:
// 编辑器命令
context.subscriptions.push(vscode.commands.registerTextEditorCommand('extension.testEditorCommand', (textEditor, edit) => {
console.log('您正在执行编辑器命令!');
console.log(textEditor, edit);
}));
这里先说一下vscode api的一个习惯设计,很多命令都是返回一个类似于Promise的Thenable对象,如果发现api里面返回的是这个对象,说明这个方法不是直接返回结果的。
使用代码执行某个命令:
vscode.commands.executeCommand('命令', 'params1', 'params2', ...).then(result => {
console.log('命令结果', result);
});
前面说到了执行命令,那我怎么知道某些操作它的命令是什么呢?
有2种方法,第一种通过代码,getCommands
接收一个参数表示是否过滤内部命令,默认否:
// 获取所有命令
vscode.commands.getCommands().then(allCommands => {
console.log('所有命令:', allCommands);
});
一般有上千个命令:
另外一种方法是直接打开快捷键设置,这里就能看到所有命令列表,右键可以复制命令:
vscode内部有一些复杂命令,所谓复杂命令,就是指一些需要特殊参数并且通常有返回值、执行一些诸如跳转到定义、执行代码高亮等特殊操作、这类命令有几十个,作为插件开发者,很多时候你可能正需要这类命令,复杂命令列表参阅:
https://code.visualstudio.com/docs/extensionAPI/vscode-api-commands
以下是演示如何在VS代码中打开新文件夹的示例:
let uri = Uri.file('/some/path/to/folder');
commands.executeCommand('vscode.openFolder', uri).then(sucess => {
console.log(success);
});
一个菜单项的完整配置如下:
"contributes": {
"menus": {
"editor/title": [{
"when": "resourceLangId == markdown",
"command": "markdown.showPreview",
"alt": "markdown.showPreviewToSide",
"group": "navigation"
}]
}
}
editor/title
是key值,定义这个菜单出现在哪里;when
控制菜单合适出现;command
定义菜单被点击后要执行什么操作;alt
定义备用命令,按住alt键打开菜单时将执行对应命令;group
定义菜单分组;目前插件可以给以下场景配置自定义菜单:
explorer/context
editor/context
editor/title
editor/title/context
debug/callstack/context
scm/title
scm/resourceGroup/context
scm/resource/context
scm/change/title
view/title
view/item/context
commandPalette
其中,最常见的应该就explorer/context
和editor/context
了,这2个应该不用多做介绍。
editor/title
:
图标在commands
里面配置,light和dark分别对应浅色和深色主题,如果不配置图标则直接显示文字:
"commands": [
{
"command": "extension.demo.testMenuShow",
"title": "这个菜单仅在JS文件中出现",
"icon": {
"light": "./images/tool-light.svg",
"dark": "./images/tool-light.svg"
}
}
]
通过可选的when
语句,VS Code可以很好地控制什么时候显示菜单项,当然,when语句语法不仅仅适用于菜单项的控制。
when语句语法有很多,这里列举几个常用的:
resourceLangId == javascript:
当编辑的文件是js文件时;resourceFilename == test.js:
当当前打开文件名是test.js时;isLinux、isMac、isWindows:
判断当前操作系统;editorFocus:
编辑器具有焦点时;editorHasSelection
:编辑器中有文本被选中时;view == someViewId:
当当前视图ID等于someViewId时;多个条件可以通过与或非进行组合,例如:editorFocus && isWindows && resourceLangId == javascript
。
有关when语句的更多完整语法请参考官方文档:
https://code.visualstudio.com/docs/getstarted/keybindings#_when-clause-contexts
alt
很好理解,表示没有按下alt
键时,点击右键菜单执行的是command
对应的命令,而按下了alt键后执行的是alt对应的命令。
控制菜单的分组和排序。不同的菜单拥有不同的默认分组。
editor/context
中有这些默认组:
navigation
- 放在这个组的永远排在最前面;1_modification
- 更改组;9_cutcopypaste
- 编辑组z_commands
- 最后一个默认组,其中包含用于打开命令选项板的条目。navigation
是强制放在最前面之外,其它分组都是按照0-9、a-z的顺序排列的,所以如果你想在1_modification
和9_cutcopypaste
插入一个新的组别的话,你可以定义一个诸如6_test
:在编辑器选项卡上下文菜单
有这些默认组:
在editor/title
有这些默认组:
默认同一个组的顺序取决于菜单名称,如果想自定义排序的话可以再组后面通过@
的方式来自定义顺序,例如:
"editor/context": [
{
"when": "editorFocus",
"command": "extension.sayHello",
// 强制放在navigation组的第2个
"group": "navigation@2"
},
{
"when": "editorFocus",
"command": "extension.demo.getCurrentFilePath",
// 强制放在navigation组的第1个
"group": "navigation@1"
}
]
如上,默认情况下,按照菜单名排序,sayHello
在getCurrentFilePath
的前面,但是通过自定义顺序,把后者放到了前面。
快捷键设置的写法比较简单,如下所示:
"contributes": {
"keybindings": [{
// 指定快捷键执行的操作
"command": "extension.sayHello",
// windows下快捷键
"key": "ctrl+f10",
// mac下快捷键
"mac": "cmd+f10",
// 快捷键何时生效
"when": "editorTextFocus"
}]
}
这个快捷键最终会出现在整个vscode快捷键设置界面:
如果您想了解更多有关快捷键绑定的详细细节可以继续阅读官方文档:
https://code.visualstudio.com/docs/getstarted/keybindings
大家都知道,整个VSCode编辑器就是一张大的网页,其实,我们还可以在Visual Studio Code中创建完全自定义的、可以间接和nodejs通信的特殊网页(通过一个acquireVsCodeApi
特殊方法),这个网页就叫WebView
。内置的Markdown的预览就是使用WebView实现的。使用Webview可以构建复杂的、支持本地文件操作的用户界面。
VSCode插件的WebView类似于iframe
的实现,但并不是真正的iframe(我猜底层应该还是基于iframe实现的,只不过上层包装了一层),通过开发者工具可以看到.
虽然Webview令人很振奋,因为基于它我们可以随意发挥不受限制,但必须注意还是要慎用,毕竟VSCode是很注重性能的,不能因为你一个插件拖累了整个IDE,一般仅在原有API和功能以及交互方式无法满足你时才需要考虑,另外,设计糟糕的Webview也很容易在VS Code中让人感觉不舒适,不能让人家一看就觉得你这是一张网页,好看的UI也很重要。
这是官网给出的建议,在使用webview之前请考虑以下事项:
context.subscriptions.push(vscode.commands.registerCommand('extension.demo.openWebview', function (uri) {
// 创建webview
const panel = vscode.window.createWebviewPanel(
'testWebview', // viewType
"WebView演示", // 视图标题
vscode.ViewColumn.One, // 显示在编辑器的哪个部位
{
enableScripts: true, // 启用JS,默认禁用
retainContextWhenHidden: true, // webview被隐藏时保持状态,避免被重置
}
);
panel.webview.html = `你好,我是Webview`
几点说明:
JavaScript
,但可以通过传入enableScripts: true
选项轻松启用;retainContextWhenHidden: true
会一直保存,但会占用较大内存开销,仅在需要时开启;出于安全考虑,Webview默认无法直接访问本地资源,它在一个孤立的上下文中运行,想要加载本地图片、js、css等必须通过特殊的vscode-resource:
协议,网页里面所有的静态资源都要转换成这种格式,否则无法被正常加载。
vscode-resource:
协议类似于file:
协议,但它只允许访问特定的本地文件。和file:一样,vscode-resource:
从磁盘加载绝对路径的资源。
我简单封装了一个转换方法:
import * as vscode from 'vscode';
export class Util {
public static buildPath(data: string, webview: vscode.Webview, contextPath: string): string {
return data.replace(/((src|href)=("|')?)(\/\/)/gi, "$1http://")
.replace(/((src|href)=("|'))((?!(http))[^"']+?\.(css|js|properties|json|png|jpg))\b/gi, "$1" + webview.asWebviewUri(vscode.Uri.file(`${contextPath}`)) + "/$4");
}
}
转换之后 -》例:https://file+.vscode-resource.vscode-webview.net/Users/liuchongyang/site/vscode/extensions/a-text-verify/media/image/u187.png
import { readFileSync } from 'fs';
import { Util } from './common/util';
...
workbenchPanel.webview.html = Util.buildPath(
readFileSync(`${this._extensionUri.path}/media/workbench.html`, 'utf8')
.replace("{{rootPath}}", rootPath)
.replace("{{baseUrl}}", workbenchPanel.webview.asWebviewUri(this._extensionUri).toString()),
workbenchPanel.webview, contextPath);
重头戏来了,Webview和普通网页非常类似,不能直接调用任何VSCodeAPI,但是,它唯一特别之处就在于多了一个名叫acquireVsCodeApi
的方法,执行这个方法会返回一个超级阉割版的vscode对象,这个对象里面有且仅有如下3个可以和插件通信的API:
插件和Webview之间如何互相通信呢?
插件给Webview
发送消息(支持发送任意可以被JSON
化的数据)
panel.webview.postMessage({text: '你好,我是小茗同学!'});
Webview
端接收:
window.addEventListener('message', event => {
const message = event.data;
console.log('Webview接收到的消息:', message);
}
Webview
主动发送消息给插件:
vscode.postMessage({text: '你好,我是Webview啊!'});
插件接收:
panel.webview.onDidReceiveMessage(message => {
console.log('插件收到的消息:', message);
}, undefined, context.subscriptions);
在webview的js中我们可以使用vscode.getState()
和vscode.setState()
方法来保存和恢复JSON可序列化状态对象。当webview被隐藏时,即使webview内容本身被破坏,这些状态仍然会保存。当然了,当webview被销毁时,状态将被销毁。
通过注册WebviewPanelSerializer
可以实现在VScode
重启后自动恢复你的webview
,当然,序列化其实也是建立在getState
和setState
之上的。
注册方法:vscode.window.registerWebviewPanelSerializer
对于具有非常复杂的UI或状态且无法快速保存和恢复的webview
,我们可以直接使用retainContextWhenHidden
选项。设置retainContextWhenHidden: true
后即使webview
被隐藏到后台其状态也不会丢失。
尽管retainContextWhenHidden
很有吸引力,但它需要很高的内存开销,一般建议在实在没办法的时候才启用。
getState
和setState
是持久化的首选方式,因为它们的性能开销要比retainContextWhenHidden
低得多。
extension.ts
import * as vscode from 'vscode'
import { decorate } from './decorator';
export function activate(context: vscode.ExtensionContext) {
vscode.workspace.onDidSaveTextDocument(e => {
decorate()
})
vscode.workspace.onDidChangeTextDocument(e => {
decorate()
})
vscode.workspace.onDidOpenTextDocument(e => {
decorate()
})
vscode.window.onDidChangeVisibleTextEditors(e => {
decorate();
})
}
export function deactivate() { }
decorator.ts
import * as vscode from "vscode"
import { rainborColors } from "./rainbow";
import { clearLine } from "readline";
let colors = Array.from(rainborColors)
let rainbows = colors.map(x => vscode.window.createTextEditorDecorationType({ color: x }))
function getRandomInt(min: number, max: number): number {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function replaceComments(buffer: string) {
var comment = /\/\*[\s\S]*?\*\/|([^\\:]|^)\/\/.*$/gm
return buffer.replace(comment, (x) => {
var len = x.length
var r = " ".repeat(len)
return r
})
}
function notContains<T>(datas: Array<T>, value: T) {
return datas.indexOf(value) == -1;
}
export function decorate() {
let editor = vscode.window.activeTextEditor;
let allText = editor.document.getText()
let noCommentText = replaceComments(allText)
// let regex = /(?:"([^"\\]*(?:\\.[^"\\]*)*)"|'([^'\\]*(?:\\.[^'\\]*)*)')|`([^`\\]*(?:\\.[^`\\]*)*)`)/g;
// let regex = /(?:"([^"\\]*(?:\\.[^"\\]*)*)"|'([^'\\]*(?:\\.[^'\\]*)*)')/g;
// let regex = /\"(.*)\"/g;
let regex = /(北京)|(沧海)|(夕)|(兮)|(十年生死)|(茫茫)|(不思量)|(自难忘)/g;
let decorators = colors.map(color => [])
let match: RegExpMatchArray;
let offset: number = getRandomInt(0, colors.length);
// console.log(888, regex.exec(noCommentText))
while ((match = regex.exec(noCommentText))) {
// console.log('match[1]', match); //['"好啊后"', '好啊后', index: 8, input: '好玩 111 "好啊后"', groups: undefined]
let chars: string[] = [...(match[0] || match[1] || match[2])];
offset--;
let startWord = match.index + 1
let endWord = startWord + chars.length
chars.forEach((_, i) => {
var matchIndex = match.index + 1
let rainbowIndex = Math.abs((i + offset) % colors.length);
let startIndex = matchIndex + i - 1
let endIndex = matchIndex + i
let start = editor.document.positionAt(startIndex)
let end = editor.document.positionAt(endIndex)
decorators[rainbowIndex].push(new vscode.Range(start, end))
});
}
decorators.forEach((d, index) => {
editor.setDecorations(rainbows[index], d)
})
}
rainbow.ts
function byte2Hex(n) {
var nybHexString = "0123456789ABCDEF"
return String(nybHexString.substr((n >> 4) & 0x0F, 1)) + nybHexString.substr(n & 0x0F, 1)
}
function RGB2Color(r, g, b) {
return '#' + byte2Hex(r) + byte2Hex(g) + byte2Hex(b)
}
function* makeColorGradient(frequency1, frequency2, frequency3, phase1, phase2, phase3, center = 128, width = 127, len = 50) {
for (var i = 0; i < len; ++i) {
var red = Math.sin(frequency1 * i + phase1) * width + center
var grn = Math.sin(frequency2 * i + phase2) * width + center
var blu = Math.sin(frequency3 * i + phase3) * width + center
yield RGB2Color(red, grn, blu)
}
}
// export const rainborColors = makeColorGradient(.3, .3, .3, 0, 2, 4)
export const rainborColors = makeColorGradient(.2, .2, .2, 0, 2, 4)
{
"name": "plaintext",
"displayName": "%displayName%",
"description": "%description%",
"version": "1.0.0",
"publisher": "vscode",
"license": "MIT",
"engines": {
"vscode": "0.10.x"
},
"contributes": {
"configurationDefaults": {
"[plaintext]": {
"editor.maxTokenizationLineLength": 2500
}
},
"languages": [
{
"id": "plaintext",
"aliases": [
"plaintext",
"txt"
],
"extensions": [
".txt"
]
}
],
"snippets": [
{
"language": "plaintext",
"path": "./snippets/plaintext.code-snippets"
}
]
},
"repository": {
"type": "git",
"url": "https://github.com/microsoft/vscode.git"
}
}
plaintext.code-snippets
{
"大连文章": {
"prefix": "沧海",
"body": [
"曾经沧海难为水",
"除却巫山不是云",
"曾经沧海难为水",
"除却巫山不是云",
"曾经沧海难为水",
"除却巫山不是云",
"曾经沧海难为水",
"除却巫山不是云",
"曾经沧海难为水",
"除却巫山不是云",
"曾经沧海难为水",
"除却巫山不是云"
],
"description": "好诗啊好诗"
},
"大连文章c": {
"prefix": "沧海",
"body": [
"秋风清,秋月明,",
"落叶聚还散,寒鸦栖复惊。",
"相思相见知何日?此时此夜难为情!",
"入我相思门,知我相思苦,",
"长相思兮长相忆,短相思兮无穷极,",
"早知如此绊人心,何如当初莫相识。",
],
"description": "好诗啊好诗"
},
"大连文章a": {
"prefix": "断肠",
"body": [
"十年生死两茫茫,不思量,自难忘。千里孤坟,无处话凄凉。纵使相逢应不识,尘满面,鬓如霜。",
"夜来幽梦忽还乡,小轩窗,正梳妆。相顾无言,惟有泪千行。料得年年肠断处,明月夜,短松冈。",
],
"description": "好诗啊好诗"
},
"大连文章b": {
"prefix": "断肠",
"body": [
"今夕何夕兮,搴舟中流。",
"蒙羞被好兮,不訾诟耻",
"今日何日兮,得与王子同舟。",
"心几烦而不绝兮,得知王子。"
],
"description": "好诗啊好诗"
}
}
let decorationType = vscode.window.createTextEditorDecorationType({
backgroundColor: 'red',
});
let editor = vscode.window.activeTextEditor;
editor.setDecorations(decorationType, [new vscode.Range(0, 3, 0, 4), new vscode.Range(0, 1, 0, 2)]);
// 通过科大讯飞返回值转化vscode位置规范
const range = new vscode.Range(editor.document.positionAt(Number(message.value.pos)),editor.document.positionAt(Number(message.value.pos)+ message.value.word.length));
if (editor) {
const document = editor.document;
const selection = editor.selection;
// var p1 = new vscode.Position(0,79);
// var p2 = new vscode.Position(0,99);
// var r = new vscode.Range(p1,p2);
// const word = document.getText(r)
editor.edit(editBuilder => {
editBuilder.replace(range , message.value.word);
});
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
const laws = ['合同法', '劳动法', '民法典', '宪法', '刑法', '教育法', '治安管理处罚条例', '婚姻法', '隐私保护法'
, '民事诉讼法', '人民法院在线诉讼规则', '中华人民共和国人民法院法庭规则', '最高人民法院关于互联网法院审理案件若干问题的规定', '法庭纪律'];
const providerDocumentSymbol = (context: vscode.ExtensionContext) => {
context.subscriptions.push(vscode.languages.registerDocumentSymbolProvider(
{language: "lawdawn"}, new FooDocumentSymbolProvider()
));
};
class FooDocumentSymbolProvider implements vscode.DocumentSymbolProvider {
public provideDocumentSymbols(document: vscode.TextDocument,token: vscode.CancellationToken): Thenable<vscode.DocumentSymbol[]> {
return new Promise((resolve, reject) => {
let symbols: vscode.DocumentSymbol[] = [];
for(let i = 0; i < document.lineCount; i++) {
let line = document.lineAt(i);
for (let j = 0; j < laws.length; j++) {
if (line.text.includes(laws[j])) {
symbols.push(new vscode.DocumentSymbol(laws[j], line.text, vscode.SymbolKind.Key, line.range, line.range ));
}
}
}
resolve(symbols);
});
}
}
export default providerDocumentSymbol;
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import providerDocumentSymbol from './language-extensions/outline';
export function activate(context: vscode.ExtensionContext) {
// 大纲provider
providerDocumentSymbol(context);
}
比较好的文章可供参考:
https://zhaomenghuan.js.org/note/vscode/awesome-vscode.html
https://zhuanlan.zhihu.com/p/99587182
插件:https://www.kancloud.cn/shangyewangchuan/vs_code/972974
坑:如果启动不来,去掉环境变量unset ELECTRON_RUN_AS_NODE
vscode插件demo: https://github.com/microsoft/vscode-extension-samples