Windows上のVSCodeでのD言語のdebug表示

* 20191210 dmdを改造する例を追記

Windows上の vscode で D言語をデバッグするとこんな感じで、

![degger.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59664/6d22edc6-e4cf-b716-b9d2-a9e10bcc7899.jpeg)

変数の表示が見やすくありません。
文字列がスライスで `\0` で終端していなかったりもします。
(c++用のデバッガ `cppvsdbg` なのでそりゃそう)

`vc` の `natvis` でカスタマイズできないか試してみた。

実験コード

https://github.com/ousttrue/d_natvis

## string は natvis できた

```json:launch.json
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "with natvis",
            "type": "cppvsdbg",
            "request": "launch",
            "program": "${workspaceFolder}/d_natvis.exe",
            "args": [],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "externalConsole": false,
            "visualizerFile": "${workspaceFolder}/d.natvis" // これ
        }
    ]
}
```

```xml:d.natvis
<?xml version="1.0" encoding="utf-8" ?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
    <Type Name="string"><!-- この Name が型名とマッチして表示される -->
        <DisplayString>"{ptr,[length]s8b}"</DisplayString>
        <StringView>ptr,length</StringView>
        <Expand>
            <Item Name="[size]">length</Item>
            <ArrayItems>
                <Size>length</Size>
                <ValuePointer>ptr</ValuePointer>
            </ArrayItems>
        </Expand>
    </Type>
</AutoVisualizer>
```

![string.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59664/376d8711-cf8a-9f7d-fe8d-5d3911fb8d48.jpeg)

## sliceはできなかったが

`alias string  = immutable(char)[]` なのでスライスもできないかと思って試したのだけどできなかった。

```d
auto array = [1, 2, 3];
```

などは、

```xml
<Type Name="int[]">
```

になっているらしく、 `natvis` 的には型名として不適合でマッチさせることができないらしい。

https://forum.dlang.org/post/urgffrjsvydlcnmibdxz@forum.dlang.org

### 妥協してstructに代入してみる

自前のstructはnatvisをマッチさせることができたので以下のようなヘルパーを書いてみた。

```d
struct SliceView(T)
{
	T* ptr;
	ulong size;

	this(T[] src)
	{
		ptr = src.ptr;
		size = src.length;
	}
}

SliceView!T makeView(T)(T[] slice)
{
	return SliceView!T(slice);
}
```

```xml:d.natvis
    <Type Name="app.SliceView">
        <DisplayString>{{size = {size}}}</DisplayString>
        <Expand>
            <Item Name="[size]">size</Item>
            <ArrayItems>
                <Size>size</Size>
                <ValuePointer>ptr</ValuePointer>
            </ArrayItems>
        </Expand>
    </Type>
```

![array.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59664/878f52cd-d798-7147-1be1-44d35ed97aa0.jpeg)

デバッグプリントするよりはいいんでないか。

## DMDを改造したらarrayをデバッグ表示できるようになった

https://forum.dlang.org/post/urgffrjsvydlcnmibdxz@forum.dlang.org

の記事の通りにやるだけ。
話が立ち消えになっているような気がするが、
pull request 出さなかったんだろうか。
もったいない。

### clone する

* https://github.com/dlang/dmd

### コードを修正する

```d:src/dmd/hdrgen.d
    void visitDArray(TypeDArray t)
    {
        Type ut = t.castMod(0);
        if (hgs.declstring)
            goto L1;
        if (ut.equals(Type.tstring))
            buf.writestring("string");
        else if (ut.equals(Type.twstring))
            buf.writestring("wstring");
        else if (ut.equals(Type.tdstring))
            buf.writestring("dstring");
        else
        {
        L1:
            buf.writestring("__dlang::__darray<"); // ここから
            visitWithMask(t.next, t.mod, buf, hgs);
            //buf.writestring("[]");
            buf.writestring(">"); // ここまで。
        }
    }
```

`T[]` から `__dlang::__darray<T>` という `C++` で合法的な名前に変えてあげるのがよいらしい。

`T` は `const(char)` とかになり得るみたいなので、もう少し改造が要るかもしれない(Natvisが丸かっこを許すかよくわからない)。

### build する

`src\vcbuild\dmd.sln`

を開いてビルドするだけ。
コンパイラなのですごい時間かかるかと思いきや、わりとすぐに終わる。

### exe を dub から呼べるようにする。

ビルドされた

`generated\windows\release\64\dmd.exe`

をPATHを通すなり、

`C:\D\dmd2\windows\bin\dmd.exe`

にコピーするなり(元のファイルはバックアップ)する。

### natvis 

```xml:改造版のarrayにマッチするnatvis
    <Type Name="__dlang::__darray&lt;*&gt;">
        <DisplayString>{{size = {length}}}</DisplayString>
        <Expand>
            <Item Name="[size]">length</Item>
            <ArrayItems>
                <Size>length</Size>
                <ValuePointer>ptr</ValuePointer>
            </ArrayItems>
        </Expand>
    </Type>
```

### 試しに使ってみた

![gltf_natvis.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59664/6969fabf-42fe-7764-316b-53c5af0ad98d.jpeg)

`gltf.meshes[0].primitives[0]` のようにネストしたコレクションの中にずんずん潜っていけてデバッグしやすい。
DMDの自前ビルドは簡単なので、WindowsでDするときはやってみるとよいかも。