| 602 | } |
| 603 | |
| 604 | function wordDiffStrings(oldStr: string, newStr: string): [Range[], Range[]] { |
| 605 | const oldTokens = tokenize(oldStr) |
| 606 | const newTokens = tokenize(newStr) |
| 607 | const ops = diffArrays(oldTokens, newTokens) |
| 608 | |
| 609 | const totalLen = oldStr.length + newStr.length |
| 610 | let changedLen = 0 |
| 611 | const oldRanges: Range[] = [] |
| 612 | const newRanges: Range[] = [] |
| 613 | let oldOff = 0 |
| 614 | let newOff = 0 |
| 615 | |
| 616 | for (const op of ops) { |
| 617 | const len = op.value.reduce((s, t) => s + t.length, 0) |
| 618 | if (op.removed) { |
| 619 | changedLen += len |
| 620 | oldRanges.push({ start: oldOff, end: oldOff + len }) |
| 621 | oldOff += len |
| 622 | } else if (op.added) { |
| 623 | changedLen += len |
| 624 | newRanges.push({ start: newOff, end: newOff + len }) |
| 625 | newOff += len |
| 626 | } else { |
| 627 | oldOff += len |
| 628 | newOff += len |
| 629 | } |
| 630 | } |
| 631 | |
| 632 | if (totalLen > 0 && changedLen / totalLen > CHANGE_THRESHOLD) { |
| 633 | return [[], []] |
| 634 | } |
| 635 | return [oldRanges, newRanges] |
| 636 | } |
| 637 | |
| 638 | // --------------------------------------------------------------------------- |
| 639 | // Highlight (per-line transform pipeline) |