这次来看一下如何开发vscode插件,插件的功能是方便排查本地日志文件。
vscode文档官网地址 : Your First Extension 
 
配置环境 请先安装好Node.js和Git,
然后安装Yeoman和VS Code Extension Generator:
1 2 3 npm install -g yo generator-code 
 
通过脚手架生成模板项目,我们可以通过这个模板工程来开发:
 
输入yo code后会出现一个命令行交互:进行对应的信息输入就好
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18      _-----_     ╭──────────────────────────╮     |       |    │   Welcome to the Visual  │     |--(o)--|    │   Studio Code Extension  │    `---------´   │        generator!        │     ( _´U`_ )    ╰──────────────────────────╯     /___A___\   /      |  ~  |    __'.___.' __  ´   `  |° ´ Y ` ? What type  of extension do  you want to create? New Extension (JavaScript) ? What's the name of your extension? helloWorld  ? What' s the identifier of your extension? helloWorld? What's the description of your extension? helloWorld  ? Enable JavaScript type checking in ' jsconfig.json'? Yes ? Initialize a git repository? No ? Which package manager to use? npm 
 
完成交互后 命令行会出现
1 2 3 4 5 Your extension helloWorld has been created! To start editing with Visual Studio Code, use the following commands:      code helloWorld 
 
调试helloWorld 用VS Code打开helloWorld文件夹 ,按下F5,你会立即看到一个插件发开主机窗口,其中就运行着插件。
在命令面板(Ctrl+Shift+P)中输入Hello World命令。
如果你看到了Hello World提示弹窗,恭喜你成功了!
插件目录结构 1 2 3 4 5 6 7 8 9 10 . ├── .vscode │   ├── launch.json     // 插件加载和调试的配置 │   └── tasks.json      // 配置TypeScript编译任务 ├── .gitignore          // 忽略构建输出和node_modules文件 ├── README.md           // 一个友好的插件文档 ├── src │   └── extension.ts    // 插件源代码 ├── package.json        // 插件配置清单 ├── tsconfig.json       // TypeScript配置 
 
目前我们只有着重看package.json和 extension.ts 文件
每个VS Code插件都必须包含一个package.json,它就是插件的配置清单。package.json混合了Node.js字段,如:scripts、dependencies,还加入了一些VS Code独有的字段,如:publisher、activationEvents、contributes等。关于这些VS Code字段说明都在插件清单参考中可以找到。
extension.ts 插件入口文件会导出两个函数,activate 和 deactivate,你注册的激活事件被触发之时执行activate,deactivate则提供了插件关闭前执行清理工作的机会。
所需的插件功能 目前基本了解一下vscode插件的大概,接下来具体看下我们可能需要哪些功能:
一个左侧pannel上显示的icon 
点击icon打开的左侧面板UI
面板上需要打开文件功能 
面板上需要将当前打开的文件设置为所需文件功能 
一个输入筛选条件的输入框 
根据筛选条件过滤文件内容的功能 
将过滤后信息输出的功能 
 
 
 
侧边icon:contributes.viewsContainers & contributes.views 在package.json中通过viewsContainers 和 views 配置来声明 左侧pannel上显示的icon 和 点击icon打开的左侧面板UI。
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 "contributes" :  {     "viewsContainers" :  {        "activitybar" :  [          {            "id" :  "ai-log-assistant" ,            "title" :  "AI Log Assistant" ,            "icon" :  "resources/dark/ai-kit-icon.svg"          }        ]      } ,      "views" :  {        "ai-log-assistant" :  [          {            "id" :  "ai-log-assistant" ,            "type" :  "webview" ,            "name" :  "AI Log Assistant" ,            "icon" :  "resources/dark/dependency.svg" ,            "contextualTitle" :  "AI Logger"          }        ]      } ,  } 
 
侧边视图:自定义webview 在 extension.ts 中注册一个 与 package.json 对应的 ai-log-assistan 侧边栏ID
1 2 3 4 5 6 7 8 9 import  * as  vscode from  "vscode" ;import  { SidebarProvider  } from  "./SidebarProvider" ;export  function  activate (context: vscode.ExtensionContext ) {  const  sidebarPanel = new  SidebarProvider (context.extensionUri );   context.subscriptions .push (     vscode.window .registerWebviewViewProvider ("ai-log-assistant" , sidebarPanel)   ); } 
 
实现侧边栏
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 import  * as  vscode from  "vscode" ;export  class  AILogWebviewViewProvider  implements vscode.WebviewViewProvider  {    public static  readonly viewType = 'ai-log-assistant' ;     private _view?: vscode.WebviewView ;     private readonly _extensionUri : vscode.Uri ;     private readonly _context : vscode.ExtensionContext ;     constructor (extensionUri: vscode.Uri, context: vscode.ExtensionContext ) {         this ._extensionUri  = extensionUri;         this ._context  = context;     }     public resolveWebviewView (webviewView : vscode.WebviewView ): void  {         this ._view  = webviewView;         this ._view .webview .options  = {             enableScripts : true ,         };         const  projectPath = utils.getProjectPath (this ._context );         utils.loadToken ();         console .log ("projectPath: "  + projectPath);         this ._view .webview .onDidReceiveMessage (message  =>  {             operateMessage (this ._context , projectPath, webviewView.webview , message);         }, undefined , this ._context .subscriptions );         this ._view .webview .html  = this ._getHtmlForWebview (webviewView);     }     private _getHtmlForWebview (view : vscode.WebviewView ): string {         return  getWebViewContent (this ._context , 'view/ai-webview.html' , view.webview );     } } 
 
上述代码采用面向对象的方式实现一个 AILogWebviewViewProvider类,根据 vscode.WebviewViewProvider, 其实实现所有的 WebviewViewProvider 都是是这段代码,其他代码都是相同的,因为关于 webview 中的 HTML 我们都可以使用js来生成,这不正是我们的单页面应用开发?
UI与逻辑通信 在webview html的按钮点击事件中添加:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 function  callVscode (data, cb ) {    if  (typeof  data === 'string' ) {         data = { cmd : data };     }     if  (cb) {                  const  cbid = Date .now () + ''  + Math .round (Math .random () * 100000 );         callbacks[cbid] = cb;         data.cbid  = cbid;     }     vscode.postMessage (data); } 
 
在上面AILogWebviewViewProvider注册了:
1 2 3 this ._view .webview .onDidReceiveMessage (message  =>  {    operateMessage (this ._context , projectPath, webviewView.webview , message); }, undefined , this ._context .subscriptions ); 
 
然后通过operateMessage分发对应的时间请求:
1 2 3 4 5 6 function  operateMessage (context: vscode.ExtensionContext, projectPath: string, webview: vscode.Webview, message: any ) {     console .log ("received msg : "  + message);     switch  (message.cmd ) {     } } 
 
打开文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 async  function  selectXLogFile (pcontext: vscode.ExtensionContext, webview: vscode.Webview, message: any ) {         const  uris = await  vscode.window .showOpenDialog ({         canSelectFiles : true ,         canSelectFolders : false ,         canSelectMany : false ,     });          if  (uris && uris.length  > 0 ) {         const  uri = uris[0 ];         parseFilePath = uri.fsPath ;         console .log ("select a log file: "  + parseFilePath);         invokeCallback (webview, message, parseFilePath);     } } 
 
获取当前打开的文件 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 function  parseCurLogFile (pcontext: vscode.ExtensionContext, webview: vscode.Webview, message: any ) {    console .log ("start parseCurLogFile" );     curShowDocument = null ;     const  editor = vscode.window .activeTextEditor ;     let  filePath = '' ;     if  (editor) {                  filePath = editor.document .uri .fsPath ;                  const  fileName = editor.document .fileName ;         console .log ("filePath: "  + filePath + "  fileName:"  + fileName);     }     if  (filePath === '' ) {         utils.showError ("当前文件信息为空" );         invokeCallback (webview, message, "当前文件信息为空" );         return ;     }     if  (!filePath.endsWith (".log" )) {         utils.showError (filePostfixHint);     }     parseFilePath = filePath;     invokeCallback (webview, message, parseFilePath);      }