blog.anqou.net
rss
author
tags

cmark-gfm で east asian line break する

blog.anqou.net では、Markdown で書かれた記事を HTML に変換するために cmark-gfm を使っています。これは CommonMark という Markdown の方言のリファレンス実装である cmark を GitHub がフォークしたもので、GitHub Flavored Markdown (GFM) をサポートしており、オリジナルの cmark に注釈(footnotes)やオートリンクのサポートが拡張として入っています。注釈をつけまくる記事をよく書く自分[1]としては注釈がないとブログ記事なんて書けないので、たいへん助かっています。

さてそんな便利な cmark-gfm ですが、残念ながら east asian line break のサポートがありません[2]。East asian line break とは[3]、次のような段落を Markdown で書いたときに:

あ
い

次のような HTML ではなく

<p>あ い</p>

次のような HTML を出力してくれる機能のことです:

<p>あい</p>

HTML 上で「あ」と「い」の間に改行が挟まると、ブラウザによっては[4]半角スペースを入れてしまい あ い のように表示されてしまいます。そこで、Markdown 上での改行(soft break)前後の文字が日本語などの east asian な文字の場合には、改行を省いた HTML にしてしまうことで、余計な空白が入ることを防ぎます。 (u)pLaTeX に慣れきってしまった身としては、段落は適当に改行を入れながら書きたいので、この仕組みは必須です。

Pandoc では、この機能は east_asian_line_breaks 拡張として実装されています。そのため cmark-gfm ではなく Pandoc を使えば解決……なのですが、 SSG として使っている Soupault のシンタックスハイライトの仕組みと Pandoc は相性が悪いので、残念ながら使えません。

#cmark-gfm を改造する

ということで cmark-gfm をフォークして、east asian line break をサポートするためのパッチを書いてみました。実装は例によって GitHub に上げてあります

cmark-gfm を改造するにあたって、まず Pandoc の実装を見てみました。 Pandoc では、この機能は soft break の前後の文字の幅が 2 であれば、その soft break を削除するという形で実装されています。文字の幅は Unicode であれば East Asian Width というものが定義されているので、これを使えば良さそうです。

まず East Asian Width の定義から文字幅を判定する関数を適当なシェルスクリプトで生成します:

curl http://www.unicode.org/Public/UCD/latest/ucd/EastAsianWidth.txt > EastAsianWidth.txt

echo -e "A\nF\nH\nN\nNa\nW" | while read PROPERTY; do
  cat EastAsianWidth.txt | \
  egrep -v "^#" | \
  sed -r 's/^([0-9A-F]+)(\.\.([0-9A-F]+))? +; ([^ ]+).*$/\1 \3 \4/' | \
  awk -F' ' "$(echo '
BEGIN { print "if (" }
$1 != "" && $2 == "XXX" && $3 == "" { print "uc == 0x" $1 " || " }
$1 != "" && $2 != "" && $3 == "XXX" { print "(0x" $1 " <= uc && uc <= 0x" $2 ") ||" }
END { print "false) { return XXX; }" }
' | sed "s/XXX/$PROPERTY/g")"
done > foo

このスクリプトの出力を適当に整形すると C の関数ができあがります。あとは cmark-gfm が HTML を生成しているところに手を入れて、soft break の出力の際に前後の文字の East Asian Width を調べ、両方ともが全角っぽければ[5]改行を出力しないようにすれば完成です。詳細はコードを見てください。

ということで、この改造版 cmark-gfm で blog.anqou.net 配下の記事は生成しなおしたので、変なところに改行が入らなくなっているはずです。よかったよかった。

#ちなみに

この作り方だと HTML を生成する際にしか east asian line break できません。 cmark・cmark-gfm コマンドは HTML の他に LaTeX コードなどの生成にも対応しているので、そういう生成器を使いたい場合には困ることになります。

このようなときに便利なのが、cmark-gfm に追加された、処理系拡張のための API です。cmark と異なり cmark-gfm では拡張を作るための一般的な仕組みが追加されており、これを使うことで CommonMark の AST に手を入れることができます[6]。この仕組みで east asian line break をサポートすれば、HTML 以外を出力する場合でも対応できるはずです。ただし今回は HTML だけのサポートで十分だったので手を抜いていて、それはやっていません。誰かやってください。

#注釈

  1. 中学の頃に読んだラクダ本の影響だと思います。多分。

  2. オリジナルの cmark にももちろんありません。

  3. この機能を指すのに“east asian line break” という名前が正しいのかは正直よく知りませんが、後述する Pandoc の拡張がこういう名前になっているのでこの記事ではその名前で通しています。

  4. 自分が把握している限りでは Google Chrome がそうです。逆に Firefox は入れません。

  5. とりあえず現状は、特性が Na, N, H 以外のものを全角ということにしています。

  6. 実体は extensions/ ディレクトリ配下にあります。詳細はあまり追いかけていないのですが、おそらくこの PR で本家 cmark に提案されたものが cmark-gfm ではマージされている気がします。