leaf is a terminal Markdown previewer built around a small set of focused modules:
-
src/main.rs- entrypoint
- loads CLI options
- reads the initial document or opens the file picker
- initializes terminal + syntax/theme assets
-
src/app/mod.rs: central runtime state: document content, TOC, search, watch, editor config, mode detection (has_content())content.rs: document loading, reload, reparse, modification detectionnavigation.rs: scroll, TOC jump, numkey cycle, reverse modegoto_line.rs: go-to-line mode (Ctrl+L): draft input, target validation, error state, contextual scroll offsetflash.rs: flash notification state (editor, watch, config, link, reload)popups.rs: help, path popup, editor picker state and methodslinks.rs: link detection, hover tracking, link span mappingfile_picker.rs: fuzzy and browser picker state, queue/pending lifecycleio_picker.rs: filesystem scanning, async loading via thread + mpsc channel, fuzzy matchingfuzzy.rs: fuzzy matching algorithm and directory sort helperssearch.rs: search state and match trackingtheme_picker.rs: theme picker state with preview cache
-
src/markdown/mod.rs: core Markdown parsing loop and render preparationblocks.rs: block-level rendering (headings, code blocks, blockquotes, rules, LaTeX/Mermaid blocks)spans.rs: inline style handling (bold, italic, code, LaTeX, links)markers.rs: custom inline markers (==mark==): open/close delimiters, themed styles, paddinglists.rs: list rendering (ordered, unordered, nested)highlight.rs: search match highlighting across spanssyntax.rs: syntect code highlighting and language resolutionfences.rs: code fence normalization (nested fences, tilde fences)links.rs: link span detection and constructiontables.rs: table construction, event handling, and renderingtable_layout.rs: table cell sizing, wrapping, and alignment algorithmslatex.rs: LaTeX-to-Unicode conversion:unicodeit+ postprocessing for\frac,\sqrt,^{},_{}mermaid.rs: Mermaid diagram ASCII renderingfrontmatter.rs: YAML frontmatter extraction and key-value parsingtoc.rs: TOC extraction and normalizationwidth.rs: width-aware helperswrapping.rs: line wrapping for constrained widths
-
src/render/mod.rs: TUI layout orchestration withratatuicontent.rs: main content panel renderingpopup.rs: popup rendering for help, theme picker, path displaypopup_picker.rs: popup rendering for file picker, editor picker, loading/failed statesstatus.rs: status bar construction (brand, filename, search, watch, shortcuts, percentage)toc.rs: TOC sidebar rendering
-
src/runtime/mod.rs: event loop, polling, timers, resize synchronizationkeyboard.rs: keyboard handling with mode-aware branching (help → picker_loading → picker_failed → file_picker → theme_picker → editor_picker → path_popup → goto_line → search → normal)mouse.rs: mouse handling (scroll, click, double-click, scrollbar drag, link hover)
-
src/theme/mod.rs: theme types, global state, preset selection APIpresets.rs: built-in theme definitions (Arctic, Forest, OceanDark, SolarizedDark)resolution.rs: theme resolution, color parsing, custom theme file loadingserde.rs: theme deserialization, color visitor, override macros
-
src/editor.rs- editor detection, classification (terminal vs GUI), and launch
-
src/cli.rs- command-line parsing
- usage/version text
-
src/config.rsconfig.tomlloading and creation (--config,--config reset)LeafConfigdefaults (theme, editor, watch, width, extras) with CLI overrides
-
src/completions.rs- shell completion installation (
--auto-complete) - shell detection and embedded bash/zsh/fish/PowerShell scripts
- shell completion installation (
-
src/clipboard.rs- cross-platform URL opening (
open,xdg-open,cmd start) - clipboard copy via OSC 52 escape sequence (base64)
- cross-platform URL opening (
-
src/inline.rs- non-interactive stdout rendering (
--inline) - ANSI/plain format resolution and line wrapping
- ratatui Style-to-ANSI escape code serialization
- non-interactive stdout rendering (
-
src/terminal.rs- raw mode / alternate screen lifecycle
- terminal restore guarantees
-
src/update.rs- self-update: asset download, SHA256 verification, and binary replacement
-
src/tests/app.rs: app state, search, and mode detection testsfile_picker.rs: picker opening, browser mode, queued transitionsfile_fuzzy.rs: fuzzy matching, scoring, filtering, truncationmarkdown_lists.rs: list rendering regression testsmarkdown_tables.rs: table rendering regression testsmarkdown_blocks.rs: headings, TOC, blockquotes, code blocks, rulesmarkdown_embedded.rs: LaTeX and Mermaid rendering testsmarkdown_links.rs: link detection and search highlight teststoc.rs: TOC extraction, normalization, active section tracking, and display level testseditor.rs: editor detection and classificationrender.rs: table and code block border alignmenttheme.rs: theme picker preview and restoreconfig.rs: configuration parsing testscompletions.rs: auto-complete argument parsing and completion script installation testsinline.rs: inline spec parsing, format resolution, and write_lines testsupdate.rs: release asset matching and checksum verification
main.rsparses CLI options, loadsconfig.toml, and handles standalone commands (--auto-complete,--config,--update) before any document is opened.- A document is loaded from:
- a file argument, or
stdin, or- the file picker if no input is provided interactively.
markdown/parses the source into rendered lines + TOC.- If
--inlineis active,inline.rswrites lines to stdout and exits. Appstores the state and caches.runtime.rsruns the event loop:- processes pending picker queue → spawns loading thread
- polls picker loading → installs results when ready
- handles input events through mode-aware branching
render/draws each frame fromApp.
- Initial mode (
!app.has_content()): no file loaded, picker is the main view. Quit shortcuts exit the app. - Preview mode (
app.has_content()): file loaded via argument, stdin, or picker selection. Quit shortcuts in pickers close the popup and return to the preview.
queue_fuzzy_file_picker()/queue_file_picker()setsPendingPicker- Main loop calls
start_pending_picker_loading()→ spawns thread, createsmpsc::channel poll_picker_loading()does non-blockingtry_recv()each tick (50ms)- Thread completes → result installed via
install_loaded_file_picker() - Cancel:
cancel_picker_loading()resets state toIdle,Receiveris dropped, thread finishes naturally
-
document reload / open:
- source changes
- rendered lines and TOC are rebuilt
- caches are refreshed
-
resize:
- effective render width is recomputed
- Markdown is reparsed width-aware
-
theme preview:
- previewed content is reparsed and cached per preset
Escrestores the original theme
-
search:
- query state lives in
App - active match drives highlight + scroll position
- query state lives in