feat: open chat file references directly in VS Code editor with line targeting

Markdown file links now open in VS Code editor tabs in VS Code runtime
Tool entries for edit/apply_patch now open the file at the first changed line
This commit is contained in:
Bohdan Triapitsyn
2026-03-04 02:58:48 +02:00
parent 84326e17cf
commit 5ddfc24221
2 changed files with 111 additions and 6 deletions
@@ -157,6 +157,78 @@ const parseDiffStats = (metadata?: Record<string, unknown>): { added: number; re
return { added, removed };
};
const extractFirstChangedLineFromDiff = (diffText: string): number | undefined => {
if (!diffText || typeof diffText !== 'string') {
return undefined;
}
const lines = diffText.split('\n');
let currentNewLine: number | undefined;
let firstHunkStart: number | undefined;
for (const rawLine of lines) {
const line = rawLine.replace(/\r$/, '');
const hunkMatch = line.match(/^@@\s+-\d+(?:,\d+)?\s+\+(\d+)(?:,\d+)?\s+@@/);
if (hunkMatch) {
const parsed = Number.parseInt(hunkMatch[1] ?? '', 10);
if (Number.isFinite(parsed)) {
currentNewLine = Math.max(1, parsed);
if (!Number.isFinite(firstHunkStart)) {
firstHunkStart = currentNewLine;
}
}
continue;
}
if (currentNewLine === undefined || !Number.isFinite(currentNewLine)) {
continue;
}
if (line.startsWith('+++') || line.startsWith('---') || line.startsWith('diff ')) {
continue;
}
if (line.startsWith('+')) {
return currentNewLine;
}
if (line.startsWith(' ')) {
currentNewLine += 1;
continue;
}
if (line.startsWith('-') || line.startsWith('\\')) {
continue;
}
}
return firstHunkStart;
};
const getFirstChangedLineFromMetadata = (tool: string, metadata?: Record<string, unknown>): number | undefined => {
if (!metadata || (tool !== 'edit' && tool !== 'multiedit' && tool !== 'apply_patch')) {
return undefined;
}
if (typeof metadata.diff === 'string') {
const line = extractFirstChangedLineFromDiff(metadata.diff);
if (Number.isFinite(line)) {
return line;
}
}
const files = Array.isArray(metadata.files) ? metadata.files : [];
const firstFile = files[0] as { diff?: unknown } | undefined;
if (typeof firstFile?.diff === 'string') {
const line = extractFirstChangedLineFromDiff(firstFile.diff);
if (Number.isFinite(line)) {
return line;
}
}
return undefined;
};
const getRelativePath = (absolutePath: string, currentDirectory: string): string => {
if (absolutePath.startsWith(currentDirectory)) {
const relativePath = absolutePath.substring(currentDirectory.length);
@@ -1637,12 +1709,15 @@ const ToolPart: React.FC<ToolPartProps> = ({
}
let filePath: unknown;
let targetLine: number | undefined;
if (part.tool === 'edit' || part.tool === 'multiedit') {
filePath = input?.filePath || input?.file_path || input?.path || metadata?.filePath || metadata?.file_path || metadata?.path;
targetLine = getFirstChangedLineFromMetadata(part.tool, metadata);
} else if (part.tool === 'apply_patch') {
const files = Array.isArray(metadata?.files) ? metadata?.files : [];
const firstFile = files[0] as { relativePath?: string; filePath?: string } | undefined;
filePath = firstFile?.relativePath || firstFile?.filePath;
targetLine = getFirstChangedLineFromMetadata(part.tool, metadata);
} else if (['write', 'create', 'file_write', 'read', 'view', 'file_read', 'cat'].includes(part.tool)) {
filePath = input?.filePath || input?.file_path || input?.path || metadata?.filePath || metadata?.file_path || metadata?.path;
}
@@ -1653,7 +1728,7 @@ const ToolPart: React.FC<ToolPartProps> = ({
if (!filePath.startsWith('/')) {
absolutePath = currentDirectory.endsWith('/') ? currentDirectory + filePath : currentDirectory + '/' + filePath;
}
runtime.editor.openFile(absolutePath);
runtime.editor.openFile(absolutePath, targetLine);
} else {
onToggle(part.id);
}