代码开源地址 vscode 插件 蓝色空间: 仅供测试,勿用于生产环境
const vscode = require('vscode') // vscode API 接口
const path = require('path') // 路径拼接
const fs = require('fs') // 文件操作
const os = require('os') // 可获得系统信息
class 插件服务类 extends 通用nodejs类{
constructor(context){ //构造 创建对象实例时会执行一次
super()
this.context= context
this.插件路径 = this.context.extension.extensionPath //这里包含插件基本信息
}
字符串_去开头结尾空白(字符串){ return 字符串.replace(/(^[\s]*)|([\s]*$)/g , '') }
打开vscode域名信任列表(){ this.执行vscode指令("workbench.action.manageTrustedDomain") }
//-------杂项
插件重启(标识符id){ this.执行vscode指令("workbench.action.restartExtensionHost", 标识符id) } //package.json里定义的名字
通过shell查找软件版本号(指令 ,正则表达式){
return new Promise((成功后回调,失败后回调)=>{
this.终端_执行shell指令_then(指令)
.then((返回值)=>{
let 版本号=this.查找版本号(正则表达式, 返回值.stdout)
成功后回调( 版本号 )//查找版本号
})
})
}
查找版本号(正则表达式,字符串 ){
let 数组 =正则表达式.exec(字符串) //查找版本号
if(数组===null) 数组=["未安装"]
return 数组[0]
}
//-------vscode 指令和配置
获取用户定义值(配置){ return vscode.workspace.getConfiguration().get(配置) }
生效配置(官方配置, 属性){ vscode.workspace.getConfiguration().update( 官方配置, 属性, true ) }
注册vscode用户指令(指令, 处理函数){ vscode.commands.registerCommand(指令, 处理函数) }
注册vscode配置变化事件( 事件函数 ){ return vscode.workspace.onDidChangeConfiguration( 事件函数 ) }
打开vscode选择主题界面(){ this.执行vscode指令("workbench.action.selectTheme"); }
async 执行vscode指令(指令,...参数){ return await vscode.commands.executeCommand(指令, ...参数) } //可变参数
//-------UI界面 窗口相关
选择后显示文件(绝对路径, 标题文本, 打开按钮文本){
vscode.window.showOpenDialog( { defaultUri: vscode.Uri.file(绝对路径) ,
canSelectFiles:true ,
canSelectFolders:false,
canSelectMany:false,
title:标题文本,
openLabel:打开按钮文本 }) //返回一个数组
.then( 路径数组 => {
if (路径数组 !== undefined) this.用vscode编辑文件( 路径数组[0].path) //选择多个文件只打开第一个
}) //获得数据才处理
}
打开窗口选择本地路径文件数组(绝对路径, 标题文本, 打开按钮文本){
return new Promise(成功后回调 =>{
vscode.window.showOpenDialog( { defaultUri: vscode.Uri.file(绝对路径) ,
canSelectFiles:false ,
canSelectFolders:true,
canSelectMany:false, //能否多选
title:标题文本,
openLabel:打开按钮文本 }) //返回一个数组
.then(路径数组 => 成功后回调(路径数组))
})
}
用vscode打开文件2(绝对路径){ //这个只能打开文本
vscode.workspace.openTextDocument( vscode.Uri.file( 绝对路径 ) )
.then( 文件 => vscode.window.showTextDocument(文件) )
}
用系统默认应用打开(文件路径){ vscode.env.openExternal(vscode.Uri.parse(文件路径)) }
用vscode编辑文件(绝对路径){ this.执行vscode指令('vscode.open', vscode.Uri.file(绝对路径)) } //这个比上面显示文件更加全面
用vscode预览md文件(文件路径){ this.执行vscode指令("markdown.showPreview" , vscode.Uri.file(文件路径)) }
用vscode编辑项目(路径){this.执行vscode指令('vscode.openFolder', vscode.Uri.file(路径), true) }
生成输出界面(界面名称){ return vscode.window.createOutputChannel(界面名称 )}
生成按钮(左右, 优先级){ //优先级越高越靠边
if (左右 === "左边") return vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 优先级)
else return vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 优先级)
}
vscode窗口激活事件(){
vscode.window.onDidChangeWindowState((窗口)=>{ //参数是vscode软件聚焦激活 还是非激活
})
}
打开插件设置页面(){ this.执行vscode指令( "workbench.action.openSettings","@ext:" + this.context.extension.id ) } //打开指定的 设置UI
打开插件某项设置页面(某项设置id){this.执行vscode指令( "workbench.action.openSettings", 某项设置id ) }
打开侧边栏view视图(id){ this.执行vscode指令(`workbench.view.extension.${id}`) } // package.json 里定义的 view id
//-------终端相关
用vscode终端执行(指令文本,工作路径, 传入终端名){
let 终端名 = 传入终端名 || path.basename(工作路径)
let 终端 = this.生成vscode终端界面(终端名, 工作路径)
终端.sendText( `${指令文本}\n` )
}
用vscode终端执行后销毁( 指令文本, 工作路径){
this.用vscode终端执行(`${指令文本}\n; sleep 2; exit` ,工作路径 , "临时终端" )
}
生成vscode终端界面(界面名称, 工作路径 , 欢迎信息){ //isTransient true vs重启后不再打开旧终端窗口
let 终端数组 = vscode.window.terminals
let 查找终端数组 = 终端数组.filter(终端 => 终端.name === 界面名称)
let 终端 = 查找终端数组?.length !==0 ? 查找终端数组[0] : vscode.window.createTerminal({ name:界面名称, cwd: 工作路径, message:欢迎信息 ,isTransient:true})
终端.show()
this.执行vscode指令("workbench.action.terminal.focus", 终端)
return 终端
}
vscode终端激活事件(){
vscode.window.onDidChangeActiveTerminal((终端)=>{ //参数是当前激活的终端
})
}
获取vscode终端数组(){ return vscode.window.terminals }
//-------文件操作相关
保存配置JSON到电脑(配置对象){ this.文件写JSON文件( 配置对象.配置文件路径, 配置对象)}
//-------常用网页接口
读网页html_转换路径(网页面板, html绝对路径){
const 目录路径 = path.dirname(html绝对路径);
let 页面 = fs.readFileSync(html绝对路径, 'utf-8'); //读取文件 ---- vscode不支持直接加载本地资源
//会自动将HTML文件中link、href、script、img的资源相对路径全部替换成正确的vscode-resource:绝对路径
let html文本 = 页面.replace(/( {
let Uri路径 = vscode.Uri.file(path.join(目录路径, 第二个正则括号里匹配的内容))
return 第一个正则括号里匹配的内容 + 网页面板.webview.asWebviewUri(Uri路径) + '"'
});
return html文本
}
创建网页面板(标题){ //每个网页需要一个面板
let 网页面板 = vscode.window.createWebviewPanel(
'test', // viewType
标题, // 视图标题
vscode.ViewColumn.One, // 显示在编辑器的哪个部位
{
enableScripts: true, // 启用JS,默认禁用
retainContextWhenHidden: true, // webview被隐藏时保持状态,避免被重置 影响性能
},
{ // 限制只能访问这个目录 [] 空表示限制访问
localResourceRoots: [ vscode.Uri.file(this.插件路径) ]
})
return 网页面板
}
用vscode显示网页(相对路径, 标题){
let 网页面板 = this.创建网页面板(标题)
网页面板.webview.html = this.读网页html_转换路径(网页面板,相对路径) // 显示网页
return 网页面板
}
async 用vscode侧边栏显示网页(预设id, html绝对路径 ,消息处理函数 ){
return new Promise((成功后回调,失败后回调)=>{
vscode.window.registerWebviewViewProvider( 预设id,
{
resolveWebviewView: (网页面板)=>{
网页面板.webview.options={
enableScripts: true,
enableForms: true,
localResourceRoots: [ vscode.Uri.file(this.插件路径 )]
};
网页面板.webview.html = this.读网页html_转换路径(网页面板, html绝对路径) // fs.readFileSync(网页路径, 'utf-8') // vue 单文件网页
网页面板.webview.onDidReceiveMessage( 消息处理函数 ) //注册网页面板消息事件
成功后回调(网页面板)
}
},
{ webviewOptions:{ retainContextWhenHidden:true } } //保持内容,切换后不重启
)
})
}
处理收到的网页信令(网页面板, 处理函数){ // 网页面板接收消息
网页面板.webview.onDidReceiveMessage( 消息=>{ 处理函数(消息) }, undefined, this.context.subscriptions);
}
//-------下面备用
// vscode.DocumentSemanticTokensProvider 实现可编程的语义分析 「Sematic Tokens Provider」 是 vscode 内置的一种对象协议,它需要自行扫描代码文件内容,然后以整数数组形式返回语义 token 序列,告诉 vscode 在文件的哪一行、那一列、多长的区间内是一个什么类型的 token。
// 告诉 vscode 在文件的哪一行、那一列、多长的区间内是一个什么类型的 token(比如变量)。
注册编辑器_选择文本事件(){ //选中 移动关闭都会触发
vscode.window.onDidChangeTextEditorSelection()
}
注册编辑器_切换编辑器事件(){
vscode.window.onDidChangeActiveTextEditor()
}
注册编辑器_列变化事件(){
vscode.window.onDidChangeTextEditorViewColumn()
}
注册编辑器_打开文档事件(){
vscode.window.onDidOpenTextDocument()
}
注册编辑器_关闭文档事件(){
vscode.window.onDidCloseTextDocument()
}
注册编辑器_文档可视变化事件(){
vscode.window.onDidChangeTextEditorVisibleRanges()
}
注册编辑器_文本变化事件(){ //每次输入都会触发
vscode.workspace.onDidChangeTextDocument( (变化事件)=>{
})
}
数组里是否有子集(数组, 子集元素){
if(数组.includes(子集元素)) return true
else return false
}
字符串是否有子集(字符串, 子集字符串){ // 有问题 ---> 字符里有正则符号会出错
// includes 是测试数组
if( 字符串.search(子集字符串) === 0) return true
else return false
}
创建文件监视器(){
vscode.workspace.createFileSystemWatcher()
}
获取vscode所有内部指令(){
vscode.commands.getCommands().then(allCommands => { // 获取所有命令
});
}
重启所有的webview页面(){ this.执行vscode指令("workbench.action.webview.reloadWebviewAction") }
创建问题诊断集合( 名称 ){ return vscode.languages.createDiagnosticCollection(名称); } //创建问题诊断集合
添加问题诊断( 问题诊断集合 , 编辑器, 起始位置, 结束位置 ){
问题诊断集合.set(编辑器.document.uri, [{ //vscode内部代码诊断
message: '异常中文标点',
range: new vscode.Range(起始位置, 结束位置),
severity: vscode.DiagnosticSeverity.Warning
} ])
}
获取当前编辑器(){ return vscode.window.activeTextEditor }
内容坐标( 编辑器, 位置 ){ return 编辑器.document.positionAt(位置)}
对内容装饰(编辑器, CSS样式 , 起始位置, 结束位置){ //对页面代码进行外观上的装饰
编辑器.setDecorations( vscode.window.createTextEditorDecorationType({ CSS样式 }) //某段范围添加一些 CSS
,[{
range: new vscode.Range(起始位置, 结束位置)
}])
}
注册代码自动补全(补全条目, 悬浮菜单 ){
this.context.subscriptions.push(
vscode.languages.registerCompletionItemProvider()
)
}
}