VSCodeのMarkdownでGitHubのcommit detailsみたいなやつをやりたいけどコードの色は消したくない

# 背景
Markdownでコードを書く上で，便利な機能が二つあります．
まず一つは，コードブロックを書く機能．

\`\`\`c
#include <stdio.h>

int main() {
    printf("hello, world!!\n");
}
\`\`\`

```c
#include <stdio.h>

int main() {
    printf("hello, world!!\n");
}
```

もう一つは，GitHubのcommit detailsのように，変更部分を分かりやすく表記するもの．

\`\`\`diff_c
#include <stdio.h>

int main() {
\-    printf("hello, world!!");
\+    printf("hello, world!!\n");
}
\`\`\`

```diff_c
#include <stdio.h>

int main() {
-    printf("hello, world!!");
+    printf("hello, world!!\n");
}
```

しかしVSCodeの拡張機能によるMarkdownでは，`diff_c`のようなものがサポートされておらず，変更部分を強調するなら以下のように`int`や`main`の色を変えることができません．~~ついでに言うと背景色もないです．~~

\`\`\`diff
#include <stdio.h>

int main() {
\-    printf("hello, world!!");
\+    printf("hello, world!!\n");
}
\`\`\`

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1925706/4c8b466f-d866-9a3c-45ca-e16325d007d1.png)

一方，コードとして見やすい表示を選択すると，今度は変更部分が強調されず分かりづらいです．

\`\`\`c
#include <stdio.h>

int main() {
\-    printf("hello, world!!");
\+    printf("hello, world!!\n");
}
\`\`\`

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1925706/51a00cad-f5ca-2f38-625a-69a97b3a38a7.png)

そこで，JavaScriptとCSSを使うことでVSCodeのMarkdownでもコードの変更部分と予約語に着色したpdf出力を得ることを考えました．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1925706/b9ecf871-f413-1027-9da6-ad5d57f30dae.png)

# 本論
## リバースエンジニアリング
まず，以下のソースコードをVSCodeのMarkdownでHTML化しました．

\`\`\`diff
-import numpy
+import numpy as np
\`\`\`

そうして得られたHTMLコードの，関係ある部分を抜粋すると以下のようになっていました．

```html
<style>
.hljs-deletion {
	color: #c82829;
}

.hljs-addition {
	color: #718c00;
}
</style>

<pre class="hljs"><code><div><span class="hljs-deletion">-import numpy</span>
<span class="hljs-addition">+import numpy as np</span>
</div></code></pre>
```

追加部分は`hljs-additoin`クラスに，削除部分は`hljs-deletion`クラスに属させることでそれぞれ装飾しているようです．

そこでここでは，

\`\`\`c
#include <stdio.h>

int main() {
\-    printf("hello, world!!");
\+    printf("hello, world!!\n");
}
\`\`\`

という普通のコード表記に`+`や`-`を入れ，この`+`や`-`に`hljs-additoin`クラスなどを付けることで，`int`や`main`，そして追加・削除部分の全てに着色することにしました．

## JavaScriptコード
Markdownコードから`+`と`-`を読み取り，それぞれ`<span class='hljs-addition'>+</span>`，`<span class='hljs-deletion'>-</span>`に書き換えます．

```js
// Markdownファイルの最後に実行
// +や-を上書き
// ただし，プログラム中の普通の足し算や引き算に影響がないよう，改行直後の+-のみを変更
const pmChange = () => {
    var codes = document.getElementsByTagName("code");

    for (let i = 0; i < codes.length; i++) {
        var c = codes.item(i).getElementsByTagName("div").item(0);

        var cs = c.innerHTML.split("\n+");
        for (let j = 0; j < cs.length-1; j++) {
            c.innerHTML = c.innerHTML.replace(
                "\n+",
                "\n<span class='hljs-addition'>+</span>"
            );
        }
        cs = c.innerHTML.split("\n-");
        for (let j = 0; j < cs.length-1; j++) {
            c.innerHTML = c.innerHTML.replace(
                "\n-",
                "\n<span class='hljs-deletion'>-</span>"
            );
        }
    }
};
```

## CSS
VSCodeのMarkdownでは，削除・追加部分の文字色は変わっていましたが背景色までは変わっていませんでした．
ここでは背景色も変えることにします．

```css
/* 透明度の定義 */
body {
    --opacity: 0.2;
}

/* 背景色 */
span.hljs-addition::before,
span.hljs-deletion::before {
    position: absolute;
    max-width: 100%;
    content:
        "                    "
        "                    "
        "                    "
        "                    ";  /* 80文字の空白 */
}
span.hljs-addition::before {
    background-color: rgba(124, 252, 0, var(--opacity));
}
span.hljs-deletion::before {
    background-color: rgba(255, 99, 71, var(--opacity));
}

/* 文字色 */
span.hljs-addition {
    color: #718c00;
}
span.hljs-deletion {
    color: #c82829;
}
```

# 結果
無事，見やすく表示されました！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1925706/b9ecf871-f413-1027-9da6-ad5d57f30dae.png)

# コード全部
表記の都合上，コードブロックの「\`\`\`」の前にバックスラッシュを入れています．
コピペするときは，貼り付けた後にバックスラッシュを削除してください．

```html
<style>
/* 透明度の定義 */
body {
    --opacity: 0.2;
}

/* 背景色 */
span.hljs-addition::before,
span.hljs-deletion::before {
    position: absolute;
    max-width: 100%;
    content:
        "                    "
        "                    "
        "                    "
        "                    ";  /* 80文字の空白 */
}
span.hljs-addition::before {
    background-color: rgba(124, 252, 0, var(--opacity));
}
span.hljs-deletion::before {
    background-color: rgba(255, 99, 71, var(--opacity));
}

/* 文字色 */
span.hljs-addition {
    color: #718c00;
}
span.hljs-deletion {
    color: #c82829;
}
</style>

\```c
#include <stdio.h>

int main() {
-    printf("hello, world!!");
+    printf("hello, world!!\n");
}
\```

<script>
// Markdownファイルの最後に実行
// +や-を上書き
// ただし，プログラム中の普通の足し算や引き算に影響がないよう，改行直後の+-のみを変更
const pmChange = () => {
    document.write("abc\ndef<br>");
    var codes = document.getElementsByTagName("code");

    for (let i = 0; i < codes.length; i++) {
        var c = codes.item(i).getElementsByTagName("div").item(0);

        var cs = c.innerHTML.split("\n+");
        for (let j = 0; j < cs.length-1; j++) {
            c.innerHTML = c.innerHTML.replace(
                "\n+",
                "\n<span class='hljs-addition'>+</span>"
            );
        }
        cs = c.innerHTML.split("\n-");
        for (let j = 0; j < cs.length-1; j++) {
            c.innerHTML = c.innerHTML.replace(
                "\n-",
                "\n<span class='hljs-deletion'>-</span>"
            );
        }
    }
};
pmChange();
</script>
```