vscode-扩展插件

因为 vscode 已经是我的主用开发工具, 已经抛弃了 sublime text, vs. 开发 unity, shader, lua, h5 等几乎都是用它了. 很多时候需要偷懒, 就写个插件辅助一下. ( 工欲善其事必先利其器 )


相关资料


本地插件保存路径

可以参考 别人 写插件的方式来写 自己 的插件.

  • 已有插件所在目录

    os path
    windows %USERPROFILE%.vscode\extensions
    macOS ~/.vscode/extensions
    Linux ~/.vscode/extensions
  • 插件保存文件夹名字规则, [作者名].[插件名].[版本号] , 例如


开发目的-左边栏右键增加自定义选项

  • 可以参考已有插件 - Code Runner 左侧栏的右键的 Run Code 选项

前置物料

  1. 安装 Yeoman , 命令 : npm install -g yo
  2. 安装 Yeoman 的 generator-code, 命令 : npm install -g generator-code
  3. 安装打包插件的工具 命令 : npm install -g vsce

初始化工程

  1. 初始化一个新工程, 命令: yo code . 这里选择的是 ts extension 工程. 然后照着提示输入 name, description 等等

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    C:\Users\Administrator>yo code
    _-----_ ╭──────────────────────────╮
    | | │ Welcome to the Visual │
    |--(o)--| │ Studio Code Extension │
    `---------´ │ generator! │
    ( _´U`_ ) ╰──────────────────────────╯
    /___A___\ /
    | ~ |
    __'.___.'__
    ´ ` |° ´ Y `

    ? What type of extension do you want to create? New Extension (TypeScript)
    ? What's the name of your extension? VSC-Plugin001
    ? What's the identifier of your extension? wilkeryun
    ? What's the description of your extension? my custom plugin
    ? What's your publisher name (more info: https://code.visualstudio.com/docs/tools/vscecli#_publishing-extensions)? yangxuan0261
    ? Enable stricter TypeScript checking in 'tsconfig.json'? Yes
    ? Setup linting using 'tslint'? Yes
    ? Initialize a git repository? Yes
    create wilkeryun\.vscode\launch.json
    ...
    vscode.d.ts successfully installed!

    wilkeryun@0.0.1 C:\Users\Administrator\wilkeryun
    • 生成目录结构

    • package.json : 定义 入口文件, 命令, 显示在那些地方 (左边栏, 标题栏 等等), 插件描述等 信息. 基本所有的配置这里


新建一个命令

  1. package.json 文件中加入相关配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    {
    ...
    "activationEvents": [
    "onCommand:extension.sayHello",
    "onCommand:myext.copyLuaFileName" // 3. 激活这个命令
    ],
    "main": "./out/extension",
    "contributes": {
    "commands": [
    {
    "command": "extension.sayHello",
    "title": "Hello World title"
    },
    { // 1. 新增一个命令 myext.copyLuaFileName
    "command": "myext.copyLuaFileName",
    "title": "复制lua文件" // 命名显示名称
    }
    ],
    "menus": {
    "explorer/context": [
    { // 2. 设置这个定义出现在左边栏
    "when": "!explorerResourceIsFolder", // 自定义显示条件, 非文件夹就显示
    "command": "myext.copyLuaFileName",
    "group": "navigation"
    }
    ]
    }
    },
    ...
    }
  2. extension.ts 文件中 注册这个命令及对应的相关自定义逻辑

    1
    2
    3
    4
    5
    6
    7
    export function activate(context: vscode.ExtensionContext) {
    ...
    let run = vscode.commands.registerCommand("myext.copyLuaFileName", (fileUri) => {
    vscode.window.showInformationMessage('复制的文件 fileUri:' + fileUri);
    });
    context.subscriptions.push(run);
    }
  3. 测试. 按 F5 , 会运行一个 新的vscode进程


打包 使用 插件

需要先安装打包插件: npm install -g vsce

打包

  • 在插件根目录下使用命令: vsce package , 会在该目录下生产一个 xxx.vsix 插件文件

    1
    2
    3
    4
    5
    6
    F:\git_repo\wilkeryun>vsce package
    Executing prepublish script 'npm run vscode:prepublish'...
    ...
    A 'repository' field is missing from the 'package.json' manifest file.
    Do you want to continue? [y/N] y
    Created: F:\git_repo\wilkeryun\wilkeryun-0.0.1.vsix (7 files, 3.21KB)
    • TODO: 这个报错暂时未去查
    • 过程中可能会提示你先修改 README.md 文件才能打包,简单描述功能即可。

使用

  1. 安装, 手动安装插件文件

    然后选择 从 VSIX 安装…, 选择 xxx.vsix 文件即可

  2. 可以在插件列表中看到这个插件, ctrl + shift + x 显示插件列表

打包, 发布 参考: http://jdc.jd.com/archives/212586


发布

  1. 生成 PAT (如: hqg5tqkkjsdasdasdasdadasdasdasdasd).

    首先访问 https://login.live.com/ 登录你的Microsoft账号

    生成 PAT - https://dev.azure.com/YOUR_ORGANIZATION/_usersSettings/tokens

  2. 创建 发布者. 有两种方式可以创建. 以创建 yangx 为例

    • 网页上创建. https://marketplace.visualstudio.com/manage/publishers/

    • 命令行创建

      1
      2
      3
      4
      5
      6
      F:\git_repo\wilkeryun>vsce create-publisher yangx //  
      Publisher human-friendly name: (wilker)
      E-mail: wolegequ@live.com // 这个邮箱是微软的登录账号
      Personal Access Token: **************************************************** // (PAT)

      Successfully created publisher 'yangx'.

    创建完之后, 在 package.json 文件中指定 发布者

    1
    2
    3
    {
    "publisher": "yangx",
    }
  3. 发布

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    F:\git_repo\wilkeryun>vsce login yangx // 1. 先登录 发布者
    F:\git_repo\wilkeryun>vsce publish -p hqg5tqkkjsdasdasdasdadasdasdasdasd // 2. 再进行发布 (PAT)
    Executing prepublish script 'npm run vscode:prepublish'...

    > wilkeryun@0.0.1 vscode:prepublish F:\git_repo\wilkeryun
    > npm run compile

    > wilkeryun@0.0.1 compile F:\git_repo\wilkeryun
    > tsc -p ./

    A 'repository' field is missing from the 'package.json' manifest file.
    Do you want to continue? [y/N] y
    Publishing yangxuan0261.wilkeryun@0.0.1...
    Successfully published yangxuan0261.wilkeryun@0.0.1! // 发布成功
    Your extension will live at https://marketplace.visualstudio.com/items?itemName=yangxuan0261.wilkeryun (might take a few seconds for it to show up).

踩坑

  • 报错: Error: Failed Request: Unauthorized

    1
    2
    3
    Error: Failed Request: Unauthorized(401) - https://marketplace.visualstudio.com/_apis/gallery
    Be sure to use a Personal Access Token which has access to **all accessible accounts**.
    See https://code.visualstudio.com/docs/tools/vscecli#_common-questions for more information.

    没有授权成功. 参考: https://github.com/Microsoft/vscode-vsce/issues/11

    organization: all accessible organizations

    scopes: full access

  • 报错: Error: Command failed: npm list. missing xxx

    报找不到包的错. 把 node_modules 文件夹删了, 重新安装库: npm i


扩展清单文件 package.json

每个VS Code扩展需要一个清单文件package.json,该文件位于扩展的根目录中。

字段

名称 是否必要 类型 说明
name string 扩展的名称,该名称必须为小写且不能有空格。
version string SemVer 兼容版本.
publisher string 发布人名字
engines object 一个至少包含vscode键值对的对象,该键表示的是本扩展可兼容的VS Code的版本,其值不能为*。比如 ^0.10.5 表示扩展兼容VS Code的最低版本是0.10.5
license string 参考 npm’s 文档. 如果你确实需要在扩展根目录下有一个授权文档,那么应该把license值设为"SEE LICENSE IN <filename>"
displayName string 用于在扩展市场中本扩展显示的名字。
description string 一份简短的说明,用来说明本插件是什么以及做什么
categories string[] 你希望你的扩展属于哪一类,只允许使用这几种值:[Languages, Snippets, Linters, Themes, Debuggers, Other]
keywords array 一组 关键字 或者 标记,方便在市场中查找。
galleryBanner object 帮助格式化市场标题以匹配你的图标,详情如下。
preview boolean 在市场中把本扩展标记为预览版本。
main string 扩展的入口点。
contributes object 一个描述扩展 贡献点的对象。
activationEvents array 一组用于本扩展的 激活事件
dependencies object 你的扩展所需的任何运行时的Node.js依赖项,和 npm’s dependencies一样。
devDependencies object 你的扩展所需的任何开发的Node.js依赖项. 和 npm’s devDependencies一样。
extensionDependencies array 一组本扩展所需的其他扩展的ID值。扩展的ID值始终是 ${publisher}.${name}。比如:vscode.csharp
scripts object npm’s scripts一样,但还有一些额外VS Code特定字段.
icon string 一个128x128像素图标的路径。

也可以查看npm’s package.json参考文档.

范例

这里有一个完整的package.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
{
"name": "Spell",
"displayName": "Spelling and Grammar Checker",
"description": "Detect mistakes as you type and suggest fixes - great for Markdown.",
"icon": "images/spellIcon.svg",
"version": "0.0.19",
"publisher": "seanmcbreen",
"galleryBanner": {
"color": "#0000FF",
"theme": "dark"
},
"license": "SEE LICENSE IN LICENSE.md",
"bugs": {
"url": "https://github.com/Microsoft/vscode-spell-check/issues",
"email": "smcbreen@microsoft.com"
},
"homepage": "https://github.com/Microsoft/vscode-spell-check/blob/master/README.md",
"repository": {
"type": "git",
"url": "https://github.com/Microsoft/vscode-spell-check.git"
},
"categories": [
"Linters", "Languages", "Other"
],
"engines": {
"vscode": "0.10.x"
},
"main": "./out/extension",
"activationEvents": [
"onLanguage:markdown"
],
"contributes": {
"commands": [
{
"command": "Spell.suggestFix",
"title": "Spell Checker Suggestions"
}
],
"keybindings": [
{
"command": "Spell.suggestFix",
"key": "Alt+."
}
]
},
"scripts": {
"vscode:prepublish": "node ./node_modules/vscode/bin/compile",
"compile": "node ./node_modules/vscode/bin/compile -watch -p ./"
},
"dependencies": {
"teacher": "^0.0.1"
},
"devDependencies": {
"vscode": "^0.11.x"
}
}


相关api

contributes.configuration

参考: https://code.visualstudio.com/docs/extensionAPI/extension-points#_contributesconfiguration

contributes.commands

参考: https://code.visualstudio.com/docs/extensionAPI/extension-points#_contributescommands

contributes.menus

参考: https://code.visualstudio.com/docs/extensionAPI/extension-points#_contributesmenus

Language Identifiers

参考: https://code.visualstudio.com/docs/languages/identifiers

vscode.StatusBarItem 状态栏

  • icon 使用只需要在 text 中加入占位符 $(pencil) 即可, 如 "$(pencil) hello status".

    icon 图片参考: https://octicons.github.com/

‘when’ clause contexts

参考: https://code.visualstudio.com/docs/getstarted/keybindings#_when-clause-contexts


显示命令的各种地方

配置在 package.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"contributes": {
"menus": { // 配置在这个字段中
"explorer/context": [
{
"when": "!explorerResourceIsFolder",
"command": "myext.copyLuaFileName",
"group": "navigation"
}
]
...
}
},

}


左边栏 右键

key : "explorer/context"

编辑区 右键

key: "editor/context"


复制粘贴到剪切板


webview相关


调用系统程序 (windows的exe)

尝试了几个nodejs库 如 child_process , shelljs 等去执行命令, 均失败, 但是用纯js写的就可以执行命令. 一度失望, 让后想到可以使用终端相关api, 在终端中打开, 尝试了一下结果ok啊啊啊!!!

以用Markdown编辑器打开Markdown文件为例.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
   private mdTml: vscode.Terminal | undefined;
public async openMarkdown() {
let doc = vscode.window.activeTextEditor!.document;
let path = doc.uri.fsPath;
if (doc.languageId !== "markdown") {
Utils.showErrMsg(`不是 Markdown 文件, (${path})`);
return;
}

if (this.mdTml === undefined) {
this.mdTml = vscode.window.createTerminal("TyporaOpen");
}

let cmdStr = `Typora ${path}`; // Typora 所在目录必须在环境变量中, 你也可以把它抽出来作为配置
this.mdTml.show(false);
this.mdTml.sendText(cmdStr);
}

vscode.window.onDidCloseTerminal((terminal) => { // 监听终端被关闭
if (terminal.name === "TyporaOpen") {
this.mdTml = undefined;
}
});

踩坑

  • 空指针用的是 undefined 而不是 null .

  • 报错: 未能分析 package.json

    原因一般有两个

    1. 文件中不是严格的 json 格式, (结构中最后一个字段不能有 , 逗号)

    2. 文件含有注释, 如:

      1
      2
      3
      4
      5
      6
      {
      "command": "wilker-ext.copyPathRelative",
      // "title": "%wilker-lang.command.copyPathRelative%",
      "title": "复制路径-相对",
      "category": "wilker"
      }
  • 所有注册的命令都无效, 报错: can't found xxx command

    可能是新加了库, 但是没有保存到项目中, 少了 --save 参数, 比如

    1
    2
    # npm install request # 错误
    # npm install request --save # 正确, 且要在项目中执行这个命令才能保存到 package.json 中

npm 安装报错

执行 npm i 命令时报错: Error installing vscode.d.ts: Error: Request returned status code: 404

更新一下即可

1
2
$ npm update
$ npm i