spacehub

surshar / claude-code

Claude Code is an agentic coding tool that lives in your terminal, understands your codebase, and helps you code faster by executing routine tasks, explaining complex code, and handling git workflows - all through natural language commands.

Built by Anthropic · github.com/anthropics

claude-code / mods / diff / hooks / word-diff / diff-parts / diff-parts.ts
76 lines · 1.8 KBRaw
1import { MAX_LCS_CELLS } from '../max-lcs-cells'
2import type { WordPart } from '../word-part'
3
4/**
5 * The parts of a longest-common-subsequence diff of two token lists, in
6 * order, adjacent parts of one kind merged.
7 *
8 * Null when the table would pass MAX_LCS_CELLS.
9 *
10 * @param before the removed line's tokens
11 * @param after the added line's tokens
12 * @returns the parts, or null for lines too long to compare
13 */
14export function diffParts(
15 before: readonly string[],
16 after: readonly string[],
17): WordPart[] | null {
18 const columns = after.length + 1
19
20 if ((before.length + 1) * columns > MAX_LCS_CELLS) {
21 return null
22 }
23
24 const lengths = new Uint32Array((before.length + 1) * columns)
25 const at = (i: number, j: number) => lengths[i * columns + j] ?? 0
26
27 for (let i = before.length - 1; i >= 0; i--) {
28 for (let j = after.length - 1; j >= 0; j--) {
29 const isMatch = before[i] === after[j]
30 lengths[i * columns + j] = isMatch
31 ? at(i + 1, j + 1) + 1
32 : Math.max(at(i + 1, j), at(i, j + 1))
33 }
34 }
35
36 const parts: WordPart[] = []
37
38 function emit(text: string, kind: WordPart['kind']) {
39 const last = parts.at(-1)
40
41 if (last?.kind === kind) {
42 last.text += text
43
44 return
45 }
46
47 parts.push({ text, kind })
48 }
49
50 let i = 0
51 let j = 0
52
53 while (i < before.length || j < after.length) {
54 const old = before[i]
55 const fresh = after[j]
56 const isSame = old !== undefined && old === fresh
57 const isRemoved =
58 !isSame &&
59 old !== undefined &&
60 (fresh === undefined || at(i + 1, j) >= at(i, j + 1))
61
62 if (isSame) {
63 emit(old, 'same')
64 i += 1
65 j += 1
66 } else if (isRemoved) {
67 emit(old, 'removed')
68 i += 1
69 } else if (fresh !== undefined) {
70 emit(fresh, 'added')
71 j += 1
72 }
73 }
74
75 return parts
76}