| Item | Value |
|---|---|
| Version | 1.0 |
| Status | Active |
| Product | mdv |
| Language | Rust 2024 |
| Toolchain | Rust 1.92.0 |
| Document Basis | Repository audit on 2026-03-29 |
mdv は Rust 製の single-binary CLI で、Markdown を一度 Document に正規化したうえで、2 つの出力経路に分岐する。
- 対話モード: GitHub HTML 風に整形したページを PNG に snapshot し、Kitty graphics protocol で terminal に表示する
- 非対話モード:
Documentから plain-text rendering を生成して stdout に出す
エントリポイントはシンプルで、src/main.rs が mdv::cli::parse() と mdv::app::run() を呼ぶだけになっている。
| Crate | 用途 |
|---|---|
clap |
CLI 引数解析 |
anyhow / thiserror |
エラー文脈の付与 |
comrak |
GFM ベースの Markdown parse と HTML 出力 |
crossterm |
TTY 制御、キー入力、alternate screen |
image |
画像 decode、PNG 変換、寸法取得 |
resvg |
SVG rasterize 関連 |
syntect |
code block syntax highlight |
serde / serde_json |
snapshot diagnostics の JSON 処理 |
tracing / tracing-subscriber |
起動、描画、外部コマンド周辺の trace |
条件:
stdoutまたはstdinが TTY ではない
挙動:
render::text::render_plain_text()を使う- alternate screen は使わない
- image / Mermaid はメタ情報ベースの degrade 表現を返す
条件:
stdoutとstdinがともに TTY- terminal 判定が Ghostty または Kitty
挙動:
TerminalViewer::try_new()を生成- raw mode と alternate screen に入る
- graphic page を描画し、キー入力ループで scroll / reload / open link を処理する
制約:
- 現行実装では graphic page 生成が前提で、失敗時の runtime fallback はない
webkit_snapshotは非 macOS で未対応のため、interactive rich path は実質 macOS 前提
app::run()がファイル本文を読むrender::markdown::parse_document()がcomrakAST を走査する- AST を
core::document::DocumentとBlockKind群へ正規化する DocumentMetaに title、links、source length を格納する
Document はこのアプリの共通中間表現であり、headless と interactive の双方がこれを起点にする。
render::github_html::build_github_html()が GitHub 風 HTML を生成する- Mermaid code fence は事前に
replace_mermaid_code_blocks()で SVG か fallback HTML に差し替える io::webkit_snapshot::render_html_to_png()が HTML を PNG と diagnostics report に変換するui::page_graphics::build_graphic_page()が PNG の display size と viewport slice 情報を作るui::terminalが Kitty graphics command を発行して terminal に置く
render_plain_text()がDocumentを block ごとに走査する- block を plain-text へ整形する
- image / Mermaid / footnote / table を可読な degrade 表現に変換する
- stdout に UTF-8 で出力する
| Module | 責務 |
|---|---|
cli |
MdvArgs 定義、theme enum、引数 parse |
app |
起動 orchestration、TTY 判定、render mode 分岐 |
core |
Document、BlockKind、テーマ token、layout 補助、diff |
render::markdown |
GFM parse と Document 正規化 |
render::text |
headless 表示と structured text layout |
render::github_html |
GitHub CSS ベースの HTML 生成と Mermaid 埋め込み |
render::svg |
SVG ベースの描画補助と関連テスト |
io::fs |
ドキュメントの読み込みと更新時刻取得 |
io::image_decoder |
ローカル画像の解決と PNG 化 |
io::mermaid_cli |
mmdc / npx @mermaid-js/mermaid-cli 呼び出しと cache |
io::webkit_snapshot |
Swift helper を使った HTML snapshot |
io::browser |
既定ブラウザ起動 |
io::kitty_graphics |
Kitty graphics escape sequence 生成 |
ui::terminal |
イベントループ、status line、graphics placement |
ui::page_graphics |
full-page PNG の viewport 切り出し |
Mermaid は MermaidCliRenderer::from_env() で次の順に探索する。
MDV_MERMAID_CMDmmdcnpx -y @mermaid-js/mermaid-cli
レンダリング結果は cache directory に保存される。
HTML snapshot は Swift helper 経由で WKWebView を使っている。これは src/io/webkit_snapshot/mod.rs と同配下の script / diagnostics / paths モジュールで構成される。
生成物:
snapshot.pngsnapshot-report.json
diagnostics には以下が含まれる。
- image readiness
- Mermaid metrics
- typography metrics
- asset failure diagnostics
io::browser は OS ごとの既定ブラウザ起動コマンドを選ぶ。対話モードで o を押したときのみ使用する。
テーマは Theme::Light と Theme::Dark の 2 種類だけである。
interactive path では次を組み合わせる。
- GitHub の light / dark CSS アセット
- 埋め込み
Mona Sans VFとMonaspace Neon Var syntectの syntax highlight theme
headless path では ThemeTokens は持つが、最終出力は plain text 中心で、interactive ほど theme 差は大きくない。
cargo build --releasecargo fmt --allcargo clippy --workspace --all-targets --all-features -- -D warningscargo test --workspace --all-targets --all-features
Makefile でも同等の entrypoint が定義されている。
GitHub Actions の ci.yml は次を実行する。
- format check
- clippy
- test
Rust toolchain は 1.92.0 に固定されている。
release automation は現在持たない。配布契約は次の 2 本だけである。
scripts/install.shは GitHubmain上の追跡対象bin/mdvを取得して install directory に配置するmdv updateは現在の実行ファイルと GitHubmainのbin/mdvを byte-for-byte で比較し、差分があるときだけ置き換える
repo の bin/mdv は install / update の実体であり、main への push 後に ci.yml の macOS job が自動生成して必要時のみ commit する。ローカルでは make build-tracked-bin で同じ packaging path を再現できるが、追跡 binary の更新責務は人手ではなく CI が持つ。
テストは 3 層に分かれている。
tests/unit: parser、renderer、snapshot、terminal 補助、Mermaid adapter などの単体確認tests/integration: CLI と出力契約の確認tests/e2e: rich fixture や asset 解決を含む実行経路の確認
特に重要なのは次。
- headless rendering contract
- GitHub HTML typography fidelity
- local image rendering
- Mermaid diagnostics
- terminal scroll / graphics placement
- interactive rich rendering が macOS WebKit に依存している
TerminalViewer::try_new()に graphic page failure 時の fallback がない- link open は first link 固定で、link focus state を持たない
- terminal 判定は Ghostty / Kitty に限定される
- README の platform statement と現実装の runtime contract に差がある
- Linux でも動く snapshot backend か structured TUI fallback を用意する
DocumentのrevisionやSourceSpanを reload diff に活用する- interactive path の fallback を
render::text::render_document()に戻す - 複数リンクナビゲーションや検索 UI を足す場合は
DocumentMetaと UI state を拡張する