mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-19 09:33:53 +00:00
feat(vscode-ide-companion/read): implement diff auto-open functionality
Add diff viewing capabilities to Read tool calls with automatic opening of VS Code diff tabs when diff content is detected. Includes: - Import necessary React hooks and VS Code context - Memoize content grouping for performance - Auto-open diff in VS Code with useEffect - Handle diff messages with useCallback - Display compact UI when diff content is present
This commit is contained in:
@@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import type React from 'react';
|
import type React from 'react';
|
||||||
|
import { useCallback, useEffect, useMemo } from 'react';
|
||||||
import type { BaseToolCallProps } from '../shared/types.js';
|
import type { BaseToolCallProps } from '../shared/types.js';
|
||||||
import { ToolCallContainer } from '../shared/LayoutComponents.js';
|
import { ToolCallContainer } from '../shared/LayoutComponents.js';
|
||||||
import {
|
import {
|
||||||
@@ -14,6 +15,7 @@ import {
|
|||||||
mapToolStatusToContainerStatus,
|
mapToolStatusToContainerStatus,
|
||||||
} from '../shared/utils.js';
|
} from '../shared/utils.js';
|
||||||
import { FileLink } from '../../ui/FileLink.js';
|
import { FileLink } from '../../ui/FileLink.js';
|
||||||
|
import { useVSCode } from '../../../hooks/useVSCode.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specialized component for Read tool calls
|
* Specialized component for Read tool calls
|
||||||
@@ -22,9 +24,48 @@ import { FileLink } from '../../ui/FileLink.js';
|
|||||||
*/
|
*/
|
||||||
export const ReadToolCall: React.FC<BaseToolCallProps> = ({ toolCall }) => {
|
export const ReadToolCall: React.FC<BaseToolCallProps> = ({ toolCall }) => {
|
||||||
const { content, locations, toolCallId } = toolCall;
|
const { content, locations, toolCallId } = toolCall;
|
||||||
|
const vscode = useVSCode();
|
||||||
|
|
||||||
// Group content by type
|
// Group content by type; memoize to avoid new array identities on every render
|
||||||
const { errors } = groupContent(content);
|
const { errors, diffs } = useMemo(() => groupContent(content), [content]);
|
||||||
|
|
||||||
|
// Post a message to the extension host to open a VS Code diff tab
|
||||||
|
const handleOpenDiff = useCallback(
|
||||||
|
(
|
||||||
|
path: string | undefined,
|
||||||
|
oldText: string | null | undefined,
|
||||||
|
newText: string | undefined,
|
||||||
|
) => {
|
||||||
|
if (path) {
|
||||||
|
vscode.postMessage({
|
||||||
|
type: 'openDiff',
|
||||||
|
data: { path, oldText: oldText || '', newText: newText || '' },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[vscode],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Auto-open diff (Claude-style) when a read call returns diff content.
|
||||||
|
// Only trigger once per toolCallId so we don't spam as in-progress updates stream in.
|
||||||
|
useEffect(() => {
|
||||||
|
if (diffs.length > 0) {
|
||||||
|
const firstDiff = diffs[0];
|
||||||
|
const path = firstDiff.path || (locations && locations[0]?.path) || '';
|
||||||
|
|
||||||
|
if (
|
||||||
|
path &&
|
||||||
|
firstDiff.oldText !== undefined &&
|
||||||
|
firstDiff.newText !== undefined
|
||||||
|
) {
|
||||||
|
const timer = setTimeout(() => {
|
||||||
|
handleOpenDiff(path, firstDiff.oldText, firstDiff.newText);
|
||||||
|
}, 100);
|
||||||
|
return () => timer && clearTimeout(timer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [toolCallId]);
|
||||||
|
|
||||||
// Compute container status based on toolCall.status (pending/in_progress -> loading)
|
// Compute container status based on toolCall.status (pending/in_progress -> loading)
|
||||||
const containerStatus:
|
const containerStatus:
|
||||||
@@ -58,6 +99,30 @@ export const ReadToolCall: React.FC<BaseToolCallProps> = ({ toolCall }) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Success case with diff: keep UI compact; VS Code diff is auto-opened above
|
||||||
|
if (diffs.length > 0) {
|
||||||
|
const path = diffs[0]?.path || locations?.[0]?.path || '';
|
||||||
|
return (
|
||||||
|
<ToolCallContainer
|
||||||
|
label={'Read'}
|
||||||
|
className="read-tool-call-success"
|
||||||
|
status={containerStatus}
|
||||||
|
toolCallId={toolCallId}
|
||||||
|
labelSuffix={
|
||||||
|
path ? (
|
||||||
|
<FileLink
|
||||||
|
path={path}
|
||||||
|
showFullPath={false}
|
||||||
|
className="text-xs font-mono text-[var(--app-secondary-foreground)] hover:underline"
|
||||||
|
/>
|
||||||
|
) : undefined
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{null}
|
||||||
|
</ToolCallContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Success case: show which file was read with filename in label
|
// Success case: show which file was read with filename in label
|
||||||
if (locations && locations.length > 0) {
|
if (locations && locations.length > 0) {
|
||||||
const path = locations[0].path;
|
const path = locations[0].path;
|
||||||
|
|||||||
Reference in New Issue
Block a user