ドキュメントの読みにくさが致命的nなGo!、nな Chrome Extentsion 的解法

「ドキュメントを読めない」のは誰のせいなのか。

何かしらの「説明」とか「解説」が提供される場合に、その「提供された説明」を「わかりやすく読む」のは読者の責任である。…なわけないよね。読む方にも努力はもちろん必要だけれど、その努力を是とすることが提供側の責任回避にはならない。読者の誰にとってもストレスとなるのならばそれは提供側の努力が足りない。…の、ワタシにとっては二大巨頭が Go 言語と ffmpeg の公式ドキュメントね。ほかにも読みにくいサイトは当然山ほどあれど、「量的に大きい」「状況によっては毎日参照する必要がある」の両方に当てはまるものは、ワタシにとってはこの二つだけ。

ffmpeg のがあるんでもちろん前から思っていたことではあるんだけれど、まぁまだ ffmpeg のは「少し疲れる」で済むんだよね、だけどさ、Go のはもう…、とにかく目に悪い。メチャクチャ疲れる。これはもう「毎日読むのに疲れないための、何らかの術が必要だ」と。

最初に考えたのは「ローカルにインストールした Go のインストールフォルダ内にある doc のスタイルシートを書き換えちゃおうか」だったのだが、ダメなんだわこれ。WEB に上がってるヤツは入ってないの。ので、https://go.dev にあがってるものをダウンロードしてしまうか、ダウンロードせずに直接読む際に使える手段を考える必要がある、てこった。ダウンロードするのは保守の手間がかかってしょーがないから却下。ゆえに「プライベートスタイルシート」て発想。

いくつか試した中で、Styler がいいかなと思った。これには StackExchange から辿り着いた。CSS を記述するためのサポートはシンタクスハイライトしかないので、いわゆる「熟練者向け」ということにはなるんだろうけれど、まぁワタシにはこれで十分。

にしてもさ、この「オレだけのための CSS」って、CSS が最初に提案された時から「ブラウザに組み込まれていて欲しい」というものだったはずなんだけれど、どうにもうまくいってないんだよね。Chrome の場合昔は「custom.css」を使えたのだけれど、今はこれはサポート対象外になった。なんでなんだろうか…。こういう、提供側と受け取り側のミスマッチというのは、こういう単なるスキル不足みたいなものだけじゃなくて、例えば「アクセシビリティ」に関するものがあるはずなんだよね、例えば極度の近視の人がフォントサイズを巨大にしなければ読めないとして、提供者側がその考慮を欠いているなら、こういうカスタムスタイルシートで対応するしかないわけ。なんでこういう非常に基礎的なところの整理が進まないのか、ずっと昔から不思議なんだよな。ずっと昔って、CSS 黎明の日から、だからね、もう20年くらいになるぞ、さすがにちょっといい加減にしろよ、て気分よ。


2022-03-23(トピック違いだけどの)追記:
「Chrome Extension」の話ではなくて「読みにきーんだよ」だけに対するのほーの話。

「ローカルにダウンロードして、そやつを読みやすくする」とまでやりたくなっちゃうのは、「CSS だけで」のアプローチでは Syntax Highlighting まではまかなえないからね。Sphinx 化したいじゃねーか、て話。これが「非現実的」だったとしてもこうやって書くネタにならんし、「誰でもできーる」ならそれでもネタにならんけれど、まさに「丁度いいあんばい」だったんでね。

要約するとめっちゃ簡単な話で、「pandoc の助けを借りて rst にする」なんだけれど、「一癖以上あった」の。でも解決となった最終形は簡単:

 1 # -*- coding: utf-8 -*-
 2 import io
 3 import re
 4 import urllib.request
 5 import shutil
 6 import subprocess
 7 
 8 import bs4
 9 
10 
11 def _download(pn):
12     cont, msg = urllib.request.urlretrieve("https://go.dev/doc/" + pn)
13     shutil.move(cont, pn)
14     return io.open(pn, encoding="utf-8").read()
15 
16 
17 def _simplify(cont):
18     cont = cont.replace("\t", 4 * " ")
19     cont = re.sub(r"</?(main|article)(?: [^<>]+)?>", "", cont)
20     cont = re.sub(r'<a href="/', r'<a href="https://go.dev/', cont)
21     soup = bs4.BeautifulSoup(cont, features="lxml")
22     for t, m in (
23             ("noscript", {}),
24             ("aside", {}),
25             ("header", {}),
26             ("footer", {}),
27             ("script", {}),
28             ("nav", {}),
29             ("head", {}),
30 
31             ("div", {"class": "TOC"}),
32             ("div", {"class": "js-scrim"}),
33     ):
34         for e in soup.find_all(t, m):
35             e.decompose()
36     return str(soup)
37 
38 
39 if __name__ == '__main__':
40     pn = "effective_go"
41     cont = _simplify(_download(pn))
42     with io.open(pn, "w", encoding="utf-8", newline="\n") as fo:
43         fo.write(cont)
44     subprocess.check_call(["pandoc", "-f", "html", pn, "-o", pn + ".md"])
45     subprocess.check_call(["pandoc", pn + ".md", "-o", pn + ".rst"])
46     cont = io.open(pn + ".rst", encoding="utf-8").read()
47     cont = re.sub(r"^::$", ".. code-block:: go", cont, flags=re.M)
48     with io.open(pn + ".rst", "w", encoding="utf-8", newline="\n") as fo:
49         fo.write(cont)

まず、pandoc が結構真面目に「いらんもの」を忠実にマッピングしようとしてしまうので、aside だのなんだのをゴリゴリ取り除いてる。そして、pandoc なのだが、直接 html から rst に変換しようとするとなぜかヘディングのレベルを全無視してしまうという謎仕様ね。markdown を経由すると維持される。これは設計と違うことしてるぞ。AST はどうした AST は。ともあれ、これで「およそ95点くらいの rst」に変換出来る。何か所かリンクが壊れてるのを確認したのと、「.. code-block:: go」にしちゃダメなところも問答無用で変換してるんで、そこは当然オカシイ。でもまぁそのくらい、手で直せばいいじゃん、て思う。

この作った rst を Sphinx プロジェクトに仕立て上げるのはそれなりの手間だけれど、まぁそこまでまかなうスクリプトにしちゃうのがほんとはいいんだろうねぇ。ともあれ Sphinx で処理した例 → effective_go_doc.zip