diff --git a/ui-tui/src/app/interfaces.ts b/ui-tui/src/app/interfaces.ts index 1d7cdaead0..9b987f87d3 100644 --- a/ui-tui/src/app/interfaces.ts +++ b/ui-tui/src/app/interfaces.ts @@ -285,6 +285,7 @@ export interface AppLayoutActions { answerClarify: (answer: string) => void answerSecret: (value: string) => void answerSudo: (pw: string) => void + clearSelection: () => void onModelSelect: (value: string) => void resumeById: (id: string) => void setStickyPrompt: (value: string) => void diff --git a/ui-tui/src/app/useMainApp.ts b/ui-tui/src/app/useMainApp.ts index 9f2cae78d6..168454f8ba 100644 --- a/ui-tui/src/app/useMainApp.ts +++ b/ui-tui/src/app/useMainApp.ts @@ -25,6 +25,7 @@ import type { Msg, PanelSection, SlashCatalog } from '../types.js' import { createGatewayEventHandler } from './createGatewayEventHandler.js' import { createSlashHandler } from './createSlashHandler.js' +import { getInputSelection } from './inputSelectionStore.js' import { type GatewayRpc, type TranscriptRow } from './interfaces.js' import { $overlayState, patchOverlayState } from './overlayStore.js' import { scrollWithSelectionBy } from './scroll.js' @@ -147,6 +148,11 @@ export function useMainApp(gw: GatewayClient) { selection.setSelectionBgColor(ui.theme.color.selectionBg) }, [selection, ui.theme.color.selectionBg]) + const clearSelection = useCallback(() => { + selection.clearSelection() + getInputSelection()?.clear() + }, [selection]) + const composer = useComposerState({ gw, onClipboardPaste: quiet => clipboardPasteRef.current(quiet), @@ -519,6 +525,7 @@ export function useMainApp(gw: GatewayClient) { [ appendMessage, bellOnComplete, + clearSelection, composerActions.setInput, gateway, panel, @@ -691,11 +698,12 @@ export function useMainApp(gw: GatewayClient) { answerClarify, answerSecret, answerSudo, + clearSelection, onModelSelect, resumeById: session.resumeById, setStickyPrompt }), - [answerApproval, answerClarify, answerSecret, answerSudo, onModelSelect, session.resumeById] + [answerApproval, answerClarify, answerSecret, answerSudo, clearSelection, onModelSelect, session.resumeById] ) const appComposer = useMemo( diff --git a/ui-tui/src/components/appLayout.tsx b/ui-tui/src/components/appLayout.tsx index e4e9608365..3c7989a93e 100644 --- a/ui-tui/src/components/appLayout.tsx +++ b/ui-tui/src/components/appLayout.tsx @@ -47,7 +47,18 @@ const TranscriptPane = memo(function TranscriptPane({ return ( <> - + { + if (e.cellIsBlank) { + actions.clearSelection() + } + }} + ref={transcript.scrollRef} + stickyScroll + > {transcript.virtualHistory.topSpacer > 0 ? : null} @@ -118,7 +129,17 @@ const ComposerPane = memo(function ComposerPane({ const inputHeight = inputVisualHeight(composer.input, inputColumns) return ( - + { + if (e.cellIsBlank) { + actions.clearSelection() + } + }} + paddingX={1} + > { + onClick={(e: { localCol?: number; localRow?: number; stopImmediatePropagation?: () => void }) => { if (!focus) { return } + e.stopImmediatePropagation?.() clearSel() const pos = mouseOffset(e) const next = offsetFromPosition(display, pos.row, pos.col, columns)