2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

VSCode拡張機能を作ってみる3 - 文字の装飾

Last updated at Posted at 2021-06-23

はじめに

公式サンプルにVSCode APIを使ったサンプルがあるので、いくつか使いそうなものをピックアップしてみました。

今回は、Decorations API を使ってハイライトや文字色などの装飾をする機能を付けます。

前回
VSCode拡張機能を作ってみる1 - インストールとHelloWorld!
VSCode拡張機能を作ってみる2 - 入力補完

事前準備

まず、空のdecorator.tsファイルを作成し、extension.ts で読み込んでおきます。
ファイルを分けたかったので、公式から結構変更がありますが、やっていることは同じです。

エディタの変更が合った場合とテキストの変更があった場合に、Decolator処理を実行します。

extension.ts
import * as vscode from 'vscode';
import Decorator from './decorator';

export function activate(context: vscode.ExtensionContext) {
    let decorator = new Decorator();

    vscode.window.onDidChangeActiveTextEditor(editor => {
        decorator.changeActiveTextEditor(editor);
    }, null, context.subscriptions);

    vscode.workspace.onDidChangeTextDocument(event => {
        decorator.changeTextDocument(event);
    }, null, context.subscriptions);
}

export function deactivate() {}

エディタの変更が合った場合にはchangeActiveTextEditor、テキストの変更があった場合にはchangeTextDocumentを実行しています。
どちらもtimeout設定を経由してupdateDecorationsのメイン処理を実行しています。
constructorでsetDecoratorsにあるスタイル設定を事前におこなっています。

decorator.ts
import * as vscode from 'vscode';

export default class Decolator
{
    private activeEditor = vscode.window.activeTextEditor;
    private timeout: NodeJS.Timer | undefined = undefined;
    private decorationTypes: vscode.TextEditorDecorationType[] = [];

    constructor() {
        this.setDecorators();

        if (this.activeEditor) {
            this.triggerUpdateDecorations();
        }
    }

    public changeActiveTextEditor(editor: vscode.TextEditor | undefined): void {
        this.activeEditor = editor;
        if (editor) {
            this.triggerUpdateDecorations();
        }
    }

    public changeTextDocument(event: vscode.TextDocumentChangeEvent): void {
        if (this.activeEditor && event.document === this.activeEditor.document) {
            this.triggerUpdateDecorations();
        }
    }

    private triggerUpdateDecorations(): void {
        if (this.timeout) {
            clearTimeout(this.timeout);
            this.timeout = undefined;
        }
        this.timeout = setTimeout(() => {
            this.updateDecorations();
        }, 500);
    }

    private updateDecorations(): void {
        if (!this.activeEditor) {
            return;
        }

        // ここでDecorationsを実行します
    }

    private setDecorators(): void {
        // ここでスタイルの設定をおこないます
    }
}

数値の装飾サンプル

まずは公式サンプルにある数値の装飾をしてみます。

スタイルの設定が2パターンあります。
smallNumberDecorationTypeはハードコーディングされていますが、
largeNumberDecorationTypepackage.jsoncontributes.colorsに定義された情報を参照しています。
そうしておけば、ユーザー設定で色を再定義できます。

decorator.ts
    private setDecorators(): void {
        let smallNumberDecorationType = vscode.window.createTextEditorDecorationType({
            borderWidth: '1px',
            borderStyle: 'solid',
            overviewRulerColor: 'blue',
            overviewRulerLane: vscode.OverviewRulerLane.Right,
            light: {
                // this color will be used in light color themes
                borderColor: 'darkblue'
            },
            dark: {
                // this color will be used in dark color themes
                borderColor: 'lightblue'
            }
        });
        this.decorationTypes.push(smallNumberDecorationType);

        let largeNumberDecorationType = vscode.window.createTextEditorDecorationType({
            cursor: 'crosshair',
            // use a themable color. See package.json for the declaration and default values.
            backgroundColor: { id: 'myextension.largeNumberBackground' }
        });
        this.decorationTypes.push(largeNumberDecorationType);
    }

regExで指定した数字を正規表現で取得し、3以下ならsmallNumbers、それ以外はlargeNumbersとして対象ヵ所のrangeとhoverMessageの設定をしています。

最後にsetDecorationsで対象ヵ所にスタイルを反映することができます。

decorator.ts
    private updateDecorations(): void {
        if (!this.activeEditor) {
            return;
        }
        const regEx = /\d+/g;
        const text = this.activeEditor.document.getText();
        const smallNumbers: vscode.DecorationOptions[] = [];
        const largeNumbers: vscode.DecorationOptions[] = [];
        let match;
        while ((match = regEx.exec(text))) {
            const startPos = this.activeEditor.document.positionAt(match.index);
            const endPos = this.activeEditor.document.positionAt(match.index + match[0].length);
            const decoration = { range: new vscode.Range(startPos, endPos), hoverMessage: 'Number **' + match[0] + '**' };
            if (match[0].length < 3) {
                smallNumbers.push(decoration);
            } else {
                largeNumbers.push(decoration);
            }
        }

        this.activeEditor.setDecorations(this.decorationTypes[0], smallNumbers);
        this.activeEditor.setDecorations(this.decorationTypes[1], largeNumbers);
    }

まとめ

highlightの拡張機能はたくさんあるので、あえて作ることは少ないとは思うが、オレオレ言語だったり、そのほかの作りたい拡張機能と組み合わせると便利なものになりそう。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?