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
| 1 | import { MAX_LCS_CELLS } from '../max-lcs-cells' |
| 2 | import 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 | */ |
| 14 | export 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 | } |