● just ci green, line-mode fallback still works under pipe input. #40
No reviewers
Labels
No labels
bug
documentation
duplicate
enhancement
good first issue
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
1 participant
Due date
No due date set.
Dependencies
No dependencies set.
Reference
navicore/patch-prolog-v1!40
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "repl-slice-B-phase-1"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Phase 1 of slice B is in:
Editing | Streaming }. All state transitions
(insert/backspace/move/recall/take_prompt/submit/advance/stop_streaming) are pure — no terminal, no ratatui. 8
new unit tests cover edge cases: multibyte chars at cursor, backspace at column 0, history walk +
in-progress-edit snapshot, submit-then-advance to Done, parse error stays in Editing, stop_streaming is silent.
and ./Esc/Enter commits; in Editing, ; is just a literal char (you need it for (a; b) disjunction goals).
Ctrl-C quits in either mode. Esc in Editing is Ignore so it doesn't clash with Streaming's Esc=StopStreaming
muscle memory.
lines), prompt (Length 1, real terminal cursor via Frame::set_cursor_position). Bindings panel shows "(no
current solution)" when idle. Per-mode prompt prefix: ?- editing, ; or . > streaming.
to the original hook), event loop (100ms poll, dispatch Action through App). commit_goal handles SWI-parity
quit/halt, records history before submit (typo-recall), and pushes to the in-session recall buffer.
run_line_mode. Headless smoke tests that pipe stdin still hit line-mode unchanged.
Tests: 28 + 7 keys + 0 tui = 35 (12 → 35). Workspace just ci clean.
Phase 2 is vim-line — swap the editing-mode keymap and the prompt rendering for modal vim semantics.
Phase 1 of slice B is in: - app.rs — App extended with prompt: String, cursor: usize, history_index, saved_prompt, mode: PromptMode { Editing | Streaming }. All state transitions (insert/backspace/move/recall/take_prompt/submit/advance/stop_streaming) are pure — no terminal, no ratatui. 8 new unit tests cover edge cases: multibyte chars at cursor, backspace at column 0, history walk + in-progress-edit snapshot, submit-then-advance to Done, parse error stays in Editing, stop_streaming is silent. - keys.rs — Action enum filled in; map_key(KeyEvent, PromptMode) -> Action. Mode-aware: in Streaming, ; advances and ./Esc/Enter commits; in Editing, ; is just a literal char (you need it for (a; b) disjunction goals). Ctrl-C quits in either mode. Esc in Editing is Ignore so it doesn't clash with Streaming's Esc=StopStreaming muscle memory. - ui.rs — 3-region vertical layout: transcript (Min, scroll-tail), bindings (Length 5, border + 3 content lines), prompt (Length 1, real terminal cursor via Frame::set_cursor_position). Bindings panel shows "(no current solution)" when idle. Per-mode prompt prefix: ?- editing, ; or . > streaming. - tui.rs — terminal lifecycle (raw mode + alternate screen + panic hook that restores terminal before delegating to the original hook), event loop (100ms poll, dispatch Action through App). commit_goal handles SWI-parity quit/halt, records history before submit (typo-recall), and pushes to the in-session recall buffer. - main.rs — --no-tui flag added; TTY auto-detect via IsTerminal::is_terminal() picks tui::run vs the existing run_line_mode. Headless smoke tests that pipe stdin still hit line-mode unchanged. Tests: 28 + 7 keys + 0 tui = 35 (12 → 35). Workspace just ci clean. Phase 2 is vim-line — swap the editing-mode keymap and the prompt rendering for modal vim semantics.Review
What it does: Phase 1 of slice B — the real TUI. Pure state transitions on
App(prompt buffer/cursor/history-walk/mode), mode-aware key mapping, 3-panel ratatui layout, terminal lifecycle with a panic hook, and TTY auto-detect with--no-tui+ line-mode fallback.Verified locally (scratch copy of the branch): 28 + 7 = 35 tests pass, clippy clean, piped line-mode unchanged, and — driving the real binary under a pty — the full TUI path works: goal commit →
X = ain transcript + bindings panel with the; for nexthint →;advance →.stop →quit.exits cleanly, terminal restored. The architecture is right:Appmutators are genuinely pure (the 8 new tests prove the multibyte cursor handling — the #36 lesson applied at the editing layer), the panic hook is the correct shape,;-as-literal-while-Editing is the right call for disjunction goals, and record-before-submit carries the #38 typo-recall rationale forward with a comment.🟡 Worth addressing
main.rs):echo "p(1)." | prlg-replin a terminal launches the TUI and silently discards the piped input — demonstrated under a pty (alt-screen entered, goal never consulted; crossterm falls back to/dev/ttyfor keys so the keyboard still works, but the pipe is lost).io::stdin().is_terminal() && io::stdout().is_terminal()routes piped-stdin runs to line mode, which consumes them as intended.KeyEventKindnot filtered (tui.rs):Event::Key(key)dispatches without checkingkey.kind == KeyEventKind::Press. On Windows — and any kitty-protocol terminal — crossterm also emits Release/Repeat, so every keystroke inserts twice. One-line guard.ui.rs::latest_solution): the doc comment says it returnsNone"if the last outcome was Done/Error," butfind_mapskips overDone/Error/Goalentries and returns an older goal's solution. Repro: run a goal, commit after a solution, then submit a goal that parse-errors — the bindings panel still shows the previous goal's bindings as if current. Cleanest fix isn't transcript archaeology at render time: holdcurrent_solution: Option<RenderedSolution>onApp, set inadvance, cleared instop_streaming/Done/Error.:qtyped and committed" — neither exists inmap_keyorcommit_goal. Terminal users will hit Ctrl-D. Relatedly, crossterm delivers^Jas Ctrl-J rather than Enter (crossterm #371) — the pty harness proved input queued before raw-mode enables arrives as\n→ Ctrl-J → silently swallowed. Mapping Ctrl-J → CommitGoal and Ctrl-D-on-empty → Quit closes both.scrollis computed from logical line count, but theParagraphhasWrapon — each wrapped line adds a visual row the calculation doesn't see, so the newest entries scroll out of view exactly when output gets long. Either drop wrap, or render only the last N entries that fit.submit()doc comment overpromises: it claims "single-solution-zero-binding goals never need the;prompt," buttrue.yieldsSolutionfirst → enters Streaming and demands an extra keypress; only goals whose first step is Done/Error skip it. That's the #38 deferred-lookahead item — fine to keep deferring, but the comment should say what the code does.🟢 Minor
ui.rs) misplaces the caret on multibyte input — acknowledged in the comment as phase-2/vim-line territory, fine. Same for long prompts walking off the right edge (no horizontal scroll).recalled.pushdoesn't dedup consecutive repeats — tenp(1).s = ten up-arrows.enter_terminal: ifEnterAlternateScreenfails, raw mode is left enabled (no rollback on the error path).Verdict
Solid phase-1 TUI — clean state/render/lifecycle separation, honest tests, and it demonstrably works end-to-end under a pty. Items 1–4 are each a few lines and worth landing now (1 and 3 are user-visible wrong behavior, 2 bites every Windows user, 4 is comments promising keys that don't exist); 5–6 can ride with phase 2 if preferred.
Review by Claude Code