1.前言
喜欢或者尝试过写文章的朋友可能会在需要打符号的时候,中英切换出错,将英文感叹号打成中文感叹号,比如 markdown 语法里展示链接或者图片,如果你打错就会变成下面这样
就很烦,有的朋友就会写完整篇文章之后,统一 ctrl+H
全文替换
我之前就是全文替换那种,写完记得替换还好,要是忘了或者改起以前写过的,那中英文标点穿插出现,那酸爽
作为一个易怒人,我能受得了这气?,一怒之下研读 VSCode 插件 API,直接将中文标点替换成英文标点的功能写成了 VSCode 插件(VSCode 文档写的真好,赞一下),于是就有了这篇文章,手把手教你写一个 VSCode 插件。
2. 准备
众所周知 VSCode 是基于 Electron 框架写的,也就是 javaScript,所以写一个插件对前端仔还是很友好的.
- 首先安装环境
$ npm install -g yo generator-code
复制代码
- 执行命令
$ yo code
复制代码
- 选择 New Extension (TypeScript)
- 填写项目配置
# ? What type of extension do you want to create? New Extension (TypeScript)
# ? What's the name of your extension? `your-extension-name`
### Press <Enter> to choose default for all options below ###
# ? What's the identifier of your extension? `your-extension-name`
# ? What's the description of your extension? `some description`
# ? Initialize a git repository? Yes
# ? Bundle the source code with webpack? Yes
# ? Which package manager to use? npm
复制代码
$ ? What type of extension do you want to create? New Extension (TypeScript)
$ ? What's the name of your extension? test (你的插件名)
$ ? What's the identifier of your extension? test (你的插件的标识)
$ ? What's the description of your extension? just a test (简单描述)
$ ? Initialize a git repository? no
$ ? Bundle the source code with webpack? Yes
$ ? Which package manager to use? npm
复制代码
- 进入项目
$ cd `your-extension-name`
$ code .
复制代码
- 可以调试了!
在编辑器中,按 F5,或者点击左边的甲虫进入调试模式,会自动打开一个新的 VSCode 窗口,这个窗口就是给你专门调试插件用的ctrl+shift+P
调出命令面板,输入Hello World
,右下角就会弹出Hello World from test
的消息,至此,一个输出Hello World
,弹出Hello World from test
的简单插件就完成了!
3.项目目录
看到目录的那一刻,你会感觉非常亲切,因为这就是个 node 项目目录,^3^
- 编写的核心文件
package.json
和extension.ts
-
Hello World 插件工作流程及基本概念
既然是 webpack 打包的,那从哪里看起就再简单不过了,打开
webpack.config.js
,看到entry
是'./src/extension.ts'
,那就是项目入口
import * as vscode from "vscode";
export function activate(context: vscode.ExtensionContext) {
console.log('Congratulations, your extension "test" is now active!');
let disposable = vscode.commands.registerCommand("test.helloWorld", () => {
vscode.window.showInformationMessage("Hello World from test!");
});
context.subscriptions.push(disposable);
}
export function deactivate() {}
复制代码
该入口导出两个函数activate
和deactivate
英语好的应该看懂,也应该猜的出来,这第一个函数是插件启用的时候调用的,第二个函数是插件关闭的时候调用的。
其中activate
函数中调用两个内置 API,注册了name
为test.helloworld
的命令,该命令的作用就是传入回调中写的输出刚才看到的信息
核心逻辑写在这了,搞懂了,那么问题来了,什么时候插件会启用?
这就要说到第二个核心文件package.json
了
这package.json
中包含了一些通用属性,比如name
、version
,但还有一些是 vscode 专属的配置属性,比如说contributes
、activationEvents
,眼尖的同学可能已经注意到activationEvents
中就有提到启用的时机
"activationEvents": [
"onCommand:test.helloWorld"
],
"contributes": {
"commands": [
{
"command": "test.helloWorld",
"title": "Hello World"
}
]
},
复制代码
其中activationEvents
说明如下,表示插件激活的条件
而contributes
的commands
配置项就是配置命令面板输入字符串和响应得命令得映射
HelloWorld 流程总结
contributes
的commands
配置项配置命令面板输入字符串和应该响应命令extension.ts
的activate
中注册命令和命令具体逻辑activationEvents
配置插件启用时机
4. 实现目标
到这里,我们回顾初心,我们是要写一个将 markdown 文件中的中文字符替换成英文字符的插件,那怎么着手呢?这时候就要泡上一杯咖啡,轻轻的打开官网文档
了
从官网可以了解到,一个插件可以拓展一下几个方面
- Common Capabilities
- Theming
- Declarative Language Features
- Programmatic Language Features
- Workbench Extensions
- Debugging
这里就不深入说明了,需要详解的请移步 Extensions Capabilities Overview
回到需求,目标是用户调出命令面板
或者使用快捷键
就可以马上将中文标点转换为英文标点,主要分为一下几个步骤:
- 首先定义在
package.json
中定义命令和对应快捷键
"contributes": {
"commands": {
"command": "test.replace",
"title": "markdown cp replacer"
},
"keybindings": {
"command": "test.replace",
"key": "alt+f"
}
},
复制代码
- 设置插件启用时机,显然这里是当文件以.md 结尾时启用
"activationEvents": [
"onLanguage:markdown"
],
复制代码
- 编写具体转换逻辑
- 注册自定义命令
export function activate(context: vscode.ExtensionContext) {
context.subscriptions.push(
vscode.commands.registerCommand("test.replace", () => {
replace();
})
);
}
复制代码
- 完善转换逻辑函数
const fs = require("fs");
//中文字符
const CP = [",", ":", "?", "!", "。", "“", "”", "(", ")"];
//用于替换的英文字符
const EP = [",", ":", "?", "!", ".", '"', '"', "(", ")"];
const map = new Map();
let len = CP.length;
for (let i = 0; i < len; i++) {
map.set(CP[i], EP[i]);
}
function replace() {
let fileName: string | undefined =
vscode.window.activeTextEditor?.document.fileName;
let content: string;
try {
content = fs.readFileSync(fileName).toString();
} catch (err) {
throw err;
}
let charArr = content.split("");
for (let i = 0; i < charArr.length; i++) {
let char = charArr[i];
if (map.has(char)) {
charArr[i] = map.get(char);
}
}
content = charArr.join("");
fs.writeFile(fileName, content, (err: Error) => {
if (err) {
throw err;
}
});
}
复制代码
- 完成!
运行debug,输入快捷键alt+f
就可以马上替换了.
5.发布与迭代
官方指引