diff --git a/static/src/components/chat/actions/toolRenderers.ts b/static/src/components/chat/actions/toolRenderers.ts index 2414461..e3873ec 100644 --- a/static/src/components/chat/actions/toolRenderers.ts +++ b/static/src/components/chat/actions/toolRenderers.ts @@ -298,19 +298,19 @@ function renderEditFile(result: any, args: any): string { const newText = rep.new_string || ''; const detail = details[idx] || {}; const contexts = Array.isArray(detail.contexts) ? detail.contexts : []; + const oldLines = oldText ? oldText.split('\n') : []; + const newLines = newText ? newText.split('\n') : []; const buildPairRows = (context?: any) => { const rows: any[] = []; const startLineCandidate = Number(context?.old_start_line ?? detail.matched_lines?.[0]); const startLine = Number.isFinite(startLineCandidate) ? startLineCandidate : null; if (oldText) { - const oldLines = oldText.split('\n'); oldLines.forEach((line: string, lineIdx: number) => { rows.push({ lineNo: startLine === null ? null : startLine + lineIdx, marker: '-', text: line, className: 'diff-remove' }); }); } if (newText) { - const newLines = newText.split('\n'); newLines.forEach((line: string, lineIdx: number) => { rows.push({ lineNo: startLine === null ? null : startLine + lineIdx, marker: '+', text: line, className: 'diff-add' }); }); @@ -337,12 +337,24 @@ function renderEditFile(result: any, args: any): string { rawAfterLines.length >= 2 && String(rawAfterLines[rawAfterLines.length - 1]?.text ?? '') === '' ? rawAfterLines.slice(0, -1) : rawAfterLines; + + // 编辑后新增/删除行数不同会导致后续行号偏移,after context 需按新文件位置重新编号 + const contextOldStartLine = Number(context?.old_start_line ?? detail.matched_lines?.[0]); + const contextOldEndLine = Number(context?.old_end_line ?? contextOldStartLine); + const oldLineCount = Number.isFinite(contextOldStartLine) && Number.isFinite(contextOldEndLine) + ? Math.max(1, contextOldEndLine - contextOldStartLine + 1) + : Math.max(1, (oldText ? oldText.split('\n').length : 1)); + const newLineCount = newText === '' ? 0 : newText.split('\n').length; + const afterContextOffset = newLineCount - oldLineCount; + beforeLines.forEach((item: any) => { rows.push({ lineNo: Number(item.line), marker: ' ', text: String(item.text ?? ''), className: '' }); }); rows.push(...buildPairRows(context)); afterLines.forEach((item: any) => { - rows.push({ lineNo: Number(item.line), marker: ' ', text: String(item.text ?? ''), className: '' }); + const rawLineNo = Number(item.line); + const lineNo = Number.isFinite(rawLineNo) ? rawLineNo + afterContextOffset : rawLineNo; + rows.push({ lineNo, marker: ' ', text: String(item.text ?? ''), className: '' }); }); const numberedRows = rows.filter((row) => typeof row.lineNo === 'number' && Number.isFinite(row.lineNo)); hunks.push({ @@ -375,14 +387,8 @@ function renderEditFile(result: any, args: any): string { const markerOrder: Record = { ' ': 0, '-': 1, '+': 2 }; mergedHunks.forEach((hunk, hunkIdx) => { if (hunkIdx > 0) renderDiffLine(null, ' ', '⋮', 'diff-separator'); - const changedLines = new Set( - hunk.rows - .filter((row: any) => (row.marker === '-' || row.marker === '+') && typeof row.lineNo === 'number') - .map((row: any) => row.lineNo) - ); const seenContextLines = new Set(); - hunk.rows - .filter((row: any) => !(row.marker === ' ' && changedLines.has(row.lineNo))) + const filteredRows = hunk.rows .filter((row: any) => { if (row.marker !== ' ' || typeof row.lineNo !== 'number') return true; if (seenContextLines.has(row.lineNo)) return false; @@ -400,8 +406,8 @@ function renderEditFile(result: any, args: any): string { // 上下文行或跨类型:按行号优先 const lineDelta = (a.lineNo ?? Number.MAX_SAFE_INTEGER) - (b.lineNo ?? Number.MAX_SAFE_INTEGER); return lineDelta || (markerOrder[a.marker] ?? 9) - (markerOrder[b.marker] ?? 9); - }) - .forEach((row: any) => renderDiffLine(row.lineNo, row.marker, row.text, row.className)); + }); + filteredRows.forEach((row: any) => renderDiffLine(row.lineNo, row.marker, row.text, row.className)); }); html += ''; }