2) VS Code 插件项目结构与配置文件
14 Oct 2016- 1) VS Code 插件创建与发布
 - 2) VS Code 插件项目结构与配置文件
 - 3) VS Code 插件示例,一个 TypeScript 即时预览插件
 
VS Code Extension 项目结构
打开 yo code 创建的项目,我们能看到下面的目录结构。

展开之后得到的是下面的层级结构(我省略了大部分用于测试的 node_modules)。
├─.vscode
│      launch.json
│      settings.json
│      tasks.json
│          
├─src
│      extension.ts
│      
├─test
│       extension.test.ts
│       index.ts
│      
├─node_modules
│  ├─@types
│  │  ├─mocha
│  │  │      index.d.ts
│  │  │      
│  │  └─node
│  │          index.d.ts
│  │          
│  ├─typescript
│  │                  
│  └─vscode
│     │  thenable.d.ts
│     │  tslint.json
│     └─ vscode.d.ts     
│          
├─out
│  └─src
│     └─  extension.js
│  
│  .gitignore
│  .vscodeignore
│  package.json
│  README.md
│  tsconfig.json
└─ vsc-extension-quickstart.md
package.json是整个 extension 的配置文件。它除了描述 extension 的基本信息,如名称,作者版本等外, 更重要的是描述插件对 vscode 所做的扩展,注册用户可以执行的命令,标记该 extension 应该何时启动。src/extension.ts是插件的入口,这个文件 export 了activate方法,在插件被激活时,vscode 将调用这个方法,执行用户代码。 在这个例子中我们在这里用vscode.commands.registerCommand注册了extension.sayHello这个 command 的具体实现。显示一个消息:Hello World。.vscode这里是 vscode 的项目文件。其中launch.json定义了当前项目的调试方式。tasks.json定义了编译动作。settings.json定义了针对当前项目的编辑器设定。例如排除不想要显示的文件。
node_modules中绝大多数 package 为 test 的 devDependencies。与插件开发相关的是typescript、vscode和@types。- 这里引入一个 
typescript的原因是为了更好的限定开发中使用的 TS 版本 和 JS 的运行环境。比如,在插件中是不能使用window对象的,通过在tsconfig.json中指定lib即可。 vscode主要是为了引入 vscode package 的 TypeScript 定义。让开发体验更加友好。@types是 TS 2.0 引入的第三方 js 库的 TypeScript 定义文件安装方式,这里引入了 nodejs 和 mocha 的定义文件。
- 这里引入一个 
 .vscodeignore指定在发布插件时需要排除的文件。
大体了解了整个项目的结构,让我们来看一下实际运行的效果。在 VS Code 中直接按 F5 即可启动调试。VS Code 会 启动一个新的 VS Code 窗口,在这个窗口中会额外加载我们的插件项目以便我们进行测试。

我们按 F1 或者 ctrl+shift+p 输入 hello 就能发现我们刚刚注册的 command。

执行这个 command 可以看到此时,我们项目调试控制台输出 
Congratulations, your extension "vscode-extension" is now active! 插件的 activate 方法被调用。
VS Code 显示一个 Hello World 信息。

你可能会问,为什么我们的代码在我们真正执行了 command 的时候才会被激活,这是 VS Code 的一个优化。
vscode 可以直接根据 package.json 来展示插件定义的 command,而不必执行插件的代码,
保证 vscode 的启动速度。在这个插件模板中,我们注册了一个 title 为 Hello World 的 command。
activationEvents 为 onCommand:extension.sayHello, 仅当我们执行这个 command 的时候,插件才被激活。
VS Code 才会真正开始执行我们的代码。
package.json
字段定义
| 名称 | 必需 | 类型 | 描述 | 
|---|---|---|---|
name | 
      是 | string | 
      插件扩展的名称, 全部是小写字母,并且不能有空格. | 
version | 
      是 | string | 
      参考Semver. 例如: 1.0.0 | 
    
publisher | 
      是 | string | 
      发布者名称 | 
engines | 
      是 | object | 
      包含vscode字段的对象, 定义所需环境的版本。例如 ^1.5.0 表示需要1.5.0或者更高版本. | 
    
displayName | 
      string | 
      插件显示的名称. | |
description | 
      string | 
      插件的描述文本. | |
icon | 
      string | 
      插件使用的图标,大小为 128*128. | |
main | 
      string | 
      插件入口的相对路径,当插件启动时将调用入口文件的activate方法. | 
    |
categories | 
      string[] | 
      插件的分类,常用分类有: [Languages, Snippets, Linters, Themes, Debuggers, Other]. | 
    |
contributes | 
      object | 
      插件扩展点的描述对象,详见 contributions. | |
activationEvents | 
      string[] | 
      插件激活事件的描述数组,详见 activation events. | |
keywords | 
      string[] | 
      插件的关键词,准确的关键词有助于更好的找到插件. | |
dependencies | 
      object | 
      插件依赖的 Node.js 库. 参见 npm dependencies. | 
    |
devDependencies | 
      object | 
      插件开发环境下依赖的 Node.js 库. 例如,如果插件使用TypeScript编写,则开发环境需要依赖 typescript. 参见 npm devDependencies. | 
    |
extensionDependencies | 
      string[] | 
      插件依赖的其他插件的id. 插件id为 ${publisher}.${name}. 例如: egret.text-tools. | 
    |
scripts | 
      object | 
      详见 npm scripts | 
contributes(扩展点)
扩展点允许开发者在 vscode 中自定义一些扩展功能。
contributes.commands
自定义命令 command 。定义的命令可以在命令面板(Command Palette)中找到并执行。
Note: 当命令通过快捷键或者命令面板被执行时, 将派发
activationEventonCommand:${command}.
可使用下列字段:
| 名称 | 必需 | 类型 | 描述 | 
|---|---|---|---|
command | 
      是 | string | 
      表示命令的唯一id. | 
title | 
      是 | string | 
      表示命令的名称,此属性将显示在命令面板中. | 
例子
...
"contributes": {
	"commands": [{
		"command": "extension.sayHello",
		"title": "Hello World"
	}]
}
...
contributes.keybindings
自定义快捷键 keybinding。可以自定义命令执行的按键绑定。
Note: 可以定义不同操作系统平台的快捷键。
Note: 当命令通过快捷键或者命令面板被执行时, 将派发
activationEventonCommand:${command}.
可使用下列字段:
| 名称 | 必需 | 类型 | 描述 | 
|---|---|---|---|
command | 
      是 | string | 
      快捷键绑定的命令的id | 
key | 
      是 | string | 
      快捷键的按键组合,可以的按键的组合字符串参见 附录1 . | 
win | 
      string | 
      在windows平台下的按键组合,如果用户在windows下,此属性将覆盖key字段指定的按键组合. | 
    |
mac | 
      string | 
      在mac平台下的按键组合,如果用户在mac下,此属性将覆盖key字段指定的按键组合. | 
    |
when | 
      string | 
      快捷键何时被触发的表达式,可用的属性值参见 附录2 . | 
附录1 key字段可用的按键组合字符串规则
按键规则一般由组合键 + 其他按键组成。
组合按键表示如下:
| 操作系统 | 组合键 | 
|---|---|
| MACOS X | ctrl+, shift+, alt+, cmd+ | 
    
| Windows | ctrl+, shift+, alt+, win+ | 
    
Note: 特殊的可以使用
ctrlcmd表示windows下的ctrl, mac下的cmd
其他按键表示如下:
f1-f15,a-z,0-9`,-,=,[,],\,;,',,,.,/left,up,right,down,pageup,pagedown,end,hometab,enter,escape,space,backspace,deletepausebreak,capslock,insert
使用空格分割的按键序列,例如(ctrl+k ctrl+c),表示先按ctrl+k,再按ctrl+c 才能触发该快捷键。
如果要使某一命令既可以按ctrl+k触发,又可以按ctrl+c触发,请定义两组keybinding,command相同,但是key字段不同。
附录2 when字段可用的字符串
when字段可以使用 !, &&, ==, != 等表达式限定条件。如
!inDebugMode  , editorTextFocus && editorLangId == 'ts' 都是可用的表达式。
editorFocus编辑器获得焦点时editorTextFocus文本编辑器获得焦点时editorLangId表示编辑器的语言id,editorLangId通常对应编辑器对应文档的扩展名inDebugMode表示启动调试时
例子
定义命令 "extension.sayHello" 的windows下快捷键为 Ctrl+F1,mac下快捷键为 Cmd+Shift+F1 :
...
"contributes": {
	"keybindings": [{
		"command": "extension.sayHello",
		"key": "ctrl+f1",
		"mac": "cmd+shift+f1",
		"when": "editorTextFocus"
	}]
}
...
contributes.configuration
提供可设置的选项,用户可以在全局或者工作空间的设置中修改这些设置信息。
插件的开发者需要提供一套 JSON schema 来描述这些可以配置的选项,这样用户在修改时,能够得到编辑器的智能提示。
你可以通过下面的方法来读取用户自定义的配置信息
vscode.workspace.getConfiguration('myExtension').
例子
...
"contributes": {
	"configuration": {
		"type": "object",
		"title": "TypeScript configuration",
		"properties": {
			"typescript.useCodeSnippetsOnMethodSuggest": {
				"type": "boolean",
				"default": false,
				"description": "Complete functions with their parameter signature."
			},
			"typescript.tsdk": {
				"type": "string",
				"default": null,
				"description": "Specifies the folder path containing the tsserver and lib*.d.ts files to use."
			}
		}
	}
}
contributes.languages
提供一种新语言的信息,以便 VS Code 能够支持它的开发.
这这一节中, language 一般是指一个跟文件名相关的id (See TextDocument.getLanguageId()).
VS Code 有三种方式确定一个文件使用的开发语言,这三种方式可以独立使用
- 文件的扩展名 (下面说的 
extensions) - 文件名 ( 下面说的 
filenames) - 文件的第一行中的文本 (下面说的 
firstLine) 
最后一项 VS Code 需要的信息就是 aliases:语言的别名,这个属性值列表的第一个会作为语言的显示名称,显示在编辑器的右下角和语言选择列表中。
当用户打开了一个文件,VS Code会用这三个规则匹配文件,来确认文件所使用的语言,同时,VS Code会抛出一个 activationEvent onLanguage:${language}(例如下面例子的 onLanguage:python),来激活对应的插件。
例子
...
"contributes": {
	"languages": [{
		"id": "python",
		"extensions": [ ".py" ],
		"aliases": [ "Python", "py" ],
		"filenames": [ ... ]
		"firstLine": "^#!/.*\\bpython[0-9.-]*\\b"
	}]
}
contributes.debuggers
为 VS Code 提供一个 debug 适配器,帮助 VS Code 连接到一个外部的 debug 服务,扩展 VS Code 的调试功能。
debug 适配器运行在一个单独的进程中,与 VS Code 之间采用特定的协议来通信。你需要提供至少一个可执行的脚本来实现这个 debug 适配器。
例子
...
"contributes": {
	"debuggers": [{
        	"type": "node",
        	"program": "./debugger/out/node/nodeDebug.js",
        	"runtime": "node",
        	"enableBreakpointsFor": { "languageIds": ["javascript", "typescript", "coffeescript"] }
        }]
}
...
contributes.grammars
提供一套 TextMate grammar 来为 VS Code 添加语言支持。你需要提供,这组语法需要适配的语言 language,语法的 TextMate scopeName 值,和 语法定义文件的路径
注意: 语法定义文件的格式可以是 JSON (扩展名 .json) 或 XML plist 格式 (如果扩展名不是 json 就认为是这种格式).
例子
...
"contributes": {
	"grammars": [{
		"language": "shellscript",
		"scopeName": "source.shell",
		"path": "./syntaxes/Shell-Unix-Bash.tmLanguage"
	}]
}
...
contributes.themes
为 VS Code 提供一个 TextMate theme 代码配色主题。你需要指定一个 label 表明这个主题是暗色主题还是浅色主题,还有主题文件的路径(XML plist 格式)
例子
"contributes": {
	"themes": [{
		"label": "Monokai",
		"uiTheme": "vs-dark",
		"path": "./themes/Monokai.tmTheme"
	}]
}
contributes.snippets
"contributes": {
	"snippets": [{
			"language": "go",
			"path": "./snippets/go.json"
	}]
}
contributes.jsonValidation
提供特定 json 文件的 JSON schema, url可以是插件中内置的文件,或者一个远程的url,例如 json schema store
"contributes": {
    "jsonValidation": [{ 
 		"fileMatch": ".jshintrc",
 		"url": "http://json.schemastore.org/jshintrc"
	}]
} 
更多信息可以参考 Extension Manifest File - package.json
下面,让我们来写一个 即时预览 TypeScript 执行的插件。VS Code 插件示例,一个 TypeScript 即时预览插件