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

# はじめに

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

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

# WinMergeとは

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

https://winmerge.org/

# 開発環境

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

* Windows 10 (バージョン 2004)
* [Visual C++ ビルドツール 2019](https://visualstudio.microsoft.com/ja/downloads/) (v16.11.5)　→　[インストール手順](https://www.kkaneko.jp/tools/win/buildtool.html)
 * MSVC v142 Buildtools
 * C++ MFC for v142 Buildtools
 * [Windows SDK](https://developer.microsoft.com/en-us/windows/downloads/windows-sdk/) (10.0.19041.0)
* [Git](https://gitforwindows.org/) (version 2.24.1.windows.2)
* [7-Zip](https://sevenzip.osdn.jp/download.html) (Ver 19.00)

参考：Visual Studio Build Tools 2019 インストール対象
![VC19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675901/01b14a2e-c5fe-ca3b-575a-04777f671c4f.png)

# WinMergeのビルド

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

```text:コマンドプロンプト
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言語向け機能の実装を行った中で、以下がメインの作業となりました。
ソースコードでの実装方法に選択肢が多いのは、ソースコードを書く側としてありがたいのですが、今回ソースコードを解析する側に立つと、大変だなと思いました。:sweat_smile:

## D言語の特徴１：コメントのネスト（入れ子）構造
D言語は、[コメント行](https://dlang.org/spec/lex.html#comment)の書き方を３種類提供しています。

```d:sample1.d
//  一行コメント
/+
    string s = "ここは、コメント行１";
    /+
        string s = "ここは、コメント行２";
    +/
    string s = "ここは、コメント行３";
+/
/*
    string s = "ここは、コメント行４";
/*
    string s = "ここは、コメント行５";
*/
    string s = "ここは、コメント行ではない";
```

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

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

## D言語の特徴２：文字列の表現
D言語は、[文字列リテラル](https://dlang.org/spec/lex.html#string_literals)の表現方法がたくさん用意されています。

```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](https://dlang.org/spec/lex.html#wysiwyg)でエスケープシーケンスを使わずにダブルクォーテーション`"`やバックスラッシュ（円マーク）`\`を表現できます。ただし、`arr[1]`ではダブルクォーテーション`"`自体を文字列に含めることができません。
また、文字列中に改行があると、改行文字`\n`として扱われます。

```text: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での実装が難しく、以下の文字列は未対応（断念）としました。
`"EOS`と`EOS"`の間にあるのが文字列になります。
以下の例の`EOS`に限らず、D言語では任意の文字列を区切り文字（デリミタ）にできます。

```d:sample2b.d
import std.stdio;

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

void main()
{
    writeln(s);
}
```

```text:sample2b.dのコンパイル実行結果
This
is a multi-line
heredoc string
```

## D言語の特徴３：文字列のネスト（入れ子）構造

D言語では、文字列の区切り文字（デリミタ）のネストを許容するパターンがあります。[Token strings](https://dlang.org/spec/lex.html#token_strings)

```d:sample3.d
import std.stdio;

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

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

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

# WinMerge実装結果

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

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675901/59646094-abb8-3881-775e-9881b708dc4b.png)

# おわりに
私なんかが、いきなりプルリクエストして採用されるのだろうか・・・
と、ちょっと心配でしたが、v2.16.17の追加機能として、無事[マージ](https://github.com/WinMerge/winmerge/pull/1042)されました。

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

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


# 参考情報
https://winmerge.org/

https://github.com/WinMerge/winmerge

https://ja.wikipedia.org/wiki/WinMerge