Add readKeyTimeout primitive for non-blocking keystroke reads#45
Open
chapelsoftware wants to merge 2 commits into
Open
Add readKeyTimeout primitive for non-blocking keystroke reads#45chapelsoftware wants to merge 2 commits into
chapelsoftware wants to merge 2 commits into
Conversation
Adds readKeyTimeout : ℤ → ⟨Bool, ℤ⟩ — reads a single byte from stdin with a millisecond timeout. Returns ⟨⊤, keycode⟩ if a key arrives within the timeout, ⟨⊥, 0⟩ if it elapses first. Option-shape matches stdlib/option.goth convention. Implementation uses libc::poll under #[cfg(unix)], matching the existing rawModeEnter / rawModeExit precedent (Unix-only terminal primitives, Err(not_implemented) elsewhere). Unblocks timer-driven TUI programs — tickers, blinking cursors, animated displays, updatetime-style features, ambiguous-keybind timeouts — that are impossible with the blocking readKey. Includes examples/tui/timer.goth: a live elapsed-seconds counter that pauses with space and quits with q. Without readKeyTimeout, readKey would block and the timer couldn't tick. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
- Add three unit tests for readKeyTimeout error paths (arity 0, arity 2, wrong type). Success/timeout paths depend on stdin state and are left for interactive verification, as reflected in the test names. - Reword the builtins.rs comment to accurately describe the ◇io annotation's current status — "not currently accepted by the parser" rather than the earlier "parsed but not enforced," which contradicted the PR's own finding. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds
readKeyTimeout : ℤ → ⟨Bool, ℤ⟩— a non-blocking keystroke read withmillisecond precision.
⟨⊤, keycode⟩when a key arrives within the timeout⟨⊥, 0⟩when the timeout elapses firststdlib/option.gothconventionImplementation uses
libc::pollunder#[cfg(unix)], matching the existingrawModeEnter/rawModeExitprecedent (Unix-only terminal primitives,not_implementedelsewhere).Motivation
The current
readKeyprimitive blocks indefinitely on stdin, which makestimer-driven TUI programs impossible: tickers, blinking cursors, animated
displays,
updatetime-style features, ambiguous-keybind timeouts (vim'sjkescape), autosave ticks. Every such program needs a read-with-timeout.docs/PROJECT-STATUS.mdlists "TUI demo compilation (tui_demo.goth)" asactive work. This primitive is the smallest step toward enabling it.
Demo
examples/tui/timer.goth: a live elapsed-seconds counter.spacepauses,qquits. WithoutreadKeyTimeout,readKeywould block and the countercouldn't tick.
Design notes
no hidden granularity footgun.
Option(⟨Bool, α⟩perstdlib/option.goth):reuses the project's existing vocabulary rather than introducing a new one.
◇ioeffect: the type signature's comment notes the◇ioannotationas aspirational — see "Parser note" below.
values above
i32::MAXsaturate.Test plan
⟨⊤, keycode⟩when a byte is piped in⟨⊥, 0⟩when stdin stays open but quiet for the timeoutcargo test --package goth-eval— 216/216 passcargo test --package goth-check— 1/1 passexamples/tui/timer.gothParser note (separate finding)
While writing this I noticed
stdlib/tui.gothdoes not currently parse. Aminimal reproducer:
fails with
Unexpected token: Some(Diamond), expected identifier. Thiscontradicts
docs/EFFECT-SYSTEM-ROADMAP.md, which lists "Lexer/Parser: The◇token… recognized in function box middle lines" under "What Works".Because of this, I intentionally did not add
│ ◇ioannotations to thenew primitive's stdlib wrapper and kept the demo using primitives
directly. Happy to submit a follow-up PR targeting the parser if useful.
Scope
No stdlib or interpreter behavior changes outside the new primitive and
its registration. No dependencies added (
libcwas already a target-cfg(unix)dep). No new error variants.
🤖 Generated with Claude Code