vs Code 扩展子命令菜单
· 阅读需 6 分钟
当时看官方文档介绍这一块有点懵,也可能是当时看的比较潦草。所以找资料总结下构建带子菜单的自定义菜单命令组。
一、声明命令
与普通命令一致,需要先在 contributes.commands 中进行注册:
{
"contributes": {
"commands": [
// ... 其他命令
{
"command": "extensionName.submenuCommand1",
"title": "插件的第一个子命令"
},
{
"command": "extensionName.submenuCommand2",
"title": "插件的第二个子命令"
},
{
"command": "extensionName.submenuCommand3",
"title": "插件的第三个子命令"
},
{
"command": "extensionName.submenuCommand4",
"title": "插件的第四个子命令"
},
{
"command": "extensionName.submenuCommand5",
"title": "插件的第五个子命令"
},
{
"command": "extensionName.submenuCommand6",
"title": "插件的第六个子命令"
}
]
}
}
二、构建菜单组
自定义组需要显式的在 contributes.submenus 中定义子菜单命令组
{
"contributes": {
"submenus": [
{
"id": "extensionName.submenuCommandGroup0", // 唯一 id
"label": "自定义菜单项 0"
},
{
"id": "extensionName.submenuCommandGroup1",
"label": "自定义菜单项 1"
}
]
}
}
三、将菜单子命令挂载到组
子命令需要在(自定义)组中进行显示声明挂载才可显示在分组中:
{
"contributes": {
"menus": {
"extensionName.submenuCommandGroup0": [
{
"command": "extensionName.submenuCommand1"
// 这里可以配置该子项的显示规则
},
{
"command": "extensionName.submenuCommand2"
},
{
"command": "extensionName.submenuCommand2"
}
],
"extensionName.submenuCommandGroup1": [
{
"command": "extensionName.submenuCommand3"
},
{
"command": "extensionName.submenuCommand4"
},
{
"command": "extensionName.submenuCommand5"
},
{
"command": "extensionName.submenuCommand6"
}
]
}
}
}
四、将组挂载到菜单栏
菜单项可以分组,按辞典序排列。可以将分组添加到菜单项,或中间、上方或上方添加新的菜单项组。
编辑器的右菜单项默认有以下分组:
navigation- 群体在所有情况下都优先1_modification- 修改代码命令组9_cutcopypaste- 倒数第二组默认组,包含基本编辑命令z_commands- 最后一个默认组,带有打开命令调色板的条目
右键功能菜单示意
---------------------------
Go to Definition
Peek Definition ←-------- navigation
Find All References
---------------------------
Change All Occurrences
←-------- 1_modification
Format Document
---------------------------
Cut
Copy ←-------- 9_cutcopypaste
Paste
---------------------------
Command Palette ... ←-------- z_commands
---------------------------
信息
其他分组详见 sorting-of-groups
可以将组放在任何想放置的位置
{
"contributes": {
"menus": {
"editor/context": [
{
"submenu": "extensionName.submenuCommandGroup0",
"group": "navigation@3", // 将 submenuCommandGroup0 自定义组放到了优先组
"when": "true" // 控制该分组出现的条件
},
{
"submenu": "extensionName.submenuCommandGroup1",
"group": "9_cutcopypaste@5" // 将 submenuCommandGroup1 自定义分组放置到了剪辑命令组
}
]
}
}
}
五、超级计划之
1. 子命令匿于命令面板
每一个没有特殊设置的 contributes.commands 子项都将可在命令面板 contributes.menus.commandPalette 可见,
而自分组的子项命令由于其特殊性,其 title 值可能将与其他专门用于控制面板的命令不同:
包含不同命令的命令组
{
"contributes": {
"commands": [
{
"command": "extensionName.commandForCommandPalette0",
"title": "extensionName: 专门用于控制面板的命令 0" // 为了显著,可能添加插件名
},
{
"command": "extensionName.commandForCommandPalette1",
"title": "extensionName: 专门用于控制面板的命令 1"
},
{
"command": "extensionName.submenuCommand1",
"title": "插件的第一个子命令" // 子组件由于分组的 label 已经有相关说明,可能更简洁
},
{
"command": "extensionName.submenuCommand2",
"title": "插件的第二个子命令"
}
]
}
}
如果不在 contributes.menus.commandPalette 中显式关闭分组,分组在命令面板可见。但又由于其 title 描述的不完整性,可能对用于不太友好:
显式关闭用于子组命令的命令条
{
"contributes": {
"menus": {
"commandPalette": [
{
"command": "extensionName.submenuCommand1",
"when": "false" // 关闭该命令在命令面板的显示
},
{
"command": "extensionName.submenuCommand2",
"when": "false"
}
]
}
}
}
2. 多语言支持
既然可能国际友人使用的情况比较少,但是功能不能不知晓。vsCode 提供原生支持!
使用 packages.nls.xxx.json 构建相应语言的示条,使用 packages.nls.json 设定默认(没有设定对应的语言时的兜底语言)。
- packages.json 文件
- packages.nls.json 文件
- packages.nls.zh-cn.json 文件
{
"name": "extensionName",
"displayName": "%plugin.displayName%",
"description": "%plugin.descriptions%",
"contributes": {
"commands": [
{
"command": "extensionName.command1",
"title": "%command.command1%"
},
{
"command": "extensionName.command2",
"title": "%command.command2%"
}
],
"submenus": [
{
"id": "extensionName.submenus1",
"label": "%submenus.submenus1%"
},
{
"id": "extensionName.submenus2",
"label": "%submenus.submenus2%"
}
]
}
}
{
"plugin.displayName": "extension plugin display name in extensions store",
"plugin.descriptions": "some text for describing extension plugin in extensions store",
"command.command1": "extensionName: command1 description",
"command.command2": "extensionName: command1 description",
"submenus.submenus1": "extensionName: submenus1 description",
"submenus.submenus2": "extensionName: submenus2 description"
}
{
"plugin.displayName": "插件在扩展商城的展示名称",
"plugin.descriptions": "插件在扩展商城展示的描述",
"command.command1": "中文扩展名:命令 1 的描述",
"command.command2": "中文扩展名:命令 2 的描述",
"submenus.submenus1": "中文扩展名:子组 1 的描述",
"submenus.submenus2": "中文扩展名:子组 2 的描述"
}
六、完整示意
简单示意
{
"name": "super-file-header", // 扩展唯一 ID 名
"publisher": "Mr.MudBean", // 发布者
"displayName": "%plugin.displayName%", // 扩展在扩展商店展示名
"description": "%plugin.description%", // 扩展在扩展商店展示描述
"type": "commonjs", // 开发模式
"version": "0.0.1", // 版本信息
"license": "MIT", // 开源声明类型
"engines": {
"vscode": "^1.90.0" // 扩展支持的最低引擎
},
"categories": [
"Other" // 功能分类
],
"keywords": ["文件头注释"],
"activationEvents": [
// 启动事件
"onLanguages:javascript",
"onLanguages:javascriptreact",
"onLanguages:typescript",
"onLanguages:typescriptreact",
"onLanguages:markdown",
"onLanguages:mdx",
"onLanguages:vue",
"onStartupFinished"
],
"main": "./dist/extension.js", // 扩展入口
"contributes": {
"commands": [
{
"command": "superFileHeader.createJavaScriptHeaderCommentPalette",
"title": "%command.createJavaScriptHeaderComment%"
},
{
"command": "superFileHeader.createJavaScriptHeaderCommentSubmenu",
"title": "%submenu.createJavaScriptHeaderComment%"
},
{
"command": "superFileHeader.createMdxPageHeaderCommentPalette",
"title": "%command.createMdxPageHeaderComment%"
},
{
"command": "superFileHeader.createMdxPageHeaderCommentSubmenu",
"title": "%command.createMdxHeaderComment%"
},
{
"command": "superFileHeader.createMdxBlogHeaderCommentPalette",
"title": "%command.createMdxBlogHeaderComment%"
},
{
"command": "superFileHeader.createMdxBlogHeaderCommentSubmenu",
"title": "%command.createMdxBlogHeaderComment%"
}
],
"submenus": [
{
"id": "superFileHeader.createFileHeader",
"label": "%submenus.createFileHeader%"
}
],
"menus": {
"superFileHeader.createFileHeader": [
{
"command": "superFileHeader.createJavaScriptHeaderCommentSubmenu"
},
{
"command": "superFileHeader.createMdxPageHeaderCommentSubmenu"
},
{
"command": "superFileHeader.createMdxBlogHeaderCommentSubmenu"
}
],
"editor/context": [
{
"submenu": "superFileHeader.createFileHeader",
"group": "1_modification@8"
}
],
"commandPalette": [
{
"command": "superFileHeader.createJavaScriptHeaderCommentPalette",
"when": "resourceFilename =~ /\\.(js|ts|vue|jsx|tsx)$/"
},
{
"command": "superFileHeader.createJavaScriptHeaderCommentSubmenu",
"when": "false" // 显式关闭子命令在命令面板的显示
},
{
"command": "superFileHeader.createMdxPageHeaderCommentPalette",
"when": "resourceFilename =~ /\\.(md|mdx)$/"
},
{
"command": "superFileHeader.createMdxPageHeaderCommentSubmenu",
"when": "false" // 显式关闭子命令在命令面板的显示
},
{
"command": "superFileHeader.createMdxBlogHeaderCommentPalette",
"when": "resourceFilename =~ /\\.(md|mdx)$/"
},
{
"command": "superFileHeader.createMdxBlogHeaderCommentSubmenu",
"when": "false" // 显式关闭子命令在命令面板的显示
}
]
}
}
// ... 其他配置
}
信息
记录下来是因为本扩展最终并没有采用该方案,因为
- 命令声明比较麻烦,需要在命令面板和菜单功能区分别定义同逻辑命令而展示文本不同
- 将命令放进子组之中在某些时候使用并不便捷,有一些画蛇添足