1- import { TextAttributes } from '@opentui/core'
21import { useCallback , useEffect , useMemo , useRef , useState } from 'react'
32import { useShallow } from 'zustand/react/shallow'
43
@@ -32,15 +31,15 @@ import { useSuggestionMenuHandlers } from './hooks/use-suggestion-menu-handlers'
3231import { useTerminalDimensions } from './hooks/use-terminal-dimensions'
3332import { useTheme } from './hooks/use-theme'
3433import { useValidationBanner } from './hooks/use-validation-banner'
34+ import { useQueueUi } from './hooks/use-queue-ui'
35+ import { useQueueControls } from './hooks/use-queue-controls'
3536import { useChatStore } from './state/chat-store'
3637import { createChatScrollAcceleration } from './utils/chat-scroll-accel'
37- import { formatQueuedPreview } from './utils/helpers'
3838import { loadLocalAgents } from './utils/local-agent-registry'
3939import { buildMessageTree } from './utils/message-tree-utils'
4040import { computeInputLayoutMetrics } from './utils/text-layout'
4141import { createMarkdownPalette } from './utils/theme-system'
4242import { BORDER_CHARS } from './utils/ui-constants'
43- import { pluralize } from '@codebuff/common/util/string'
4443
4544import type { ContentBlock } from './types/chat'
4645import type { SendMessageFn } from './types/contracts/send-message'
@@ -363,27 +362,31 @@ export const Chat = ({
363362 activeAgentStreamsRef ,
364363 )
365364
365+ const {
366+ queuedCount,
367+ shouldShowQueuePreview,
368+ queuePreviewTitle,
369+ pausedQueueText,
370+ inputPlaceholder,
371+ } = useQueueUi ( {
372+ queuePaused,
373+ queuedMessages,
374+ separatorWidth,
375+ terminalWidth,
376+ } )
377+
366378 const { handleCtrlC : baseHandleCtrlC , nextCtrlCWillExit } = useExitHandler ( {
367379 inputValue,
368380 setInputValue,
369381 } )
370382
371- const handleCtrlC = useCallback ( ( ) => {
372- if ( queuePaused && queuedMessages . length > 0 ) {
373- clearQueue ( )
374- resumeQueue ( )
375- return true
376- }
377- return baseHandleCtrlC ( )
378- } , [
379- baseHandleCtrlC ,
380- clearQueue ,
383+ const { handleCtrlC, ensureQueueActiveBeforeSubmit } = useQueueControls ( {
381384 queuePaused,
382- queuedMessages . length ,
385+ queuedCount,
386+ clearQueue,
383387 resumeQueue,
384- ] )
385-
386- const [ scrollIndicatorHovered , setScrollIndicatorHovered ] = useState ( false )
388+ baseHandleCtrlC,
389+ } )
387390
388391 // Derive boolean flags from streamStatus for convenience
389392 const isWaitingForResponse = streamStatus === 'waiting'
@@ -438,9 +441,7 @@ export const Chat = ({
438441 } )
439442
440443 const handleSubmit = useCallback ( ( ) => {
441- if ( queuePaused ) {
442- resumeQueue ( )
443- }
444+ ensureQueueActiveBeforeSubmit ( )
444445
445446 return routeUserPrompt ( {
446447 abortControllerRef,
@@ -467,21 +468,29 @@ export const Chat = ({
467468 stopStreaming,
468469 } )
469470 } , [
471+ abortControllerRef ,
470472 agentMode ,
473+ inputRef ,
471474 inputValue ,
475+ isChainInProgressRef ,
472476 isStreaming ,
473- sendMessage ,
474- saveToHistory ,
475- addToQueue ,
477+ logoutMutation ,
476478 streamMessageIdRef ,
477- isChainInProgressRef ,
478- scrollToLatest ,
479- handleCtrlC ,
479+ addToQueue ,
480+ clearMessages ,
480481 clearQueue ,
481- queuedMessages ,
482- pauseQueue ,
483- queuePaused ,
484- resumeQueue ,
482+ handleCtrlC ,
483+ saveToHistory ,
484+ scrollToLatest ,
485+ sendMessage ,
486+ setCanProcessQueue ,
487+ setInputFocused ,
488+ setInputValue ,
489+ setIsAuthenticated ,
490+ setMessages ,
491+ setUser ,
492+ stopStreaming ,
493+ ensureQueueActiveBeforeSubmit ,
485494 ] )
486495
487496 const totalMentionMatches = agentMatches . length + fileMatches . length
@@ -546,28 +555,6 @@ export const Chat = ({
546555 </ text >
547556 ) : null
548557
549- const shouldShowQueuePreview = queuedMessages . length > 0 && ! queuePaused
550- const queuePreviewTitle = useMemo ( ( ) => {
551- if ( ! shouldShowQueuePreview ) return undefined
552- const previewWidth = Math . max ( 30 , separatorWidth - 20 )
553- return formatQueuedPreview ( queuedMessages , previewWidth )
554- } , [ queuedMessages , separatorWidth , shouldShowQueuePreview ] )
555-
556- const pausedQueueText = useMemo ( ( ) => {
557- if ( ! queuePaused || queuedMessages . length === 0 ) return undefined
558- const count = queuedMessages . length
559- return `${ pluralize ( count , 'message' ) } queued — your message sends first`
560- } , [ queuePaused , queuedMessages . length ] )
561- const inputPlaceholder = useMemo ( ( ) => {
562- const base =
563- terminalWidth < 65
564- ? 'Enter a coding task'
565- : 'Enter a coding task or / for commands'
566- if ( queuePaused && queuedMessages . length > 0 ) {
567- return 'Ctrl-C to cancel queued messages'
568- }
569- return base
570- } , [ queuePaused , queuedMessages . length , terminalWidth ] )
571558 const hasSlashSuggestions =
572559 slashContext . active && slashSuggestionItems . length > 0
573560 const hasMentionSuggestions =
@@ -709,8 +696,6 @@ export const Chat = ({
709696 isConnected = { isConnected }
710697 isAtBottom = { isAtBottom }
711698 scrollToLatest = { scrollToLatest }
712- scrollIndicatorHovered = { scrollIndicatorHovered }
713- setScrollIndicatorHovered = { setScrollIndicatorHovered }
714699 />
715700 ) }
716701
0 commit comments