内容简介:为vscode编写扩展
vscode 是个超级好用的开发工具,谁用谁知道。
背景故事
一个项目开发、维护的时间久了之后,总会多多少少碰到一段不是你写的,而现在你要维护,但你却看不明白的那是什么鬼的代码;当然有时候也可能是多人在同一个项目里协作开发时,对于bug最终责任人的确诊问题(找到最终责任人不是要“修理他”。帮助他认识问题,提高自身能力,加深团队协作意识才是重点)。
大多数人都用 git
,也知道git里诸如: git log
, git blame
等命令都可以帮我们做到以上需求,可每次看到一段代码之后,先从 IDE 里切换到 Terminal 下,然后敲打命令,并且要记好事故代码的行号,以及准确的文件路径,敲来敲去还是挺烦人的。
于是,能在不来回切换工作环境的情况下,迅速找到某一段代码的作者、写作时间、写作目的就显的还是有点用了。
一个扩展的诞生
写作思路
为了更直观表达这个扩展的设计思路,我用了一个图:
后面我们就根据图里描述的思路来开展工作。
获取信息
要得到一段指定行号(行区间)代码的信息,大家都知道用 git blame
,展示结果如下:
»git blame -L 10,11 js/index.js 297cb0df (Howard.Zuo 2017-03-08 21:58:03 +0800 10) render(h) { 297cb0df (Howard.Zuo 2017-03-08 21:58:03 +0800 11) return h(Game);
少了,"写作目的",也就是说,这个命令的结果无法告诉我们作者提交这段代码时的 commit message
写了什么。于是我得翻翻 git blame --help
,可喜的是被我找到了 --line-porcelain
选项,在她的描述里看到了这么一句: but output commit information for each line
。好像有戏,来试试看:
»git blame -L 10,11 js/index.js --line-porcelain 297cb0df8ab1fe06ee935798d1a2dd4e712a070d 10 10 2 author Howard.Zuo author-mail <leftstick@qq.com> author-time 1488981483 author-tz +0800 committer Howard.Zuo committer-mail <leftstick@qq.com> committer-time 1488981503 committer-tz +0800 summary fix duplicate key issue previous 43966e5cc4c70998c265781fe8acf02946c28f6e js/index.js filename js/index.js render(h) { 297cb0df8ab1fe06ee935798d1a2dd4e712a070d 11 11 author Howard.Zuo author-mail <leftstick@qq.com> author-time 1488981483 author-tz +0800 committer Howard.Zuo committer-mail <leftstick@qq.com> committer-time 1488981503 committer-tz +0800 summary fix duplicate key issue previous 43966e5cc4c70998c265781fe8acf02946c28f6e js/index.js filename js/index.js return h(Game);
不错,这明显是个可以被解析的数据结构。所以获取信息就靠她了 git blame -L <start,end> <filePath> --line-porcelain
。
因为 vscode 是一个基于 electron 开发的 IDE ,所以 node.js
的API对我们是可用的,于是可以通过如下代码执行上面的命令,并且拿到结果数据:
//vscode api,获取当前正在操作的编辑页面 const editor = vscode.window.activeTextEditor; if (!editor) { vscode.window.showWarningMessage('You have to active a file first'); return; } //拿到鼠标选择的内容 const selection = editor.selection; //合成git命令 const cmd = `git blame -L ${selection.start.line + 1},${selection.end.line + 1} ${editor.document.fileName} --line-porcelain`; //通过child_press执行该命令, child_process.exec(cmd, { cwd: vscode.workspace.rootPath }, (error, stdout, stderr) => { //这里的stdout就是上面我们看到的输出内容了 });
解析信息
看了上面的输出内容,我们需要一个model来描述一个这样一个 条目 :
export interface Item { hash: string; shortHash: string; author: string; authorEmail: string; authorTime: number; authorTz: string; committer: string; committerEmail: string; committerTime: number; committerTz: string; commitMessage: string; previousCommit?: string; fileName: string; change: string; }
接下来就是如何解析 git
命令的输出结果了,一个大大的循环来搞定:
export function parse(output: string): Array<Item> { const lines = output.replace(/\r\n/mg, '\n').split('\n'); const commits: Array<Item> = []; let commit; for (let i = 0; i < lines.length - 1; i++) { const line = lines[i]; //一个item的开始标志就是commit的hash if (/^[a-z0-9]{15,}/.test(line)) { commit = {}; commits.push(commit); commit.hash = line.split(' ')[0]; commit.shortHash = commit.hash.substring(0, 8); } else if (/^author\s/.test(line)) { commit.author = line.split(' ')[1]; } else if (/^author-mail\s/.test(line)) { commit.authorEmail = line.split(' ')[1]; } else if (/^author-time\s/.test(line)) { commit.authorTime = +line.split(' ')[1]; } else if (/^author-tz\s/.test(line)) { commit.authorTz = line.split(' ')[1]; } else if (/^committer\s/.test(line)) { commit.committer = line.split(' ')[1]; } else if (/^committer-mail\s/.test(line)) { commit.committerEmail = line.split(' ')[1]; } else if (/^committer-time\s/.test(line)) { commit.committerTime = +line.split(' ')[1]; } else if (/^committer-tz\s/.test(line)) { commit.committerTz = line.split(' ')[1]; } else if (/^previous\s/.test(line)) { commit.previousCommit = line.split(' ')[1]; } else if (/^filename\s/.test(line)) { commit.fileName = line.split(' ')[1]; } else if (!commit.fileName) { commit.commitMessage = line; } else { commit.change = line; } } return commits; }
展示
有了上面解析完毕的 Array<Item>
,简单转换一下字符串,对任何人都是没什么难度的:
export function pretty(commits: Array<Item>): string { return commits.map(c => { return `${c.shortHash} ${c.author} ${formatDate(c.authorTime * 1000)} "${c.commitMessage}" ${c.change}`; }) .join('\n'); }
解决了所有核心问题,剩下的就是按照 vscode-docs ,动手补充一个扩展需要的额外因素了。
安装代码骨架生成器
npm install -g yo generator-code
生成插件项目
yo code
在提问中,依次回答所有问题,最后项目骨架生成。
生成右键菜单
修改 package.json
,增加/修改 contributes
字段:
"contributes": { "menus": { "editor/context": [{ "command": "extension.gitblame", "group": "sourcecontrol", "when": "config.git.enabled && scmProvider == git && gitState == idle" }] }, "commands": [{ "command": "extension.gitblame", "title": "Git blame", "key": "ctrl+b" }], "keybindings": [{ "command": "extension.gitblame", "key": "alt+b" }] }
于是乎,一个右键选项 Git blame 就会出现在你选择一段代码后的右键菜单里
懒加载扩展
一个扩展根据需求,并不一定要随 vscode
的启动而启动,那样影响 vscode
的整体性能,而且没什么特别的好处。所以我们要懒加载。修改 package.json
,增加/修改 activationEvents
字段:
"activationEvents": [ "onCommand:extension.gitblame" ]
只有当用户使用 extension.gitblame
这个命令时(也就是在右键菜单里选择了 Git blame 时),该扩展才正式激活。
到此为止,这个扩展就基本完成了。效果如下:
扩展下载地址: vscode-git-blamer
项目源码地址: vscode-git-blamer
以上所述就是小编给大家介绍的《为vscode编写扩展》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- (全栈学习实践)三、创建php、添加扩展,其他Dockerfile编写
- Just for fun——PHP7扩展编写中的宏
- DockOne微信分享(二六五):如何基于 OAM 编写一个扩展 Trait?
- 使用 Dingo API 扩展包快速构建 Laravel RESTful API(二) —— 编写第一个 API 接口
- 在项目文件 / MSBuild / NuGet 包中编写扩展编译的时候,正确使用 props 文件和 targets 文件
- 基于顺丰同城接口编写sdk,java三方sdk编写思路
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。