From 95fd023eeb8c9051732c3daacf174a7311d6acb4 Mon Sep 17 00:00:00 2001 From: Brooklyn Nicholson Date: Tue, 21 Apr 2026 18:48:35 -0500 Subject: [PATCH] fix(tui): only cycle history at input boundaries on arrows Follow-up on #13726 from blitz feedback: Up/Down history cycling should only trigger when the caret is at the start/end boundary (or the input is empty).\n\nPreviously useInputHandlers intercepted arrows whenever inputBuf was empty, which still stole Up/Down from normal multiline editing. textInput now publishes caret position through inputSelectionStore even with no active selection, and useInputHandlers gates history/queue cycling on those boundaries. --- ui-tui/src/app/useInputHandlers.ts | 20 ++++++++++++++++---- ui-tui/src/components/textInput.tsx | 22 ++++++++++------------ 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/ui-tui/src/app/useInputHandlers.ts b/ui-tui/src/app/useInputHandlers.ts index 25243e992..f777ba27d 100644 --- a/ui-tui/src/app/useInputHandlers.ts +++ b/ui-tui/src/app/useInputHandlers.ts @@ -288,15 +288,27 @@ export function useInputHandlers(ctx: InputHandlerContext): InputHandlerResult { } if (key.upArrow && !cState.inputBuf.length) { - cycleQueue(1) || cycleHistory(-1) + const inputSel = getInputSelection() + const atStart = !cState.input || (!!inputSel && inputSel.start === 0 && inputSel.end === 0) - return + if (atStart) { + cycleQueue(1) || cycleHistory(-1) + + return + } } if (key.downArrow && !cState.inputBuf.length) { - cycleQueue(-1) || cycleHistory(1) + const inputSel = getInputSelection() + const atEnd = + !cState.input || + (!!inputSel && inputSel.start === cState.input.length && inputSel.end === cState.input.length) - return + if (atEnd || cState.historyIdx !== null) { + cycleQueue(-1) || cycleHistory(1) + + return + } } if (isAction(key, ch, 'c')) { diff --git a/ui-tui/src/components/textInput.tsx b/ui-tui/src/components/textInput.tsx index 536f2f018..d5380faa2 100644 --- a/ui-tui/src/components/textInput.tsx +++ b/ui-tui/src/components/textInput.tsx @@ -400,22 +400,20 @@ export function TextInput({ return } - if (selected) { - setInputSelection({ - clear: () => { + setInputSelection({ + clear: () => { + if (selRef.current) { selRef.current = null setSel(null) - }, - end: selected.end, - start: selected.start, - value: vRef.current - }) - } else { - setInputSelection(null) - } + } + }, + end: selected?.end ?? curRef.current, + start: selected?.start ?? curRef.current, + value: vRef.current + }) return () => setInputSelection(null) - }, [focus, selected]) + }, [cur, focus, selected]) useEffect( () => () => {