Skip to content
Open
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
25 changes: 25 additions & 0 deletions apps/web/src/components/ChatView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -816,6 +816,9 @@ export default function ChatView(props: ChatViewProps) {
const attachmentPreviewHandoffTimeoutByMessageIdRef = useRef<Record<string, number>>({});
const sendInFlightRef = useRef(false);
const dragDepthRef = useRef(0);
const inputHistoryRef = useRef<string[]>([]);
const historyIdxRef = useRef(-1);
const historyDraftRef = useRef('');
const terminalOpenByThreadRef = useRef<Record<string, boolean>>({});
const setMessagesScrollContainerRef = useCallback((element: HTMLDivElement | null) => {
messagesScrollRef.current = element;
Expand Down Expand Up @@ -2509,6 +2512,14 @@ export default function ChatView(props: ChatViewProps) {
composerTerminalContextsRef.current = composerTerminalContexts;
}, [composerTerminalContexts]);

useEffect(() => {
inputHistoryRef.current = (activeThread?.messages ?? [])
.filter((m) => m.role === 'user' && m.text.trim())
.map((m) => m.text.trim())
.reverse();
historyIdxRef.current = -1;
}, [activeThread?.id]); // eslint-disable-line react-hooks/exhaustive-deps

useEffect(() => {
if (!activeThread?.id) return;
if (activeThread.messages.length === 0) {
Expand Down Expand Up @@ -3178,6 +3189,7 @@ export default function ChatView(props: ChatViewProps) {
description: toastCopy.description,
});
}
if (promptForSend.trim()) { inputHistoryRef.current.unshift(promptForSend.trim()); historyIdxRef.current = -1; }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

History index not reset on early-return send paths

Low Severity

The plan-follow-up path and standalone-slash-command path both clear the prompt and return early from onSend, never reaching the historyIdxRef.current = -1 reset at line 3192. If the user was navigating history before triggering either path, historyIdxRef remains positive, so a subsequent ArrowDown would unexpectedly restore a history entry instead of behaving as normal cursor movement.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 069183c. Configure here.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cant produce any buggy interactions with slash commands.

promptRef.current = "";
clearComposerDraftContent(scopeThreadRef(activeThread.environmentId, threadIdForSend));
setComposerHighlightedItemId(null);
Expand Down Expand Up @@ -4066,6 +4078,19 @@ export default function ChatView(props: ChatViewProps) {
}
}

const cur = composerEditorRef.current?.readSnapshot()?.cursor ?? 0;
if (key === 'ArrowUp' && inputHistoryRef.current.length > 0 && !promptRef.current.slice(0, cur).includes('\n')) {
if (historyIdxRef.current === -1) historyDraftRef.current = promptRef.current;
historyIdxRef.current = Math.min(historyIdxRef.current + 1, inputHistoryRef.current.length - 1);
setPrompt(inputHistoryRef.current[historyIdxRef.current]!);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

History navigation doesn't synchronously update promptRef

High Severity

The composer's new history navigation updates the prompt state but not promptRef.current synchronously. This leaves promptRef.current stale, causing onSend to potentially send the wrong message and the ArrowUp multiline guard to misbehave.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 375ee94. Configure here.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this does not happen during testing.

return true;
}
if (key === 'ArrowDown' && historyIdxRef.current >= 0 && !promptRef.current.slice(cur).includes('\n')) {
const next = historyIdxRef.current - 1;
historyIdxRef.current = next;
setPrompt(next >= 0 ? inputHistoryRef.current[next]! : historyDraftRef.current);
return true;
}
if (key === "Enter" && !event.shiftKey) {
void onSend();
return true;
Expand Down
Loading