0x00 前言

在前几天的美国纽约,微软举行了Connect(); //2015大会。通过这次大会,我们可以很高兴的看到微软的确变得更加开放也更加务实了。当然,会上放出了不少新产品和新功能,其中就包括了VS Code的beta版本。而且微软更进一步,已经在github将VS Code的代码开源了。除了这些让人兴奋的消息,我们还应该注意到VS Code提供了对拓展的支持。
所以本文就来聊一聊使用TypeScript开发VS Code拓展的话题吧。

本文所使用的拓展的应用商店页面:

https://marketplace.visualstudio.com/items/JiadongChen.LicenseHeader

github页面:

https://github.com/chenjd/VSCode-StandardHeader

0x01 你好,世界

"万事开头,Hello World"。所以我们就从一个Hello World作为起点,开始一步一步构建自己的VScode的拓展。
在开发vscode的拓展之前,我们先要确保电脑上已经安装了Node.js。之后,我们便可以利用微软所提供的基于Yeoman的模板生成器来生成vscode拓展的模板了。

npm install -g yo generator-code

之后,我们只需要在终端中运行yo code命令,即可以进入创建拓展模板的引导过程。

yo code

在引导过程中将TypeScript选择为开发语言,并且填完一些基本信息之后,我们的第一个vscode拓展便创建完成了。
那么,yo code命令主要为我们做了一些什么事情呢?

  1. 会根据我们在引导中所填的信息,在当前目录生成一个拓展的文件夹,文件夹名即我们在引导中填入的拓展名称。
  2. 该文件夹中主要包括了盛放源文件(extension.ts)的src文件夹、test文件夹以及out文件夹。需要注意的是out文件夹,在编译typescript源文件之前out文件夹是没有创建的,而编译之后会创建out文件夹并且其中的内容是typescript经过编译之后生成的js文件。
  3. 生成了资源配置文件package.json,package.json文件描述了该拓展的信息和它的功能。下文我还会具体说明package.json文件。
  4. 创建了launch.json以及tasks.json和settings.json(位于项目中的.vscode目录下),其中launch.json文件规定了启动一个在拓展开发(Extension Development)模式的VS Code进程,并且规定在VS Code启动之前会先运行tasks.json文件中所定义的task(根据tasks.json中的定义,相当于npm run compile),即先使用TypeScript的编译器将ts文件编译为js文件。这样我们就可以直接编译(因为是typescript)运行并且调试我们的拓展项目了。
  5. 当然,还会根据我们在引导中的选择来决定是否创建一个Git仓库,用来做版本控制。

下面便是我们的拓展项目的完整目录:

.
├── .gitignore //配置不需要加入版本管理的文件
├── .vscode // VS Code的整合
│ ├── launch.json
│ ├── settings.json
│ └── tasks.json
├── .vscodeignore //配置不需要加入最终发布到拓展中的文件
├── README.md
├── src // 源文件
│ └── extension.ts // 如果我们使用js来开发拓展,则该文件的后缀为.js
├── test // test文件夹
│ ├── extension.test.ts // 如果我们使用js来开发拓展,则该文件的后缀为.js
│ └── index.ts // 如果我们使用js来开发拓展,则该文件的后缀为.js
├── node_modules
│ ├── vscode // vscode对typescript的语言支持。
│ └── typescript // TypeScript的编译器
├── out // 编译之后的输出文件夹(只有TypeScript需要,JS无需)
│ ├── src
│ | ├── extension.js
│ | └── extension.js.map
│ └── test
│ ├── extension.test.js
│ ├── extension.test.js.map
│ ├── index.js
│ └── index.js.map
├── package.json // 该拓展的资源配置文件
├── tsconfig.json //
├── typings // 类型定义文件夹
│ ├── node.d.ts // 和Node.js关联的类型定义
│ └── vscode-typings.d.ts // 和VS Code关联的类型定义
└── vsc-extension-quickstart.md

此时,我们只需要点击在VS Code的Debug区域的Start按钮即可。

在接下来开启的一个处于拓展开发模式的新的VS Code中,我们只需要在命令面板中输入Hello World便可以激活这个模板拓展,弹出一个Hello World的消息弹窗。

那么,VS Code到底是如何加载并运行拓展的呢?我们又应该如何开发拓展供自己甚至是分享给更多的人更好的使用VS Code呢?

0x02 关于package.json的两三事

作为拓展项目的资源配置文件,package.json不仅仅描述了该拓展的信息还描述了拓展的功能。需要说明的是,当VS Code启动时,拓展的package.json文件便会被读取,并且VS Code还会对package.json文件中的contributes部分的内容做处理。这一点和拓展的源文件extension.ts有所区别。VS Code并不会在启动时便加载拓展的源代码。
下面我们就来看一看我们刚刚生成的这个拓展项目中的package.json文件的内容吧。

{
"name": "Standard-Header",
"displayName": "Standard-Header",
"description": "standard-header",
"version": "0.0.1",
"publisher": "JiadongChen",
"engines": {
"vscode": "^0.10.1"
},
"categories": [
"Other"
],
"activationEvents": [
"onCommand:extension.sayHello"
],
"main": "./out/src/extension",
"contributes": {
"commands": [{
"command": "extension.sayHello",
"title": "Hello World"
}]
},
"scripts": {
"vscode:prepublish": "node ./node_modules/vscode/bin/compile",
"compile": "node ./node_modules/vscode/bin/compile -watch -p ./"
},
"devDependencies": {
"typescript": "^1.6.2",
"vscode": "0.10.x"
}
}

我们可以看到,package.json描述了该拓展的一些基本信息,例如拓展的名称name、拓展的描述信息description以及拓展的版本号version和发布者的信息publisher等等。顺带提一句,直接通过提高版本号的方式就可以使用拓展发布工具来更新已经发布到VS Code应用商店的拓展版本。
除了这些,我们甚至还可以在package.json文件中配置一些拓展在VS Code的应用商店中的展示信息,例如拓展在商店中的种类:categories、拓展的icon图:icon以及拓展在应用市场主页的一些展示信息:galleryBanner等等。

...
"icon": "res/icon.png",
"galleryBanner": {
"color": "#5c2d91",
"theme": "dark"
},
"categories": [
"Other"
],
...

当然,更重要的内容是activationEvents、contributes以及scripts和main这几项内容。其中scripts项的内容是使用TypeScript进行开发时所特有的,主要的作用是用来提供对ts文件进行编译的相关信息。而main项则指向了将ts源文件编译后所生成的js文件。

ActivationEvents

正如上文所说,VS Code默认状况下并不会在启动时立刻执行拓展中的代码。因此,为了使拓展能够被激活,我们需要在package.json文件中定义activationEvents项的内容。例如上例中,activationEvents的定义如下:

...
"activationEvents": [
"onCommand:extension.sayHello"
],
...

意思是当“onCommand:extension.sayHello”事件被触发之后,拓展会被激活。那么在VS Code中,激活事件都有哪些种类呢?下面我们就来归一下类。

根据文件所使用的语言:onLanguage:${language}
当打开的文件是使用onLanguage所规定的语言时,拓展会被激活。
例如:

...
"activationEvents": [
"onLanguage:python"
]
...

根据所输入的命令:onCommand:${command}
当在onCommand中规定的命令被触发时,拓展会被激活。在上文生成的Hello World模板中,我们就可以看到。

...
"activationEvents": [
"onCommand:extension.sayHello"
]
...

根据文件夹:workspaceContains:${toplevelfilename}

"activationEvents": [
"workspaceContains:package.json"
],

无限制:*

...
"activationEvents": [
"*"
]
...

由于没有限制,因此在VS Code一启动时便会激活该拓展。因此,这种不加以条件限制就激活拓展的方式并不是十分推荐的。大家最好谨慎使用。

Contribution

在package.json文件中的contributes项中,同样包含很多种类。如果需要归类的话,可以分为以下几个类型。

  • configuration
  • commands
  • keybindings
  • languages
  • debuggers
  • grammars
  • themes
  • snippets

但是本文限于篇幅,将只关注commands和keybindings这两种。

commands
还以上文中的Hello World为例,我们在commands项中定义了命令的title以及title所对应的具体命令。如下所示:

"contributes": {
"commands": [{
"command": "extension.sayHello",
"title": "Hello World"
}]
},

此时一旦安装了该拓展,我们就可以在VS Code中的命令面板(我在Mac上的快捷键是Shift+cmd+p)中找到“Hello World”,输入便会触发extension.sayHello这条命令,而上文中的拓展激活事件项activationEvents中如果定义的内容是"onCommand:extension.sayHello",则激活事件被触发,拓展的代码被激活。

keybindings
当然,和commands对应的,我们还可以通过在package.json中定义keybindings项,通过绑定快捷键的方式触发命令。这样操作起来更加便捷,例如下文中我们自己开发一个插入标准页眉的拓展时,使用的便是绑定快捷键的方式。

"contributes": {
"keybindings": [{
"command": "extension.insertHeader",
"key": "shift+cmd+1",
"when": "editorTextFocus"
}]
},

如果我们在VS Code中安装了定义了快捷键触发的拓展,则打开VS Code的KeyBoard ShortCut就可以看到拓展中定义的快捷键和它对应的命令了。

0x03 VS Code运行拓展的原理

通过上一小节的内容,我们就能很清楚的理解上文中那个模板拓展的运行过程了。

VS Code首先会检测到拓展并且读取拓展的package.json文件的内容并将package.json文件中的contributes项应用到VS Code中。这样,我们就可以根据contributes项中的内容,或者是在命令面板中输入contributes项中定义的commands,或者是使用contributes项中所定义的快捷键keybindings来触发extension.sayHello命令。
一旦extension.sayHello触发,VS Code会创建一个叫做onCommand:extension.sayHello的激活事件。
与此同时,所有在自己的package.json文件中将activationEvents设置为onCommand:extension.sayHello的拓展会被激活。并且会根据package.json文件中main项的内容,将./out/src/extension.js文件加载到JavaScript VM中。接下来,VS Code会调用在extension.js文件中的active函数,在active函数中,我们需要提供“extension.sayHello”这个函数的具体实现并执行。
好了,了解了VS Code拓展的基本知识之后我们就可以开始着手开发自己的拓展了,这个拓展的目的是向源文件添加License页眉。

0x04 一个插入License页眉的拓展

既然要打造自己的VS Code,那么自己喜欢的一些操作习惯自然希望能够用在VS Code上。而插入页眉便是这样一个简单的小功能。

我们首先来看一看在上文中那个Hello World模板拓展的源文件即extension.ts文件的基本内容。

import * as vscode from 'vscode';

export function activate(context: vscode.ExtensionContext) {

    var disposable = vscode.commands.registerCommand('extension.sayHello', () => {
    ...
     vscode.window.showInformationMessage('Hello World!');
...

});
}

首先,我们自然要引入vscode命名空间下的API,以获得控制VS Code的能力。

其次,我们注意到了拓展的源文件需要export一个叫做activate的函数,当拓展的package.json文件中activationEvents所定义的事件被触发时,VS Code会调用activate函数。

最后,我们可以看到我们使用vscode的API注册了一个叫做“extension.sayHello”的命令,并且提供了它的具体实现,按照模板中的逻辑,“extension.sayHello”命令的逻辑是在窗口中显示一个内容为“Hello World”的信息消息。具体的效果在本文一开始的部分各位已经看到了。

那么接下来就十分简单了,我们首先新建一个叫做HeaderGenerator的类,用来执行插入页眉的任务。

class HeaderGenerator {
private _disposable: Disposable;
public insertHeader() { // Get the current text editor
let editor = window.activeTextEditor;
if (!editor) {
return;
} // Define header content
var header = "License Header"; // Get the document
var doc = editor.document; // Insert header
editor.edit((eb) => {
eb.insert(doc.positionAt(0), header);
});
} dispose() {
this._disposable.dispose();
}
}

插入页眉的具体执行是当前窗口的editor(TextEditor类)的edit方法,通过利用TextEditorEdit类的insert方法实现对当前的文档doc(TextDocument类)插入新的内容。

之后,我们只需在extension.ts文件中的activate函数中实现调用HeaderGenerator类的insertHeader方法即可。

import * as vscode from 'vscode';
import {window, commands, Disposable, ExtensionContext, TextDocument} from 'vscode'; export function activate(context: vscode.ExtensionContext) {
console.log('Congratulations, your extension "standard-header" is now active!');
let headerGen = new HeaderGenerator();
var disposable = vscode.commands.registerCommand('extension.insertHeader', () => {
headerGen.insertHeader();
});
context.subscriptions.push(headerGen);
context.subscriptions.push(disposable);
}

当然,为了增加快捷键“shift+cmd+1”的支持,我们还需要在package.json中修改contributes的内容:

"contributes": {
"keybindings": [{
"command": "extension.insertHeader",
"key": "shift+cmd+1",
"when": "editorTextFocus"
}]
},

之后,让我们先进入拓展开发模式看一下效果。使用快捷键shift+cmd+1,我们可以看到在VS Code的窗口中插入了页眉(截图中的页眉内容我已经换成了MIT协议)。

好了,到此我们的小小的在源文件中插入页眉的拓展就完成了,下面就让我们来使用安装、甚至是发布到VS Code的应用商店让大家一起分享我们的劳动成果吧。

0x05 本地安装或在应用商店发布

为了不必再每次都要进入拓展开发模式才能“使用”我们的拓展,我们就必须让自己的VS Code安装这个拓展。

事实上在本地安装供自己的拓展是十分简单并且方便的事情。VS Code会在.vscode/extensions文件夹中获取本地的拓展。而.vscode/extensions文件夹所在的位置我们可以总结如下:

  • Windows %USERPROFILE%\.vscode\extensions
  • Mac $HOME/.vscode/extensions
  • Linux $HOME/.vscode/extensions

我们只需拷贝一份我们的拓展到.vscode/extensions文件夹中,VS Code在启动时便能够检查到该拓展了。

当然,除了自己使用自己开发的拓展之外,我们还可以将拓展发布到VS Code的应用商店。此时我们就要借助一个拓展发布工具——vsce了。

首先是安装vsce:

npm install -g vsce

之后我们还需要到Visual Studio Team Services注册并登陆,以获取Personal Access Token。

一旦获取了Personal Access Token,我们就可以使用vsce创建一个发布者账号了。

vsce create-publisher 

紧接着,登陆并发布:

vsce login
vsce publish

发布成功之后,我们就可以在VS Code的应用商店中看到自己的拓展了。

并且在VS Code的命令面板中,我们也可以使用命令安装:

ext install 

好啦,行文至此,使用TypeScript拓展你自己的VS Code讲的已经差不多了。希望各位多多交流~

使用TypeScript拓展你自己的VS Code!的更多相关文章

  1. 使用TypeScript拓展你自己的VSCode

    转自:http://www.iplaysoft.com/brackets.html使用TypeScript拓展你自己的VSCode! 0x00 前言在前几天的美国纽约,微软举行了Connect(); ...

  2. 使用Visual Studio Code搭建TypeScript开发环境

    使用Visual Studio Code搭建TypeScript开发环境 1.TypeScript是干什么的 ? TypeScript是由微软Anders Hejlsberg(安德斯·海尔斯伯格,也是 ...

  3. [Tool] 使用Visual Studio Code开发TypeScript

    [Tool] 使用Visual Studio Code开发TypeScript 注意 依照本篇操作步骤实作,就可以在「Windows」.「OS X」操作系统上,使用Visual Studio Code ...

  4. Visual Studio Code开发TypeScript

    [Tool] 使用Visual Studio Code开发TypeScript   [Tool] 使用Visual Studio Code开发TypeScript 注意 依照本篇操作步骤实作,就可以在 ...

  5. TypeScript开发环境搭建(Visual studio code)

    使用Visual Studio Code搭建TypeScript开发环境 1.TypeScript是干什么的 ? TypeScript是由微软Anders Hejlsberg(安德斯·海尔斯伯格,也是 ...

  6. Vs Code推荐安装插件

    前言: Visual Studio Code是一个轻量级但功能强大的源代码编辑器,轻量级指的是下载下来的Vs Code其实就是一个简单的编辑器,强大指的是支持多种语言的环境插件拓展,也正是因为这种支持 ...

  7. TypeScript 2.0候选版(RC)已出,哪些新特性值得我们关注?

    注:本文提及到的代码示例下载地址 - Runnable sample to introduce Typescript 2.0 RC new features 作为一个Javascript的超集, Ty ...

  8. 《TypeScript 中文入门教程》 1、基础数据类型

    转载:https://github.com/MyErpSoft/TypeScript-Handbook/blob/master/pages/zh-CHS/Basic%20Types.md 概述 为了让 ...

  9. TypeScript中的枚举类型

    TypeScript拓展了Javascript原生的标准数据类型集,增加了枚举类型(enmu)和其他语言一 样 它提供我们一种数字类型的值,用来设置由于辨别的名字和方法 enum Students { ...

随机推荐

  1. JavaScript中Math对象的方法介绍

    1.比较最值方法 比较最值有两种方法,max() 和 min() 方法. 1.1 max() 方法,比较一组数值中的最大值,返回最大值. var maxnum = Math.max(12,6,43,5 ...

  2. ExtJS 4.2 组件介绍

    目录 1. 介绍 1.1 说明 1.2 组件分类 1.3 组件名称 1.4 组件结构 2. 组件的创建方式 2.1 Ext.create()创建 2.2 xtype创建 1. 介绍 1.1 说明 Ex ...

  3. html与html5

    HTML 是一种在 Web 上使用的通用标记语言.HTML 允许你格式化文本,添加图片,创建链接.输入表单.框架和表格等等,并可将之存为文本文件,浏览器即可读取和显示.HTML 的关键是标签,其作用是 ...

  4. 基于SignalR实现B/S系统对windows服务运行状态的监测

    通常来讲一个BS项目肯定不止单独的一个BS应用,可能涉及到很多后台服务来支持BS的运行,特别是针对耗时较长的某些任务来说,Windows服务肯定是必不可少的,我们还需要利用B/S与windows服务进 ...

  5. js学习之类型识别

    用来判别类型的方法有好多,整理了一下4种方法,平时用的时候,在不同情景下,还是要结合着使用的. 方法一 typeof:可以识别标准类型,除了Null:不能识别具体的对象类型,除了Function &l ...

  6. maven 中snapshot版本和release版本的区别

    maven中的仓库分为两种,snapshot快照仓库和release发布仓库.snapshot快照仓库用于保存开发过程中的不稳定版本,release正式仓库则是用来保存稳定的发行版本.定义一个组件/模 ...

  7. Nginx反向代理,负载均衡,redis session共享,keepalived高可用

    相关知识自行搜索,直接上干货... 使用的资源: nginx主服务器一台,nginx备服务器一台,使用keepalived进行宕机切换. tomcat服务器两台,由nginx进行反向代理和负载均衡,此 ...

  8. xss和sql注入原理学习

    8.4 Web跨站脚本攻击 8.4.1  跨站脚本攻击的原理(1) 跨站脚本在英文中称为Cross-Site Scripting,缩写为CSS.但是,由于层叠样式表 (Cascading Style ...

  9. Linux基础介绍【第七篇】

    linux用户分类 超级用户:UID=0,root 普通用户:UID 500起,由超级用户或具有超级用户权限的用户创建的用户. 虚拟用户:UID 1-499,为了满足文件或服务启动的需要而存在,一般都 ...

  10. Aop动态生成代理类时支持带参数构造函数

    一.背景 在某些情况下,我们需要植入AOP代码的类并没有默认构造函数.那么此时动态生成的代理类也需要相同签名的构造函数,并且内部调用原始类的构造函数.自己折腾了1晚上没搞定,现在搞定了发出来供大家一起 ...