aimdevel’s blog

勉強したことを書きます

vscode拡張機能としてhoverを実装する

概要

vscode拡張機能にhoverを実装するために以下を行う。 今回はlanguage serverとして実装する。
* ベースとするソースコードの入手
* 初期化処理の編集
* hover関数を実装
* hover関数をサーバに登録

ベースとするソースコードの入手

以下のリポジトリをクローンして、lsp-sampleのソースコードを使用する。
クローン後にmoduleをインストールする。

github.com

$ git clone https://github.com/microsoft/vscode-extension-samples.git
$ cd vscode-extension-samples/lsp-sample
$ npm install

その後vscodeでこのvscode-extension-samples/lsp-sampleを開く。


以下ではserver/src/server.tsを編集していく。

importの追加

以下のようにHoverParamsを追加でimportする。

import {
    createConnection,
    TextDocuments,
    Diagnostic,
    DiagnosticSeverity,
    ProposedFeatures,
    InitializeParams,
    DidChangeConfigurationNotification,
    CompletionItem,
    CompletionItemKind,
    TextDocumentPositionParams,
    TextDocumentSyncKind,
    InitializeResult,
    HoverParams,    // ここを追加
    Hover   // ここを追加
} from 'vscode-languageserver/node';

初期化処理の編集

初期化時に設定するcapabilitiesにhoverの設定を追加する。server.tsの67行目あたりに追加すればよい。

// for hover
result.capabilities.hoverProvider = true;

hover用関数を実装

hover用の関数を実装する。 server.tsの適当な場所に以下を追記する。

// for hover
async function HoverSample(params:HoverParams): Promise<Hover> {
    var contents = "# Hover Test!\nyour hover!!!"
    var range = {
        start: { line: params.position.line, character: params.position.character },
        end : { line: params.position.line, character: params.position.character+5 }
    }
    return {
        contents,
        range,
    }
}

hover用関数をサーバに登録

実装した関数をサーバに登録する。server.tsの適当な場所に以下を追記する。

// for hover
connection.onHover(params => HoverSample(params));

以上でhoverの実装ができた。

F5で拡張機能を起動し、Plain Textファイルの適当なところにマウスを持っていくとhoverで文字列が表示されるはず。

Hoverレスポンスの構造

Hoverリクエストの結果として返すデータ構造を見ていく。
以下のサイトを参考にする。
Specification

Hoverは以下の構造になっている。

/**
 * The result of a hover request.
 */
export interface Hover {
    /**
    * The hover's content
    */
    contents: MarkedString | MarkedString[] | MarkupContent;

    /**
    * An optional range is a range inside a text document
    * that is used to visualize a hover, e.g. by changing the background color.
    */
    range?: Range;
}
  • contentsは以下の定義で、文字列で指定できる。
type MarkedString = string | { language: string; value: string };
  • rangeは以下の形式で、hoverの対象となる文字列がドキュメントのどの位置にあるかを示す。
interface Range {
    /**
    * The range's start position.
    */
    start: Position;

    /**
    * The range's end position.
    */
    end: Position;
}

interface Position {
    /**
    * Line position in a document (zero-based).
    */
    line: uinteger;

    /**
    * Character offset on a line in a document (zero-based). The meaning of this
    * offset is determined by the negotiated `PositionEncodingKind`.
    *
    * If the character value is greater than the line length it defaults back
    * to the line length.
    */
    character: uinteger;
}

今回はHoverで通知する情報はほぼ固定だったが、これらの値を変更することで必要な情報をhoverで通知できる。