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