summaryrefslogtreecommitdiff
path: root/src/term.rs
diff options
context:
space:
mode:
authorskylar <me@casper>2026-11-10 06:50:08 -0800
committerskylar <me@casper>2026-11-10 06:50:08 -0800
commitd36c54d996f3c14ae811312dbbe621e12a39edde (patch)
tree1807134323479ac90bf69d28e410a7f70cb235a1 /src/term.rs
Orrery: game loop, name generator and derelict dungeons
An ASCII sci-fi-fantasy game for the terminal, built on ratatui. - Game loop with a fixed 30 Hz tick and a stack of scenes; the kitty keyboard protocol is turned on where the terminal supports it, so later real-time scenes can tell when a key is held. - Stable hierarchical seeds: the whole universe derives from one u64, with tests pinning the exact outputs so old seeds keep working. - Name generator with four cultures, each with its own syllables and templates, plus unidentified/true names for artifacts. - Title screen with an animated orrery, and a name forge for browsing generated names. - Derelict ships to board: ship-shaped maps with an engine room, spine corridor, side rooms and bridge; symmetric shadowcasting sight; monsters that wake on sight and hunt; loot carried out through the airlock goes into the hold. - `orrery names` and `orrery ship` print the generators' output without the TUI, for tuning. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'src/term.rs')
-rw-r--r--src/term.rs50
1 files changed, 50 insertions, 0 deletions
diff --git a/src/term.rs b/src/term.rs
new file mode 100644
index 0000000..b11bbdc
--- /dev/null
+++ b/src/term.rs
@@ -0,0 +1,50 @@
+//! Terminal setup and teardown.
+
+use std::io::{self, stdout};
+
+use ratatui::DefaultTerminal;
+use ratatui::crossterm::event::{
+ KeyboardEnhancementFlags, PopKeyboardEnhancementFlags, PushKeyboardEnhancementFlags,
+};
+use ratatui::crossterm::{execute, terminal};
+
+/// What this terminal can tell us about the keyboard.
+#[derive(Clone, Copy, Debug)]
+pub struct KeyboardCaps {
+ /// The terminal reports key releases (the kitty keyboard protocol), so a
+ /// scene can know a key is being held. Without it, holding a key looks
+ /// like one press, a ~0.5 s pause, then auto-repeats, and real-time
+ /// controls need a fallback such as a throttle you step up and down.
+ pub key_release: bool,
+}
+
+/// Raw mode, alternate screen, and the kitty keyboard protocol where available.
+pub fn init() -> io::Result<(DefaultTerminal, KeyboardCaps)> {
+ let terminal = ratatui::try_init()?;
+ let key_release = terminal::supports_keyboard_enhancement().unwrap_or(false);
+ if key_release {
+ execute!(
+ stdout(),
+ PushKeyboardEnhancementFlags(
+ KeyboardEnhancementFlags::DISAMBIGUATE_ESCAPE_CODES
+ | KeyboardEnhancementFlags::REPORT_EVENT_TYPES
+ )
+ )?;
+ // ratatui's panic hook restores raw mode and the alternate screen but
+ // not these flags, which would leave the shell receiving kitty-encoded
+ // keys. Pop them first, then hand over to ratatui's hook.
+ let previous = std::panic::take_hook();
+ std::panic::set_hook(Box::new(move |info| {
+ let _ = execute!(stdout(), PopKeyboardEnhancementFlags);
+ previous(info);
+ }));
+ }
+ Ok((terminal, KeyboardCaps { key_release }))
+}
+
+pub fn restore(caps: KeyboardCaps) {
+ if caps.key_release {
+ let _ = execute!(stdout(), PopKeyboardEnhancementFlags);
+ }
+ ratatui::restore();
+}