menowのPDF出力は、
自前実装ではなくPandoc連携で作った

  • menowにMarkdownをPDFとして書き出す機能を追加した。ただし自前でPDF生成処理を書くのではなく、PandocとLaTeX環境を呼び出す設計にした。
  • PandocのPDF生成にはLaTeXエンジンが必要で、軽量なBasicTeXとtlmgrで日本語組版パッケージを追加インストールした。
  • 起動時にPandocやLaTeXの有無をチェックする設計は採らず、PDF書き出しボタンを押したときだけ外部コマンドを確認するようにした。
  • 用紙サイズやフォントなどのスタイル設定は、menow側の独自仕様ではなくPandoc defaultsファイルであるstyle.yamlに委ねた。

関連記事

1. menowに直接PDF出力を実装しなかった理由

最近、menowで書いたMarkdown本文を、そのまま印刷したいと思うことが増えました。 プレーンテキストのまま印刷すると改行やコードブロックが崩れてしまい、結局別のアプリにコピーして整形し直す羽目になっていたからです。

では、PDF生成をmenow自身に実装すべきか。 Markdownの構文解析からページレイアウト、フォント埋め込みまで自分で書くとなると、それなりの作業量になります。 しかも印刷の見た目にこだわり出すとキリがない。

自前実装は、menow内で完結する分だけ環境依存を減らせますが、機能としては薄いものにしかなりません。 それに対して、すでに枯れたPandocを呼び出す方式なら、変換品質はPandoc側の実績にそのまま乗ることができる。

起動時にPandocやLaTeXの有無を確認する設計も検討しましたが、これは見送りました。 PDFを使わない人にとっては、起動のたびに余計なチェックが走るだけで実利がないからです。 PDF Exportボタンを押した瞬間だけ、外部コマンドの有無を見にいく設計にしました。

2. PandocとBasicTeXを繋ぐ

実際の構成は、PDF↑ボタンをPandocとLuaLaTeXによる書き出し処理へつなぐというものです1。 PandocのパスはデフォルトでLocal bin配下のpandocとし、LaTeXのbinはTeXbin配下を既定値にしました。 もちろんこれらは環境によって変わるので、設定画面から変更できるようにしてあります。

PDF出力のスタイルは、style.yamlというファイルにまとめています。 これはmenow独自の設定ファイルではなく、Pandoc defaultsファイルという形式です2。 用紙サイズや余白、フォント、pdf-engine: lualatexといった指定をそのまま書けるので、menow側でオプションをラップする必要がありません。

PDF生成処理とログ操作は、pdf_export.pyとdebug_log.pyという別ファイルに分けました。 UI層からsubprocessの呼び出しやログファイル操作を切り離しておくと、後で処理だけ差し替えたくなったときに楽です。 あわせて、PDF Exportと設定永続化の単体テストも足しました。

実際にPandocとBasicTeXをインストールして試したところ、指定通りのPDFが開き、印刷まで問題なく通りました。 ここでつまずくと本末転倒だったので、正直ほっとしました。

2.1. 日本語組版でつまずく

ただ、BasicTeXをそのまま入れただけでは日本語が組めません。 BasicTeXは名前の通り最小構成のTeX Live配布で、日本語組版に必要なパッケージが含まれていないからです3。

必要になるのはluatexjaとcollection-langjapaneseで、これらはtlmgrで追加インストールします45。 BasicTeXとMacTeX、どちらを使うかは悩ましいところで、確実性を優先するならGUIなしのMacTeXという選択肢もあります6。 ただ、必要なパッケージだけを足していくBasicTeXの方が、ディスクを圧迫しない分だけ扱いやすいと感じました。 READMEには、この追加手順を独立したセクションとして整理しています。

2.2. 失敗したときにどう調べるか

PDF書き出しは、うまくいかないときの原因が分かりにくい処理でもあります。 Pandocのエラーなのか、LaTeXのエラーなのか、パスの設定ミスなのか、切り分けが必要になる場面が出てくる。

そこで設定画面にDebug Logタブを作り、デバッグログのON/OFF、クリア、コピー、エクスポートをまとめました。 PDF Exportの詳細ログは、デバッグログがONのときだけログファイルに記録される仕組みです。 常時ログを取る設計にしなかったのは、PDFを使わない利用にまで余計な書き込みを増やしたくなかったからです。

3. 見た目の窮屈さから設定画面の再編まで

PDF↑ボタンをどこに置くかは、前日の作業から続いていた課題でした。 既存のツールバーはNew、Paste New、Copy All、Kill、Record、History、Settingという文字ラベルを横並びにしていて、余白がほとんど残っていなかったからです。

表示順を◯Rec、New、+Paste、Copy、PDF↑、Kill、History、Settingに変更し、まずは準備中メッセージを出すだけの入口としてPDF↑ボタンを先に追加しておきました。 実装が固まっていない段階でも、置き場所だけ先に決めておくというやり方です。

設定画面もあわせて、General、PDF Export、Debug Logというタブ構成に変えました。 PDF Exportタブには、Pandocのパス、LaTeXのbin、style.yaml、自動検出、テスト、styleを開く操作をまとめています。 機能が増えるたびに設定項目を並べるのではなく、タブで区切ったことで、後から見返しても迷わない画面になったと思います。

menowはもともと、クリップボードとMarkdownを扱う軽量なテキストツールとして育ってきたアプリです。 今回のPDF出力も、menow自身が何かを新しく作り込むのではなく、すでにあるPandocという仕組みに乗る形で実現しました。 すべてを自分の手で書きたくなる場面はあります。 それでも、既存のツールをうまく呼び出せるかどうかを先に考えるくせは、しばらく持っておきたいと思います。

  1. LuaLaTeXはLuaTeXエンジン上に構築されており、LuaTeX-jaプロジェクトの成果によってupLaTeX以上の自由度で日本語組版ができ、DVIファイルを経由せず直接PDFを生成できる点が特徴です。 – LuaLaTeXのすゝめ
  2. Pandocの公式マニュアルでは、defaultsファイルはコマンドラインオプションに対応するYAMLまたはJSON形式の設定ファイルで、出力形式や入力ファイルを含むあらゆる変換オプションをまとめて指定できると説明されています。 – Pandoc User’s Guide
  3. MacTeXの公式サイトは、BasicTeXについてTeXやLaTeX、pdfTeX、LuaTeXなど標準的なツール一式を含みながらもGUIアプリやGhostscriptを含まない、容量を抑えた代替ディストリビューションと説明しています。 – More Packages – MacTeX
  4. CTANのパッケージページによると、luatexjaはLuaTeX上で日本語文書を組版するためのサポートパッケージで、プレーンTeXとLaTeX2εの両方の書式で利用できるとされています。 – CTAN: Package luatexja
  5. TeX Users Groupの公式ドキュメントでは、tlmgrはTeX Liveのインストール後にパッケージのインストールや更新を管理するためのツールと位置づけられています。 – tlmgr – the native TeX Live Manager
  6. TeX Users Groupは、初心者には必要なファイルがひとまとめになったフルのMacTeXを推奨する一方、フルのTeX Liveをダウンロードしたくない場合や回線が不安定な場合の代替としてBasicTeXを挙げています。 – More Packages – MacTeX