MCPcopy
hub / github.com/codeaashu/claude-code / formatDiff

Function formatDiff

src/components/StructuredDiff/Fallback.tsx:349–422  ·  view source on GitHub ↗
(lines: string[], startingLineNumber: number, width: number, dim: boolean, overrideTheme?: ThemeName)

Source from the content-addressed store, hash-verified

347 });
348}
349function formatDiff(lines: string[], startingLineNumber: number, width: number, dim: boolean, overrideTheme?: ThemeName): React.ReactNode[] {
350 // Ensure width is at least 1 to prevent rendering issues with very narrow terminals
351 const safeWidth = Math.max(1, Math.floor(width));
352
353 // Step 1: Transform lines to line objects with type information
354 const lineObjects = transformLinesToObjects(lines);
355
356 // Step 2: Group adjacent add/remove lines for word-level diffing
357 const processedLines = processAdjacentLines(lineObjects);
358
359 // Step 3: Number the diff lines
360 const ls = numberDiffLines(processedLines, startingLineNumber);
361
362 // Find max line number width for alignment
363 const maxLineNumber = Math.max(...ls.map(({
364 i
365 }) => i), 0);
366 const maxWidth = Math.max(maxLineNumber.toString().length + 1, 0);
367
368 // Step 4: Render formatting
369 return ls.flatMap((item): React.ReactNode[] => {
370 const {
371 type,
372 code,
373 i,
374 wordDiff,
375 matchedLine
376 } = item;
377
378 // Handle word-level diffing for add/remove pairs
379 if (wordDiff && matchedLine) {
380 const wordDiffElements = generateWordDiffElements(item, safeWidth, maxWidth, dim, overrideTheme);
381
382 // word-diff might refuse (e.g. due to lines being substantially different) in which
383 // case we'll fall through to normal renderin gbelow
384 if (wordDiffElements !== null) {
385 return wordDiffElements;
386 }
387 }
388
389 // Standard rendering for lines without word diffing or as fallback
390 // Calculate available width accounting for line number + space + diff prefix
391 const diffPrefixWidth = 2; // " " for unchanged, "+ " or "- " for changes
392 const availableContentWidth = Math.max(1, safeWidth - maxWidth - 1 - diffPrefixWidth); // -1 for space after line number
393 const wrappedText = wrapText(code, availableContentWidth, 'wrap');
394 const wrappedLines = wrappedText.split('\n');
395 return wrappedLines.map((line, lineIndex) => {
396 const key = `${type}-${i}-${lineIndex}`;
397 const lineNum = lineIndex === 0 ? i : undefined;
398 const lineNumStr = (lineNum !== undefined ? lineNum.toString().padStart(maxWidth) : ' '.repeat(maxWidth)) + ' ';
399 const sigil = type === 'add' ? '+' : type === 'remove' ? '-' : ' ';
400 // Calculate padding to fill the entire terminal width
401 const contentWidth = lineNumStr.length + 1 + stringWidth(line); // lineNum + sigil + code
402 const padding = Math.max(0, safeWidth - contentWidth);
403 const bgColor = type === 'add' ? dim ? 'diffAddedDimmed' : 'diffAdded' : type === 'remove' ? dim ? 'diffRemovedDimmed' : 'diffRemoved' : undefined;
404
405 // Gutter (line number + sigil) is wrapped in <NoSelect> so fullscreen
406 // text selection yields clean code. bgColor carries across both boxes

Callers 1

StructuredDiffFallbackFunction · 0.85

Calls 7

transformLinesToObjectsFunction · 0.85
processAdjacentLinesFunction · 0.85
numberDiffLinesFunction · 0.85
generateWordDiffElementsFunction · 0.85
maxMethod · 0.80
toStringMethod · 0.65
wrapTextFunction · 0.50

Tested by

no test coverage detected