mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-07 08:26:51 +00:00
refactor: move selection capture from webview to extension
- Remove selection context state management from ChatView - Remove requestSelectionContext message type and handler - Extension now captures selection directly in newTask and askResponse handlers - Eliminates race condition between selection request and message send - Simplifies architecture by removing unnecessary webview complexity
This commit is contained in:
parent
338d8d01a3
commit
3c7a510c21
4 changed files with 46 additions and 104 deletions
|
|
@ -427,45 +427,46 @@ export const webviewMessageHandler = async (
|
|||
}
|
||||
}
|
||||
|
||||
switch (message.type) {
|
||||
case "requestSelectionContext": {
|
||||
// Get the active editor and its selection
|
||||
const editor = vscode.window.activeTextEditor
|
||||
if (editor && !editor.selection.isEmpty) {
|
||||
const selection = editor.selection
|
||||
const selectedText = editor.document.getText(selection)
|
||||
const filePath = editor.document.uri.fsPath
|
||||
// Helper function to capture current editor selection
|
||||
const captureSelectionContext = ():
|
||||
| {
|
||||
selectedText: string
|
||||
selectionFilePath: string
|
||||
selectionStartLine: number
|
||||
selectionEndLine: number
|
||||
}
|
||||
| undefined => {
|
||||
const editor = vscode.window.activeTextEditor
|
||||
if (editor && !editor.selection.isEmpty) {
|
||||
const selection = editor.selection
|
||||
const selectedText = editor.document.getText(selection)
|
||||
const filePath = editor.document.uri.fsPath
|
||||
|
||||
// Convert to workspace-relative path if possible
|
||||
const workspacePath = provider.cwd
|
||||
let relativeFilePath: string
|
||||
if (filePath.startsWith(workspacePath)) {
|
||||
relativeFilePath = path.relative(workspacePath, filePath)
|
||||
} else {
|
||||
// File is outside workspace, use absolute path
|
||||
relativeFilePath = filePath
|
||||
}
|
||||
|
||||
// VSCode uses 0-based line numbers, convert to 1-based for user-friendly display
|
||||
const startLine = selection.start.line + 1
|
||||
const endLine = selection.end.line + 1
|
||||
|
||||
// Send selection context to webview only - don't store in task
|
||||
await provider.postMessageToWebview({
|
||||
type: "selectionContext",
|
||||
selectedText,
|
||||
selectionFilePath: relativeFilePath,
|
||||
selectionStartLine: startLine,
|
||||
selectionEndLine: endLine,
|
||||
})
|
||||
// Convert to workspace-relative path if possible
|
||||
const workspacePath = provider.cwd
|
||||
let relativeFilePath: string
|
||||
if (filePath.startsWith(workspacePath)) {
|
||||
relativeFilePath = path.relative(workspacePath, filePath)
|
||||
} else {
|
||||
// No selection, send empty context
|
||||
await provider.postMessageToWebview({
|
||||
type: "selectionContext",
|
||||
})
|
||||
// File is outside workspace, use absolute path
|
||||
relativeFilePath = filePath
|
||||
}
|
||||
|
||||
// VSCode uses 0-based line numbers, convert to 1-based for user-friendly display
|
||||
const startLine = selection.start.line + 1
|
||||
const endLine = selection.end.line + 1
|
||||
|
||||
return {
|
||||
selectedText,
|
||||
selectionFilePath: relativeFilePath,
|
||||
selectionStartLine: startLine,
|
||||
selectionEndLine: endLine,
|
||||
}
|
||||
break
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
switch (message.type) {
|
||||
case "webviewDidLaunch":
|
||||
// Load custom modes first
|
||||
const customModes = await provider.customModesManager.getCustomModes()
|
||||
|
|
@ -545,19 +546,11 @@ export const webviewMessageHandler = async (
|
|||
// agentically running promises in old instance don't affect our new
|
||||
// task. This essentially creates a fresh slate for the new task.
|
||||
try {
|
||||
// Capture selection context directly when creating task
|
||||
const selectionContext = captureSelectionContext()
|
||||
|
||||
await provider.createTask(message.text, message.images, undefined, {
|
||||
selectionContext:
|
||||
message.selectedText &&
|
||||
message.selectionFilePath &&
|
||||
typeof message.selectionStartLine === "number" &&
|
||||
typeof message.selectionEndLine === "number"
|
||||
? {
|
||||
selectedText: message.selectedText,
|
||||
selectionFilePath: message.selectionFilePath,
|
||||
selectionStartLine: message.selectionStartLine,
|
||||
selectionEndLine: message.selectionEndLine,
|
||||
}
|
||||
: undefined,
|
||||
selectionContext,
|
||||
})
|
||||
|
||||
// Task created successfully - notify the UI to reset
|
||||
|
|
@ -577,19 +570,9 @@ export const webviewMessageHandler = async (
|
|||
|
||||
case "askResponse": {
|
||||
const task = provider.getCurrentTask()
|
||||
// Pass selection context through to handleWebviewAskResponse
|
||||
const selectionContext =
|
||||
message.selectedText &&
|
||||
message.selectionFilePath &&
|
||||
typeof message.selectionStartLine === "number" &&
|
||||
typeof message.selectionEndLine === "number"
|
||||
? {
|
||||
selectedText: message.selectedText,
|
||||
selectionFilePath: message.selectionFilePath,
|
||||
selectionStartLine: message.selectionStartLine,
|
||||
selectionEndLine: message.selectionEndLine,
|
||||
}
|
||||
: undefined
|
||||
// Capture selection context directly when handling response
|
||||
const selectionContext = captureSelectionContext()
|
||||
|
||||
task?.handleWebviewAskResponse(message.askResponse!, message.text, message.images, selectionContext)
|
||||
break
|
||||
}
|
||||
|
|
|
|||
|
|
@ -128,12 +128,7 @@ export interface ExtensionMessage {
|
|||
| "dismissedUpsells"
|
||||
| "organizationSwitchResult"
|
||||
| "interactionRequired"
|
||||
| "selectionContext"
|
||||
text?: string
|
||||
selectedText?: string
|
||||
selectionFilePath?: string
|
||||
selectionStartLine?: number
|
||||
selectionEndLine?: number
|
||||
payload?: any // Add a generic payload for now, can refine later
|
||||
// Checkpoint warning message
|
||||
checkpointWarning?: {
|
||||
|
|
|
|||
|
|
@ -165,12 +165,7 @@ export interface WebviewMessage {
|
|||
| "dismissUpsell"
|
||||
| "getDismissedUpsells"
|
||||
| "updateSettings"
|
||||
| "requestSelectionContext"
|
||||
text?: string
|
||||
selectedText?: string
|
||||
selectionFilePath?: string
|
||||
selectionStartLine?: number
|
||||
selectionEndLine?: number
|
||||
editedMessageContent?: string
|
||||
tab?: "settings" | "history" | "mcp" | "modes" | "chat" | "marketplace" | "cloud"
|
||||
disabled?: boolean
|
||||
|
|
|
|||
|
|
@ -134,13 +134,6 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
|
|||
const textAreaRef = useRef<HTMLTextAreaElement>(null)
|
||||
const [sendingDisabled, setSendingDisabled] = useState(false)
|
||||
const [selectedImages, setSelectedImages] = useState<string[]>([])
|
||||
const [selectionContext, setSelectionContext] = useState<{
|
||||
selectedText?: string
|
||||
selectionFilePath?: string
|
||||
selectionStartLine?: number
|
||||
selectionEndLine?: number
|
||||
} | null>(null)
|
||||
|
||||
// We need to hold on to the ask because useEffect > lastMessage will always
|
||||
// let us know when an ask comes in and handle it, but by the time
|
||||
// handleMessage is called, the last message might not be the ask anymore
|
||||
|
|
@ -568,16 +561,8 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
|
|||
// Mark that user has responded - this prevents any pending auto-approvals.
|
||||
userRespondedRef.current = true
|
||||
|
||||
// Request fresh selection context before sending
|
||||
vscode.postMessage({ type: "requestSelectionContext" })
|
||||
|
||||
if (messagesRef.current.length === 0) {
|
||||
vscode.postMessage({
|
||||
type: "newTask",
|
||||
text,
|
||||
images,
|
||||
...(selectionContext || {}),
|
||||
})
|
||||
vscode.postMessage({ type: "newTask", text, images })
|
||||
} else if (clineAskRef.current) {
|
||||
if (clineAskRef.current === "followup") {
|
||||
markFollowUpAsAnswered()
|
||||
|
|
@ -602,26 +587,19 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
|
|||
askResponse: "messageResponse",
|
||||
text,
|
||||
images,
|
||||
...(selectionContext || {}),
|
||||
})
|
||||
break
|
||||
// There is no other case that a textfield should be enabled.
|
||||
}
|
||||
} else {
|
||||
// This is a new message in an ongoing task.
|
||||
vscode.postMessage({
|
||||
type: "askResponse",
|
||||
askResponse: "messageResponse",
|
||||
text,
|
||||
images,
|
||||
...(selectionContext || {}),
|
||||
})
|
||||
vscode.postMessage({ type: "askResponse", askResponse: "messageResponse", text, images })
|
||||
}
|
||||
|
||||
handleChatReset()
|
||||
}
|
||||
},
|
||||
[handleChatReset, markFollowUpAsAnswered, sendingDisabled, isStreaming, messageQueue.length, selectionContext], // messagesRef and clineAskRef are stable
|
||||
[handleChatReset, markFollowUpAsAnswered, sendingDisabled, isStreaming, messageQueue.length], // messagesRef and clineAskRef are stable
|
||||
)
|
||||
|
||||
const handleSetChatBoxMessage = useCallback(
|
||||
|
|
@ -764,15 +742,6 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
|
|||
break
|
||||
}
|
||||
break
|
||||
case "selectionContext":
|
||||
// Update selection context when received from extension
|
||||
setSelectionContext({
|
||||
selectedText: message.selectedText,
|
||||
selectionFilePath: message.selectionFilePath,
|
||||
selectionStartLine: message.selectionStartLine,
|
||||
selectionEndLine: message.selectionEndLine,
|
||||
})
|
||||
break
|
||||
case "selectedImages":
|
||||
// Only handle selectedImages if it's not for editing context
|
||||
// When context is "edit", ChatRow will handle the images
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue