Single-binary Markdown viewer with 2-pane UI (file tree + content). Renders GFM, Mermaid, syntax highlighting. All assets embedded. Part of util-series.
make build # Build → dist/mdv
make test # Run all tests
make test-linux # same suite on Linux (container)
make build-all # Cross-compile for 4 platforms (darwin arm64 only; no Intel)
make package # Build + create .zip archives
make verify-release # gate: .notarized marker + freshness (run before upload)
make clean # Remove dist/github.com/nlink-jp/markdown-viewer
markdown-viewer/
├── main.go ← entry point
├── cmd/root.go ← cobra CLI, server lifecycle
├── internal/
│ ├── assets/ ← embedded HTML/CSS/JS (go:embed)
│ │ └── embed_assets/
│ │ ├── static/ ← main.css, main.js, treeview.css, treeview.js
│ │ └── templates/ ← index.html, treeview.html, markdown.html, etc.
│ ├── browser/ ← open URL in default browser
│ ├── config/ ← viper-based config (JSON + env + flags)
│ ├── filebrowser/ ← directory listing (markdown files only)
│ ├── markdown/ ← goldmark SafeLinkRenderer
│ └── server/ ← HTTP server, handlers, routing
├── Makefile
└── config.json.example
Priority: defaults → ~/.config/mdv/config.json → ./config.json → env (MDV_*) → CLI flags.
-p, --port(default: 8080)-o, --open(default: false)-d, --dir(default: .)
- Directory traversal: blocked by
containsDotDot()on raw URI - XSS: HTML sanitized via bluemonday UGCPolicy
- Links: only relative
.md/.markdownfiles rendered as<a>tags - Protocol schemes (
http://,ftp://,javascript:,data:) blocked in links - Server binds to 127.0.0.1 only (no network exposure)
- All UI assets are embedded via
go:embed— changes to HTML/CSS/JS require rebuild isSafeLinkblocks all protocol schemes, not just http/https- Config uses viper: flag binding happens in PersistentPreRunE, not init()
- Server implements
http.Handlerdirectly (no mux)