ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
&emsp;&emsp;VSCode提供了丰富的[API](https://code.visualstudio.com/api/references/vscode-api),可以借助编辑器扩展许多定制功能。 &emsp;&emsp;本次研发了一款名为[Search Method](https://github.com/pwstrick/search-method)的插件,在此记录整个研发过程。 ## 一、准备工作 **1)安装环境** &emsp;&emsp;首先是全局安装 yo 和 generator-code 两个库,我本地全局安装了[cnpm](https://npmmirror.com/),所以用它来安装。 ~~~ npm install yo generator-code -g ~~~ :-: ![](https://img.kancloud.cn/e4/3c/e43c1a3723e0bf60d852b376b7848677_2174x856.png =800x) &emsp;&emsp;然后使用 yo 命令初始化插件项目。 ~~~ yo code ~~~ &emsp;&emsp;回答些问题,但如果在回答 Initialize a git repository 时选择 yes,那么就会出现报错。 :-: ![](https://img.kancloud.cn/4f/71/4f71d7d7af77f5bad7cb80422123147b_2474x858.png =800x) &emsp;&emsp;选择 no 之后,才会提示安装成功,这个莫名其妙的问题就处理了好久。 :-: ![](https://img.kancloud.cn/a1/30/a130361f1a0a100fbd5fdb1462fe0ea2_1060x1314.png =400x) &emsp;&emsp;初始化成功后,就会得到一个项目结构(大致如下),建议单独打开个窗口调试插件。 ~~~ |-- test |-- extension.js // 插件入口文件,插件的逻辑在此完成 |-- CHANGELOG.md |-- package-lock.json |-- package.json |-- README.md // 插件说明 README,发布后会展示 |-- jsconfig.json |-- .eslintrc.json |-- vsc-extension-quickstart.md ~~~ &emsp;&emsp;最重要的就是 extension.js 和 package.json,前者会实现插件的核心功能,后者包括插件的配置信息。 **2)调试** &emsp;&emsp;选择 run =》 Start Debugging 后,就会自动弹出另一个 VSCode 窗口。 ![](https://img.kancloud.cn/dd/61/dd619df8f77fb0bec732c2a36519f4b7_2118x840.png =800x)  &emsp;&emsp;在这个窗口中,会默认安装上正在调试的插件,其实我本来起的插件名字叫 Search Function。 &emsp;&emsp;但是在调试时,按下 Command + Shift + P 打开命令面板,却无法在此处找到默认的 Hello World 命令。 :-: ![](https://img.kancloud.cn/57/36/5736917f941c8ff38a9fb4852ab428fe_698x236.png =500x) &emsp;&emsp;直到我换了名字后,才能在调试时找到 Hello World,这个坑也花了我好几个小时。 &emsp;&emsp;还有个问题,就是在在编辑器的 Debug Console 标签内无法看到打印信息,相当于是在盲调,电脑重启后,就能看到了,还是重启大法好。 :-: ![](https://img.kancloud.cn/b3/7e/b37e55bb6b2c93fec7e5b4823c9c15a4_1198x530.png =500x) &emsp;&emsp;至此,完成了整个准备工作。 ## 二、开发过程 &emsp;&emsp;公司有个 Node 项目,现在有个问题,就是 router 层的代码无法自动关联到 service 层的方法声明。 &emsp;&emsp;下面这段代码存在于 router 层,common 存在于service 层,它有一个 aggregation() 方法。 &emsp;&emsp;原先鼠标拖到方法处,按住 command 键,就能跳转到声明处,查看方法实现逻辑,但是现在无法跳转。  ~~~ const data = await services.common.aggregation({ tableName }); ~~~ &emsp;&emsp;因为项目为了不用每次初始化 service 中的类,一下子全部都初始化好了,赋到一个对象中,如下所示。 ~~~ Object.keys(dir).forEach((item) => { services[item] = new dir[item](models); }); ~~~ &emsp;&emsp;这次要开发的插件,其实就是为了解决此问题,提升大家的开发效率。 **1)最终效果** &emsp;&emsp;在经过多轮深思熟虑的设计之后,确定了要达到的效果,那就是先选中要查看的方法以及文件名称,然后右键找到 Search Services File 菜单,此时就能直接跳转过去了。 :-: ![](https://img.kancloud.cn/9c/a5/9ca5813f8acb7d23f2913e37e2b29df7_1217x765.png =500x) **2)菜单配置** &emsp;&emsp;要想在右键显示这个自定义的菜单,需要在 package.json 中做些配置。 &emsp;&emsp;commands 是默认就存在的,主要是 menus 字段,注册菜单。 ~~~ "contributes": { "commands": [ { "command": "search-method.services", "title": "Search Services File" } ], "menus": { "editor/context": [ { "command": "search-method.services", "group": "navigation", "when": "editorHasSelection" } ] } }, ~~~ &emsp;&emsp;editor/context 是指编辑器上下文菜单,在[contributes.menus](https://code.visualstudio.com/api/references/contribution-points#contributes.menus)一栏中,还可以找到其余 menus 的关键字,可以都尝试下。 &emsp;&emsp;editor/context 的值是一个数组,可以配置多个菜单,菜单中的 group 就是菜单所处的位置。 &emsp;&emsp;navigation 就是最上面,还有 1\_modification,9\_cutcopypaste 和 z\_commands[参考下图](https://code.visualstudio.com/api/references/contribution-points#Sorting-of-groups)。 :-: ![](https://img.kancloud.cn/24/72/24727a7e9a6ae20899435159946e5038_624x271.png =400x) &emsp;&emsp;when 就是触发条件,editorHasSelection 就是指在编辑器中选中时触发。 &emsp;&emsp;可选的关键字还可以是 editorFocus、inputFocus、editorHasMultipleSelections 等,参考[available contexts](https://code.visualstudio.com/api/references/when-clause-contexts#available-contexts)。 **3)核心逻辑** &emsp;&emsp;下面这段就是最精简的 extension.js 代码了,注册一个名为 search-method.services 的命令,核心功能会在此回调函数中实现。  ~~~ const vscode = require('vscode'); function activate(context) { const disposable = vscode.commands.registerCommand( 'search-method.services', (uri) => { } context.subscriptions.push(disposable); } function deactivate() {} module.exports = { activate, deactivate } ~~~ &emsp;&emsp;在研发时,以为像下面这样就能直接得到 webMonitor.js 绝对目录,但其实此处读的是插件的根目录,而不是项目的。 ~~~ path.resolve(__dirname, '../services/webMonitor.js') ~~~ &emsp;&emsp;通过回调函数的参数 uri.fsPath 才能得到当前选中的代码所处的绝对位置。下面是完整的插件逻辑。 ~~~ 1 const vscode = require('vscode'); 2 const path = require('path'); 3 const fs = require('fs'); 4 const { Uri, window, Position, Range, Selection } = vscode; 5 const disposable = vscode.commands.registerCommand( 6 "search-method.services", 7 (uri) => { 8 // 获取编辑器对象 9 const editor = window.activeTextEditor; 10 if (!editor) { 11 return; 12 } 13 // 当前选中的代码所处的绝对位置 14 const dirPath = uri.fsPath; 15 // services的绝对目录 16 const serviceDir = path.resolve(dirPath, "../../services"); 17 // 获取选中文本 18 const doc = editor.document; 19 const selection = editor.selection; 20 const words = doc.getText(selection).split("."); 21 const serviceName = words[0]; 22 const methodName = words.length > 1 ? words[1] : ""; 23 // 列出目录中所有的文件 24 const files = fs.readdirSync(serviceDir); 25 for (const item of files) { 26 // 读取文件名称 27 const name = item.split(".")[0]; 28 // 文件匹配 29 if (serviceName === name) { 30 const file = Uri.file(path.resolve(serviceDir, item)); 31 // 根据换行符分隔字符串 32 const fileContentArr = fs 33 .readFileSync(path.resolve(serviceDir, item), "utf8") 34 .split(/\r?\n/); 35 // 声明的方法会有 async 关键字,或者通过空格和括号匹配 36 const index = fileContentArr.findIndex( 37 (element) => 38 element.indexOf(`async ${methodName}`) >= 0 || 39 element.indexOf(` ${methodName}(`) >= 0 40 ); 41 // 跳转到指定行数的文件 42 window.showTextDocument(file).then((editor) => { 43 // 开始位置 44 const start = new Position(index, 0); 45 // 结束位置加了 20 行,为了便于查看 46 const end = new Position(index + 20, 0); 47 // 光标聚焦的位置 48 editor.selections = [new Selection(start, start)]; 49 // 可见范围 50 const range = new Range(start, end); 51 editor.revealRange(range); 52 }); 53 break; 54 } 55 } 56 } 57 ); ~~~ &emsp;&emsp;上面这段代码比较长,核心思路: * 第13行,读取当前项目 services 的绝对路径。 * 第17行,获取选中的文本,例如 common.aggregation,然后分隔得到文件名和方法名。 * 第23行,列出 services 的所有文件,并与选中的文件名匹配。 * 第28行,匹配成功时读取文件内容并通过换行符分隔,查找方法所在的行。 * 第41行,通过[window.showTextDocument](https://code.visualstudio.com/api/references/vscode-api#window)打开[Uri.file()](https://code.visualstudio.com/api/references/vscode-api#Uri)处理过的文件,初始化[Position](https://code.visualstudio.com/api/references/vscode-api#Position)类,配置光标聚焦的位置([Selection](https://code.visualstudio.com/api/references/vscode-api#Selection))和可见范围([Range](https://code.visualstudio.com/api/references/vscode-api#Range))。 &emsp;&emsp;虽然只有40多行代码,但花费了我一天的时间才完成,中间走了不少弯路,最麻烦的是跳转文件,showTextDocument() 方法也是偶然间才发现的。 &emsp;&emsp;还有个小技巧,可以通过看 window、Uri 这些类的声明,就能了解到它们提供的功能。 ## 三、对外发布 &emsp;&emsp;为了能在 VSCode 的 Extensions 中被搜索到,还需要几个步骤。 **1)注册账号** &emsp;&emsp;首先到[Azure DevOps](https://dev.azure.com/pwstrick/) 创建管理账号,根据提示来就行了。 &emsp;&emsp;然后选中 Personal access tokens,去创建 token。 :-: ![](https://img.kancloud.cn/cc/c7/ccc7416829c93c5a78b75e9b5ca56936_296x427.png =200x) &emsp;&emsp;接着在创建时,有些选项要注意,Organization 和 Scopes,网上说不能乱选,否则发布会不成功。创建后,记得自己将 token 保存一下,后面就无法查看了。 :-: ![](https://img.kancloud.cn/32/ed/32ed2febbd2ced35069a0bccd9a81418_619x372.png =400x) &emsp;&emsp;最后创建[发布账号](https://marketplace.visualstudio.com/manage),填些信息,下一步登录时使用。 **2)vsce** &emsp;&emsp;vsce 用于上传插件,首先全局安装。  ~~~ npm i vsce -g ~~~ &emsp;&emsp;然后是登录刚刚注册的发布账号,例如 vsce login pwstrick。 ~~~ vsce login <publisher name> ~~~ &emsp;&emsp;选好后会要求你输入之前申请的 token,登录成功后就会有下面的一段提示。 ~~~ Personal Access Token for publisher 'pwstrick': ************************ The Personal Access Token verification succeeded for the publisher 'pwstrick'. ~~~ &emsp;&emsp;此时,就可以输入发布命令了,成功的话,就会出现 DONE 的提示。 ~~~ vsce publish INFO Publishing 'pwstrick.search-method v0.0.1'... INFO Extension URL (might take a few minutes): https://marketplace.visualstudio.com/items?itemName=pwstrick.search-method INFO Hub URL: https://marketplace.visualstudio.com/manage/publishers/pwstrick/extensions/search-method/hub DONE Published pwstrick.search-method v0.0.1. ~~~ &emsp;&emsp;上传成功后,不会马上就能搜索到。 &emsp;&emsp;在[插件管理](https://marketplace.visualstudio.com/manage/publishers/)中,当出现绿色的勾时,才表示插件发布完成,现在可以在应用市场搜索到了。 :-: ![](https://img.kancloud.cn/f5/3a/f53a5bf6cc480cd0b0772e3c962cb360_908x141.png =600x) &emsp;&emsp;可以看到并不是在第一行,需要往下翻一翻。 :-: ![](https://img.kancloud.cn/9f/d9/9fd94eb749b69654ce82ef2c590ca742_1996x1220.png =800x) &emsp;&emsp;在给组员使用时,发现他们不能安装,因为我设置的最低版本是 1.7.0,这个在开发的时候也需要注意。 ~~~ "engines": { "vscode": "^1.70.0" }, ~~~ 参考: [vscode插件开发指南(一)-理论篇](https://juejin.cn/post/6960626872791072798) [vscode插件编写体验-右键菜单](https://segmentfault.com/a/1190000041672434) [vscode window.showTextDocument示例](https://javascript.hotexamples.com/zh/examples/vscode/window/showTextDocument/javascript-window-showtextdocument-method-examples.html) [编写一个VSCode插件](https://juejin.cn/post/7119095066810908679) ***** > 原文出处: [博客园-前端利器躬行记](https://www.cnblogs.com/strick/category/1472499.html) [知乎专栏-前端利器躬行记](https://zhuanlan.zhihu.com/pwtool) 已建立一个微信前端交流群,如要进群,请先加微信号freedom20180706或扫描下面的二维码,请求中需注明“看云加群”,在通过请求后就会把你拉进来。还搜集整理了一套[面试资料](https://github.com/pwstrick/daily),欢迎浏览。 ![](https://box.kancloud.cn/2e1f8ecf9512ecdd2fcaae8250e7d48a_430x430.jpg =200x200) 推荐一款前端监控脚本:[shin-monitor](https://github.com/pwstrick/shin-monitor),不仅能监控前端的错误、通信、打印等行为,还能计算各类性能参数,包括 FMP、LCP、FP 等。