Skip to content

Markdown Preview Example

A markdown file viewer showcasing the debug layer and advanced tui-dispatch features.

Running

Terminal window
# View README.md
cargo run -p markdown-preview
# View a specific file
cargo run -p markdown-preview -- path/to/file.md

What It Shows

Debug Layer Setup

The debug layer is set up with sensible defaults (F12 toggle key), wired into the runtime helper:

let debug = DebugLayer::<Action>::simple().active(args.debug);
let mut runtime = DispatchRuntime::new(AppState::new(file_path, features), reducer)
.with_debug(debug);
let mut bus = EventBus::new();
let keybindings = Keybindings::new();
runtime
.run_with_bus(
terminal,
&mut bus,
&keybindings,
|frame, area, state, ctx, event_ctx| {
event_ctx.set_component_area(MarkdownComponentId::Viewer, area);
render_app(frame, area, state, ctx);
},
|action| matches!(action, Action::Quit),
)
.await?;

Press F12 to enter debug mode. The debug layer freezes the frame and provides inspection tools:

KeyAction
s / SShow state overlay (document stats, view metrics)
a / AShow action log
y / YCopy frame to clipboard (via OSC52)
i / IEnable mouse capture for cell inspection
Esc / QClose overlay

When mouse capture is enabled, click any cell to inspect its styling (symbol, foreground, background, modifiers).

DebugState Implementation

To enable state inspection, implement the DebugState trait. You can use the derive macro:

#[derive(DebugState)]
struct AppState {
#[debug(section = "Document")]
file_path: String,
#[debug(section = "Document")]
total_lines: usize,
#[debug(section = "AST Statistics")]
heading_count: usize,
#[debug(section = "AST Statistics")]
link_count: usize,
#[debug(skip)]
internal_cache: Vec<u8>,
}

Or implement it manually for more control:

impl DebugState for AppState {
fn debug_sections(&self) -> Vec<DebugSection> {
vec![
DebugSection::new("Document")
.entry("file", &self.file_path)
.entry("total_lines", self.stats.total_lines.to_string()),
DebugSection::new("AST Statistics")
.entry("headings", self.stats.heading_count.to_string())
.entry("links", self.stats.link_count.to_string()),
// ...
]
}
}

Feature Flags (CLI)

Feature flags via command line using #[derive(FeatureFlags)]:

#[derive(FeatureFlags)]
pub struct Features {
#[flag(default = false)]
pub line_numbers: bool,
#[flag(default = true)]
pub wrap_lines: bool,
#[flag(default = true)]
pub show_stats: bool,
}

Enable/disable via CLI:

Terminal window
# Enable line numbers
cargo run -p markdown-preview -- README.md --enable line_numbers
# Disable wrapping, enable line numbers
cargo run -p markdown-preview -- README.md --disable wrap_lines --enable line_numbers
# Multiple flags (comma-separated)
cargo run -p markdown-preview -- README.md --enable line_numbers,show_stats

Search Functionality

The example includes vim-style search:

  1. Press / to start search
  2. Type query, press Enter to confirm
  3. n / N to navigate matches
  4. Esc to cancel

Search matches are highlighted in the document with the current match emphasized.

Keybindings

Normal Mode

KeyAction
j / Scroll down
k / Scroll up
Ctrl+d / PageDownPage down
Ctrl+u / PageUpPage up
g / HomeJump to top
G / EndJump to bottom
/Start search
nNext match
NPrevious match
rReload file
F12Enter debug mode
qQuit

Search Mode

KeyAction
Any characterAdd to query
BackspaceDelete character
EnterSubmit search
EscCancel search

Key Files

FilePurpose
src/main.rsEntry point, debug layer setup, event handling
src/action.rsNavigation, search, file actions
src/state.rsAppState with markdown rendering, search state
src/reducer.rsState mutations for scrolling, search, file ops
src/features.rsCLI feature flags (line numbers, wrapping, stats)