例子——单词计数

本文档假设您已经阅读了第一个扩展,它涵盖了VS Code可扩展性的基础知识。

单词计数是一个端到端教程,向您展示如何创建一个扩展来帮助Markdown创作。在我们深入了解所有这些工作原理之前,让我们先快速演示一下您将要构建的核心特性,这样您就知道会发生什么了。

无论何时编辑标记文件,都会添加状态栏消息。该消息包括当前的字数和更新,当您键入和移动到文件:

wordcountevent2

提示:如果您有任何问题,可以从GitHub存储库中获得完成的示例。

概述

这个示例有三个部分,将带您了解一系列相关概念:

更新状态栏-在VS代码状态栏中显示自定义文本
订阅事件——根据编辑事件更新状态栏
配置扩展资源——释放事件订阅或UI句柄等资源

首先确保安装了最新的VS Code扩展生成器,然后运行它:

1
2
npm install -g yo generator-code
yo code

这将打开扩展生成器——我们将以TypeScript New扩展选项为基础。现在,按照您在下图中看到的方法填写字段(使用’WordCount’作为扩展名,您自己的名字作为发布者)。

yo1

你现在可以打开VS Code在生成器输出描述:

1
2
cd WordCount
code .

运行扩展

在继续之前,我们可以通过按F5来运行扩展以确保一切正常。正如您在前面的“Hello World”演练中看到的,VS代码打开了另一个窗口([扩展开发主机]窗口),在这个窗口中您的扩展将被加载。你应该找“Hello World”命令在命令面板中(按⇧⌘P),当你选择它,您将看到一个通知在窗口的右下角说“Hello World !”。

既然您已经确认了扩展正在正确地运行,那么如果您愿意,您可以继续打开扩展开发窗口。要测试您对扩展所做的任何更改,您可以在开发窗口中再次按F5,或者通过按Ctrl+R (macOS: Cmd+R)重新加载扩展开发窗口。

更新状态栏
用下面的代码替换生成的extension.ts文件的内容。它声明并实例化一个WordCounter类,该类可以计数单词,并在VS代码状态栏中显示它们。“Hello Word”命令在调用时将调用updateWordCount。

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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
// The module 'vscode' contains the VS Code extensibility API
// Import the necessary extensibility types to use in your code below
import {window, commands, Disposable, ExtensionContext, StatusBarAlignment, StatusBarItem, TextDocument} from 'vscode';

// This method is called when your extension is activated. Activation is
// controlled by the activation events defined in package.json.
export function activate(context: ExtensionContext) {

// Use the console to output diagnostic information (console.log) and errors (console.error).
// This line of code will only be executed once when your extension is activated.
console.log('Congratulations, your extension "WordCount" is now active!');

// create a new word counter
let wordCounter = new WordCounter();

let disposable = commands.registerCommand('extension.sayHello', () => {
wordCounter.updateWordCount();
});

// Add to a list of disposables which are disposed when this extension is deactivated.
context.subscriptions.push(wordCounter);
context.subscriptions.push(disposable);
}

class WordCounter {

private _statusBarItem: StatusBarItem = window.createStatusBarItem(StatusBarAlignment.Left);

public updateWordCount() {

// Get the current text editor
let editor = window.activeTextEditor;
if (!editor) {
this._statusBarItem.hide();
return;
}

let doc = editor.document;

// Only update status if an Markdown file
if (doc.languageId === "markdown") {
let wordCount = this._getWordCount(doc);

// Update the status bar
this._statusBarItem.text = wordCount !== 1 ? `${wordCount} Words` : '1 Word';
this._statusBarItem.show();
} else {
this._statusBarItem.hide();
}
}

public _getWordCount(doc: TextDocument): number {

let docContent = doc.getText();

// Parse out unwanted whitespace so the split is accurate
docContent = docContent.replace(/(< ([^>]+)<)/g, '').replace(/\s+/g, ' ');
docContent = docContent.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
let wordCount = 0;
if (docContent !== "") {
wordCount = docContent.split(" ").length;
}

return wordCount;
}

dispose() {
this._statusBarItem.dispose();
}
}

现在让我们尝试对扩展的更新。

我们将TypeScript文件的编译设置在一个手表上(扩展名是.vscode\tasks.json文件),所以不需要重新构建。在[扩展开发主机]窗口中按Ctrl+R键,您的代码正在运行,扩展将重新加载(您也可以从您的主开发窗口F5)。我们仍然需要像以前一样使用“Hello World”命令激活代码。假设您在一个标记文件中,您的状态栏将显示单词计数。

wordcount2

这是一个很好的开始,但如果计数随着文件的更改而更新,会更酷。

订阅事件

让我们将助手类与一组事件挂钩。

  • onDidChangeTextEditorSelection -当游标位置发生变化时将引发事件
  • onDidChangeActiveTextEditor—当活动编辑器更改时引发事件。

为此,我们将在extension.ts文件中添加一个新类。它将设置这些事件的订阅,并要求WordCounter更新单词计数。还要注意这个类如何将订阅管理为可丢弃的,以及如何在自行处理时停止列出。

将下面所示的WordCounterController添加到extension.ts文件的底部。

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
class WordCounterController {

private _wordCounter: WordCounter;
private _disposable: Disposable;

constructor(wordCounter: WordCounter) {
this._wordCounter = wordCounter;

// subscribe to selection change and editor activation events
let subscriptions: Disposable[] = [];
window.onDidChangeTextEditorSelection(this._onEvent, this, subscriptions);
window.onDidChangeActiveTextEditor(this._onEvent, this, subscriptions);

// update the counter for the current file
this._wordCounter.updateWordCount();

// create a combined disposable from both event subscriptions
this._disposable = Disposable.from(...subscriptions);
}

dispose() {
this._disposable.dispose();
}

private _onEvent() {
this._wordCounter.updateWordCount();
}
}

我们不再希望在调用命令时加载单词计数扩展名,而是希望每个标记文件都可用。

首先,将激活功能的主体替换为:

1
2
3
4
5
6
7
8
9
10
11
// Use the console to output diagnostic information (console.log) and errors (console.error).
// This line of code will only be executed once when your extension is activated.
console.log('Congratulations, your extension "WordCount" is now active!');

// create a new word counter
let wordCounter = new WordCounter();
let controller = new WordCounterController(wordCounter);

// Add to a list of disposables which are disposed when this extension is deactivated.
context.subscriptions.push(controller);
context.subscriptions.push(wordCounter);

其次,我们必须确保在打开标记文件时激活扩展名。为此,我们需要修改package.json文件。之前,扩展是通过extension.sayHello命令激活的,我们不再需要这个命令,所以我们可以从package.json删除整个贡献属性:

1
2
3
4
5
6
7
8
"contributes": {
"commands":
[{
"command": "extension.sayHello",
"title": "Hello World"
}
]
},

现在更改您的扩展名,以便在打开标记文件时激活它,方法是更新activationEvents属性:

1
2
3
"activationEvents": [
"onLanguage:markdown"
]

onLanguage:${language}事件接受语言id(在本例中为“markdown”),并且在打开该语言的文件时将引发该事件。

通过窗口重载Ctrl+R或使用F5运行扩展,然后开始编辑一个标记文件。现在应该有一个实时更新的单词计数。

wordcountevent2

如果您在activate函数上设置了断点,那么您会注意到,当打开第一个标记文件时,它只调用一次。WordCountController构造函数运行并订阅编辑器事件,这样updateWordCount函数就被称为“标记文件”(Markdown),它们的文本也会发生变化。

定制状态栏

我们已经看到了如何在状态栏上显示格式化文本。VS代码允许您定制您的状态栏添加进一步与颜色,图标,工具提示等。使用智能感知,您可以看到各种StatusBarItem字段。学习VS代码可扩展性api的另一个很好的资源是生成的扩展项目中包含的node_modules\vscode\vscode.d.ts类型声明文件。在编辑器中打开vscode.d.ts,您将看到带有注释的完整VS代码可扩展性API。

vscode-d-ts

将StatusBarItem更新代码替换为:

1
2
3
// Update the status bar
this._statusBarItem.text = wordCount !== 1 ? `$(pencil) ${wordCount} Words` : '$(pencil) 1 Word';
this._statusBarItem.show();

在计算字数的左边显示一个GitHub Octicon铅笔图标。

处理扩展资源

现在,我们将更深入地了解扩展如何通过可丢弃件处理VS代码资源。

当一个扩展被激活时,它会被传递一个ExtensionContext对象,该对象具有一个可丢弃的可订阅集合。扩展可以将它们的一次性对象添加到这个集合中,VS代码将在扩展停用时处理这些对象。

许多创建工作区或UI对象(例如registerCommand)的VS代码api返回一个一次性的,扩展可以通过直接调用它们的dispose方法从VS代码中删除这些元素。

事件是onDid*事件订阅方方法返回一次性消息的另一个例子。通过处理事件的可丢弃性,取消订阅事件。在我们的示例中,WordCountController通过保留自己的一次性集合(在停用时清除)直接处理事件订阅可丢弃项。

1
2
3
4
5
6
7
// subscribe to selection change and editor activation events
let subscriptions: Disposable[] = [];
window.onDidChangeTextEditorSelection(this._onEvent, this, subscriptions);
window.onDidChangeActiveTextEditor(this._onEvent, this, subscriptions);

// create a combined disposable from both event subscriptions
this._disposable = Disposable.from(...subscriptions);

在本地安装您的扩展

到目前为止,您编写的扩展只在VS代码的一个特殊实例中运行,即扩展开发主机实例。要使您的扩展可以用于所有VS代码实例,请将扩展文件夹内容复制到.vscode/extensions文件夹下的新文件夹中

发布您的扩展

阅读如何共享扩展

下一个步骤

继续往下读,你会发现:

扩展生成器-了解Yo代码扩展生成器中的其他选项。
扩展API - 获得扩展API的概述。
发布工具-学习如何发布一个扩展到公共市场。
编辑器API -学习更多关于文本文档,文本编辑器和编辑文本。
其他扩展示例—查看我们的示例扩展项目列表。

Powered by Hexo and Hexo-theme-hiker

Copyright © 2013 - 2021 朝着牛逼的道路一路狂奔 All Rights Reserved.

访客数 : | 访问量 :