Skip to content
Closed
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
57 changes: 57 additions & 0 deletions webview-ui/src/components/chat/ChatTextArea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import { MAX_IMAGES_PER_MESSAGE } from "./ChatView"
import ContextMenu from "./ContextMenu"
import { IndexingStatusBadge } from "./IndexingStatusBadge"
import { usePromptHistory } from "./hooks/usePromptHistory"
import "../../styles/chat-textarea.css"

interface ChatTextAreaProps {
inputValue: string
Expand Down Expand Up @@ -205,6 +206,7 @@ export const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
const [isMouseDownOnMenu, setIsMouseDownOnMenu] = useState(false)
const highlightLayerRef = useRef<HTMLDivElement>(null)
const [selectedMenuIndex, setSelectedMenuIndex] = useState(-1)
const [isCtrlOrCmdPressed, setIsCtrlOrCmdPressed] = useState(false)
const [selectedType, setSelectedType] = useState<ContextMenuOptionType | null>(null)
const [justDeletedSpaceAfterMention, setJustDeletedSpaceAfterMention] = useState(false)
const [intendedCursorPosition, setIntendedCursorPosition] = useState<number | null>(null)
Expand Down Expand Up @@ -712,6 +714,59 @@ export const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
setIsMouseDownOnMenu(true)
}, [])

// Track ctrl/cmd key state
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
if (e.ctrlKey || e.metaKey) {
setIsCtrlOrCmdPressed(true)
}
}

const handleKeyUp = (e: KeyboardEvent) => {
if (!e.ctrlKey && !e.metaKey) {
setIsCtrlOrCmdPressed(false)
}
}

window.addEventListener("keydown", handleKeyDown)
window.addEventListener("keyup", handleKeyUp)

return () => {
window.removeEventListener("keydown", handleKeyDown)
window.removeEventListener("keyup", handleKeyUp)
}
}, [])

// Handle clicks on mentions in the highlight layer
const handleHighlightClick = useCallback((e: React.MouseEvent<HTMLDivElement>) => {
// Only handle clicks with ctrl/cmd key pressed
if (!e.ctrlKey && !e.metaKey) {
return
}

// Get the clicked element
const target = e.target as HTMLElement

// Check if we clicked on a mention highlight
if (target.classList.contains("mention-context-textarea-highlight")) {
const mentionText = target.textContent
if (mentionText) {
// Extract the mention text (remove @ prefix if present)
const cleanMention = mentionText.startsWith("@") ? mentionText.slice(1) : mentionText

// Send message to open the mention
vscode.postMessage({
type: "openMention",
text: cleanMention,
})

// Prevent default behavior
e.preventDefault()
e.stopPropagation()
}
}
}, [])

const updateHighlights = useCallback(() => {
if (!textAreaRef.current || !highlightLayerRef.current) return

Expand Down Expand Up @@ -982,6 +1037,7 @@ export const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
<div
ref={highlightLayerRef}
data-testid="highlight-layer"
onClick={handleHighlightClick}
className={cn(
"absolute",
"inset-0",
Expand All @@ -1004,6 +1060,7 @@ export const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
"z-10",
"forced-color-adjust-none",
"rounded",
isCtrlOrCmdPressed && "mention-highlight-clickable",
)}
style={{
color: "transparent",
Expand Down
28 changes: 28 additions & 0 deletions webview-ui/src/styles/chat-textarea.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/* Styles for clickable mentions in the chat textarea */
.mention-highlight-clickable .mention-context-textarea-highlight {
cursor: pointer;
position: relative;
}

.mention-highlight-clickable .mention-context-textarea-highlight:hover {
text-decoration: underline;
text-decoration-color: var(--vscode-textLink-foreground);
text-underline-offset: 2px;
}

/* Visual feedback for clickable state */
.mention-highlight-clickable .mention-context-textarea-highlight::after {
content: "";
position: absolute;
inset: -2px;
border-radius: 3px;
pointer-events: none;
opacity: 0;
transition: opacity 0.15s ease;
background: var(--vscode-textLink-foreground);
mix-blend-mode: multiply;
}

.mention-highlight-clickable .mention-context-textarea-highlight:hover::after {
opacity: 0.1;
}
Loading