说在前面
🤯平时我们写代码的时候总是少不了cv,cv的时候还要先去找到旧的代码片段,然后将其复制过来,这样操作还是显得有些繁琐,针对这个问题,我们可以写一个代码片段保存复用 vscode 插件,支持同步代码片段到自己指定的 gitee 仓库,实现在不同电脑上 vscode 中共享代码片段📑
一、准备工作
新建 gitee 仓库
直接在gitee上新建仓库即可。
我们不想要书签信息公开,所以选择勾选上私有:
创建完的初始仓库是这样的:
我们再新增一个目录codeSnippets
,用于存放代码片段相关的文件:
在该目录下新增一个文件snippets.json
,用于保存代码片段数据:
二、插件实现
1、环境准备
确保你已经安装了 Node.js 和 npm(Node.js 包管理器),因为 VSCode 插件是使用 JavaScript 或 TypeScript 编写的,并且依赖于这些工具进行开发和构建。
2、生成插件项目脚手架
- 可以使用 Yeoman 和 VSCode Extension Generator 来快速生成插件项目的基础结构。首先,全局安装 Yeoman 和 VSCode Extension Generator:
npm install -g yo generator-code
- 然后,在你想要创建插件项目的目录下,运行以下命令来生成项目脚手架:
yo code
这会启动一个交互式的向导,按提示填写信息即可:
3、gitee仓库配置
(1)注册命令
const giteeConfigDisposable = vscode.commands.registerCommand( "saveCodeSnippetsAndReusePlugins.giteeConfig", async () => { // 后续具体操作逻辑在此处 } ); context.subscriptions.push(giteeConfigDisposable);
通过 vscode.commands.registerCommand
注册了一个名为 "saveCodeSnippetsAndReusePlugins.giteeConfig"
的命令。当这个命令在 VSCode 中被触发时,会执行后续定义的异步函数中的操作。
(2)获取gitee配置信息
async function getGiteeConfig(context) {
const gitConfigFilePath = path.join(
context.extensionPath,
"config/gitConfig.json"
);
let gitConfigData = {};
if (fs.existsSync(gitConfigFilePath)) {
gitConfigData = JSON.parse(
fs.readFileSync(gitConfigFilePath, "utf8") || "{}"
);
}
return gitConfigData;
}
读取本地配置记录文件,获取旧的配置信息。
(3)获取用户输入配置信息
async function getStr(name, value = "") {
const token = await vscode.window.showInputBox({
placeHolder: `请输入${name}`,
value,
});
return token;
}
const gitConfigData = await getGiteeConfig(context);
const token = await getStr("token", gitConfigData.token);
if (!token) {
vscode.window.showInformationMessage(`请输入token`);
return;
}
const owner = await getStr("owner", gitConfigData.owner);
if (!owner) {
vscode.window.showInformationMessage(`请输入owner`);
return;
}
const repo = await getStr("仓库名", gitConfigData.repo);
if (!repo) {
vscode.window.showInformationMessage(`请输入仓库名`);
return;
}
先获取本地配置记录,获取旧的配置信息,有配置信息的话会在用户输入框默认回填。
(4)保存gitee配置信息
async function saveGiteeConfig(gitConfigData, context) {
const gitConfigFilePath = path.join(
context.extensionPath,
"config/gitConfig.json"
);
fs.writeFileSync(
gitConfigFilePath,
JSON.stringify(gitConfigData, null, 2),
"utf8"
);
vscode.window.showInformationMessage(`gitee配置已成功保存!`);
}
await saveGiteeConfig(
{
token,
owner,
repo,
},
context
);
将gitee配置信息保存到本地配置文件中去。
(5)同步仓库代码片段
const url = ` https://gitee.com/api/v5/repos/${owner}/${repo}/contents/codeSnippets/snippets.json`;
const file = await fetchFileContent(url, token);
if (file.message) {
vscode.window.showInformationMessage(
`${file.message},获取gitee代码片段出错,请检查gitee配置信息`
);
return;
}
const fileContent = file.content || "";
const content = await getDecodedContent(fileContent);
const snippetsFilePath = path.join(
context.extensionPath,
"config/snippets.json"
);
const snippetsData = JSON.parse(
fs.readFileSync(snippetsFilePath, "utf8")
);
fs.writeFileSync(
snippetsFilePath,
JSON.stringify(Object.assign(content, snippetsData), null, 2),
"utf8"
);
const modifiedContent = JSON.stringify(
Object.assign(content, snippetsData),
null,
2
);
const encoder = new TextEncoder();
const data = encoder.encode(modifiedContent);
const encodedContent = btoa(
String.fromCharCode.apply(null, new Uint8Array(data))
);
await putFileContent(
url,
token,
encodedContent,
file.sha,
"更新代码片段"
);
vscode.window.showInformationMessage("已同步gitee最新代码片段");
根据输入的gitee配置信息去获取gitee仓库中的代码片段,并将本地代码片段与仓库中的代码进行合并,合并后同步更新本地和仓库的代码片段。
4、代码片段同步
function codeSnippetSynchronization(context) {
const codeSnippetSynchronizationDisposable = vscode.commands.registerCommand(
"saveCodeSnippetsAndReusePlugins.codeSnippetSynchronization",
async () => {
const gitConfigData = await getGiteeConfig(context);
const { owner, repo, token } = gitConfigData;
const url = `https://gitee.com/api/v5/repos/${owner}/${repo}/contents/codeSnippets/snippets.json`;
const file = await fetchFileContent(url, token);
if (file.message) {
vscode.window.showInformationMessage(
`${file.message},获取gitee代码片段出错,请检查gitee配置信息`
);
return;
}
const fileContent = file.content || "";
const content = await getDecodedContent(fileContent);
const snippetsFilePath = path.join(
context.extensionPath,
"config/snippets.json"
);
const snippetsData = JSON.parse(
fs.readFileSync(snippetsFilePath, "utf8")
);
fs.writeFileSync(
snippetsFilePath,
JSON.stringify(Object.assign(content, snippetsData), null, 2),
"utf8"
);
const modifiedContent = JSON.stringify(
Object.assign(content, snippetsData),
null,
2
);
const encoder = new TextEncoder();
const data = encoder.encode(modifiedContent);
const encodedContent = btoa(
String.fromCharCode.apply(null, new Uint8Array(data))
);
await putFileContent(
url,
token,
encodedContent,
file.sha,
"更新代码片段"
);
vscode.window.showInformationMessage("已同步gitee最新代码片段");
}
);
context.subscriptions.push(codeSnippetSynchronizationDisposable);
}
根据配置信息获取gitee仓库中的代码片段,并将本地代码片段与仓库中的代码进行合并,合并后同步更新本地和仓库的代码片段。
5、保存代码片段
function saveSnippet(context) {
const saveSnippetDisposable = vscode.commands.registerCommand(
"saveCodeSnippetsAndReusePlugins.saveSnippet",
async () => {
const editor = vscode.window.activeTextEditor;
if (editor) {
const selection = editor.selection;
const text = editor.document.getText(selection);
// 提示用户输入自定义名称
const snippetName = await vscode.window.showInputBox({
placeHolder: "请输入代码片段的自定义名称",
});
if (snippetName) {
// 读取已有的代码片段数据
const snippetsFilePath = path.join(
context.extensionPath,
"config/snippets.json"
);
let snippetsData = {};
if (fs.existsSync(snippetsFilePath)) {
snippetsData = JSON.parse(
fs.readFileSync(snippetsFilePath, "utf8")
);
}
// 将新的代码片段添加到数据中
snippetsData.snippets[snippetName] = text;
// 保存更新后的代码片段数据
fs.writeFileSync(
snippetsFilePath,
JSON.stringify(snippetsData, null, 2),
"utf8"
);
vscode.window.showInformationMessage(`代码片段已保存到本地!`);
const giteeConfig = await getGiteeConfig(context);
const { token, owner, repo } = giteeConfig;
const url = `https://gitee.com/api/v5/repos/${owner}/${repo}/contents/codeSnippets/snippets.json`;
const file = await fetchFileContent(url, token);
const modifiedContent = JSON.stringify(snippetsData, null, 2);
const encoder = new TextEncoder();
const data = encoder.encode(modifiedContent);
const encodedContent = btoa(
String.fromCharCode.apply(null, new Uint8Array(data))
);
const res = await putFileContent(
url,
token,
encodedContent,
file.sha,
"更新代码片段"
);
vscode.window.showInformationMessage(
`代码片段 "${snippetName}" 同步到gitee仓库 ${
res ? "成功" : "失败"
}!`
);
}
}
}
);
context.subscriptions.push(saveSnippetDisposable);
}
选择代码块后,鼠标右键(快捷键ctrl + alt + s)选择保存代码片段,输入代码片段名称后,将选择的代码片段保存到本地的文件中,并同步更新到gitee仓库。
6、插入代码片段
(1)获取当前活动文本编辑器
const editor = vscode.window.activeTextEditor;
首先尝试获取 VSCode 窗口中的当前活动文本编辑器实例。如果获取成功(即 editor 不为 null),则继续执行后续的代码片段插入相关操作;如果获取失败(比如没有打开任何文本编辑器窗口),则整个函数的后续操作不会执行,因为没有合适的目标编辑器来插入代码片段。
(2)读取代码片段数据
const snippetsFilePath = path.join(
context.extensionPath,
"config/snippets.json"
);
let snippetsData = {};
if (fs.existsSync(snippetsFilePath)) {
snippetsData = JSON.parse(fs.readFileSync(snippetsFilePath, "utf8"));
}
- 构建了指向本地存储代码片段数据的文件路径,该文件位于插件的扩展路径下的 config 目录中,文件名为 snippets.json。
- 初始化一个空对象 snippetsData 用于存储读取到的代码片段数据。然后通过 fs.existsSync 检查该文件是否存在,如果存在,则使用 JSON.parse 解析从文件中读取到的内容(通过 fs.readFileSync 读取文件内容),并将解析后的结果赋值给 snippetsData。
(3)获取代码片段名称列表并容用户选择
const snippetNames = Object.keys(snippetsData.snippets);
const selectedSnippetName = await vscode.window.showQuickPick(
snippetNames,
{
placeHolder: "请选择要插入的代码片段",
}
);
if (selectedSnippetName) {
//后续操作
}
- 首先通过 Object.keys 获取 snippetsData.snippets 中的所有键(这里假设 snippetsData 是一个包含 snippets 属性的对象,且 snippets 属性的值是一个以代码片段名称为键的对象或数组),这些键就是代码片段的名称,将它们存储在 snippetNames 数组中。
- 然后使用 vscode.window.showQuickPick 弹出一个快速选择列表,让用户从 snippetNames 数组中的代码片段名称列表中选择要插入的代码片段。如果用户选择了一个名称(即 selectedSnippetName 不为 null),则继续执行后续操作来插入所选的代码片段;如果用户没有选择(比如关闭了选择列表窗口而没有做出选择),则整个函数的后续操作不会执行。
(4)插入所选代码片段
const selectedSnippet = snippetsData.snippets[selectedSnippetName];
if (selectedSnippet) {
const position = editor.selection.start;
editor.edit((editBuilder) => {
editBuilder.insert(position, selectedSnippet);
});
}
- 首先根据用户选择的代码片段名称 selectedSnippetName 从 snippetsData.snippets 中获取对应的代码片段内容(这里假设 snippetsData.snippets 是以代码片段名称为键,代码片段内容为值的对象),将其存储在 selectedSnippet 变量中。
- 如果获取到了有效的代码片段内容(即 selectedSnippet 不为 null),则获取当前编辑器中光标所在的位置(通过 editor.selection.start),并使用 editor.edit 方法来创建一个编辑操作构建器 editBuilder。通过 editBuilder.insert 将所选的代码片段内容插入到光标所在的位置。
7、删除代码片段
(1)获取代码片段数据
const snippetsFilePath = path.join(
context.extensionPath,
"config/snippets.json"
);
let snippetsData = {};
if (fs.existsSync(snippetsFilePath)) {
snippetsData = JSON.parse(fs.readFileSync(snippetsFilePath, "utf8"));
}
(2)选择需要删除的代码片段并进行二次确认
const snippetNames = Object.keys(snippetsData.snippets);
const selectedSnippetName = await vscode.window.showQuickPick(
snippetNames,
{
placeHolder: "请选择要删除的代码片段",
}
);
if (selectedSnippetName) {
const confirmation = await vscode.window.showWarningMessage(
`你确定要删除${selectedSnippetName}这个代码片段吗?此操作不可撤销。`,
"是",
"否"
);
if (confirmation === "是") {
//执行删除操作
}
}
(3)删除代码片段并同步更新到仓库
delete snippetsData.snippets[selectedSnippetName];
// 保存更新后的代码片段数据
fs.writeFileSync(
snippetsFilePath,
JSON.stringify(snippetsData, null, 2),
"utf8"
);
vscode.window.showInformationMessage(`本地代码片段已删除!`);
const giteeConfig = await getGiteeConfig(context);
const { token, owner, repo } = giteeConfig;
const url = `https://gitee.com/api/v5/repos/${owner}/${repo}/contents/codeSnippets/snippets.json`;
const file = await fetchFileContent(url, token);
const modifiedContent = JSON.stringify(snippetsData, null, 2);
const encoder = new TextEncoder();
const data = encoder.encode(modifiedContent);
const encodedContent = btoa(
String.fromCharCode.apply(null, new Uint8Array(data))
);
const res = await putFileContent(
url,
token,
encodedContent,
file.sha,
"更新代码片段"
);
vscode.window.showInformationMessage(
`gitee仓库代码片段删除${res ? "成功" : "失败"}!`
);
8、package.json配置
(1)命令配置
"commands": [
{
"command": "saveCodeSnippetsAndReusePlugins.saveSnippet",
"title": "保存代码片段"
},
{
"command": "saveCodeSnippetsAndReusePlugins.insertSnippet",
"title": "插入代码片段"
},
{
"command": "saveCodeSnippetsAndReusePlugins.deleteSnippet",
"title": "删除代码片段"
},
{
"command": "saveCodeSnippetsAndReusePlugins.giteeConfig",
"title": "仓库配置修改"
},
{
"command": "saveCodeSnippetsAndReusePlugins.codeSnippetSynchronization",
"title": "代码片段同步"
}
]
(2)快捷键配置
"keybindings": [
{
"command": "saveCodeSnippetsAndReusePlugins.saveSnippet",
"key": "ctrl+alt+s",
"mac": "cmd+alt+s",
"when": "editorHasSelection"
},
{
"command": "saveCodeSnippetsAndReusePlugins.insertSnippet",
"key": "ctrl+alt+i",
"mac": "cmd+alt+i",
"when": "editorTextFocus"
},
{
"command": "saveCodeSnippetsAndReusePlugins.deleteSnippet",
"key": "ctrl+alt+d",
"mac": "cmd+alt+d"
}
]
(3)菜单配置
"menus": {
"editor/context": [
{
"submenu": "saveCodeSnippetsAndReusePlugins",
"group": "navigation"
}
],
"saveCodeSnippetsAndReusePlugins": [
{
"command": "saveCodeSnippetsAndReusePlugins.giteeConfig",
"group": "group1"
},
{
"command": "saveCodeSnippetsAndReusePlugins.codeSnippetSynchronization",
"group": "group1"
},
{
"command": "saveCodeSnippetsAndReusePlugins.saveSnippet",
"group": "group2",
"when": "editorHasSelection"
},
{
"command": "saveCodeSnippetsAndReusePlugins.insertSnippet",
"group": "group2",
"when": "editorTextFocus"
},
{
"command": "saveCodeSnippetsAndReusePlugins.deleteSnippet",
"group": "group2"
}
]
},
"submenus": [
{
"id": "saveCodeSnippetsAndReusePlugins",
"label": "代码片段仓库"
}
]
三、插件使用
1、插件安装
直接在vscode插件商场中搜索saveCodeSnippetsAndReusePlugins
点击安装即可:
2、仓库配置
需要配置以下三个信息:
- token
在gitee设置中生成然后复制填写即可:
- owner
- repo
前面准备工作中新建的仓库,填写仓库名
3、代码片段同步
在多机使用时,可以同步拉取其他电脑保存的代码片段
4、保存代码片段
- 快捷键(ctrl + alt + s)
将选中的代码保存为代码片段,可以自己命名
5、插入代码片段
- 快捷键(ctrl + alt + i)
选择已保存的代码片段插入到当前代码
6、删除代码片段
- 快捷键(ctrl + alt + d)
选择需要删除的代码片段进行删除
源码
组件库已开源到gitee,有兴趣的也可以到这里看看:gitee.com/zheng_yongt…
🌟觉得有帮助的可以点个star~
🖊有什么问题或错误可以指出,欢迎pr~
📬有什么想要实现的功能或想法可以联系我~
公众号
关注公众号『前端也能这么有趣
』,获取更多有趣内容。
说在后面
🎉 这里是 JYeontu,现在是一名前端工程师,有空会刷刷算法题,平时喜欢打羽毛球 🏸 ,平时也喜欢写些东西,既为自己记录 📋,也希望可以对大家有那么一丢丢的帮助,写的不好望多多谅解 🙇,写错的地方望指出,定会认真改进 😊,偶尔也会在自己的公众号『
前端也能这么有趣
』发一些比较有趣的文章,有兴趣的也可以关注下。在此谢谢大家的支持,我们下文再见 🙌。