Notes for hacking on mdview itself.
Layout
mdview/
├── bin/mdview # the only file end-users execute
├── completions/_mdview # zsh completion (installed alongside the binary)
├── docs/
│ ├── USAGE.md # extended user docs
│ └── DEVELOPMENT.md # this file
├── tests/test-mdview.zsh # end-to-end test suite
├── install.zsh # symlink-based installer
├── Makefile # test / lint / install / uninstall targets
├── README.md
├── CHANGELOG.md
├── CONTRIBUTING.md
├── AGENTS.md # rules for AI / automation contributors
└── .github/workflows/ci.yml
Loop
make lint # zsh -n on all scripts
make test # full e2e
make install # dogfood — symlinks into ~/.local/bin
make uninstall # clean up the symlinks
make test and make lint run on every push via GitHub Actions on both
Ubuntu and macOS — see .github/workflows/ci.yml.
Adding a flag
- Add the case to the
while (( $# > 0 ))arg loop inbin/mdview. - Document it in the file’s header comment block (the
usage()extractor reads from there). - Mirror the entry in
README.mdanddocs/USAGE.mdflag tables. - Add a completion line in
completions/_mdview. - Add a test case in
tests/test-mdview.zshcovering both the happy path and at least one failure mode (missing arg, conflicting flag). - Bump
MDVIEW_VERSIONif you intend to ship a release.
Testing approach
- The suite never spawns a real browser. It puts a fake
openscript ahead of macOS’sopenon$PATHand asserts against the captured invocation log. - Tests run identically on macOS and Linux. The fake
openmakes the Linux runner happy too (noxdg-openneeded). - Pandoc is optional. Tests gate the
marked.js-specific assertions behindif ! (( $+commands[pandoc] ))so they pass either way. To exercise the pandoc branch locally:brew install pandoc && make test.
zsh idioms in use
${0:A}— absolute, symlink-resolved path of the file currently being sourced/executed. Captured intoscript_pathbefore any function defines, because inside a zsh function$0is the function name.${var:t}— basename,${var:h}— dirname.(( $+commands[name] ))— true iffnameis on PATH.print -r --— likeprintf '%s\n', doesn’t interpret escapes; safer thanechofor arbitrary strings.
Release checklist
- All tests green locally (
make lint test) and in CI. - Bump
MDVIEW_VERSIONinbin/mdview. - Update
CHANGELOG.md— move “Unreleased” entries under a new dated## [x.y.z]header. Add the comparison link at the bottom. git commit -am "chore(release): vX.Y.Z"git tag vX.Y.Z && git push origin main --tags- Cut the GitHub release from the tag — paste the changelog section as the release notes.