Skip to content

feat(terminal): pin the input line to a fixed footer row in every state - #952

Merged
grhohertz merged 1 commit into
mainfrom
feat/pinned-input-row
Oct 9, 2026
Merged

grhohertz merged 1 commit into
mainfrom
feat/pinned-input-row

Conversation

@grhohertz

@grhohertz grhohertz commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

What

The prompt used to render wherever the transcript happened to end, so the input line moved with every scroll, tool call, and state change. This pins it to a fixed footer row that is present in every shell state — interactive, mid-turn, tool call, worker, coordinator, goal, idle.

Row Content
H-3 horizontal rule (separator)
H-2 INPUT row — always the prompt
H-1 status message
H statusline

How

  • FooterLayout grows sep_row + input_row; footer height 4 (6 with an escalation tray), with graceful degradation in short windows (down to just input + bar at 4 rows, then disabled entirely).
  • LAST_PROMPT caches the prompt string so every repaint path — idle heartbeat, resize, post-clear restore, mid-turn status update — redraws the resting affordance on that row. This is what makes the row unconditional rather than only-while-reading.
  • Row precedence: live editor while reading → mid-turn type-ahead (MIDTURN_INPUT) → cached resting prompt.
  • park_input_row / unpark_input_row move the editor onto the row for a read and hand the cursor back to the body. The row sits outside DECSTBM, so the submitted line is echoed into the body on submit and scrollback stays honest.
  • print_in_body routes above-the-prompt output straight into the transcript via DECSC/DECRC instead of rustyline's ExternalPrinter, which would erase-and-redraw a prompt that no longer lives in the body.
  • BODY_ROW tracks the transcript position: one bounded DSR probe per park, advanced per body write, clamped into the live body on read. Worst case degrades to "write at the bottom" — never corruption.
  • All helpers no-op when no footer region is installed, so off-tty, pre-enable, and short-window runs keep classic inline behaviour.

Known limitation

A typed line that wraps past the bottom row scrolls the screen, since the editor draws outside the scroll region. The next heartbeat repaint heals the footer. Documented in-code.

Verification

cargo test --no-default-features --locked
  1829 passed / 0 failed / 0 ignored   (lib + bins, 49 in terminal::)
  + 28 plugin_dispatcher, 26 plugin_memory, 6 plugin_state,
    4 pty_harness, 4 plugin_docs, 5 plugin_integration, 2 shebang — all green
cargo clippy -D warnings   clean
cargo fmt                  applied

Files: src/terminal.rs (+384/−129), src/editor.rs, src/tools.rs, CHANGELOG.md.

Branched directly off main (99a81c5) — no conflicts.


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

…state

The prompt used to render wherever the transcript ended, so it moved with
every scroll, tool call, and state change (interactive / worker /
coordinator / mid-turn type-ahead). Give the footer a dedicated INPUT row
at H-2 -- third line up from the bottom, directly below the horizontal
rule at H-3, above the status message (H-1) and statusline (H).

- FooterLayout grows sep_row/input_row; footer height 4 (6 with a tray).
- LAST_PROMPT caches the prompt so EVERY repaint (heartbeat, resize,
  post-clear restore, mid-turn update) redraws the resting affordance --
  this is what makes the row unconditional.
- park_input_row/unpark_input_row move the editor onto the row for a read
  and hand the cursor back to the body; the submitted line is echoed into
  the body so scrollback stays honest (the row is outside DECSTBM).
- print_in_body routes above-the-prompt output into the transcript with
  DECSC/DECRC instead of rustyline's ExternalPrinter, which would erase
  and redraw a prompt that no longer lives in the body.
- BODY_ROW tracks where the transcript left off: one bounded DSR probe per
  park, advanced per body write, clamped into the live body on read.
- Row precedence: live editor while reading > mid-turn type-ahead >
  cached resting prompt. All helpers no-op with no footer installed, so
  off-tty and short-window behaviour is unchanged.
@grhohertz
grhohertz added this pull request to the merge queue Oct 9, 2026
Merged via the queue into main with commit 03be66b Oct 9, 2026
4 checks passed
@grhohertz grhohertz mentioned this pull request Oct 9, 2026
@grhohertz
grhohertz deleted the feat/pinned-input-row branch October 13, 2026 13:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant