本文讲述一下vscode插件和源码通过命令进行通信
原文链接:https://zhouhangzooo.github.io/2019/04/10/vscode插件与源码通信/
在之前"vscode插件与webview相互通信"文章中,讲述webview和插件进行通信,里面有个注册命令,之前文章没有详细代码,其实代码vscoode官网都有,
## 接下来要说命令,那么先贴一下注册命令的代码
1 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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | context.subscriptions.push(vscode.commands.registerCommand('extension.demo.openWebview', function (uri) { //这个uri就是传递过来的参数,无论是vscode插件和webview通信还是vscode插件和vscode源码通信都可以通过这个进行数据传递 if (flag) { //判断flag让webview不重复打开 if(value == undefined) { //如果是第一次打开课程 value = uri; panel.webview.postMessage({ command: "course_id",text: value}); } else if (value != undefined && value == uri) { //如果重复点击 return; }else { value = uri; panel.webview.postMessage({ command: "course_id",text: value }); } return; } value = uri; panel = vscode.window.createWebviewPanel( 'testWebview', // viewType "课程提示", // 视图标题 2, // 显示在编辑器的哪个部位 { enableScripts: true, // 启用JS,默认禁用 retainContextWhenHidden: true, // webview被隐藏时保持状态,避免被重置 enableFindWidget: true, } ); flag = true; panel.webview.html = getWebViewContent(context, 'src/test-webview.html'); //发送消息到webview if (value !== undefined && value !== "") { panel.webview.postMessage({ command: value }); } panel.webview.onDidReceiveMessage(message => { //接收命令 switch (message.command) { case 'openHint': vscode.window.showInformationMessage(message.text, { modal: true }); break; } }, undefined, context.subscriptions); //当webview被关闭时,设置标识,就可以重新打开webview panel.onDidDispose( () => { flag = false; console.log('===============================close-webview'); }, null, context.subscriptions); })); function getWebViewContent(context, templatePath) { const resourcePath = util.getExtensionFileAbsolutePath(context, templatePath); const dirPath = path.dirname(resourcePath); let html = fs.readFileSync(resourcePath, 'utf-8'); // vscode不支持直接加载本地资源,需要替换成其专有路径格式,这里只是简单的将样式和JS的路径替换 html = html.replace(/(<link.+?href="|<script.+?src="|<img.+?src=")(.+?)"/g, (m, $1, $2) => { return $1 + vscode.Uri.file(path.resolve(dirPath, $2)).with({ scheme: 'vscode-resource' }).toString() + '"'; }); return html; } |
## webview页面
```
1 2 3 4 5 6 7 8 9 10 11 | <script> window.addEventListener('message', event => { const message = event.data; if(message.command != "course_id") { return; } courseId = message.text; // console.log("==================================courseId" + courseId); }); </script> |
```
<div>
οnclick="openHint()"
</div>
```
1 2 3 4 5 6 | function openHint() { vscode.postMessage({ command: 'openHint', text: '试着输入 helloword ' }) } |
```
可以看到上面的代码,其实和官方差不多,上面代码是注册了命令,通过命令打开webveiw,其实就是打开了src目录下的test-webview.html页面,这个html我们可以自定义,同时页面可以传输数据到这里然后panel.webview.onDidReceiveMessage接收并处理。
## 当我们想要传输数据到webivew时
```
vscode.commands.executeCommand("extension.demo.openWebview","需要传输的数据");
```
这样通过命令我们就可以将数据传输到webview页面上了,那么我们试试和源码进行交互
## 思考:源码中肯定有实现新建文件,而它给我们提供快捷键Ctrl+N打开,所以vscode源码中肯定有一个新建文件的命令,我们只需执行它,便可以新建文件
根据我的研究,源码的功能,绝大部分源码实现方法在XXService.ts中,而你想要调用它,那么方法在XXActions.ts中。
我们查看一个例子:fileActions.ts文件
```
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | export class GlobalNewUntitledFileAction extends Action { public static readonly ID = 'workbench.action.files.newUntitledFile'; public static readonly LABEL = nls.localize('newUntitledFile', "New Untitled File"); constructor( id: string, label: string, @IEditorService private readonly editorService: IEditorService ) { super(id, label); } public run(): Promise<any> { return this.editorService.openEditor({ resource: resources.joinPath(lastDir, untitledFileName), options: { pinned: true } } as IUntitledResourceInput); // untitled are always pinned } public run(): Promise<any> { return this.editorService.openEditor({ options: { pinned: true } } as IUntitledResourceInput); // untitled are always pinned } } |
上面是vsocde源码中代码,可以看到最终运行run即可新建文件,我们一步步找,可以看到官方调用run方法是通过actions.ts文件中的接口方法,通过一个参数继承这个接口,然后参数调用里面的方法实现的。
```
1 2 3 4 5 | export interface IActionRunner extends IDisposable { run(action: IAction, context?: any): Promise<any>; onDidRun: Event<IRunEvent>; onDidBeforeRun: Event<IRunEvent>; } |
```
而我们如果想要在插件中实现新建文件,那么我们只需要执行命令即可,命令就是XXAction的id,比如新建文件的命令就是GlobalNewUntitledFileAction.ID
```
1 2 | import * as vscode from "vscode"; vscode.commands.executeCommand('workbench.action.files.newUntitledFile'); |
```
因此,vscode所有快捷键的功能我们都可以通过执行命令来实现。
原文链接:https://zhouhangzooo.github.io/2019/04/10/vscode插件与源码通信/