Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 52 additions & 1 deletion webview-ui/src/components/chat/ChatTextArea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import ContextMenu from "./ContextMenu"
import { VolumeX, Pin, Check } from "lucide-react"
import { IconButton } from "./IconButton"
import { cn } from "@/lib/utils"
import { usePromptHistory } from "./hooks/usePromptHistory"

interface ChatTextAreaProps {
inputValue: string
Expand Down Expand Up @@ -75,6 +76,8 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
cwd,
pinnedApiConfigs,
togglePinnedApiConfig,
taskHistory,
clineMessages,
} = useExtensionState()

// Find the ID and display text for the currently selected API configuration
Expand Down Expand Up @@ -153,6 +156,21 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
const [isEnhancingPrompt, setIsEnhancingPrompt] = useState(false)
const [isFocused, setIsFocused] = useState(false)

// Use custom hook for prompt history navigation
const {
inputValueWithCursor,
setInputValueWithCursor,
handleHistoryNavigation,
resetHistoryNavigation,
resetOnInputChange,
} = usePromptHistory({
clineMessages,
taskHistory,
cwd,
inputValue,
setInputValue,
})

// Fetch git commits when Git is selected or when typing a hash.
useEffect(() => {
if (selectedType === ContextMenuOptionType.Git || /^[a-f0-9]+$/i.test(searchQuery)) {
Expand Down Expand Up @@ -360,10 +378,17 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(

const isComposing = event.nativeEvent?.isComposing ?? false

// Handle prompt history navigation using custom hook
if (handleHistoryNavigation(event, showContextMenu, isComposing)) {
return
}

if (event.key === "Enter" && !event.shiftKey && !isComposing) {
event.preventDefault()

if (!sendingDisabled) {
// Reset history navigation state when sending
resetHistoryNavigation()
onSend()
}
}
Expand Down Expand Up @@ -427,6 +452,8 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
queryItems,
customModes,
fileSearchResults,
handleHistoryNavigation,
resetHistoryNavigation,
],
)

Expand All @@ -437,6 +464,27 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
}
}, [inputValue, intendedCursorPosition])

// Handle cursor positioning after history navigation
useLayoutEffect(() => {
if (!inputValueWithCursor.afterRender || !textAreaRef.current) return

if (inputValueWithCursor.afterRender === "SET_CURSOR_FIRST_LINE") {
const firstLineEnd =
inputValueWithCursor.value.indexOf("\n") === -1
? inputValueWithCursor.value.length
: inputValueWithCursor.value.indexOf("\n")
textAreaRef.current.setSelectionRange(firstLineEnd, firstLineEnd)
} else if (inputValueWithCursor.afterRender === "SET_CURSOR_LAST_LINE") {
const lines = inputValueWithCursor.value.split("\n")
const lastLineStart = inputValueWithCursor.value.length - lines[lines.length - 1].length
textAreaRef.current.setSelectionRange(lastLineStart, lastLineStart)
} else if (inputValueWithCursor.afterRender === "SET_CURSOR_START") {
textAreaRef.current.setSelectionRange(0, 0)
}

setInputValueWithCursor({ value: inputValueWithCursor.value })
}, [inputValueWithCursor, setInputValueWithCursor])

// Ref to store the search timeout.
const searchTimeoutRef = useRef<NodeJS.Timeout | null>(null)

Expand All @@ -445,6 +493,9 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
const newValue = e.target.value
setInputValue(newValue)

// Reset history navigation when user types
resetOnInputChange()

const newCursorPosition = e.target.selectionStart
setCursorPosition(newCursorPosition)

Expand Down Expand Up @@ -499,7 +550,7 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
setFileSearchResults([]) // Clear file search results.
}
},
[setInputValue, setSearchRequestId, setFileSearchResults, setSearchLoading],
[setInputValue, setSearchRequestId, setFileSearchResults, setSearchLoading, resetOnInputChange],
)

useEffect(() => {
Expand Down
Loading
Loading