fix(tui): address follow-up review nits

This commit is contained in:
Brooklyn Nicholson 2026-04-26 05:06:57 -05:00
parent a0aebad673
commit 2e6c3c7d23
6 changed files with 44 additions and 35 deletions

View file

@ -21,7 +21,7 @@ const GLOBAL_MODEL_FLAG_RE = /(?:^|\s)--global(?:\s|$)/
const persistedModelArg = (arg: string) => {
const trimmed = arg.trim()
return GLOBAL_MODEL_FLAG_RE.test(trimmed) ? trimmed : `${trimmed} --global`
return !trimmed || GLOBAL_MODEL_FLAG_RE.test(trimmed) ? trimmed : `${trimmed} --global`
}
export const sessionCommands: SlashCommand[] = [
@ -73,7 +73,7 @@ export const sessionCommands: SlashCommand[] = [
return
}
if (!arg) {
if (!arg.trim()) {
return patchOverlayState({ modelPicker: true })
}

View file

@ -51,24 +51,29 @@ export function useSubmission(opts: UseSubmissionOptions) {
const typingIdleTimer = useRef<ReturnType<typeof setTimeout> | null>(null)
useEffect(() => {
if (composerState.input || composerState.inputBuf.length) {
if (getUiState().busy) {
turnController.boostStreamingForTyping()
}
if (typingIdleTimer.current) {
clearTimeout(typingIdleTimer.current)
}
typingIdleTimer.current = setTimeout(() => {
typingIdleTimer.current = null
turnController.relaxStreaming()
}, TYPING_IDLE_MS)
if (typingIdleTimer.current) {
clearTimeout(typingIdleTimer.current)
typingIdleTimer.current = null
}
if (!composerState.input && !composerState.inputBuf.length) {
turnController.relaxStreaming()
return
}
if (getUiState().busy) {
turnController.boostStreamingForTyping()
}
typingIdleTimer.current = setTimeout(() => {
typingIdleTimer.current = null
turnController.relaxStreaming()
}, TYPING_IDLE_MS)
return () => {
if (typingIdleTimer.current) {
clearTimeout(typingIdleTimer.current)
typingIdleTimer.current = null
}
}
}, [composerState.input, composerState.inputBuf])

View file

@ -110,16 +110,6 @@ const TranscriptPane = memo(function TranscriptPane({
<>
<ScrollBox flexDirection="column" flexGrow={1} flexShrink={1} ref={transcript.scrollRef} stickyScroll>
<Box flexDirection="column" paddingX={1}>
<StreamingAssistant
busy={ui.busy}
cols={composer.cols}
compact={ui.compact}
detailsMode={ui.detailsMode}
progress={progress}
sections={ui.sections}
t={ui.theme}
/>
{transcript.virtualHistory.topSpacer > 0 ? <Box height={transcript.virtualHistory.topSpacer} /> : null}
{transcript.virtualRows.slice(transcript.virtualHistory.start, transcript.virtualHistory.end).map(row => (
@ -147,6 +137,15 @@ const TranscriptPane = memo(function TranscriptPane({
{transcript.virtualHistory.bottomSpacer > 0 ? <Box height={transcript.virtualHistory.bottomSpacer} /> : null}
<StreamingAssistant
busy={ui.busy}
cols={composer.cols}
compact={ui.compact}
detailsMode={ui.detailsMode}
progress={progress}
sections={ui.sections}
t={ui.theme}
/>
</Box>
</ScrollBox>

View file

@ -431,13 +431,11 @@ export function TextInput({
parentChangeTimer.current = setTimeout(flushParentChange, 16)
}
const flushLocalRender = () => {
const cancelLocalRender = () => {
if (localRenderTimer.current) {
clearTimeout(localRenderTimer.current)
localRenderTimer.current = null
}
setCur(curRef.current)
}
const scheduleLocalRender = () => {
@ -445,7 +443,10 @@ export function TextInput({
return
}
localRenderTimer.current = setTimeout(flushLocalRender, 16)
localRenderTimer.current = setTimeout(() => {
localRenderTimer.current = null
setCur(curRef.current)
}, 16)
}
const canFastEchoBase = () => focus && termFocus && !selected && !mask && !!stdout?.isTTY
@ -468,9 +469,7 @@ export function TextInput({
return false
}
const prev = current[cursor - 1]
return !!prev && stringWidth(prev) === 1
return stringWidth(current.slice(prevPos(current, cursor), cursor)) === 1
}
const commit = (next: string, nextCur: number, track = true, syncParent = true, syncLocal = true) => {
@ -494,7 +493,7 @@ export function TextInput({
}
if (syncLocal) {
flushLocalRender()
cancelLocalRender()
setCur(c)
} else {
scheduleLocalRender()

View file

@ -235,7 +235,7 @@ export function useVirtualHistory(
if (dirty) {
setVer(v => v + 1)
}
}, [end, hasScrollRef, items, n, offsets, scrollRef, start, total, vp])
}, [end, hasScrollRef, items, n, offsets, scrollRef, start, sticky, total, vp])
return {
bottomSpacer: Math.max(0, total - (offsets[end] ?? total)),