Files
rdbms-playground/docs/adr/0049-input-field-readline-keymap.md
claude@clouddev1 66c8bdaa65 feat(input): readline keymap — Esc-clear + Ctrl-A/E/W/K/U (#29)
Implement the deferred I1b readline shortcuts in the command input
field (ADR-0049, closing issue #29):

  Esc      clear a partly-typed command (only when no completion memo)
  Ctrl-A   cursor to line start (Home alias)
  Ctrl-E   cursor to line end (End alias)
  Ctrl-W   delete the previous word (readline-style, UTF-8 safe)
  Ctrl-K   kill to end of line
  Ctrl-U   kill to start of line

Esc precedence is preserved: a live Tab-completion memo still wins
(Esc undoes the completion first, ADR-0022); Esc clears only when no
memo is alive. While a sidebar panel is focused (Ctrl-O), Esc exits
navigation mode upstream and never clears the input draft. Cursor-only
keys leave history navigation intact like Home/End; buffer-mutating
keys end it like Backspace.

New helpers clear_input / delete_prev_word / kill_to_end /
kill_to_start in src/app.rs. 22 new Tier-1 tests (2458 pass / 0 fail
/ 0 skip, clippy clean). ADR-0049 amends ADR-0046's OOS list;
requirements.md I1b marked done.
2026-06-12 22:12:08 +00:00

5.6 KiB

ADR-0049: Input-field readline keymap — Esc-clear + Ctrl-A/E/W/K/U (I1b)

Status

Accepted + implemented 2026-06-12 (issue #29). Closes Gitea #29 ("Command input keystroke support") and the deferred I1b readline requirement in requirements.md. Every fork below was escalated to the user and user-chosen before any code was written; implemented test-first (22 new Tier-1 tests in src/app.rs, all green; clippy nursery clean).

This ADR amends ADR-0046, which explicitly listed "readline shortcuts (I1b)" in its out-of-scope set: that item is now in scope and decided here. It is orthogonal to ADR-0003's input-mode model (simple vs advanced, the : sigil) — these are editing keys within the input field, not mode or sigil changes — and it extends the single-line cursor editing already shipped under requirement I1a (Left/Right/Home/End/ Backspace/Delete, app.rs).

Context

The input field already supported in-line cursor editing (I1a): Left/ Right by char (UTF-8 aware), Home/End to the extremes, Backspace/Delete. Two gaps remained, raised in issue #29:

  1. No way to clear a partly-typed command in one keystroke — a user who started typing the wrong thing had to hold Backspace.
  2. No readline cursor/kill shortcuts (Ctrl-A/Ctrl-E and friends) for keyboards without Home/End and for muscle-memory in a command-driven workflow. This is requirement I1b, deferred by ADR-0046.

Esc was free in the input field except that a live Tab-completion memo consumes it first (to undo the completion in one keystroke, ADR-0022). Ctrl-A/E/W/K/U were unbound. The existing chords are Ctrl-C (quit), Ctrl-O (nav focus cycle, ADR-0046), and Ctrl-] (demo caption toggle, ADR-0047) — none collide with a/e/w/k/u.

Decision

Bind the following in the input field (non-modal, non-navigation, both input modes), in App::handle_key:

Key Action
Esc Clear the input (empty buffer, cursor→0, scroll→0)
Ctrl-A Cursor to line start (alias of Home)
Ctrl-E Cursor to line end (alias of End)
Ctrl-W Delete the word before the cursor
Ctrl-K Kill from the cursor to end of line
Ctrl-U Kill from start of line to the cursor

Behavioural rules:

  • Esc precedence. A live completion memo still wins: the first Esc undoes the completion (ADR-0022), and Esc only clears when no memo is alive. This is a natural progression — Esc once to back out the completion, Esc again to clear.
  • Esc does not clear while navigating the sidebar. When a sidebar panel is focused (Ctrl-O, ADR-0046 DC3), handle_key routes every key to the navigation handler before the input-field keymap, where Esc exits navigation mode (nav_exit). Entering nav mode never touched the input buffer, so Esc-to-close-the-panel returns focus to the input with the partly-typed command intact — it cannot reach the clear binding. Locked by a regression test.
  • Single Esc clears (user-chosen over double-Esc). Discoverable and fast; the trade-off (an accidental Esc wipes an unsubmitted line) was accepted. A submitted line is always recoverable from history; only unsubmitted draft text is lost.
  • Cursor-only keys don't touch history navigation. Ctrl-A/Ctrl-E, like Home/End, move the cursor without ending history recall.
  • Buffer-mutating keys end history navigation. Esc-clear and Ctrl-W/K/U call cancel_history_navigation (the cleared/edited line is the new draft), matching Backspace/Delete.
  • Ctrl-W is readline-style and UTF-8 safe. It eats any run of trailing whitespace, then the preceding run of non-whitespace; word boundaries are found on char boundaries so multi-byte words delete cleanly. It only ever deletes back to the cursor (a mid-line Ctrl-W leaves the suffix intact).

Helpers added: clear_input, delete_prev_word, kill_to_end, kill_to_start (src/app.rs), mirroring the existing cursor_left / delete_before_cursor style.

Forks (all user-chosen)

  • Esc semantics: single-Esc-clears, not double-Esc — discoverable over accident-proof.
  • Scope: the full I1b set (Esc-clear + Ctrl-A/E/W/K/U), not just the issue's literal Ctrl-A/E + Esc — closes the whole I1b requirement in one pass rather than leaving Ctrl-W/K/U for a follow-up.
  • Documentation: a new ADR (this one), recording the input-field keymap convention and amending ADR-0046's OOS list — over folding it into ADR-0046 or shipping it I1a-style with no ADR.

Consequences

  • I1b is complete; requirements.md I1b moves to [x].
  • The new keys are not yet advertised on screen. Surfacing per-focus keybindings in the bottom status line is issue #27's domain (a separate, in-design UX change); this ADR makes the keys work, #27 will make them discoverable.
  • Demo-mode badges (ADR-0047) are not extended to the new Ctrl- chords here. Esc already badges as [ESC]; Ctrl-A/E/W/K/U are glyph-less and would be invisible in an asciinema cast. Whether to add [CTRL-A][CTRL-U] badges is left to ADR-0047's scope and flagged as a follow-up — it is a cast-polish concern, not a #29 requirement.

Out of scope

  • On-screen keybinding hints for the input field (issue #27).
  • Demo badges for the new chords (ADR-0047 follow-up; flagged above).
  • Multi-line input (I1) and its Ctrl-Enter submit — unrelated, still deferred.
  • Word-wise cursor motion (Alt-B/Alt-F) and transpose/yank — not requested; not part of I1b.