この記事は、Linked Open Data Advent Calendar 2020 の19日目の記事です。

Linked Open Data Advent Calendar 2020
https://adventar.org/calendars/5356

rdflintという、
RDF形式で記述されたデータをチェックするツールを作っているのですが、
このエントリでは、Visual Studio Codeから利用するために作成した
vscode拡張の実装について述べようと思います。

rdflint: RDFデータのチェックツール「rdflint」の利用ガイド
https://imas.github.io/rdflint/

作成した拡張機能は、以下のmarketplaceにて公開しています。

RDF language support via rdflint
https://marketplace.visualstudio.com/items?itemName=takemikami.vscode-rdflint

利用イメージは、以下のような画像のようになります。

vscode-rdflint

vscode拡張の作り方

まず、前提知識や参照用に、基本的な情報のリンクを記載しておきます。

vscodeの拡張の作り方は、以下のサイトを参照して下さい。

Extension API | Visual Studio Code
https://code.visualstudio.com/api

また、GitHubにもサンプルが上がっているので、参考になると思います。

vscode-extension-samples| GitHub
https://github.com/microsoft/vscode-extension-samples

vscode-rdflintのソースコードは、次の場所にあります。

vscode-rdflint | GitHub
https://github.com/imas/rdflint/tree/master/vscode-rdflint

インタラクティブモードの起動

vscode-rdflintでは、
Ctrl+Shift+Pメニューからインタラクティブモードが起動できます。

この処理は以下のように実装しています。

  • package.jsonにコマンドを定義
  • extension.jsにコマンドの処理を実装
    • コマンドの処理では、「createTerminal」でJavaを実行

package.json

        "commands": [
            {
                "command": "rdflint.interactiveMode",
                "title": "rdflint interactiveMode: SPARQL playground"
            }
        ],

src/extension.ts

    // rdflint interactive mode startup command
    let disposable = vscode.commands.registerCommand('rdflint.interactiveMode', () => {
        if (undefined === javaHome) {
            vscode.window.showInformationMessage('Please setup enviroment variable JAVA_HOME');
            return;
        }


        setupRdflintJar()
            .then((jar) => {
                let terminal = vscode.window.createTerminal(`rdflint`, javaHome + javaExe, ['-jar', '' + jar, '-i']);
                terminal.show(true);
            })
            .catch((err) => {
                vscode.window.showInformationMessage(err);
            });
    });

    context.subscriptions.push(disposable); 

setupRdflintJar()の箇所では、
jitpackからrdflintのjarファイルをダウンロード(未ダウンロードの場合)しています。

Language Server の実装

まだまだ、実験的な機能なのですが、
rdflintにはLanguage Server Protocolによって、
指摘事項をvscodeなどのIDEと連携する機能があります。

この処理は以下のように実装しています。

  • package.jsonに拡張機能の対象言語を定義
  • package.jsonに対象言語と拡張子の対応を定義
  • extension.jsでLanguage Serverとクライアントを起動

package.json

    "activationEvents": [
        "onCommand:rdflint.interactiveMode",
        "onLanguage:turtle",
        "onLanguage:rdfxml"
    ],
        "languages": [
            {
                "id": "rdfxml",
                "extensions": [
                    ".rdf"
                ],
                "aliases": [
                    "RDFXML",
                    "RDF",
                    "rdfxml",
                    "rdf"
                ],
                "configuration": "./rdfxml.language-configuration.json"
            },
            {
                "id": "turtle",
                "extensions": [
                    ".ttl"
                ],
                "aliases": [
                    "TURTLE",
                    "turtle"
                ]
            }
        ],

src/extension.ts

        setupRdflintJar()
            .then((jar) => {
                // rdflint language server
                let serverOptions: Executable = {
                    command: javaHome + javaExe,
                    args: ['-jar', '' + jar, '-ls']
                };

                // Options to control the language client
                let clientOptions: LanguageClientOptions = {
                    // Register the server for turtle documents
                    documentSelector: [
                        { scheme: 'file', language: 'turtle' },
                        { scheme: 'file', language: 'rdfxml' }
                    ],
                    synchronize: {
                        // Notify the server about file changes to '.clientrc files contained in the workspace
                        fileEvents: workspace.createFileSystemWatcher('**/.clientrc')
                    }
                };

                // Create the language client and start the client.
                client = new LanguageClient(
                    'rdflintLanguageServerExperimental',
                    'RdfLint Language Server',
                    serverOptions,
                    clientOptions
                );

                // Start the client. This will also launch the server
                client.start();
            })
            .catch((err) => {
                vscode.window.showInformationMessage(err);
            });

検証処理は、rdflint側で実装しているので、
vscodeの実装は、以上のようにシンプルなものになります。

Language Server Protocolとその実装については、以下のサイトを参照下さい。

Language Server Protocol
https://microsoft.github.io/language-server-protocol/

Language Server Extension Guide | Visual Studio Code
https://code.visualstudio.com/api/language-extensions/language-server-extension-guide

LSP4JでLanguage Server Protocol入門
https://qiita.com/minebreaker/items/c53e4dddb0709492d362

以上です。