Markdown/CommonMark 探訪(3):段落の割り込み

今日は Sphinx-users.jp の総会に行ってきました。
今年はとくになにも特別な活動をしない会長さんだったので、やや後ろめたい部分があったのですが、それもこれでおさらばです。
あたらしい会長の @usaturn 氏に頑張ってもらえれば、と思います。

さて、そんな感じで書き始めるのは第三夜でございます。
今日は小ネタで段落の割り込みについて紹介します。

CommonMark では記法ごとに段落に割り込むことができるかどうかが決まっています。
たとえば、themantic breaks は段落に割り込めます。

Foo
***
bar

これは foo, <hr />, bar と解釈されるわけですね。

一方でインデントされたコードブロック(Indented Code Blocks)は段落に割り込むことができません。

Foo
    bar

これは Foo bar というひとつの段落として扱われます。

このあたりは直感的のような、そうでないような、ちょっとむずかしいところですね。

それでは、この段落の割り込みまわりで、おや? とおもう例を紹介していきます。

HTML タグ

昨日も触れましたが、HTML はタグによって動作が変わります。
ブロック要素系のタグは段落に割り込むことができますが、インライン系のタグは割り込めません。

つまり

Foo
<div>
bar
</div>

はふたつのブロック (Foo という段落と <div> 以降の HTML ブロック) と解釈されますが、

Foo
<a href="bar">
baz

はひとつの段落にインライン HTML 要素があると解釈されます。

ここの解釈によって、強調やリンクなどのインライン要素の展開結果が異なるのですが、タグによって動作が違うというのは覚えづらいですね。Markdown マスターを目指す方は要注意です。

番号付きリスト

もうひとつは CommonMark のおかしなルールです。

The number of windows in my house is
14.  The number of doors is 6.

はひとつの段落として解釈されるのですが、なんと

The number of windows in my house is
1.  The number of doors is 6.

は 1行目は段落、2行目は番号付きリストとして解釈されます。

1番からはじまる番号付きリストは、段落に割り込むことができる要素なのです。
これが 2番から始まる場合は段落の割り込みが発生せず、段落が続いているものと解釈されます。

行の折り返しのあとに 1. や 1) からはじまる文章がある場合は注意が必要です。

themantic breaks の例外

Themantic breaks が段落の割り込みを発生させることは先ほど紹介しましたが、じつは特定の記号を使うと解釈結果が変化します。

Foo
---
bar

上記の例のように区切り文字に === や --- を使った場合、段落の割り込みは発生しないのですが、解釈結果が変化します。
前半のパートは段落ではなく、見出し (setext headings) として扱われます。
HTML で書くと <h2>Foo</h2><p>bar</p> となり、見出し(Foo)につづく本文(bar)とみなされます。

割り込みとは少しちがうのですが、 themantic breaks を間に入れようとしたときは、この点に注意が必要です。

訂正(12/10):=== は themantic breaks ではありません。--- だけでした。

おまけ:箇条書き

段落ではないですが、箇条書きでも割り込み的な例外処理があります。
それが themantic breaks の解釈です。

* Foo
* * *
* Bar

という記述があると、CommonMark パーサは箇条書き(Foo)、Themantic breaks (区切り線)、箇条書き(Bar) の 3つのパーツとみなします。

これが、別の箇条書き記号を使っていると解釈が変わります。

- Foo
- * *
- Bar

この場合、3項目のリストがあって、2番目の項目は空のリストを持っていると解釈します。

説明されると理解できるのですが、このリストの割り込みは微妙な挙動でした。
pycmark でも実装を進める中で、最後の方にこの問題が見つかって、がっかりしながら修正することになりました orz

Markdown/CommonMark 探訪(2):HTML

Markdown/CommonMark の不思議な仕様を紹介していくこのシリーズ、第二回は HTML Blocks です*1

Markdown には 2種類の HTML 要素があります。ひとつはブロック要素、もうひとつはインライン要素です。
HTML ブロックは、HTML のブロックレベルの要素をそのまま Markdown で扱うためのものです。マークアップされたものはその名の通りブロック要素として扱われます。

<table><tr><td>
this is table!
</td></tr></table>

もうひとつのインライン要素は、段落やリスト、表の中など、任意の箇所で HTML を使えます。

This is a <em>markdown</em> world!

これらの例を見ると HTML 記法は比較的シンプルなものに見えます。では、これはどう解釈されるのでしょうか。ブロック要素?インライン要素?

<h1>hello markdown!</h1>

それでは、これは?

<pre>
A example a PRE tag which is not closed...

最後にもうひとつ。これは?

<em>
A example an EM tag which is not closed...

じつは 3つともブロック要素として解釈されます。
ルールを追っていくと、それぞれ以下の理由でブロック要素として判定されます。

  • <h1> タグから始まる行はブロック要素として扱われる
  • <pre> タグから始まる行もブロック要素として扱われる
  • <em> タグは本来ブロック要素ではないが、開始タグ単体で登場した場合はブロック要素

一方で、以下のようなケースはインライン要素として扱われます。

hello <h1>markdown!</h1>!

# ブロックレベルのタグであっても、行頭でなければインライン扱い
<em> A example an EM tag which is not closed...

# 開始タグと同じ行に記述があるので、インライン扱い

CommonMark のルールに従うと、ちょっとしたマークアップの違いで HTML タグはブロック要素として扱われたり、インライン要素として扱われたりと、解釈がかんたんに変わります。

最後におだいをひとつ残して、今日は終わりにしようと思います。

<del>*em*</del>
<del>
*em*
</del>
<del>

*em*

</del>

それぞれ、どんな風にレンダリングされるのかちょっと考えてみてください。
ちなみに答えはここ(
commonmark.js demo )から確認できるようにしておきました。

*1:思いつきで書き始めたので、ネタが尽きるまで書いていこうと思います

Markdown/CommonMark 探訪(1):laziness

Markdown パーサを書くにあたってちょっと苦労したのが Laziness という考え方です。

Markdown では、引用ブロック (blockquotes) を書く際、引用符を付けるのは最初の行だけでよいと定められています。

> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.

> Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
id sem consectetuer libero luctus adipiscing.

https://daringfireball.net/projects/markdown/syntax#blockquote

引用符がある行から段落が終わるまでは、すべて引用ブロックの中の段落として扱われます。
たしかにこれは書きやすいだろうし、読めなくはないので、記法として理解できます。

しかし、さまざまな実装の共通項を探る CommonMark では、こんな風に整理されています。

>>> foo
> bar
>>baz

http://spec.commonmark.org/0.28/#example-214

このテキストを処理系に渡すと、3重にネストされた引用ブロックの中に「foo, bar, baz という 3行の段落」がある、と解釈されます。
えっ。
テキストとしての見た目と、あまりに違う解釈結果ですね。

laziness はリストでも有効

この laziness の考え方はリストでも適用されています。

*   Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
viverra nec, fringilla in, laoreet vitae, risus.
*   Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
Suspendisse id sem consectetuer libero luctus adipiscing.

印刷物とかでもこういうレイアウトが使われていることもあり、理解はできます。

では、こちらはどうでしょう。

> 1. > Blockquote
> continued here.

http://spec.commonmark.org/0.28/#example-256

2行目の「continued here」は内側の引用ブロックの内部の段落の一部です。
えっ。
またですか。

laziness の範囲

徐々に Markdown の世界観がつかめてきましたか? それではこれはどうでしょう。

> - foo
- bar

引用ブロックの中に箇条書きが記述されていますね。
さて、これはどう解釈されるのでしょうか。

実はこれは

  • 「foo」は引用ブロックの内側のリストとして扱われる
  • 「bar」は引用ブロックの外側の (別の) リストとして扱われる

と解釈されます。

というのは、laziness が適用される対象は「段落」だけです。その他の記法には laziness は適用されません。
楽しいですね。

面倒くさい例としては

> lorem ipsum
> ---

は引用ブロックの中に <h2> の見出しが記述されると判定されるのに対して

> lorem ipsum
---

は引用ブロックの後ろに区切り線 (themantic break) がある、と解釈されるものがあります。

pycmark ではどうしているのか

段落用のプロセッサーで、次のような処理をしています。
1. 同じインデントレベル (引用符やリストアイテムなどのレベル) の中で読み進める
2. その状態で空行や区切り線などの割り込み要素がきた場合は、段落の処理は終了
3. インデントレベルの最後まで段落が続いた場合は、LazyLineReader という laziness に対応した読み込みモジュールを使って読み進める
4. 割り込み要素が来るまで、段落の一部として解釈を続ける


ということで、pycmark でも無事に laziness な段落は正しく扱えます。
多用すると読みづらくなりそうですが、つかってみてください。

Re: SphinxCon JP 2017

38度の熱が出たので、楽しみにしていた SphinxCon JP 2017 を休むことになってしまいました。
おかげで、Sphinx の魔改造の話HTML テンプレートへの提案など、興味深い発表を聞きそびれてしまったのは非常に残念です。
資料は公開されているので、それぞれ噛み締めながら何度か読み返そうと思っています。

さて、今回の SphinxCon では僕はトーク枠を持っていなかったのですが、実はイベントに合わせて作っていたものがあります。
LT でお披露目しようかと思っていたのですが、間に合わなかった上に風邪でダウンしてしまったので、代わりにここで紹介しようと思います。
作ったのは pycmark というパッケージです。
github.com

まだ README すら置いていないので、なにものかがわかりづらいのですが、docutils 向けの CommonMark パーサです*1
現状では、ひととおりの記法をサポートしているので、触ってもらえるレベルにはなったかと思います。
TAB やコントロール文字類、特殊文字類の対応が済んでいないので、もう少し開発を続けるつもりです。
もう少し進めて一段落したら、一度リリースするつもりです。

使ってみる

未リリースなので、リポジトリから直接入れます。

$ pip install git+https://github.com/tk0miya/pycmark

ちなみに Python3.x 専用です。いまのところ 3.6 でしか動作確認していません。
いまのところ遡ってサポートする気はないので、使いたい人は Python のバージョンを上げてください。

Sphinx 拡張としての作り込みはしていない*2ので、conf.py に setup 関数を書き足し、直接 pycmark を有効にします。

html_experimental_html5_writer = True


def setup(app):
    from pycmark import CommonMarkParser
    app.add_source_parser('.md', CommonMarkParser)

ついでに、HTML5 writer を有効にしておきます。標準で利用される HTML4 writer では正しく動作しません。

設定はこれで完了です。あとは .md ファイルを置いて、ビルドするだけです。

pycmark のゴール

さて、Sphinx では recommonmark が CommonMark パーサとして知られています。
それなのに、敢えて新しい CommonMark パーサを開発したのはわけがあります。

recommonmark がベースにしている CommonMark-py はコア部分がモノリシックなモジュールとして実装されています。これはシンプルで正しい設計なのですが、残念ながら拡張性がありません。
CommonMark の生まれた経緯などを考えると、パーサは拡張可能である必要はないのです。しかし、実際には gfm 然り、kibe.la 然り、新し目の Markdown の派生言語は CommonMark をベースとしています。つまり、これらのパーサを用意するには CommonMark パーサをさらに拡張する必要があります。こうしたときに CommonMark-py では都合が悪いのです。

pycmark はプラガブルな構造になっており、個々の記法を個別に無効化したり、新たな記法を追加できます。
現時点では、CommonMark の範囲の実装しか提供していませんが、いずれ gfm などのよく使われている記法のプラグインを用意する予定です。

まとめ

pycmark という CommonMark パーサを作っています。
現在の pycmark CommonMark パーサとしてはおおよそ完成しているものの、未熟なところが多くまだ使用に耐えません。
しかし、いずれは gfm などの記法も解釈できる CommonMark サブセットパーサにまで実装を進める予定です。

そこまでたどり着くと、これまでの markdown 資産が活かせ、Sphinx が使える範囲が更に広まるのではないかと考えています。

はてさて、これが夢物語で終わるのか、ちゃんと実装が完了するのかはお楽しみにお待ちください。
なお、pycmark はいつでもバグレポートと PR をお待ちしております :-)

ひとまずファーストリリースを近いうちに (年内に?) やりたいところですね。

*1:Python の CommonMark パーサだから pycmark です。いい名前が思いつかなければ、このままリリースされます。

*2:現時点では、あくまで docutils の parser モジュールとしてだけ動きます

「Sphinxをはじめよう 第二版」が出ます

みなさん、Sphinx 使ってますか? PythonLinux カーネルのドキュメントでご存知の Sphinx の書籍、「Sphinxをはじめよう」が改訂されます。




計画当初は 2章だけ加筆して、残りは微調整するだけだったはずなのですが、第一版を読み直して手直ししているうちに、1章と2章は大幅に書き換えることになりました。基本的な内容は同じですが、図を入れたり説明を整理するなどしたので、旧版より読みやすさが上がっているはずです。

目次はこんな感じです。「6章 画像の変換と埋め込み」と「付録 C sphinx-quickstart の設問一覧」、「付録 E Windows への make コマンドと sh コマンドのインストール」、「付録 F Markdown で書いてみよう」あたりが新しい内容です。

  • はじめに
  • 1章 Sphinx とは
    • 1.1 Sphinx を何に使うのか
    • 1.2 Sphinx の用語と特徴
    • 1.3 Sphinx と比較されるツール
    • 1.4 まとめ
  • 2章 Sphinx のインストール
    • 2.1 Windows 環境へのインストール
    • 2.2 macOS 環境へのインストール
    • 2.3 Linux 環境へのインストール
    • 2.4 まとめ
  • 3章 議事録を書いてみよう(HTML への変換)
    • 3.1 Sphinx によるドキュメント作成の流れ
    • 3.2 プロジェクトの作成
    • 3.3 議事録を書こう
    • 3.4 HTML テーマを使おう
    • 3.5 まとめ
  • 4章 PDF に変換してみよう
    • 4.1 インストール手順書を書いてみよう
    • 4.2 いくつかのパートに分けて文章を書く
    • 4.3 まとめ
  • 5章 EPUB に変換してみよう
    • 5.1 画像を埋め込む
    • 5.2 他のページを参照する
    • 5.3 EPUB に変換する
    • 5.4 書籍の出力オプションを設定する
    • 5.5 まとめ
  • 6章 画像の変換と埋め込み
    • 6.1 基本中の基本、figure ディレクティブ
    • 6.2 Cacoo を利用する
    • 6.3 まとめ
  • おわりに
  • 付録
    • 付録 A reStructuredText リファレンス
    • 付録 B Sphinx が使える出力形式
    • 付録 C sphinx-quickstart の設問一覧
    • 付録 D TeX Live/MacTeX のインストール
    • 付録 E Windows への make コマンドと sh コマンドのインストール
    • 付録 F Markdown で書いてみよう
    • 付録 G Sphinx のコミュニティ(Sphinx-users.jp)

基本的には初心者向けの本ですので、これから Sphinx を使ってみたいという人向けの本ですが、
既に使っているという人でも、まわりに reST/Sphinx を布教するときの役に立つかと思います。

僕のこの夏の努力の結晶なので、興味がある方は是非とも見ていただけるとありがたいです。

2016年を振り返る / 2017年の抱負

あけましておめでとうございます。正月なので、毎年恒例の抱負エントリです。
年末にがーっと連続エントリを投稿したのでもう大体振り返り終わったんじゃないのか、とは思うのですが、それはそれ、これはこれということで振り返っていきます。

2016年の抱負 として挙げたのは

  • Sphinx のバグ/タスクを減らす
  • blockdiag のバグ/タスクを減らす
  • なにか使えるツールをリリースする (少なくとも一本以上)
  • 技術書を読み続ける
  • コードを書く時間を維持する
  • 体重維持

の6個でした。

まずはそれぞれについて振り返っていきます。

Sphinx のバグ/タスクを減らす:△

メンテナ活動をがつがつしていたので、さぞかしバグが減ったでのでしょう? と思ったのですが、減る勢いより増える勢いのほうが強くて押し切られました。元旦時点で 606件のイシュー + PR があります。
ほぼ安定して月に 60件(日に2件)以上のペースで減らし続けているはずなのですが、それでも追いつけないというのは非常に厳しいですね。

ちなみに2016年最初のイシューは #2207 で、最後のイシューが #3299。その数なんと 1,092本でした。

blockdiag のバグ/タスクを減らす:✕

Sphinx に空き時間をすべてつぎ込んだたので、なにもやってませんね。
そろそろ諦めてきました。
いじりたい人がいないのであれば、そろそろ放棄ですかね…。

なにか使えるツールをリリースする (少なくとも一本以上):◯

2016年に新しく作ったのはこのあたり。

Sphinx の片手間に Sphinx 拡張を手がけるような人生だったようです。
ちょいネタが多めだったのですが、ちょっとは使ってもらえそうな拡張なので、◯評価にしてしまおうと思います。

技術書を読み続ける:◯

引き続き 2016年も 新宿 Book-a-thon に助けられました。
もうこのイベントなしには本は読み進まないであろうという確信があります。

結局読み切った本は The Web Explorer と Re:VIEW 本の 2冊だけです。
実践DDDと TeX by Topic は内容が難解で読み進めるのに苦労している(しかも途中で他の本を読み始めてしまった)ので、なかなか進みがよろしくないです。
また、今年は SoftwareDesign の連載があったので、そのレビューにかなり Book-a-thon の時間を使ってしまいました。

Re:VIEW本は非常に感銘を受けたので、いつか実践をしてみたいですね。

今年はちゃんと読書の時間を確保して、ちょこちょこ前に進んでいきたいところです。

コードを書く時間を維持する:◎

Sphinx メンテナ業をやっていたおかげで、これは胸を張って達成したといえます。
f:id:tk0miya:20170101142702p:plain
(仕事では github を使っていないので、この履歴はオープンな活動のみです)

大きい課題をやっつけているとき、ML の返事を書きまくる日、レビューしている日など、コミットばかりしているわけにもいかないので、毎日草を生やすことはできていませんが、結構安定して活動していたと思います。

これまでは活動している時期としていない時期がはっきりと分かれていて、全体ではまあまあぐらいの活動量だったので、ぐっと活動が見える人になったのではないでしょうか。

体重維持:◯

2015年末が 65.0kg で、先ほどはかってみたら 66.0kg でした。

グラフを見てると多少の揺れはあるものの、65〜66kg 前後で安定しているようです。
f:id:tk0miya:20170101142747p:plain
今の職場が駅徒歩 0分のところで、通勤の負荷がなくなったにもかかわらず、なんとかキープできてよかったです。

その他の振り返り

技術的な話となるとやはり Sphinx ネタが多くなるのですが、その他プライベートではちょこちょこ動きがありました。

備忘代わりに書き留めておきます。

体調が不安定だった

なんだか体調が安定しない年でした。

  • 頭痛とめまいに襲われて CTスキャンをしたり MRI を撮ったり (結局原因がわからないうちに落ち着いてしまった)
  • キーボードのタイプしすぎなのか、手首や肘にダメージを負っていたり (まだ続いている)
  • 検診でポリープが見つかったり (でも、病院に行ったら勘違いだとわかった)
  • 胸に違和感があったり (原因不明だけど、いまは落ち着いている)

どれも原因がはっきりしないうちに症状が落ち着いてしまったので、一時的な不調だったのかなーってことで済ませてしまっていますが、頭脳は子供でも体はもうすっかりおっさんだということがわかりました。

いまは肘以外はとくに悪くないので、ぼちぼちいたわって生きていきます。

旅行しまくった

マイルやふるさと納税で宿泊券をゲットしまくったので、あちこち旅行に行ってきました。

  • 高遠 & 飛騨方面
  • 浜松らへん (Ingress)
  • 鹿児島 (帰省)
  • 京都 (RubyKaigi, 弊社タイムインターメディアに支援してもらった)
  • 京都 + 高松/岡山 (Ingress)
  • 大垣 (Ingress)
  • 上高地
  • 秋田 (日本橋ヨヲコ先生の個展を見に行ってきた)

Ingress がきっかけで遊びに行くことが多かったようですね。
イベントそのものはあまり参加していないのですが、毎回あたりをウロウロしています。

また、趣味で埋めていっている道の駅探訪マップもちょっとずつ埋まってきました(青が2015年以前、緑が2016年、赤は未訪問)。
f:id:tk0miya:20170101143123p:plain
f:id:tk0miya:20170101143123p:plain
f:id:tk0miya:20170101144758p:plain

いろいろ行けてたのしかったものの、おかげでお財布の中がかなり寂しいことになってしまいました。
宿泊券やマイルを使っても、ガソリンは減っていくし、ご飯は食べますもんね…
今年は控えめに生きていくつもりです。いまのところは。

まとめ / 2017年の抱負

去年の抱負の成果は ○ 4つ、△ 1つ、× 1つでした。まあまあですね。

というわけで、さっくり今年の抱負。

  • ひきつづき Sphinx のメンテナ活動をする
    • もうしばらく、飽きるまではメンテナ活動しようと思います
    • あと 2.0 への道筋を決めていきたい
    • そういえば Sphinx-Users.jp の 2017年の会長に就任したので、ひきつづきなんかやります
  • Sphinx 以外のネタにも手を出す
    • Sphinx ばかりだとすぐに飽きてしまいそうなので、たまには別のことも織り込んで…
  • なにか使えるツールをリリースする (少なくとも一本以上)
    • いつもの。今年もなにかがんばりたい。
  • 技術書を読み続ける。時間を取る。
    • 引き続き。ただし、今年はやや時間が確保できなかったので、今年は回復を目指すつもり。
  • 家の片付け
    • メンテナに時間を注ぎすぎて、身の回りがすこし荒れているので、なんとかしたい
  • 健康生活
    • 言わずもがな。

Sphinx in 2016

昨日は Markdown の 2016年を振り返りましたが、今日は Sphinx の 2016年を振り返りつつ、
2017年の目標を適当に挙げてみようと思います。

2つのメジャーリリースと 13のマイナーリリース

今年は 1.3.4 から 1.5.1 まで、合計で 15のリリースを行いました。
2014年が 1.2.1 から 1.2.3 までの 3リリース、2015年が 1.3 から 1.3.3 までの 4リリースだったとの比較すると、コンスタントに改善を続けられたと感じています。

もうひとりのメンテナである清水川氏と相談し、Sphinx ではリリースポリシーを刷新しました。
おおよそ 1ヶ月おきに 1回のバグフィックスリリース、6〜8ヶ月おきに 1回のメジャーリリースを行うつもりで進めています。
少し前の記事にある通り、メンテナのリソースも十分にあるというわけではないので、あくまで目標でしかありませんが、今年は無事にこの間隔が守れました。

次のメジャーリリースは夏頃に予定されている 1.6 です。
まだ具体的に動き出してはいないですが、API の整理やいくつかのあたらしい機能が実装される予定です。
いまだに手が出せていない HTML5 サポートや TeX まわりの改良など、やりたいことはいくつもあるので、その中からピックアップしながら作業を進める予定です。

Sphinx メンテナチーム

少し前に記事にしたとおり、2016年は活発的に活動するメンテナが増えました。

2015年末に自分が復帰したのは、チケットの消化にはかなり大きな変化があったと自負しています。
2015年には 350件ぐらいしかクローズできていなかったものが、2016年は1000件以上クローズできています。
先程触れたリリースの件と合わせ、テンポよくメンテナンスが行われるようになっています。

また、TeX 使いの jfbu が加入したのはメンテナチームにとってかなり大きい変化です。
これまで TeX に強いメンバーがいなかったので、おっかなびっくり修正したり、もしくは問題が放置されていたりと、結構ひどい状態だったのですが、かなり改善がありました。
1.5 系ではその恩恵をかなり得られるはずです。
引き続き、彼と一緒に TeX まわりの改善を続けていこうと思っています。
いつか TeX 出力でもテーマ的なものが実現できるといいですね。

Sphinx の各種イベント

2016年も安定して Sphinx+翻訳 Hack-a-thon と Sphinx Tea Night が開催されていました。
ふたつのイベントは引き続き、毎月開催され続ける予定です。

一方、SphinxCon は開催されませんでした。ちょっとタイミングが合わなかったので、2017年にリベンジしたいと思います。
イムリーにこんなお誘い? もありましたしね!


Software Design 誌での Sphinx 連載

連載も 2年目に入って、応用的な内容が続いています。いろんな分野に広がっていてとても面白いですね。
自分も合計で 4回ほど寄稿しました。

いままで説明されていなかった分野の記事を書いたり、不足がちな機能を補うためにあらたな拡張を書いたりしました。
sphinxcontrib-jsonschema や sphinxcontrib-apiblueprint を新たにリリースしたり、sphinxcontrib-textstyle にパッチを投げまくったりしました。
先日は toc 拡張を作ったりしましたし、やはり発表ドリブン、記事ドリブンでなにかをやるのはコードが生まれて楽しいですね。

アドベントカレンダー

2016年はアドベントカレンダーは特に開催されませんでした…が、そのかわりにこのカウントダウン連載をやっていました。
本当に白紙の状態で書き始めたので、調べ物をして、コードを書いてと大変な毎日でした。メンテナンスも放置状態ですしね。

来年はみんなで、負担を分散してできるといいですね。
せめて、ひとりでやるにしても事前にネタを仕込んでおきたいところです。

まとめ

とくにまとまりなく終わります。やっつけ気味ですみません…。
みなさま、 2016年はお疲れ様でした。2017年も引き続きよろしくお願いします。
(もう年は越してしまったのだけど、一応 12/31 の記事の体で)