@pierre/diffs 1.3.0-beta.1 → 1.3.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/dist/components/CodeView.d.ts +4 -0
  2. package/dist/components/CodeView.d.ts.map +1 -1
  3. package/dist/components/CodeView.js +38 -0
  4. package/dist/components/CodeView.js.map +1 -1
  5. package/dist/components/File.d.ts.map +1 -1
  6. package/dist/components/File.js +9 -9
  7. package/dist/components/File.js.map +1 -1
  8. package/dist/components/FileDiff.d.ts.map +1 -1
  9. package/dist/components/FileDiff.js +3 -2
  10. package/dist/components/FileDiff.js.map +1 -1
  11. package/dist/components/VirtualizedFile.js +6 -1
  12. package/dist/components/VirtualizedFile.js.map +1 -1
  13. package/dist/components/VirtualizedFileDiff.js +22 -42
  14. package/dist/components/VirtualizedFileDiff.js.map +1 -1
  15. package/dist/components/Virtualizer.js +5 -3
  16. package/dist/components/Virtualizer.js.map +1 -1
  17. package/dist/editor/editor.d.ts +7 -1
  18. package/dist/editor/editor.d.ts.map +1 -1
  19. package/dist/editor/editor.js +550 -405
  20. package/dist/editor/editor.js.map +1 -1
  21. package/dist/editor/editor2.js +6 -0
  22. package/dist/editor/editor2.js.map +1 -0
  23. package/dist/editor/pieceTable.d.ts +1 -1
  24. package/dist/editor/pieceTable.d.ts.map +1 -1
  25. package/dist/editor/pieceTable.js +2 -22
  26. package/dist/editor/pieceTable.js.map +1 -1
  27. package/dist/editor/quickEdit.js +2 -4
  28. package/dist/editor/quickEdit.js.map +1 -1
  29. package/dist/editor/searchPanel.d.ts +6 -7
  30. package/dist/editor/searchPanel.d.ts.map +1 -1
  31. package/dist/editor/searchPanel.js +102 -137
  32. package/dist/editor/searchPanel.js.map +1 -1
  33. package/dist/editor/selection.js +8 -2
  34. package/dist/editor/selection.js.map +1 -1
  35. package/dist/editor/sprite.d.ts +7 -0
  36. package/dist/editor/sprite.d.ts.map +1 -0
  37. package/dist/editor/sprite.js +38 -0
  38. package/dist/editor/sprite.js.map +1 -0
  39. package/dist/editor/textDocument.d.ts +1 -1
  40. package/dist/editor/textDocument.d.ts.map +1 -1
  41. package/dist/editor/textDocument.js +2 -2
  42. package/dist/editor/textDocument.js.map +1 -1
  43. package/dist/editor/textMeasure.js +3 -3
  44. package/dist/editor/textMeasure.js.map +1 -1
  45. package/dist/editor/tokenzier.d.ts +6 -2
  46. package/dist/editor/tokenzier.d.ts.map +1 -1
  47. package/dist/editor/tokenzier.js +127 -85
  48. package/dist/editor/tokenzier.js.map +1 -1
  49. package/dist/index.d.ts +2 -2
  50. package/dist/react/index.d.ts +2 -2
  51. package/dist/react/jsx.d.ts +1 -0
  52. package/dist/react/jsx.d.ts.map +1 -1
  53. package/dist/react/types.js +1 -0
  54. package/dist/renderers/DiffHunksRenderer.js +5 -9
  55. package/dist/renderers/DiffHunksRenderer.js.map +1 -1
  56. package/dist/ssr/index.d.ts +2 -2
  57. package/dist/style.js +1 -1
  58. package/dist/style.js.map +1 -1
  59. package/dist/types.d.ts +13 -12
  60. package/dist/types.d.ts.map +1 -1
  61. package/dist/utils/computeEstimatedDiffHeights.js +9 -20
  62. package/dist/utils/computeEstimatedDiffHeights.js.map +1 -1
  63. package/dist/utils/iterateOverDiff.js +147 -182
  64. package/dist/utils/iterateOverDiff.js.map +1 -1
  65. package/dist/utils/virtualDiffLayout.d.ts +23 -2
  66. package/dist/utils/virtualDiffLayout.d.ts.map +1 -1
  67. package/dist/utils/virtualDiffLayout.js +41 -1
  68. package/dist/utils/virtualDiffLayout.js.map +1 -1
  69. package/dist/worker/WorkerPoolManager.js +1 -1
  70. package/dist/worker/WorkerPoolManager.js.map +1 -1
  71. package/dist/worker/{wasm-D4DU5jgR.js → wasm-BaDzIkIn.js} +2 -2
  72. package/dist/worker/wasm-BaDzIkIn.js.map +1 -0
  73. package/dist/worker/worker-portable.js +294 -292
  74. package/dist/worker/worker-portable.js.map +1 -1
  75. package/dist/worker/worker.js +179 -181
  76. package/dist/worker/worker.js.map +1 -1
  77. package/package.json +22 -21
  78. package/dist/editor/css.d.ts +0 -6
  79. package/dist/editor/css.d.ts.map +0 -1
  80. package/dist/editor/css.js +0 -218
  81. package/dist/editor/css.js.map +0 -1
  82. package/dist/worker/wasm-D4DU5jgR.js.map +0 -1
@@ -754,6 +754,39 @@ function getExpandedRegion({ isPartial, rangeSize, expandedHunks, hunkIndex, col
754
754
  renderAll
755
755
  };
756
756
  }
757
+ function getTrailingContextRangeSize({ fileDiff, errorPrefix }) {
758
+ const lastHunk = fileDiff.hunks[fileDiff.hunks.length - 1];
759
+ if (lastHunk == null || fileDiff.isPartial || fileDiff.additionLines.length === 0 || fileDiff.deletionLines.length === 0) return 0;
760
+ const additionRemaining = fileDiff.additionLines.length - (lastHunk.additionLineIndex + lastHunk.additionCount);
761
+ const deletionRemaining = fileDiff.deletionLines.length - (lastHunk.deletionLineIndex + lastHunk.deletionCount);
762
+ if (additionRemaining <= 0 && deletionRemaining <= 0) return 0;
763
+ if (additionRemaining !== deletionRemaining) throw new Error(`${errorPrefix}: trailing context mismatch (additions=${additionRemaining}, deletions=${deletionRemaining}) for ${fileDiff.name}`);
764
+ return Math.min(additionRemaining, deletionRemaining);
765
+ }
766
+ function getTrailingExpandedRegion({ fileDiff, hunkIndex, expandedHunks, collapsedContextThreshold, errorPrefix }) {
767
+ if (hunkIndex !== fileDiff.hunks.length - 1) return;
768
+ const trailingRangeSize = getTrailingContextRangeSize({
769
+ fileDiff,
770
+ errorPrefix
771
+ });
772
+ if (trailingRangeSize <= 0) return;
773
+ if (expandedHunks === true || trailingRangeSize <= collapsedContextThreshold) return {
774
+ fromStart: trailingRangeSize,
775
+ fromEnd: 0,
776
+ rangeSize: trailingRangeSize,
777
+ collapsedLines: 0,
778
+ renderAll: true
779
+ };
780
+ const region = expandedHunks?.get(fileDiff.hunks.length);
781
+ const fromStart = Math.min(Math.max(region?.fromStart ?? 0, 0), trailingRangeSize);
782
+ return {
783
+ fromStart,
784
+ fromEnd: 0,
785
+ rangeSize: trailingRangeSize,
786
+ collapsedLines: trailingRangeSize - fromStart,
787
+ renderAll: fromStart >= trailingRangeSize
788
+ };
789
+ }
757
790
 
758
791
  //#endregion
759
792
  //#region src/utils/iterateOverDiff.ts
@@ -766,12 +799,12 @@ function iterateOverDiff({ diff, diffStyle, startingLine = 0, totalLines = Infin
766
799
  collapsedContextThreshold
767
800
  });
768
801
  const state = {
769
- finalHunk: diff.hunks.at(-1),
770
802
  viewportStart: startingLine,
771
803
  viewportEnd: startingLine + totalLines,
772
804
  isWindowedHighlight: startingLine > 0 || totalLines < Infinity,
773
805
  splitCount: iterationStart.splitCount,
774
806
  unifiedCount: iterationStart.unifiedCount,
807
+ finalHunkIndex: diff.hunks.length - 1,
775
808
  shouldBreak() {
776
809
  if (!state.isWindowedHighlight) return false;
777
810
  const breakUnified = state.unifiedCount >= startingLine + totalLines;
@@ -824,31 +857,24 @@ function iterateOverDiff({ diff, diffStyle, startingLine = 0, totalLines = Infin
824
857
  hunkIndex,
825
858
  collapsedContextThreshold
826
859
  });
827
- const trailingRegion = (() => {
828
- if (hunk !== state.finalHunk || !hasFinalCollapsedHunk(diff)) return;
829
- const additionRemaining = diff.additionLines.length - (hunk.additionLineIndex + hunk.additionCount);
830
- const deletionRemaining = diff.deletionLines.length - (hunk.deletionLineIndex + hunk.deletionCount);
831
- if (additionRemaining !== deletionRemaining) throw new Error(`iterateOverDiff: trailing context mismatch (additions=${additionRemaining}, deletions=${deletionRemaining}) for ${diff.name}`);
832
- const trailingRangeSize = Math.min(additionRemaining, deletionRemaining);
833
- return getExpandedRegion({
834
- isPartial: diff.isPartial,
835
- rangeSize: trailingRangeSize,
836
- expandedHunks,
837
- hunkIndex: diff.hunks.length,
838
- collapsedContextThreshold
839
- });
840
- })();
860
+ const trailingRegion = hunkIndex === state.finalHunkIndex ? getTrailingExpandedRegion({
861
+ fileDiff: diff,
862
+ hunkIndex,
863
+ expandedHunks,
864
+ collapsedContextThreshold,
865
+ errorPrefix: "iterateOverDiff"
866
+ }) : void 0;
841
867
  const expandedLineCount = leadingRegion.fromStart + leadingRegion.fromEnd;
842
868
  function getTrailingCollapsedAfter(unifiedLineIndex$1, splitLineIndex$1) {
843
869
  if (trailingRegion == null || trailingRegion.collapsedLines <= 0 || trailingRegion.fromStart + trailingRegion.fromEnd > 0) return 0;
844
870
  if (diffStyle === "unified") return unifiedLineIndex$1 === hunk.unifiedLineStart + hunk.unifiedLineCount - 1 ? trailingRegion.collapsedLines : 0;
845
871
  return splitLineIndex$1 === hunk.splitLineStart + hunk.splitLineCount - 1 ? trailingRegion.collapsedLines : 0;
846
872
  }
847
- function getPendingCollapsed() {
848
- if (leadingRegion.collapsedLines === 0) return 0;
849
- const value = leadingRegion.collapsedLines;
850
- leadingRegion.collapsedLines = 0;
851
- return value;
873
+ let consumedCollapsed = leadingRegion.collapsedLines === 0;
874
+ function consumePendingCollapsed() {
875
+ if (consumedCollapsed) return 0;
876
+ consumedCollapsed = true;
877
+ return leadingRegion.collapsedLines;
852
878
  }
853
879
  if (!state.shouldSkip(expandedLineCount, expandedLineCount)) {
854
880
  let unifiedLineIndex$1 = hunk.unifiedLineStart - leadingRegion.rangeSize;
@@ -857,81 +883,63 @@ function iterateOverDiff({ diff, diffStyle, startingLine = 0, totalLines = Infin
857
883
  let additionLineIndex$1 = hunk.additionLineIndex - leadingRegion.rangeSize;
858
884
  let deletionLineNumber$1 = hunk.deletionStart - leadingRegion.rangeSize;
859
885
  let additionLineNumber$1 = hunk.additionStart - leadingRegion.rangeSize;
860
- const [startIndex, endIndex] = getEqualLineIterationRange(state, leadingRegion.fromStart, diffStyle);
861
- if (startIndex > 0) state.incrementCounts(startIndex, startIndex);
862
- let index = startIndex;
863
- while (index < leadingRegion.fromStart) {
864
- if (index >= endIndex) {
865
- state.incrementCounts(leadingRegion.fromStart - index, leadingRegion.fromStart - index);
866
- break;
867
- }
868
- if (state.isInWindow(0, 0)) {
869
- if (state.emit({
870
- hunkIndex,
871
- hunk,
872
- collapsedBefore: 0,
873
- collapsedAfter: 0,
874
- type: "context-expanded",
875
- deletionLine: {
876
- lineNumber: deletionLineNumber$1 + index,
877
- lineIndex: deletionLineIndex$1 + index,
878
- noEOFCR: false,
879
- unifiedLineIndex: unifiedLineIndex$1 + index,
880
- splitLineIndex: splitLineIndex$1 + index
881
- },
882
- additionLine: {
883
- unifiedLineIndex: unifiedLineIndex$1 + index,
884
- splitLineIndex: splitLineIndex$1 + index,
885
- lineIndex: additionLineIndex$1 + index,
886
- lineNumber: additionLineNumber$1 + index,
887
- noEOFCR: false
888
- }
889
- })) break hunkIterator;
890
- } else state.incrementCounts(1, 1);
891
- index++;
892
- }
886
+ if (walkContextLines(state, leadingRegion.fromStart, diffStyle, (index) => {
887
+ return state.emit({
888
+ hunkIndex,
889
+ hunk,
890
+ collapsedBefore: 0,
891
+ collapsedAfter: 0,
892
+ type: "context-expanded",
893
+ deletionLine: {
894
+ lineNumber: deletionLineNumber$1 + index,
895
+ lineIndex: deletionLineIndex$1 + index,
896
+ noEOFCR: false,
897
+ unifiedLineIndex: unifiedLineIndex$1 + index,
898
+ splitLineIndex: splitLineIndex$1 + index
899
+ },
900
+ additionLine: {
901
+ unifiedLineIndex: unifiedLineIndex$1 + index,
902
+ splitLineIndex: splitLineIndex$1 + index,
903
+ lineIndex: additionLineIndex$1 + index,
904
+ lineNumber: additionLineNumber$1 + index,
905
+ noEOFCR: false
906
+ }
907
+ });
908
+ })) break hunkIterator;
893
909
  unifiedLineIndex$1 = hunk.unifiedLineStart - leadingRegion.fromEnd;
894
910
  splitLineIndex$1 = hunk.splitLineStart - leadingRegion.fromEnd;
895
911
  deletionLineIndex$1 = hunk.deletionLineIndex - leadingRegion.fromEnd;
896
912
  additionLineIndex$1 = hunk.additionLineIndex - leadingRegion.fromEnd;
897
913
  deletionLineNumber$1 = hunk.deletionStart - leadingRegion.fromEnd;
898
914
  additionLineNumber$1 = hunk.additionStart - leadingRegion.fromEnd;
899
- const [fromEndStartIndex, fromEndEndIndex] = getEqualLineIterationRange(state, leadingRegion.fromEnd, diffStyle);
900
- if (fromEndStartIndex > 0) state.incrementCounts(fromEndStartIndex, fromEndStartIndex);
901
- index = fromEndStartIndex;
902
- while (index < leadingRegion.fromEnd) {
903
- if (index >= fromEndEndIndex) {
904
- state.incrementCounts(leadingRegion.fromEnd - index, leadingRegion.fromEnd - index);
905
- break;
906
- }
907
- if (state.isInWindow(0, 0)) {
908
- if (state.emit({
909
- hunkIndex,
910
- hunk,
911
- collapsedBefore: getPendingCollapsed(),
912
- collapsedAfter: 0,
913
- type: "context-expanded",
914
- deletionLine: {
915
- lineNumber: deletionLineNumber$1 + index,
916
- lineIndex: deletionLineIndex$1 + index,
917
- noEOFCR: false,
918
- unifiedLineIndex: unifiedLineIndex$1 + index,
919
- splitLineIndex: splitLineIndex$1 + index
920
- },
921
- additionLine: {
922
- unifiedLineIndex: unifiedLineIndex$1 + index,
923
- splitLineIndex: splitLineIndex$1 + index,
924
- lineIndex: additionLineIndex$1 + index,
925
- lineNumber: additionLineNumber$1 + index,
926
- noEOFCR: false
927
- }
928
- })) break hunkIterator;
929
- } else state.incrementCounts(1, 1);
930
- index++;
931
- }
915
+ if (walkContextLines(state, leadingRegion.fromEnd, diffStyle, (index) => {
916
+ return state.emit({
917
+ hunkIndex,
918
+ hunk,
919
+ collapsedBefore: consumePendingCollapsed(),
920
+ collapsedAfter: 0,
921
+ type: "context-expanded",
922
+ deletionLine: {
923
+ lineNumber: deletionLineNumber$1 + index,
924
+ lineIndex: deletionLineIndex$1 + index,
925
+ noEOFCR: false,
926
+ unifiedLineIndex: unifiedLineIndex$1 + index,
927
+ splitLineIndex: splitLineIndex$1 + index
928
+ },
929
+ additionLine: {
930
+ unifiedLineIndex: unifiedLineIndex$1 + index,
931
+ splitLineIndex: splitLineIndex$1 + index,
932
+ lineIndex: additionLineIndex$1 + index,
933
+ lineNumber: additionLineNumber$1 + index,
934
+ noEOFCR: false
935
+ }
936
+ });
937
+ }, () => {
938
+ consumePendingCollapsed();
939
+ })) break hunkIterator;
932
940
  } else {
933
941
  state.incrementCounts(expandedLineCount, expandedLineCount);
934
- getPendingCollapsed();
942
+ consumePendingCollapsed();
935
943
  }
936
944
  let unifiedLineIndex = hunk.unifiedLineStart;
937
945
  let splitLineIndex = hunk.splitLineStart;
@@ -945,45 +953,37 @@ function iterateOverDiff({ diff, diffStyle, startingLine = 0, totalLines = Infin
945
953
  const isLastContent = content === lastContent;
946
954
  if (content.type === "context") {
947
955
  if (!state.shouldSkip(content.lines, content.lines)) {
948
- const [startIndex, endIndex] = getEqualLineIterationRange(state, content.lines, diffStyle);
949
- if (startIndex > 0) state.incrementCounts(startIndex, startIndex);
950
- let index = startIndex;
951
- while (index < content.lines) {
952
- if (index >= endIndex) {
953
- state.incrementCounts(content.lines - index, content.lines - index);
954
- break;
955
- }
956
- if (state.isInWindow(0, 0)) {
957
- const isLastLine = isLastContent && index === content.lines - 1;
958
- const unifiedRowIndex = unifiedLineIndex + index;
959
- const splitRowIndex = splitLineIndex + index;
960
- if (state.emit({
961
- hunkIndex,
962
- hunk,
963
- collapsedBefore: getPendingCollapsed(),
964
- collapsedAfter: getTrailingCollapsedAfter(unifiedRowIndex, splitRowIndex),
965
- type: "context",
966
- deletionLine: {
967
- lineNumber: deletionLineNumber + index,
968
- lineIndex: deletionLineIndex + index,
969
- noEOFCR: isLastLine && hunk.noEOFCRDeletions,
970
- unifiedLineIndex: unifiedRowIndex,
971
- splitLineIndex: splitRowIndex
972
- },
973
- additionLine: {
974
- unifiedLineIndex: unifiedRowIndex,
975
- splitLineIndex: splitRowIndex,
976
- lineIndex: additionLineIndex + index,
977
- lineNumber: additionLineNumber + index,
978
- noEOFCR: isLastLine && hunk.noEOFCRAdditions
979
- }
980
- })) break hunkIterator;
981
- } else state.incrementCounts(1, 1);
982
- index++;
983
- }
956
+ if (walkContextLines(state, content.lines, diffStyle, (index) => {
957
+ const isLastLine = isLastContent && index === content.lines - 1;
958
+ const unifiedRowIndex = unifiedLineIndex + index;
959
+ const splitRowIndex = splitLineIndex + index;
960
+ return state.emit({
961
+ hunkIndex,
962
+ hunk,
963
+ collapsedBefore: consumePendingCollapsed(),
964
+ collapsedAfter: getTrailingCollapsedAfter(unifiedRowIndex, splitRowIndex),
965
+ type: "context",
966
+ deletionLine: {
967
+ lineNumber: deletionLineNumber + index,
968
+ lineIndex: deletionLineIndex + index,
969
+ noEOFCR: isLastLine && hunk.noEOFCRDeletions,
970
+ unifiedLineIndex: unifiedRowIndex,
971
+ splitLineIndex: splitRowIndex
972
+ },
973
+ additionLine: {
974
+ unifiedLineIndex: unifiedRowIndex,
975
+ splitLineIndex: splitRowIndex,
976
+ lineIndex: additionLineIndex + index,
977
+ lineNumber: additionLineNumber + index,
978
+ noEOFCR: isLastLine && hunk.noEOFCRAdditions
979
+ }
980
+ });
981
+ }, () => {
982
+ consumePendingCollapsed();
983
+ })) break hunkIterator;
984
984
  } else {
985
985
  state.incrementCounts(content.lines, content.lines);
986
- getPendingCollapsed();
986
+ consumePendingCollapsed();
987
987
  }
988
988
  unifiedLineIndex += content.lines;
989
989
  splitLineIndex += content.lines;
@@ -996,12 +996,13 @@ function iterateOverDiff({ diff, diffStyle, startingLine = 0, totalLines = Infin
996
996
  const unifiedCount = content.deletions + content.additions;
997
997
  if (!state.shouldSkip(unifiedCount, splitCount)) {
998
998
  const iterationRanges = getChangeIterationRanges(state, content, diffStyle);
999
+ if ((iterationRanges[0]?.[0] ?? 0) > 0) consumePendingCollapsed();
999
1000
  for (const [rangeStart, rangeEnd] of iterationRanges) for (let index = rangeStart; index < rangeEnd; index++) {
1000
1001
  const collapsedAfter = getTrailingCollapsedAfter(unifiedLineIndex + index, diffStyle === "unified" ? splitLineIndex + (index < content.deletions ? index : index - content.deletions) : splitLineIndex + index);
1001
1002
  if (state.emit(getChangeLineData({
1002
1003
  hunkIndex,
1003
1004
  hunk,
1004
- collapsedBefore: getPendingCollapsed(),
1005
+ collapsedBefore: consumePendingCollapsed(),
1005
1006
  collapsedAfter,
1006
1007
  diffStyle,
1007
1008
  index,
@@ -1018,7 +1019,7 @@ function iterateOverDiff({ diff, diffStyle, startingLine = 0, totalLines = Infin
1018
1019
  }), true)) break hunkIterator;
1019
1020
  }
1020
1021
  }
1021
- getPendingCollapsed();
1022
+ consumePendingCollapsed();
1022
1023
  state.incrementCounts(unifiedCount, splitCount);
1023
1024
  unifiedLineIndex += unifiedCount;
1024
1025
  splitLineIndex += splitCount;
@@ -1031,41 +1032,30 @@ function iterateOverDiff({ diff, diffStyle, startingLine = 0, totalLines = Infin
1031
1032
  if (trailingRegion != null) {
1032
1033
  const { collapsedLines, fromStart, fromEnd } = trailingRegion;
1033
1034
  const len = fromStart + fromEnd;
1034
- const [startIndex, endIndex] = getEqualLineIterationRange(state, len, diffStyle);
1035
- if (startIndex > 0) state.incrementCounts(startIndex, startIndex);
1036
- let index = startIndex;
1037
- while (index < len) {
1038
- if (state.shouldBreak()) break hunkIterator;
1039
- if (index >= endIndex) {
1040
- state.incrementCounts(len - index, len - index);
1041
- break;
1042
- }
1043
- if (state.isInWindow(0, 0)) {
1044
- const isLastLine = index === len - 1;
1045
- if (state.emit({
1046
- hunkIndex: diff.hunks.length,
1047
- hunk: void 0,
1048
- collapsedBefore: 0,
1049
- collapsedAfter: isLastLine ? collapsedLines : 0,
1050
- type: "context-expanded",
1051
- deletionLine: {
1052
- lineNumber: deletionLineNumber + index,
1053
- lineIndex: deletionLineIndex + index,
1054
- noEOFCR: false,
1055
- unifiedLineIndex: unifiedLineIndex + index,
1056
- splitLineIndex: splitLineIndex + index
1057
- },
1058
- additionLine: {
1059
- unifiedLineIndex: unifiedLineIndex + index,
1060
- splitLineIndex: splitLineIndex + index,
1061
- lineIndex: additionLineIndex + index,
1062
- lineNumber: additionLineNumber + index,
1063
- noEOFCR: false
1064
- }
1065
- })) break hunkIterator;
1066
- } else state.incrementCounts(1, 1);
1067
- index++;
1068
- }
1035
+ if (walkContextLines(state, len, diffStyle, (index) => {
1036
+ const isLastLine = index === len - 1;
1037
+ return state.emit({
1038
+ hunkIndex: diff.hunks.length,
1039
+ hunk: void 0,
1040
+ collapsedBefore: 0,
1041
+ collapsedAfter: isLastLine ? collapsedLines : 0,
1042
+ type: "context-expanded",
1043
+ deletionLine: {
1044
+ lineNumber: deletionLineNumber + index,
1045
+ lineIndex: deletionLineIndex + index,
1046
+ noEOFCR: false,
1047
+ unifiedLineIndex: unifiedLineIndex + index,
1048
+ splitLineIndex: splitLineIndex + index
1049
+ },
1050
+ additionLine: {
1051
+ unifiedLineIndex: unifiedLineIndex + index,
1052
+ splitLineIndex: splitLineIndex + index,
1053
+ lineIndex: additionLineIndex + index,
1054
+ lineNumber: additionLineNumber + index,
1055
+ noEOFCR: false
1056
+ }
1057
+ });
1058
+ }, void 0, () => state.shouldBreak())) break hunkIterator;
1069
1059
  }
1070
1060
  }
1071
1061
  }
@@ -1130,15 +1120,14 @@ function getHunkPrefixCounts({ diff, expandedHunks, collapsedContextThreshold })
1130
1120
  const leadingCount = leadingRegion.fromStart + leadingRegion.fromEnd;
1131
1121
  splitCount += leadingCount + hunk.splitLineCount;
1132
1122
  unifiedCount += leadingCount + hunk.unifiedLineCount;
1133
- if (index === finalHunkIndex && hasFinalCollapsedHunk(diff)) {
1134
- const trailingRangeSize = getTrailingRangeSize(diff, hunk);
1135
- const trailingRegion = getExpandedRegion({
1136
- isPartial: diff.isPartial,
1137
- rangeSize: trailingRangeSize,
1138
- expandedHunks,
1139
- hunkIndex: diff.hunks.length,
1140
- collapsedContextThreshold
1141
- });
1123
+ const trailingRegion = index === finalHunkIndex ? getTrailingExpandedRegion({
1124
+ fileDiff: diff,
1125
+ hunkIndex: index,
1126
+ expandedHunks,
1127
+ collapsedContextThreshold,
1128
+ errorPrefix: "iterateOverDiff"
1129
+ }) : void 0;
1130
+ if (trailingRegion != null) {
1142
1131
  const trailingCount = trailingRegion.fromStart + trailingRegion.fromEnd;
1143
1132
  splitCount += trailingCount;
1144
1133
  unifiedCount += trailingCount;
@@ -1150,7 +1139,7 @@ function getHunkPrefixCounts({ diff, expandedHunks, collapsedContextThreshold })
1150
1139
  }
1151
1140
  return prefixCounts;
1152
1141
  }
1153
- function getEqualLineIterationRange(state, count, diffStyle) {
1142
+ function getContextLineIterationBounds(state, count, diffStyle) {
1154
1143
  if (!state.isWindowedHighlight || count <= 0) return [0, count];
1155
1144
  const ranges = [];
1156
1145
  function pushRange(currentCount) {
@@ -1170,16 +1159,25 @@ function getEqualLineIterationRange(state, count, diffStyle) {
1170
1159
  }
1171
1160
  return [start, end];
1172
1161
  }
1173
- function getTrailingRangeSize(diff, hunk) {
1174
- const additionRemaining = diff.additionLines.length - (hunk.additionLineIndex + hunk.additionCount);
1175
- const deletionRemaining = diff.deletionLines.length - (hunk.deletionLineIndex + hunk.deletionCount);
1176
- if (additionRemaining !== deletionRemaining) throw new Error(`iterateOverDiff: trailing context mismatch (additions=${additionRemaining}, deletions=${deletionRemaining}) for ${diff.name}`);
1177
- return Math.min(additionRemaining, deletionRemaining);
1178
- }
1179
- function hasFinalCollapsedHunk(diff) {
1180
- const lastHunk = diff.hunks.at(-1);
1181
- if (lastHunk == null || diff.isPartial || diff.additionLines.length === 0 || diff.deletionLines.length === 0) return false;
1182
- return lastHunk.additionLineIndex + lastHunk.additionCount < diff.additionLines.length || lastHunk.deletionLineIndex + lastHunk.deletionCount < diff.deletionLines.length;
1162
+ function walkContextLines(state, count, diffStyle, callback, onSkippedStart, shouldBreak) {
1163
+ const [startIndex, endIndex] = getContextLineIterationBounds(state, count, diffStyle);
1164
+ if (startIndex > 0) {
1165
+ state.incrementCounts(startIndex, startIndex);
1166
+ onSkippedStart?.();
1167
+ }
1168
+ let index = startIndex;
1169
+ while (index < count) {
1170
+ if (shouldBreak?.() === true) return true;
1171
+ if (index >= endIndex) {
1172
+ state.incrementCounts(count - index, count - index);
1173
+ break;
1174
+ }
1175
+ if (state.isInWindow(0, 0)) {
1176
+ if (callback(index) === true) return true;
1177
+ } else state.incrementCounts(1, 1);
1178
+ index++;
1179
+ }
1180
+ return false;
1183
1181
  }
1184
1182
  function getChangeIterationRanges(state, content, diffStyle) {
1185
1183
  if (!state.isWindowedHighlight) return [[0, diffStyle === "unified" ? content.deletions + content.additions : Math.max(content.deletions, content.additions)]];