背景
以前以下の記事でMkdocsについて紹介しました。
7rikazhexde-techlog.hatenablog.com
記事の中では言及していなかったのですが、私はMarkdown用のフォーマッターとしてmdformatを使用しています。
公式ドキュメント:
公開しているGitHub Pagesもその後更新を続けており、いくつか機能追加(多言語対応,クッキー設定,GA4対応,レイアウト変更)をしました。
mkdocsのレイアウトや設定についてはTipsページで紹介しようと考えています。
記事を更新する中で、大抵は公式のドキュメントを参照して解決できていたのですが、mdformat + mkdocs(Admonitions)の組み合わせでは意図した表示にすることができず、解決方法もすぐには見つけることができませんでした。
結論から言えばmdformatのプラグインを使用することで解決できたのですが、使用方法に指定がありました。
本記事では発生した現象と調査内容、解決方法について紹介します。
発生した現象について
mkdocsではadmonitionsという文書内にメモ、ヒント、警告などが目立つようなスタイルで表示してくれる機能です。サンプルとして以下を作成し、poetry run mkdocs serve
すると、以下のような表示になります。
OKケース
!!! info - test1 - test2
しかし、これにpoetry run mdformat .
を実行すると以下のように変換されてしまいます。
NGケース
!!! info \- test1 \- test2
解決方法
まず、mdformatのissueを調べました。すると以下のissueが見つかりました。
これは無視する対象をHTMLのコメントで囲むという方法ですが、2023/08/12時点で解決まで至っていません。
処理的には難しくはないため実際に作成することにしました。
型指定もなく上記例のみの確認のため参考にしないほうが良いと思いますが、やりたいことはできました。
def replace_mdformat_ignore(input_file, output_file, target_text): with open(input_file, "r", encoding="utf-8") as f: lines = f.readlines() converted_lines = [] ignore_mode = False for line in lines: if "<!-- mdformat ignore start -->" in line: ignore_mode = True converted_lines.append(line) elif "<!-- mdformat ignore end -->" in line: ignore_mode = False converted_lines.append(line) elif ignore_mode: if line.strip() != "" and target_text not in line: line = line.replace(r"\-", "-") converted_lines.append(" " + line) else: converted_lines.append(line) else: converted_lines.append(line) with open(output_file, "w", encoding="utf-8") as f: f.writelines(converted_lines) if __name__ == "__main__": target_text = "!!! info" input_file = "./docs/index.md" output_file = "./docs/index.md" replace_mdformat_ignore(input_file, output_file, target_text) input_file = "./docs/index.en.md" output_file = "./docs/index.en.md" replace_mdformat_ignore(input_file, output_file, target_text)
個別にスクリプトを作成する方法も良いですが、同じような問題に取り組んでいるプロジェクトがないかと思い調べることにしました。
すると、mdformatにはPlugins機能があることがわかりました。 そして、MkDocsのadmonitionsのためのmdformatプラグインとして、mdformat-admonというプラグインが存在することがわかりました。
admon以外にもmkdocsの記法に合わせたプラグインが複数存在していました。
注意点
公式ドキュメントのContributingに記載されていますが、プラグインを使用するためにはpre-commitで実行する必要があります。
mdformat単体では実行できないため注意が必要です。(もしかするとやり方があるかもしれませんが、確認できませんでした。)
使用方法
pre-commitについては割愛します。詳細は公式ドキュメントを参照ください。
.pre-commit-config.yaml
は以下のように記載します。
repos: - repo: https://github.com/executablebooks/mdformat rev: 0.7.16 hooks: - id: mdformat additional_dependencies: - mdformat-admon # ここに追加する
結果、NGケースのような結果にはならず期待する表示を確認することができました。
補足: 個別にmdformatを使用する場合
事前の動作確認でpre-commitで全てのフックを実行する場合は、poetry run pre-commit run --all-files
で実行できますが、個別に実行したい場合はpre-commitのhooksで指定したid
を指定します。
1. pre-commitフックで個別にmdformatする場合
git add your_file.md # 対象のMarkdownファイルをステージング poetry run pre-commit run mdformat
2. 未ステージング状態のファイルに対してもフックを実行する場合
poetry run pre-commit run mdformat --all-files
補足: その他フォーマッターとの差異について
開発環境でVSCodeを使用している場合はmarkdown用のフォーマッターとして以下のようなものがあります。
- Prettier - Code Fomatter
- Markdown All in One
- markdownlint
この中でデフォルトで問題なく動作するのはMarkdown All in One
とmarkdownlint
です。
Markdownファイルを全て選択(Ctrl + a) > 右クリック > ドキュメントのフォーマット…(2つある内の下で「…」の方) > Prettier - Code Fomatter
Prettierでは以下のように変換されてしまいます。
!!! info - test1 - test2
また、mdformat
ではプラグインが必要でしたが、Markdown All in One
とmarkdownlint
はデフォルトで上記NGケースのような変換にはなりませんでした。
まとめ
mdformat + mkdocs(Admonitions)で意図した表示にならない現象と解決方法について紹介しました。
mdformatは公式ドキュメントの通り、フォーマットの変更には慎重のようですが、pre-commitによるプラグインが複数存在するため、mkdocsに限らず、目的に応じてプラグインを使用することは有用だと思います。
Welcome to the mdformat developer docs! We’re excited you’re here and want to contribute. ✨
Please discuss new features in an issue before submitting a PR to make sure that the feature is wanted and will be merged. Note that mdformat is an opinionated tool that attempts to keep formatting style changing configuration to its minimum. New configuration will only be added for a very good reason and use case.
以上です。