この記事は、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

以上です。