WinMergeにD言語シンタックスハイライト機能を追加しました


はじめに

WinMergeのソースコードに手を加え、D言語のシンタックスハイライト機能を追加しました。
WinMergeのビルド方法や追加した機能ついて、書いてみたいと思います。

※v2.16.17以降に組み込まれる予定です。

WinMergeとは

詳細な説明は公式サイトを参照してください。私は普段からソースコードの修正時に愛用しています。

開発環境

WinMergeの実行モジュールであるWinMergeU.exeをビルドする際に必要なアプリケーションと、参考までに、私の開発環境のバージョンを紹介します。
インストーラを含む全体のビルドを行いたい方は、WinMerge GitHubのページを確認してください。

参考:Visual Studio Build Tools 2019 インストール対象

WinMergeのビルド

GitHubから WinMergeのソースコードを取得し、ビルドを行います。
WinMergeの実行モジュールであるWinMergeU.exeD:\Dev\winmerge\Build\x64\Releaseに作成されました。

コマンドプロンプト
D:\Dev> git clone https://github.com/winmerge/winmerge
Cloning into 'winmerge'...
remote: Enumerating objects: 124830, done.
remote: Counting objects: 100% (1119/1119), done.
remote: Compressing objects: 100% (484/484), done.
remote: Total 124830 (delta 729), reused 933 (delta 626), pack-reused 123711
Receiving objects: 100% (124830/124830), 442.15 MiB | 1.21 MiB/s, done.
Resolving deltas: 100% (54763/54763), done.
Updating files: 100% (6731/6731), done.

D:\Dev> cd winmerge

D:\Dev\winmerge> git submodule init
Submodule 'Externals/freeimage' (https://github.com/WinMerge/freeimage.git) registered for path 'Externals/freeimage'
Submodule 'Externals/frhed' (https://github.com/WinMerge/frhed.git) registered for path 'Externals/frhed'
Submodule 'Externals/jq' (https://github.com/stedolan/jq) registered for path 'Externals/jq'
Submodule 'Externals/patch' (https://github.com/WinMerge/patch.git) registered for path 'Externals/patch'
Submodule 'Externals/sevenzip' (https://github.com/WinMerge/sevenzip.git) registered for path 'Externals/sevenzip'
Submodule 'Externals/tidy-html5' (https://github.com/htacg/tidy-html5) registered for path 'Externals/tidy-html5'
Submodule 'Externals/wil' (https://github.com/microsoft/wil) registered for path 'Externals/wil'
Submodule 'Externals/winimerge' (https://github.com/WinMerge/winimerge.git) registered for path 'Externals/winimerge'

D:\Dev\winmerge> git submodule update
Cloning into 'D:/Dev/winmerge/Externals/freeimage'...
Cloning into 'D:/Dev/winmerge/Externals/frhed'...
Cloning into 'D:/Dev/winmerge/Externals/jq'...
Cloning into 'D:/Dev/winmerge/Externals/patch'...
Cloning into 'D:/Dev/winmerge/Externals/sevenzip'...
Cloning into 'D:/Dev/winmerge/Externals/tidy-html5'...
Cloning into 'D:/Dev/winmerge/Externals/wil'...
Cloning into 'D:/Dev/winmerge/Externals/winimerge'...
Submodule path 'Externals/freeimage': checked out '111502a59d938d476ebb5a975ccf0cadd14e1cab'
Submodule path 'Externals/frhed': checked out '50590011df95cac36aa5fd800d3d2653fc16e410'
Submodule path 'Externals/jq': checked out 'e73951f3d1928591b3a9a60de11ae975a21e621f'
Submodule path 'Externals/patch': checked out 'a44c7a2921d52b274ab33900a3f49e6b02a5a95f'
Submodule path 'Externals/sevenzip': checked out 'cff58f15205a4e45343a5ed9214059162039e6c0'
Submodule path 'Externals/tidy-html5': checked out '0016e0083505ccee25a5c76dcf64cfe336765128'
Submodule path 'Externals/wil': checked out '209ff9c7e30e71bf6d1405557bf78544920f8157'
Submodule path 'Externals/winimerge': checked out '7b751b2342e2bb2924df53e13b93c92a21d35632'

D:\Dev\winmerge> path="C:\Program Files\7-Zip";%PATH%

D:\Dev\winmerge> DownloadDeps.cmd

・・・省略・・・

D:\Dev\winmerge> BuildBin.vs2019.cmd x64

・・・省略・・・

開発にチャレンジ

WinMergeを使っていて、D言語のシンタックスハイライト機能が欲しいと思い、開発にチャレンジしました。
D言語向け機能の実装を行った中で、以下がメインの作業となりました。
ソースコードでの実装方法に選択肢が多いのは、ソースコードを書く側としてありがたいのですが、今回ソースコードを解析する側に立つと、大変だなと思いました。

D言語の特徴1:コメントのネスト(入れ子)構造

D言語は、コメント行の書き方を3種類提供しています。

sample1.d
//  一行コメント
/+
    string s = "ここは、コメント行1";
    /+
        string s = "ここは、コメント行2";
    +/
    string s = "ここは、コメント行3";
+/
/*
    string s = "ここは、コメント行4";
/*
    string s = "ここは、コメント行5";
*/
    string s = "ここは、コメント行ではない";

D言語のブロックコメント/+ +/は、ネストに対応しています。
/* */は、C言語と言語仕様に合わせて、ネストに対応していません。

Rustはブロックコメント/* */がネストに対応しているそうで、実装での参考にしました。

D言語の特徴2:文字列の表現

D言語は、文字列リテラルの表現方法がたくさん用意されています。

sample2a.d
import std.stdio;

void main()
{
    string[] arr = [
        "string
            1\\\"",
        r"string
            2\"c,
        `"string
            3\"`,
        q"(string
            4a\")",
        q"[string
            4b\"]",
        q"{string
            4c\"}",
        q"<string
            4d\">",
        q"/string
            4e\"/"
    ];
    foreach( i, s; arr ){
        writefln("-----arr[%s]-----\n%s", i, s);
    }
}

arr[0]は C言語と同じ文字列表現です。
arr[1]以降はWysiwyg Stringsでエスケープシーケンスを使わずにダブルクォーテーション"やバックスラッシュ(円マーク)\を表現できます。ただし、arr[1]ではダブルクォーテーション"自体を文字列に含めることができません。
また、文字列中に改行があると、改行文字\nとして扱われます。

sample2a.dのコンパイル実行結果
-----arr[0]-----
string
            1\"
-----arr[1]-----
string
            2\
-----arr[2]-----
"string
            3\"
-----arr[3]-----
string
            4a\"
-----arr[4]-----
string
            4b\"
-----arr[5]-----
string
            4c\"
-----arr[6]-----
string
            4d\"
-----arr[7]-----
string
            4e\"

WinMergeでの実装が難しく、以下の文字列は未対応(断念)としました。
"EOSEOS"の間にあるのが文字列になります。
以下の例のEOSに限らず、D言語では任意の文字列を区切り文字(デリミタ)にできます。

sample2b.d
import std.stdio;

string s =
q"EOS
This
is a multi-line
heredoc string
EOS";

void main()
{
    writeln(s);
}
sample2b.dのコンパイル実行結果
This
is a multi-line
heredoc string

D言語の特徴3:文字列のネスト(入れ子)構造

D言語では、文字列の区切り文字(デリミタ)のネストを許容するパターンがあります。Token strings

sample3.d
import std.stdio;

void main()
{
    string s =
        q{string
            5 q{string 5+} };
    writeln(s);
}

QiitaのMarkdown カラー表示が、少しわかりにくいですが、
q{}の間が文字列になります。ネストが許容されるので、内側のq{}は文字列に含まれます。
以下にコンパイル実行結果を記載します。表示されている部分が文字列です。

sample3.dのコンパイル実行結果
string
            5 q{string 5+} 

WinMerge実装結果

完成したD言語シンタックスハイライト機能のイメージです。

おわりに

私なんかが、いきなりプルリクエストして採用されるのだろうか・・・
と、ちょっと心配でしたが、v2.16.17の追加機能として、無事マージされました。

WinMergeのマイルストーンを見ると、
v2.16.17(ベータ版)は2021/12/19リリース予定、v2.16.18(安定版)は2022/1/27リリース予定となっています。

みなさまのD言語開発に活用していただければと思います。

参考情報