mirror of
https://github.com/pacnpal/Roo-Code.git
synced 2025-12-20 12:21:13 -05:00
Refactor mention regex; highlight task text mentions
This commit is contained in:
@@ -1,7 +1,14 @@
|
|||||||
import React, { forwardRef, useCallback, useEffect, useLayoutEffect, useRef, useState } from "react"
|
import React, { forwardRef, useCallback, useEffect, useLayoutEffect, useRef, useState } from "react"
|
||||||
import DynamicTextArea from "react-textarea-autosize"
|
import DynamicTextArea from "react-textarea-autosize"
|
||||||
import { useExtensionState } from "../context/ExtensionStateContext"
|
import { useExtensionState } from "../context/ExtensionStateContext"
|
||||||
import { getContextMenuOptions, insertMention, removeMention, shouldShowContextMenu } from "../utils/mention-context"
|
import {
|
||||||
|
getContextMenuOptions,
|
||||||
|
insertMention,
|
||||||
|
mentionRegex,
|
||||||
|
mentionRegexGlobal,
|
||||||
|
removeMention,
|
||||||
|
shouldShowContextMenu,
|
||||||
|
} from "../utils/mention-context"
|
||||||
import { MAX_IMAGES_PER_MESSAGE } from "./ChatView"
|
import { MAX_IMAGES_PER_MESSAGE } from "./ChatView"
|
||||||
import ContextMenu from "./ContextMenu"
|
import ContextMenu from "./ContextMenu"
|
||||||
import Thumbnails from "./Thumbnails"
|
import Thumbnails from "./Thumbnails"
|
||||||
@@ -184,11 +191,13 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
|
|||||||
charBeforeCursor === " " || charBeforeCursor === "\n" || charBeforeCursor === "\r\n"
|
charBeforeCursor === " " || charBeforeCursor === "\n" || charBeforeCursor === "\r\n"
|
||||||
const charAfterIsWhitespace =
|
const charAfterIsWhitespace =
|
||||||
charAfterCursor === " " || charAfterCursor === "\n" || charAfterCursor === "\r\n"
|
charAfterCursor === " " || charAfterCursor === "\n" || charAfterCursor === "\r\n"
|
||||||
|
// checks if char before cusor is whitespace after a mention
|
||||||
if (
|
if (
|
||||||
charBeforeIsWhitespace &&
|
charBeforeIsWhitespace &&
|
||||||
inputValue.slice(0, cursorPosition - 1).match(/@((?:\/|\w+:\/\/)[^\s]+|problems)$/)
|
inputValue.slice(0, cursorPosition - 1).match(new RegExp(mentionRegex.source + "$")) // "$" is added to ensure the match occurs at the end of the string
|
||||||
) {
|
) {
|
||||||
const newCursorPosition = cursorPosition - 1
|
const newCursorPosition = cursorPosition - 1
|
||||||
|
// if mention is followed by another word, then instead of deleting the space separating them we just move the cursor to the end of the mention
|
||||||
if (!charAfterIsWhitespace) {
|
if (!charAfterIsWhitespace) {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
textAreaRef.current?.setSelectionRange(newCursorPosition, newCursorPosition)
|
textAreaRef.current?.setSelectionRange(newCursorPosition, newCursorPosition)
|
||||||
@@ -349,12 +358,11 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
|
|||||||
if (!textAreaRef.current || !highlightLayerRef.current) return
|
if (!textAreaRef.current || !highlightLayerRef.current) return
|
||||||
|
|
||||||
const text = textAreaRef.current.value
|
const text = textAreaRef.current.value
|
||||||
const mentionRegex = /@((?:\/|\w+:\/\/)[^\s]+|problems\b)/g
|
|
||||||
|
|
||||||
highlightLayerRef.current.innerHTML = text
|
highlightLayerRef.current.innerHTML = text
|
||||||
.replace(/\n$/, "\n\n")
|
.replace(/\n$/, "\n\n")
|
||||||
.replace(/[<>&]/g, (c) => ({ "<": "<", ">": ">", "&": "&" }[c] || c))
|
.replace(/[<>&]/g, (c) => ({ "<": "<", ">": ">", "&": "&" }[c] || c))
|
||||||
.replace(mentionRegex, '<mark class="mention-context-highlight">$&</mark>')
|
.replace(mentionRegexGlobal, '<mark class="mention-context-highlight">$&</mark>')
|
||||||
|
|
||||||
highlightLayerRef.current.scrollTop = textAreaRef.current.scrollTop
|
highlightLayerRef.current.scrollTop = textAreaRef.current.scrollTop
|
||||||
highlightLayerRef.current.scrollLeft = textAreaRef.current.scrollLeft
|
highlightLayerRef.current.scrollLeft = textAreaRef.current.scrollLeft
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import React, { memo, useEffect, useMemo, useRef, useState } from "react"
|
|||||||
import { useWindowSize } from "react-use"
|
import { useWindowSize } from "react-use"
|
||||||
import { ClaudeMessage } from "../../../src/shared/ExtensionMessage"
|
import { ClaudeMessage } from "../../../src/shared/ExtensionMessage"
|
||||||
import { useExtensionState } from "../context/ExtensionStateContext"
|
import { useExtensionState } from "../context/ExtensionStateContext"
|
||||||
|
import { mentionRegexGlobal } from "../utils/mention-context"
|
||||||
import { vscode } from "../utils/vscode"
|
import { vscode } from "../utils/vscode"
|
||||||
import Thumbnails from "./Thumbnails"
|
import Thumbnails from "./Thumbnails"
|
||||||
|
|
||||||
@@ -147,7 +148,7 @@ const TaskHeader: React.FC<TaskHeaderProps> = ({
|
|||||||
minWidth: 0, // This allows the div to shrink below its content size
|
minWidth: 0, // This allows the div to shrink below its content size
|
||||||
}}>
|
}}>
|
||||||
<span style={{ fontWeight: "bold" }}>Task{!isTaskExpanded && ":"}</span>
|
<span style={{ fontWeight: "bold" }}>Task{!isTaskExpanded && ":"}</span>
|
||||||
{!isTaskExpanded && <span style={{ marginLeft: 4 }}>{task.text}</span>}
|
{!isTaskExpanded && <span style={{ marginLeft: 4 }}>{highlightMentions(task.text)}</span>}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{!isTaskExpanded && isCostAvailable && (
|
{!isTaskExpanded && isCostAvailable && (
|
||||||
@@ -193,7 +194,7 @@ const TaskHeader: React.FC<TaskHeaderProps> = ({
|
|||||||
wordBreak: "break-word",
|
wordBreak: "break-word",
|
||||||
overflowWrap: "anywhere",
|
overflowWrap: "anywhere",
|
||||||
}}>
|
}}>
|
||||||
{task.text}
|
{highlightMentions(task.text)}
|
||||||
</div>
|
</div>
|
||||||
{!isTextExpanded && showSeeMore && (
|
{!isTextExpanded && showSeeMore && (
|
||||||
<div
|
<div
|
||||||
@@ -336,6 +337,25 @@ const TaskHeader: React.FC<TaskHeaderProps> = ({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const highlightMentions = (text?: string) => {
|
||||||
|
if (!text) return []
|
||||||
|
const parts = text.split(mentionRegexGlobal)
|
||||||
|
return parts.reduce((acc, part, index) => {
|
||||||
|
if (index % 2 === 0) {
|
||||||
|
// This is regular text
|
||||||
|
acc.push(part)
|
||||||
|
} else {
|
||||||
|
// This is a mention
|
||||||
|
acc.push(
|
||||||
|
<span style={{ backgroundColor: "yellow" }} key={`mention-${index}`}>
|
||||||
|
@{part}
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return acc
|
||||||
|
}, [] as (string | JSX.Element)[])
|
||||||
|
}
|
||||||
|
|
||||||
const ExportButton = () => (
|
const ExportButton = () => (
|
||||||
<VSCodeButton
|
<VSCodeButton
|
||||||
appearance="icon"
|
appearance="icon"
|
||||||
|
|||||||
@@ -1,16 +1,12 @@
|
|||||||
// export const mockPaths = [
|
/*
|
||||||
// { type: "problems", path: "Problems" },
|
Mention regex
|
||||||
// { type: "file", path: "/src/components/Header.tsx" },
|
- File and folder paths (starting with '/')
|
||||||
// { type: "file", path: "/src/components/Footer.tsx" },
|
- URLs (containing '://')
|
||||||
// { type: "file", path: "/src/utils/helpers.ts" },
|
- The 'problems' keyword
|
||||||
// { type: "folder", path: "/src/components" },
|
- Word boundary after 'problems' to avoid partial matches
|
||||||
// { type: "folder", path: "/src/utils" },
|
*/
|
||||||
// { type: "folder", path: "/public/images" },
|
export const mentionRegex = /@((?:\/|\w+:\/\/)[^\s]+|problems\b)/
|
||||||
// { type: "file", path: "/public/index.html" },
|
export const mentionRegexGlobal = new RegExp(mentionRegex.source, "g")
|
||||||
// { type: "file", path: "/package.json" },
|
|
||||||
// { type: "folder", path: "/node_modules" },
|
|
||||||
// { type: "file", path: "/README.md" },
|
|
||||||
// ]
|
|
||||||
|
|
||||||
export function insertMention(text: string, position: number, value: string): string {
|
export function insertMention(text: string, position: number, value: string): string {
|
||||||
const beforeCursor = text.slice(0, position)
|
const beforeCursor = text.slice(0, position)
|
||||||
@@ -30,7 +26,6 @@ export function insertMention(text: string, position: number, value: string): st
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function removeMention(text: string, position: number): { newText: string; newPosition: number } {
|
export function removeMention(text: string, position: number): { newText: string; newPosition: number } {
|
||||||
const mentionRegex = /@((?:\/|\w+:\/\/)[^\s]+|problems\b)/
|
|
||||||
const beforeCursor = text.slice(0, position)
|
const beforeCursor = text.slice(0, position)
|
||||||
const afterCursor = text.slice(position)
|
const afterCursor = text.slice(position)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user