Skip to content

Unify TUI input editing in Tui::InputField - #134

Closed
tobi wants to merge 2 commits into
spinel-aot-lintfrom
tui-input-field
Closed

Unify TUI input editing in Tui::InputField#134
tobi wants to merge 2 commits into
spinel-aot-lintfrom
tui-input-field

Conversation

@tobi

@tobi tobi commented Aug 13, 2026

Copy link
Copy Markdown
Owner

Stacked on #133.

Steal from tobi/try-cli: one real input widget instead of four copy-pasted editors. try-cli's tui_push/tui_pop is an ANSI style stack, not a view stack; Ruby's Screen/Section/Line layout is already better, so this only ports the input/terminal layer.

  • Tui::InputField#handle_key used by search, rename, graduate, and the YES prompt
  • Left/Right move the cursor; Ctrl-U kill-to-start; Delete-forward; Ctrl-H backspace
  • Reverse-video cursor #to_s unchanged (existing screenshots still match)
  • TryEntry#method_missing replaced with explicit accessors
  • at_exit restores alt-screen / cooked / cursor if we crash in raw mode
  • Drain leftover stdin on TUI exit; consume unknown CSI/mouse so trackpad junk doesn't land in the filter

MRI and native: 399/399 (original 397 plus two keyboard tests). runner_and_compare.sh 13/13.

Not in this PR: C style stack, C fuzzy scoring, ghost-placeholder rename UX, collapsing dialogs into a single-loop mode enum.

Demo

Same key story on both runtimes (cursor into spin, insert x, Ctrl-A/E, Ctrl-U, rename):

MRI

try MRI

Native / Spinel

try native

Playable: MRI asciinema · native asciinema

Benchmark (hyperfine)

MRI ruby try.rb vs native dist/try, 2026-08-13 16:04 EDT. hyperfine 1.19.0, --shell=none -w 3 -r 20. Ruby 3.3.8, Spinel 79b1aba8bdef (PR 3906). Native at measurement was ~1.0 MiB unstripped; current dist/try after -Os+strip is 705 KB. Native won every case.

Case MRI native Speedup
--help 69.4 ± 4.8 ms 0.956 ± 0.096 ms 72.6×
--version 70.8 ± 6.3 ms 0.959 ± 0.125 ms 73.8×
no args (exit 2) 68.7 ± 4.3 ms 0.982 ± 0.068 ms 69.9×
init 96.5 ± 9.4 ms 21.2 ± 1.3 ms 4.5×
TUI empty 74.0 ± 8.4 ms 1.28 ± 0.14 ms 57.8×
TUI 5 dirs 72.0 ± 6.0 ms 1.38 ± 0.08 ms 52.1×
TUI --and-keys=beta 72.4 ± 5.9 ms 2.70 ± 0.35 ms 26.8×
TUI exec beta 74.6 ± 8.1 ms 1.49 ± 0.16 ms 50.2×
clone script 70.3 ± 6.2 ms 0.959 ± 0.103 ms 73.3×
worktree script 72.9 ± 8.6 ms 1.01 ± 0.09 ms 71.9×
scan 1000 dirs 80.3 ± 7.3 ms 8.57 ± 0.69 ms 9.4×
filter 1000 dirs 93.9 ± 5.5 ms 40.9 ± 4.8 ms 2.3×

init still forks ps to detect fish vs bash (~20 ms on native). The 1000-entry filter is whole-process (scan + four keystrokes + re-renders), not an isolated matcher.

tobi added 2 commits August 13, 2026 20:53
Steal try-cli's editor keys (arrows, Ctrl-U, Delete) into one Spinel-safe widget used by search, rename, graduate, and delete prompts, with emergency terminal restore on crash.
Short asciinema captures of the InputField editor (cursor motion, insert-in-middle, Ctrl-U) on both ruby try.rb and dist/try.
@tobi

tobi commented Aug 13, 2026

Copy link
Copy Markdown
Owner Author

TUI demos

Same key story on MRI and the Spinel native binary: type spin, Left into the word, insert xsxpin, Ctrl-A/E, Backspace, Ctrl-U, filter tui, open rename, Esc.

MRI (ruby try.rb)

try MRI

Native / Spinel (dist/try)

try native

Playable asciinema (unclaimed uploads expire in 7 days):

.cast files are in demo/ (asciinema play demo/try-mri.cast).

@tobi

tobi commented Aug 13, 2026

Copy link
Copy Markdown
Owner Author

Benchmark (hyperfine, MRI vs native)

Measured 2026-08-13 16:04 EDT on this box. hyperfine 1.19.0, --shell=none -w 3 -r 20 (native is <5 ms; a shell would swamp it). Ruby 3.3.8, Spinel 79b1aba8bdef (PR 3906). Native at measurement was the unstripped ~1.0 MiB binary; current dist/try after -Os+strip is 705 KB.

Speedup is MRI mean / native mean. Native won every case.

| Case | MRI mean ± σ | native mean ± σ | Speedup |
|------|----------------|-------------------|
| --help | 69.4 ± 4.8 ms | 0.956 ± 0.096 ms | 72.6× |
| --version | 70.8 ± 6.3 ms | 0.959 ± 0.125 ms | 73.8× |
| no args (exit 2) | 68.7 ± 4.3 ms | 0.982 ± 0.068 ms | 69.9× |
| init | 96.5 ± 9.4 ms | 21.2 ± 1.3 ms | 4.5× |
| TUI empty + --and-exit | 74.0 ± 8.4 ms | 1.28 ± 0.14 ms | 57.8× |
| TUI 5 dirs | 72.0 ± 6.0 ms | 1.38 ± 0.08 ms | 52.1× |
| TUI filter --and-keys=beta | 72.4 ± 5.9 ms | 2.70 ± 0.35 ms | 26.8× |
| TUI exec beta | 74.6 ± 8.1 ms | 1.49 ± 0.16 ms | 50.2× |
| clone script only | 70.3 ± 6.2 ms | 0.959 ± 0.103 ms | 73.3× |
| worktree script only | 72.9 ± 8.6 ms | 1.01 ± 0.09 ms | 71.9× |
| TUI scan 1000 dirs | 80.3 ± 7.3 ms | 8.57 ± 0.69 ms | 9.4× |
| TUI filter 1000 dirs | 93.9 ± 5.5 ms | 40.9 ± 4.8 ms | 2.3× |

init is the outlier because native still forks ps to detect fish vs bash (~20 ms). The 1000-entry filter is whole-process (scan + four keystrokes + re-renders), not an isolated matcher microbench.

@tobi

tobi commented Aug 13, 2026

Copy link
Copy Markdown
Owner Author

Moved off the Spinel stack. The TUI InputField work now lives on main as #135 (no TryCompat, 399/399 MRI).

This stacked PR mixed Spinel + TUI + native demos; closing so #130#131#133 stays Spinel-only.

@tobi tobi closed this Aug 13, 2026
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