Runtime integration
Event loops, keymaps, time, effects, and host ownership.
The canonical termrock-catalog application is the executable on-ramp. It
mounts the shared catalog shell and state model used by native, headless, and
browser hosts; runtime behavior remains independent of product-specific state:
cargo run -p termrock-catalog --release
cargo run -p termrock-catalog --release -- --page datagridTermRock does not require an application architecture. Consumers may use a direct loop, Elm-style update flow, components, or another state model while keeping rendering and interaction primitives shared.
Runtime keymaps
Keymap is one resolved source for dispatch, hints, glyph lookup, and conflict
diagnostics. Static defaults use KeyBinding::borrowed and
Keymap::from_static without startup allocation. Clone that map and apply
runtime configuration before entering the event loop; its first successful
edit copies the table, while unchanged chord and label data stays borrowed.
use termrock::{
input::KeyCode,
keymap::{KeyBinding, KeyChord, Keymap, Visibility},
};
#[derive(Clone, Copy, PartialEq)]
enum Action { Quit }
static BINDINGS: &[KeyBinding<Action>] = &[KeyBinding::borrowed(
&[KeyChord::plain(KeyCode::Char('q'))],
Action::Quit,
Some("quit"),
Visibility::Shown,
None,
)];
let mut keymap = Keymap::from_static(BINDINGS);
keymap.remap(Action::Quit, vec![KeyChord::ctrl(KeyCode::Char('c'))]);
assert_eq!(keymap.dispatch(KeyChord::ctrl(KeyCode::Char('c'))), Some(Action::Quit));
assert_eq!(keymap.glyph_for(Action::Quit), "Ctrl-C");remap clears an explicit glyph so the canonical glyph follows the new first
chord. Use replace when configuration intentionally supplies a custom grouped
glyph. conflicts reports declaration-ordered collisions; dispatch remains
deterministic and first-binding-wins. With the serde feature, serializing a
borrowed map and deserializing it produces an owned map ready for mutation.
Crossterm runner
With the crossterm feature, runtime::run centralizes terminal mode setup,
neutral event conversion, redraw cadence, deadline-aware polling, and reverse
restoration. Mutable render state remains valid; effects and process policy
remain application-owned.
use std::ops::ControlFlow;
use termrock::runtime::{Instant, RunOptions, run};
# struct App;
# impl App {
# fn render(&mut self, _: &mut ratatui_core::terminal::Frame<'_>, _: termrock::runtime::FrameTick) {}
# fn update(&mut self, _: termrock::input::Event, _: termrock::runtime::FrameTick) -> ControlFlow<()> { ControlFlow::Break(()) }
# fn next_deadline(&self) -> Option<Instant> { None }
# }
# let mut app = App;
run(
&mut app,
RunOptions::default(),
App::render,
App::update,
App::next_deadline,
)?;
# Ok::<(), std::io::Error>(())Runner samples one FrameTick before each draw and passes the same value to
that cycle's update. It polls for the lesser of RunOptions::poll_timeout and
the model's next deadline. Return None when no animation or TTL needs a timed
wakeup. Widgets consume time only through passed FrameTick values, making
tests deterministic through FrameTick::manual.