Java
TypeScript
VSCode
native2ascii

VSCodeのPluginをつくる。

初めに

Java9以前のアプリケーションの設定ファイル(Propertiesファイル)は、日本語(2バイトコード)をそのまま利用することができず、'¥u'から始まるコードに置き換える必要がありました。
Java9以前のアプリケーションをメンテナンスする立場になり、VSCodeを利用する上で、毎度、native2asciiするのが億劫で退屈な作業でした。

そこで、VScodeのプラグインでnative2asciiと同等の機能を作ることにしました。

まず、VSCodeのpluginを開発する環境を作ります。環境の作成方法は、@rmaさんの「Visual Studio Code はじめての拡張機能開発」をご覧ください。

方針

自分が調べた範囲では、VSCode上でコマンドをキックすることも、「Propertiesファイルを読んだ」イベントを拾うこともできそうになかったので(誰か情報ください。)、VSCodeのコマンドを利用して手動で変換(文字→コード化)リバース(コード→文字)をする方針で進めました。

コード化

以下のような感じで、文字→コード化を実現しました。

  1. ドキュメントからファイルの文字列を取得。
  2. 1行ごとに繰り返し、日本語を正規表現現で取得し配列を作成。
  3. 2.で作成した配列からコードを作りだし、日本語と、コードの連想配列を作成。
  4. 元の1行にreplaceメソッドで置き換える。
  5. 置き換えた文字列をまとめて新しいドキュメントを作成。
  6. エディタ内のドキュメントを5.で作成したドキュメントで置き換える。

なお、サロゲート文字には対応してません。

function ascii(e: vscode.TextEditor, d: vscode.TextDocument, sel: vscode.Selection[]) {
    console.log(d.getText());
    let text = d.getText();
    let newTest = text.split("\n");
    let replaced = "";
    newTest.forEach(val => {
        let reg = val.match(/([^\x01-\x7E])/g);
        if (reg) {
            let t = reg.map(code => {
                let unicode = code.charCodeAt(0).toString(16);
                return {code, value:`\\u${unicode}`};
            }).reduce( (v,obj) => {
                let {code, value} = obj;
                let reg = new RegExp(code);
                return v.replace(reg, value);
            }, val);
            replaced = `${replaced}${t}\n`; 
        } else {
            replaced = `${replaced}${val}\n`; 
        }
    });
    e.edit((builder)=>{
        if (e) {
            let startPos = e.document.positionAt(0);
            let endPos = e.document.positionAt(text.length);
            let allRange = new vscode.Range(startPos,endPos);
            builder.replace(allRange,replaced);
        }
    });
}

リバース

コード化したものと大差ありません。ユニコードから文字を作成しています。

function reverse(e: vscode.TextEditor, d: vscode.TextDocument, sel: vscode.Selection[]) {
        console.log(d.getText());
        let text = d.getText();
        let newTest = text.split("\n");
        let replaced = "";
        newTest.forEach(val => {
            let reg = val.match(/(\\u[0-9|a-f]{4})/g);
            if (reg) {
                let t = reg.map(unicode => {
                    let codeStrs = unicode.split("\\u");
                    let codePoints = parseInt(codeStrs[1], 16);
                    return {code:`\\${unicode}`, value:String.fromCharCode(codePoints)};
                }).reduce( (v,obj) => {
                    let {code, value} = obj;
                    let reg = new RegExp(code);
                    return v.replace(reg, value);
                }, val);
                replaced = `${replaced}${t}\n`; 
            } else {
                replaced = `${replaced}${val}\n`; 
            }
        });
        e.edit((builder)=>{
            if (e) {
                let startPos = e.document.positionAt(0);
                let endPos = e.document.positionAt(text.length);
                let allRange = new vscode.Range(startPos,endPos);
                builder.replace(allRange,replaced);
            }
        });
}

native2ascii

以下の関数を作成して、上記で作成した関数をコマンドで呼べるようにまとめました。
この関数を、registerCommandで呼び出せば完成です。

function native2ascii() {
    if (!vscode.window.activeTextEditor) {
        vscode.window.showInformationMessage('Open a file first to manipulate text selections');
        return;
    }   
    var items: vscode.QuickPickItem[] = [];

    items.push({ label: "ascii", description: "文字からUnicodeに変換" });
    items.push({ label: "reverse", description: "Unicodeから文字に変換" });

    Window.showQuickPick(items).then((selection) => {
        if (!selection) {
            return;
        }
        let e = Window.activeTextEditor;
        if (e) {
            let d = e.document;
            let sel = e.selections;
            switch (selection.label) {
                case "ascii":
                    ascii(e, d, sel);
                    break;
                case "reverse":
                    reverse(e, d, sel);
                    break;
                default:
           console.log("hum this should not have happend - no selection")
           break;
            }
        }
    });
}

VSCEでVSIXファイルを作る。

作成したpluginをパッケージングをします。
VSCEを利用しました。
以下のコマンドでインストールしました。

npm install -g vsce

インストールできたら、以下のコマンドでパッケージングします。
README.mdを書き換えないとパッケージングに失敗します。

vsce package

ソースコードはGitHubに保存しています。

まとめ

プラグインを作るための環境が充実しており、引っかかるところはなかった(@rmaさんに感謝)
typescriptは初めてだったのですが、ES2015を触っていたので違和感はありませんでした。
むしろ、VScodeの言語サポートがよくできていて、typescriptを本格的に使いたいと思いました。