@pierre/diffs 1.3.0-beta.6 → 1.3.0-beta.7

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 (119) hide show
  1. package/dist/components/CodeView.d.ts +4 -1
  2. package/dist/components/CodeView.d.ts.map +1 -1
  3. package/dist/components/CodeView.js +45 -6
  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 +5 -2
  7. package/dist/components/File.js.map +1 -1
  8. package/dist/components/FileDiff.d.ts +36 -23
  9. package/dist/components/FileDiff.d.ts.map +1 -1
  10. package/dist/components/FileDiff.js +126 -58
  11. package/dist/components/FileDiff.js.map +1 -1
  12. package/dist/components/UnresolvedFile.d.ts +3 -2
  13. package/dist/components/UnresolvedFile.d.ts.map +1 -1
  14. package/dist/components/UnresolvedFile.js +4 -2
  15. package/dist/components/UnresolvedFile.js.map +1 -1
  16. package/dist/components/VirtualizedFile.d.ts.map +1 -1
  17. package/dist/components/VirtualizedFile.js +3 -7
  18. package/dist/components/VirtualizedFile.js.map +1 -1
  19. package/dist/components/VirtualizedFileDiff.d.ts +10 -4
  20. package/dist/components/VirtualizedFileDiff.d.ts.map +1 -1
  21. package/dist/components/VirtualizedFileDiff.js +178 -49
  22. package/dist/components/VirtualizedFileDiff.js.map +1 -1
  23. package/dist/editor/editor.d.ts +2 -2
  24. package/dist/editor/editor.d.ts.map +1 -1
  25. package/dist/editor/editor.js +163 -106
  26. package/dist/editor/editor.js.map +1 -1
  27. package/dist/editor/editor2.js +1 -1
  28. package/dist/editor/selection.d.ts +1 -1
  29. package/dist/editor/selection.d.ts.map +1 -1
  30. package/dist/editor/selection.js +87 -37
  31. package/dist/editor/selection.js.map +1 -1
  32. package/dist/editor/textMeasure.d.ts.map +1 -1
  33. package/dist/editor/textMeasure.js +25 -7
  34. package/dist/editor/textMeasure.js.map +1 -1
  35. package/dist/editor/tokenzier.d.ts +2 -0
  36. package/dist/editor/tokenzier.d.ts.map +1 -1
  37. package/dist/editor/tokenzier.js +11 -3
  38. package/dist/editor/tokenzier.js.map +1 -1
  39. package/dist/editor/utils.d.ts +3 -1
  40. package/dist/editor/utils.d.ts.map +1 -1
  41. package/dist/editor/utils.js +14 -1
  42. package/dist/editor/utils.js.map +1 -1
  43. package/dist/index.d.ts +5 -3
  44. package/dist/index.js +3 -1
  45. package/dist/managers/InteractionManager.d.ts.map +1 -1
  46. package/dist/managers/InteractionManager.js +0 -1
  47. package/dist/managers/InteractionManager.js.map +1 -1
  48. package/dist/react/EditorContext.js.map +1 -1
  49. package/dist/react/MultiFileDiff.d.ts +3 -4
  50. package/dist/react/MultiFileDiff.d.ts.map +1 -1
  51. package/dist/react/MultiFileDiff.js.map +1 -1
  52. package/dist/react/index.d.ts +2 -2
  53. package/dist/react/utils/useFileDiffInstance.js +14 -15
  54. package/dist/react/utils/useFileDiffInstance.js.map +1 -1
  55. package/dist/renderers/DiffHunksRenderer.d.ts +2 -2
  56. package/dist/renderers/DiffHunksRenderer.d.ts.map +1 -1
  57. package/dist/renderers/DiffHunksRenderer.js +29 -16
  58. package/dist/renderers/DiffHunksRenderer.js.map +1 -1
  59. package/dist/renderers/FileRenderer.js.map +1 -1
  60. package/dist/ssr/index.d.ts +2 -2
  61. package/dist/ssr/preloadDiffs.d.ts +11 -10
  62. package/dist/ssr/preloadDiffs.d.ts.map +1 -1
  63. package/dist/ssr/preloadDiffs.js +14 -6
  64. package/dist/ssr/preloadDiffs.js.map +1 -1
  65. package/dist/types.d.ts +59 -5
  66. package/dist/types.d.ts.map +1 -1
  67. package/dist/utils/areHunkDataEqual.js +1 -1
  68. package/dist/utils/areHunkDataEqual.js.map +1 -1
  69. package/dist/utils/awaitWithTimeout.d.ts +5 -0
  70. package/dist/utils/awaitWithTimeout.d.ts.map +1 -0
  71. package/dist/utils/awaitWithTimeout.js +15 -0
  72. package/dist/utils/awaitWithTimeout.js.map +1 -0
  73. package/dist/utils/cloneFileDiffMetadata.d.ts +7 -0
  74. package/dist/utils/cloneFileDiffMetadata.d.ts.map +1 -0
  75. package/dist/utils/cloneFileDiffMetadata.js +16 -0
  76. package/dist/utils/cloneFileDiffMetadata.js.map +1 -0
  77. package/dist/utils/computeEstimatedDiffHeights.d.ts +3 -1
  78. package/dist/utils/computeEstimatedDiffHeights.d.ts.map +1 -1
  79. package/dist/utils/computeEstimatedDiffHeights.js +8 -1
  80. package/dist/utils/computeEstimatedDiffHeights.js.map +1 -1
  81. package/dist/utils/createPreElement.js +0 -1
  82. package/dist/utils/createPreElement.js.map +1 -1
  83. package/dist/utils/getDiffFileInput.d.ts +14 -0
  84. package/dist/utils/getDiffFileInput.d.ts.map +1 -0
  85. package/dist/utils/getDiffFileInput.js +24 -0
  86. package/dist/utils/getDiffFileInput.js.map +1 -0
  87. package/dist/utils/getDiffHunksRendererOptions.js +1 -0
  88. package/dist/utils/getDiffHunksRendererOptions.js.map +1 -1
  89. package/dist/utils/getFiletypeFromFileName.d.ts.map +1 -1
  90. package/dist/utils/getFiletypeFromFileName.js +2 -0
  91. package/dist/utils/getFiletypeFromFileName.js.map +1 -1
  92. package/dist/utils/hydratePartialDiff.d.ts +10 -0
  93. package/dist/utils/hydratePartialDiff.d.ts.map +1 -0
  94. package/dist/utils/hydratePartialDiff.js +140 -0
  95. package/dist/utils/hydratePartialDiff.js.map +1 -0
  96. package/dist/utils/iterateOverDiff.js +3 -3
  97. package/dist/utils/iterateOverDiff.js.map +1 -1
  98. package/dist/utils/parseDiffFromFile.d.ts +1 -1
  99. package/dist/utils/parseDiffFromFile.d.ts.map +1 -1
  100. package/dist/utils/parseDiffFromFile.js +26 -5
  101. package/dist/utils/parseDiffFromFile.js.map +1 -1
  102. package/dist/utils/setWrapperNodeProps.js +0 -1
  103. package/dist/utils/setWrapperNodeProps.js.map +1 -1
  104. package/dist/utils/updateDiffHunks.d.ts +5 -1
  105. package/dist/utils/updateDiffHunks.d.ts.map +1 -1
  106. package/dist/utils/updateDiffHunks.js +26 -4
  107. package/dist/utils/updateDiffHunks.js.map +1 -1
  108. package/dist/worker/WorkerPoolManager.d.ts +7 -2
  109. package/dist/worker/WorkerPoolManager.d.ts.map +1 -1
  110. package/dist/worker/WorkerPoolManager.js +78 -15
  111. package/dist/worker/WorkerPoolManager.js.map +1 -1
  112. package/dist/worker/index.d.ts +2 -2
  113. package/dist/worker/types.d.ts +7 -1
  114. package/dist/worker/types.d.ts.map +1 -1
  115. package/dist/worker/worker-portable.js +5 -3
  116. package/dist/worker/worker-portable.js.map +1 -1
  117. package/dist/worker/worker.js +5 -3
  118. package/dist/worker/worker.js.map +1 -1
  119. package/package.json +1 -1
@@ -29,7 +29,7 @@ var Editor = class {
29
29
  #contentWidthCache;
30
30
  #lineYCache = /* @__PURE__ */ new Map();
31
31
  #wrapLineOffsetsCache = /* @__PURE__ */ new Map();
32
- #lastAccessedLineElement;
32
+ #lineElementsCache = /* @__PURE__ */ new Map();
33
33
  #lastAccessedCharX;
34
34
  #globalStyleElement;
35
35
  #editorStyleElement;
@@ -52,6 +52,7 @@ var Editor = class {
52
52
  #searchPanel;
53
53
  #selectionAction;
54
54
  #shouldIgnoreSelectionChange = false;
55
+ #suppressNativeSelectionSync = false;
55
56
  #contentHasFocus = false;
56
57
  #isComposing = false;
57
58
  #isGutterMouseDown = false;
@@ -65,11 +66,13 @@ var Editor = class {
65
66
  #matches;
66
67
  #scrollingToLine;
67
68
  #scrollingToLineChar;
69
+ #scrollingToLineFixed = false;
68
70
  #scrollingToLineNoFocus = false;
69
71
  #retainSearchPanelFocus = false;
70
72
  #fontRemeasureScheduled = false;
73
+ #themeSelectionRefreshFrame;
71
74
  #onDeferTokenize = (lines, themeType) => {
72
- this.#fileInstance?.updateRenderCache(lines, themeType);
75
+ this.#fileInstance?.updateRenderCache(lines, themeType, false);
73
76
  if (this.#renderRange !== void 0 && this.#renderRange.totalLines !== Infinity) {
74
77
  const { startingLine, totalLines } = this.#renderRange;
75
78
  const endLine = Math.min(startingLine + totalLines, this.#textDocument?.lineCount ?? 0);
@@ -82,11 +85,10 @@ var Editor = class {
82
85
  constructor(options = {}) {
83
86
  this.#options = options;
84
87
  }
85
- edit(component) {
86
- const { useTokenTransformer, enableGutterUtility, enableLineSelection, expandUnchanged, lineHoverHighlight, ...rest } = component.options;
87
- const isDiff = component.type === "file-diff";
88
- if (useTokenTransformer !== true || enableGutterUtility === true || enableLineSelection === true || expandUnchanged !== true && isDiff || lineHoverHighlight !== "disabled") {
89
- component.setOptions({
88
+ edit(fileInstance) {
89
+ const { useTokenTransformer, enableGutterUtility, enableLineSelection, expandUnchanged, lineHoverHighlight = "disabled", ...rest } = fileInstance.options;
90
+ if (useTokenTransformer !== true || enableGutterUtility === true || enableLineSelection === true || expandUnchanged !== true && fileInstance.type === "file-diff" || lineHoverHighlight !== "disabled") {
91
+ fileInstance.setOptions({
90
92
  ...rest,
91
93
  useTokenTransformer: true,
92
94
  enableGutterUtility: false,
@@ -94,11 +96,11 @@ var Editor = class {
94
96
  expandUnchanged: true,
95
97
  lineHoverHighlight: "disabled"
96
98
  });
97
- component.rerender();
99
+ fileInstance.rerender();
98
100
  }
99
- this.#fileInstance = component;
101
+ this.#fileInstance = fileInstance;
100
102
  this.#initialize();
101
- this.#detach = component.attachEditor(this);
103
+ this.#detach = fileInstance.attachEditor(this);
102
104
  return () => this.cleanUp();
103
105
  }
104
106
  /**
@@ -183,7 +185,7 @@ var Editor = class {
183
185
  };
184
186
  });
185
187
  this.#updateSelections(resolvedSelections);
186
- this.#scrollToPrimaryCaret(false, "center");
188
+ this.#scrollToPrimaryCaret();
187
189
  }
188
190
  setMarkers(markers) {
189
191
  const textDocument = this.#textDocument;
@@ -220,6 +222,8 @@ var Editor = class {
220
222
  cleanUp() {
221
223
  this.#tokenizer?.cleanUp();
222
224
  this.#tokenizer = void 0;
225
+ this.#textDocument = void 0;
226
+ this.#fileInfo = void 0;
223
227
  this.#globalEventDisposes?.forEach((dispose) => dispose());
224
228
  this.#globalEventDisposes = void 0;
225
229
  this.#editorEventDisposes?.forEach((dispose) => dispose());
@@ -232,7 +236,7 @@ var Editor = class {
232
236
  this.#contentWidthCache = void 0;
233
237
  this.#lineYCache.clear();
234
238
  this.#wrapLineOffsetsCache.clear();
235
- this.#lastAccessedLineElement = void 0;
239
+ this.#lineElementsCache.clear();
236
240
  this.#lastAccessedCharX = void 0;
237
241
  this.#globalStyleElement?.remove();
238
242
  this.#globalStyleElement = void 0;
@@ -252,10 +256,14 @@ var Editor = class {
252
256
  this.#resizeObserver?.disconnect();
253
257
  this.#resizeObserver = void 0;
254
258
  this.#fontRemeasureScheduled = false;
259
+ if (this.#themeSelectionRefreshFrame !== void 0) {
260
+ cancelAnimationFrame(this.#themeSelectionRefreshFrame);
261
+ this.#themeSelectionRefreshFrame = void 0;
262
+ }
255
263
  this.#resetState();
256
264
  }
257
265
  /** @internal */
258
- __postponeBackgroundTokenizeToNextFrame() {
266
+ __postponeBgTokenizeToNextFrame() {
259
267
  const tokenizer = this.#tokenizer;
260
268
  if (tokenizer !== void 0) {
261
269
  tokenizer.pauseBackgroundTokenize();
@@ -292,8 +300,7 @@ var Editor = class {
292
300
  if (this.#themeStyleElement !== void 0) shadowRoot.appendChild(this.#themeStyleElement);
293
301
  if (this.#spriteElement !== void 0) shadowRoot.prepend(this.#spriteElement);
294
302
  }
295
- const documentReplaced = this.#textDocument === void 0 || this.#fileInfo === void 0 || this.#fileInfo.name !== fileOrDiff.name || this.#fileInfo.lang !== fileOrDiff.lang || this.#fileInfo.cacheKey !== fileOrDiff.cacheKey;
296
- if (documentReplaced) {
303
+ if (this.#textDocument === void 0 || this.#fileInfo === void 0 || this.#fileInfo.name !== fileOrDiff.name || this.#fileInfo.lang !== fileOrDiff.lang || this.#fileInfo.cacheKey !== fileOrDiff.cacheKey) {
297
304
  let contents = "";
298
305
  if ("contents" in fileOrDiff) contents = fileOrDiff.contents;
299
306
  else contents = fileOrDiff.additionLines.join("");
@@ -312,6 +319,7 @@ var Editor = class {
312
319
  textDocument,
313
320
  codeOptions: this.#fileInstance?.options ?? {},
314
321
  onDeferTokenize: this.#onDeferTokenize,
322
+ onThemeChange: () => this.#scheduleThemeSelectionRefresh(),
315
323
  setStyle: (css) => {
316
324
  this.#themeStyleElement.textContent = css;
317
325
  },
@@ -322,11 +330,9 @@ var Editor = class {
322
330
  requestAnimationFrame(() => {
323
331
  this.#options.onAttach?.(this, this.#fileInstance);
324
332
  });
325
- if (this.#textDocument !== void 0 && this.#options.__debug === true) console.log("[diffs/editor] text document changed !!!");
333
+ if (this.#textDocument !== void 0 && this.#options.__debug === true) console.log("[diffs/editor] text document rebuilt from", fileOrDiff.name);
326
334
  }
327
- let fullRerender = false;
328
335
  if (this.#contentElement !== contentEl) {
329
- fullRerender = true;
330
336
  this.#gutterElement = gutterEl;
331
337
  this.#contentElement = extend(contentEl, {
332
338
  contentEditable: "true",
@@ -356,12 +362,6 @@ var Editor = class {
356
362
  this.#renderRange = renderRange;
357
363
  this.#viewportWindowLines = renderRange?.totalLines;
358
364
  this.#tokenizer?.prebuildStateStack(renderRange);
359
- const fileInstance = this.#fileInstance;
360
- const textDocument = this.#textDocument;
361
- if (!documentReplaced && fullRerender && fileInstance?.rerenderFromDocument !== void 0 && textDocument !== void 0 && this.#shouldRenderDivergeFromDocument(textDocument)) {
362
- fileInstance.rerenderFromDocument(textDocument);
363
- return;
364
- }
365
365
  this.#markerRenderer?.removePopup();
366
366
  if (this.#selections !== void 0 || this.#matches !== void 0 || this.#markerRenderer !== void 0) this.#updateSelections(this.#selections ?? []);
367
367
  if (this.#initSelections !== void 0 && this.#primaryCaretElement !== void 0) {
@@ -387,7 +387,7 @@ var Editor = class {
387
387
  #resetCache() {
388
388
  this.#lineYCache.clear();
389
389
  this.#wrapLineOffsetsCache.clear();
390
- this.#lastAccessedLineElement = void 0;
390
+ this.#lineElementsCache.clear();
391
391
  this.#lastAccessedCharX = void 0;
392
392
  }
393
393
  #resetState() {
@@ -427,7 +427,7 @@ var Editor = class {
427
427
  this.#globalEventDisposes = [
428
428
  addEventListener(document, "selectionchange", () => {
429
429
  const shadowRoot = this.#fileContainer?.shadowRoot;
430
- if (this.#shouldIgnoreSelectionChange || shadowRoot == null || !this.#contentHasFocus) return;
430
+ if (this.#shouldIgnoreSelectionChange || this.#suppressNativeSelectionSync || shadowRoot == null || !this.#contentHasFocus) return;
431
431
  if (this.#selections !== void 0 && this.#selections.length > 1 && !this.#isContentMouseDown) return;
432
432
  const selectionRaw = document.getSelection();
433
433
  if (selectionRaw == null || typeof selectionRaw.getComposedRanges !== "function") return;
@@ -488,6 +488,7 @@ var Editor = class {
488
488
  this.#contentHasFocus = false;
489
489
  }, { passive: true }),
490
490
  addEventListener(contentEl, "pointerdown", (e) => {
491
+ this.#suppressNativeSelectionSync = false;
491
492
  if (e.pointerType !== "mouse") return;
492
493
  if (this.#isDeletedLineTarget(e)) {
493
494
  this.#setDeletedTextSelectionActive(true);
@@ -543,6 +544,7 @@ var Editor = class {
543
544
  return;
544
545
  }
545
546
  if (!targetIsContentElement(e)) return;
547
+ this.#suppressNativeSelectionSync = false;
546
548
  const mvShortcut = isMoveCursorShortcut(e);
547
549
  const textDocument = this.#textDocument;
548
550
  if (this.#selections !== void 0 && this.#selections.length > 0 && mvShortcut !== void 0 && textDocument !== void 0) {
@@ -778,15 +780,32 @@ var Editor = class {
778
780
  if (change !== void 0) this.#applyChange(change, nextSelections);
779
781
  }
780
782
  break;
781
- case "selectAll":
782
- this.#updateSelections([getDocumentFullSelection(textDocument)]);
783
+ case "selectAll": {
784
+ const fullSelection = getDocumentFullSelection(textDocument);
785
+ this.#updateSelections([fullSelection]);
783
786
  this.focus();
787
+ const renderedLines = this.#getRenderedEditableLineRange();
788
+ if (renderedLines !== void 0) {
789
+ this.#suppressNativeSelectionSync = true;
790
+ this.#setWindowSelection({
791
+ start: {
792
+ line: renderedLines.first,
793
+ character: 0
794
+ },
795
+ end: {
796
+ line: renderedLines.last,
797
+ character: textDocument.getLineLength(renderedLines.last)
798
+ },
799
+ direction: 1
800
+ });
801
+ }
784
802
  break;
803
+ }
785
804
  case "moveCursorToDocStart":
786
805
  case "moveCursorToDocEnd":
787
806
  {
788
807
  const atEnd = command === "moveCursorToDocEnd";
789
- this.#updateSelections([getDocumentBoundarySelection(textDocument, atEnd)]);
808
+ this.#updateSelections([getDocumentBoundarySelection(textDocument, atEnd, this.#isDiff)]);
790
809
  this.#scrollToPrimaryCaret();
791
810
  }
792
811
  break;
@@ -796,7 +815,7 @@ var Editor = class {
796
815
  const atEnd = command === "expandSelectionDocEnd";
797
816
  const selections = this.#selections;
798
817
  if (selections !== void 0) {
799
- this.#updateSelections(extendSelections(selections, getDocumentBoundarySelection(textDocument, atEnd)));
818
+ this.#updateSelections(extendSelections(selections, getDocumentBoundarySelection(textDocument, atEnd, this.#isDiff)));
800
819
  this.#scrollToPrimaryCaret();
801
820
  }
802
821
  }
@@ -824,7 +843,7 @@ var Editor = class {
824
843
  const gutterWidthChanged = this.#getGutterWidth() !== prevGutterWidth;
825
844
  const contentWidthChanged = this.#getContentWidth() !== prevContentWidth;
826
845
  if (!gutterWidthChanged && !contentWidthChanged) return;
827
- this.#lastAccessedLineElement = void 0;
846
+ this.#lineElementsCache.clear();
828
847
  this.#lastAccessedCharX = void 0;
829
848
  this.#metrics.clearTextWidthCache();
830
849
  if (contentWidthChanged && (this.#isWrap || lineAnnotations > 0)) {
@@ -924,27 +943,15 @@ var Editor = class {
924
943
  contentEl.style.gridRow = "span " + gridRow;
925
944
  if (gutterEl !== void 0) gutterEl.style.gridRow = "span " + gridRow;
926
945
  }
927
- fileInstance.updateRenderCache(dirtyLines, tokenizer.themeType, this.#isDiff && !didLineCountChange, didLineCountChange);
946
+ fileInstance.updateRenderCache(dirtyLines, tokenizer.themeType, !didLineCountChange);
928
947
  if (didLineCountChange) fileInstance.applyDocumentChange(textDocument, newLineAnnotations, shouldUpdateBuffer);
948
+ if (this.#isDiff && (this.#diffSyle === "unified" || didLineCountChange)) this.#resetCache();
929
949
  if (newLineAnnotations !== void 0) {
930
950
  this.#lineAnnotations = newLineAnnotations;
931
951
  renderLineAnnotations(newLineAnnotations, contentEl, gutterEl);
932
952
  }
933
953
  if (this.#options.__debug === true) console.log(`[diffs/editor] re-render in: ${round(performance.now() - t2)}ms,`, `tokenize in: ${round(t2 - t)}ms (${dirtyLines.size} dirty lines)`);
934
954
  }
935
- #shouldRenderDivergeFromDocument(textDocument) {
936
- const contentEl = this.#contentElement;
937
- if (contentEl === void 0) return false;
938
- for (const child of contentEl.children) {
939
- const el = child;
940
- const lineType = el.dataset.lineType;
941
- const lineNumber = getLineNumberAttr(el);
942
- if (lineNumber === void 0 || lineType === void 0 || !isLineEditable(lineType)) continue;
943
- const lineIndex = lineNumber - 1;
944
- if (lineIndex >= textDocument.lineCount || el.textContent !== textDocument.getLineText(lineIndex)) return true;
945
- }
946
- return false;
947
- }
948
955
  #handleInput(inputType, data) {
949
956
  switch (inputType) {
950
957
  case "insertText": {
@@ -967,6 +974,7 @@ var Editor = class {
967
974
  this.#deleteSelectionText(true);
968
975
  break;
969
976
  case "deleteSoftLineBackward":
977
+ case "deleteHardLineBackward":
970
978
  this.#deleteSoftLineBackward();
971
979
  break;
972
980
  case "deleteHardLineForward":
@@ -1045,7 +1053,7 @@ var Editor = class {
1045
1053
  return `${componentTop + top}px ${end}px 0 ${start}px`;
1046
1054
  }
1047
1055
  #scrollToLine(line, char = 0, noFocus = false) {
1048
- this.__postponeBackgroundTokenizeToNextFrame();
1056
+ this.__postponeBgTokenizeToNextFrame();
1049
1057
  const virtualCaret = h("div", { style: {
1050
1058
  position: "absolute",
1051
1059
  left: "0",
@@ -1069,33 +1077,60 @@ var Editor = class {
1069
1077
  });
1070
1078
  this.#scrollingToLine = void 0;
1071
1079
  this.#scrollingToLineChar = void 0;
1080
+ this.#scrollingToLineFixed = false;
1072
1081
  this.#scrollingToLineNoFocus = false;
1073
1082
  } else {
1074
- let yFix = 0;
1075
- if (this.#scrollingToLine === line && this.#contentElement !== void 0) for (let i = this.#contentElement.childElementCount - 1; i >= 0; i--) {
1076
- const child = this.#contentElement.children[i];
1077
- const lineType = child.dataset.lineType;
1078
- const lineNumber = getLineNumberAttr(child);
1079
- if (lineType !== void 0 && isLineEditable(lineType) && lineNumber !== void 0) {
1080
- yFix = (line - lineNumber) * this.#metrics.lineHeight;
1081
- break;
1083
+ const modelLinePosition = this.#fileInstance?.getLinePosition?.(line + 1);
1084
+ if (modelLinePosition !== void 0) {
1085
+ virtualCaret.style.top = modelLinePosition.top + "px";
1086
+ this.#fileContainer?.shadowRoot?.appendChild(virtualCaret);
1087
+ virtualCaret.scrollIntoView({
1088
+ block: "center",
1089
+ inline: "nearest"
1090
+ });
1091
+ if (modelLinePosition.height > 0) {
1092
+ this.#scrollingToLine = line;
1093
+ this.#scrollingToLineChar = char;
1094
+ this.#scrollingToLineNoFocus = noFocus;
1095
+ } else {
1096
+ this.#scrollingToLine = void 0;
1097
+ this.#scrollingToLineChar = void 0;
1098
+ this.#scrollingToLineNoFocus = false;
1082
1099
  }
1083
- }
1084
- const approximateLineY = ((this.#lineAnnotations ?? []).filter((annotation) => annotation.lineNumber < line).length + line) * this.#metrics.lineHeight + yFix;
1085
- virtualCaret.style.top = approximateLineY + "px";
1086
- this.#fileContainer?.shadowRoot?.appendChild(virtualCaret);
1087
- virtualCaret.scrollIntoView({
1088
- block: "center",
1089
- inline: "nearest"
1090
- });
1091
- if (this.#scrollingToLine === line && yFix === 0) {
1092
- this.#scrollingToLine = void 0;
1093
- this.#scrollingToLineChar = void 0;
1094
- this.#scrollingToLineNoFocus = false;
1095
1100
  } else {
1096
- this.#scrollingToLine = line;
1097
- this.#scrollingToLineChar = char;
1098
- this.#scrollingToLineNoFocus = noFocus;
1101
+ let yFix = 0;
1102
+ if (this.#scrollingToLine === line && this.#contentElement !== void 0) for (let i = this.#contentElement.childElementCount - 1; i >= 0; i--) {
1103
+ const child = this.#contentElement.children[i];
1104
+ const lineType = child.dataset.lineType;
1105
+ const lineNumber = getLineNumberAttr(child);
1106
+ if (lineType !== void 0 && isLineEditable(lineType) && lineNumber !== void 0) {
1107
+ yFix = (line - (lineNumber - 1)) * this.#metrics.lineHeight;
1108
+ break;
1109
+ }
1110
+ }
1111
+ const approximateLineY = ((this.#lineAnnotations ?? []).filter((annotation) => annotation.lineNumber < line).length + line) * this.#metrics.lineHeight + yFix;
1112
+ virtualCaret.style.top = approximateLineY + "px";
1113
+ this.#fileContainer?.shadowRoot?.appendChild(virtualCaret);
1114
+ virtualCaret.scrollIntoView({
1115
+ block: "center",
1116
+ inline: "nearest"
1117
+ });
1118
+ if (this.#scrollingToLine === line && yFix === 0) {
1119
+ this.#scrollingToLine = void 0;
1120
+ this.#scrollingToLineChar = void 0;
1121
+ this.#scrollingToLineFixed = false;
1122
+ this.#scrollingToLineNoFocus = false;
1123
+ } else if (this.#scrollingToLine === line && this.#scrollingToLineFixed) {
1124
+ this.#scrollingToLine = void 0;
1125
+ this.#scrollingToLineChar = void 0;
1126
+ this.#scrollingToLineFixed = false;
1127
+ this.#scrollingToLineNoFocus = false;
1128
+ } else {
1129
+ this.#scrollingToLine = line;
1130
+ this.#scrollingToLineChar = char;
1131
+ this.#scrollingToLineFixed = yFix !== 0;
1132
+ this.#scrollingToLineNoFocus = noFocus;
1133
+ }
1099
1134
  }
1100
1135
  }
1101
1136
  virtualCaret.remove();
@@ -1193,8 +1228,15 @@ var Editor = class {
1193
1228
  });
1194
1229
  } catch {}
1195
1230
  }
1231
+ #scheduleThemeSelectionRefresh() {
1232
+ if (this.#themeSelectionRefreshFrame !== void 0) return;
1233
+ this.#themeSelectionRefreshFrame = requestAnimationFrame(() => {
1234
+ this.#themeSelectionRefreshFrame = void 0;
1235
+ if (this.#selections !== void 0 || this.#matches !== void 0 || this.#markerRenderer !== void 0) this.#updateSelections(this.#selections ?? []);
1236
+ });
1237
+ }
1196
1238
  #updateSelections(selections) {
1197
- this.__postponeBackgroundTokenizeToNextFrame();
1239
+ this.__postponeBgTokenizeToNextFrame();
1198
1240
  this.#primaryCaretElement = void 0;
1199
1241
  this.#setSelectedLinesSafe(null);
1200
1242
  if (selections.length === 0 && this.#matches === void 0 && this.#markerRenderer === void 0) {
@@ -1252,11 +1294,11 @@ var Editor = class {
1252
1294
  for (let line = start.line; line <= end.line; line++) {
1253
1295
  if (!this.#isLineVisible(line)) continue;
1254
1296
  const isLastLine = line === end.line;
1255
- const lineText = this.#textDocument.getLineText(line);
1256
1297
  const startChar = line === start.line ? start.character : 0;
1257
- const endChar = isLastLine ? end.character : lineText.length;
1298
+ const endChar = isLastLine ? end.character : this.#textDocument.getLineLength(line);
1258
1299
  if (this.#isWrap) {
1259
1300
  const contentWidth = this.#getContentWidth();
1301
+ const lineText = this.#textDocument.getLineText(line);
1260
1302
  if (2 * this.#metrics.ch + this.#metrics.measureTextWidth(lineText) > contentWidth) {
1261
1303
  this.#renderWrappedSelection(renderCtx, line, lineText, startChar, endChar, isLastLine, type, extraDataset);
1262
1304
  continue;
@@ -1305,7 +1347,9 @@ var Editor = class {
1305
1347
  const overlayEls = this.#overlayElements;
1306
1348
  const rounded = (this.#options.roundedSelection ?? true) && type === "selection";
1307
1349
  const addRoundedCorner = (line, wrapLine, left, radius) => {
1308
- const css = `width:${ch}px;transform:translateX(${left}px) translateY(${this.#getLineY(line) + wrapLine * lineHeight}px);`;
1350
+ const top = this.#getLineY(line) + wrapLine * lineHeight;
1351
+ const cornerBg = this.#lineBackgroundColor(line);
1352
+ const css = `width:${ch}px;transform:translateX(${left}px) translateY(${top}px);` + (cornerBg !== void 0 ? `--diffs-selection-corner-bg:${cornerBg};` : "");
1309
1353
  const dataset = {
1310
1354
  selectionCorner: "",
1311
1355
  [radius]: ""
@@ -1395,14 +1439,10 @@ var Editor = class {
1395
1439
  const [left, wrapLine] = this.#getCharX(line, character);
1396
1440
  const cacheKey = "caret-" + line + "/" + wrapLine + ":" + character;
1397
1441
  if (renderCtx.elements.has(cacheKey)) return;
1398
- const x = left - 1;
1399
- const y = this.#getLineY(line) + wrapLine * this.#metrics.lineHeight;
1400
- let caretEl;
1401
- if (this.#overlayElements?.has(cacheKey) === true) {
1402
- caretEl = this.#overlayElements.get(cacheKey);
1403
- this.#overlayElements.delete(cacheKey);
1404
- } else caretEl = h("div", { dataset: "caret" }, renderCtx.fragment);
1405
- caretEl.style.transform = `translateX(${x}px) translateY(${y}px)`;
1442
+ const caretEl = h("div", {
1443
+ dataset: "caret",
1444
+ style: { transform: `translateX(${left - 1}px) translateY(${this.#getLineY(line) + wrapLine * this.#metrics.lineHeight}px)` }
1445
+ }, renderCtx.fragment);
1406
1446
  renderCtx.elements.set(cacheKey, caretEl);
1407
1447
  if (isPrimary) {
1408
1448
  caretEl.style.scrollMargin = this.#getScrollMargin();
@@ -1643,7 +1683,7 @@ var Editor = class {
1643
1683
  });
1644
1684
  return file;
1645
1685
  }
1646
- #applyChange(change, selections, newLineAnnotations, options) {
1686
+ #applyChange(change, newSelections, newLineAnnotations, options) {
1647
1687
  const fileRef = this.#getFileRef();
1648
1688
  const onChange = this.#options.onChange;
1649
1689
  if (fileRef !== void 0 && onChange !== void 0) onChange(fileRef, newLineAnnotations ?? this.#lineAnnotations);
@@ -1656,8 +1696,8 @@ var Editor = class {
1656
1696
  this.#lastAccessedCharX = void 0;
1657
1697
  let renderRange = this.#renderRange;
1658
1698
  let shouldUpdateBuffer;
1659
- if (renderRange !== void 0 && selections !== void 0 && selections.length > 0) {
1660
- const primarySelection = selections.at(-1);
1699
+ if (renderRange !== void 0 && newSelections !== void 0 && newSelections.length > 0) {
1700
+ const primarySelection = newSelections.at(-1);
1661
1701
  const renderRangeEndLine = renderRange.startingLine + renderRange.totalLines;
1662
1702
  if (primarySelection.end.line >= renderRangeEndLine) {
1663
1703
  const widenedTotalLines = primarySelection.end.line - renderRange.startingLine + 1;
@@ -1674,15 +1714,17 @@ var Editor = class {
1674
1714
  }
1675
1715
  this.#rerender(change, newLineAnnotations, renderRange, shouldUpdateBuffer);
1676
1716
  if (options?.skipSearchRefresh !== true && this.#searchPanel !== void 0 && this.#matches !== void 0) this.#searchPanel.updateMatches({ syncSelection: false });
1677
- if (selections !== void 0) {
1678
- this.#updateSelections(selections);
1717
+ if (newSelections !== void 0) {
1718
+ this.#updateSelections(newSelections);
1679
1719
  if (options?.skipFocus !== true) {
1680
- if (this.#primaryCaretElement !== void 0) this.#primaryCaretElement.scrollIntoView({
1681
- block: "nearest",
1682
- inline: "nearest"
1720
+ if (this.#primaryCaretElement !== void 0) requestAnimationFrame(() => {
1721
+ this.#primaryCaretElement?.scrollIntoView({
1722
+ block: "nearest",
1723
+ inline: "nearest"
1724
+ });
1683
1725
  });
1684
- else if (selections.length > 0) {
1685
- const pos = getCaretPosition(selections.at(-1));
1726
+ else if (newSelections.length > 0) {
1727
+ const pos = getCaretPosition(newSelections.at(-1));
1686
1728
  this.#scrollToLine(pos.line, pos.character);
1687
1729
  }
1688
1730
  this.focus({ preventScroll: true });
@@ -1698,12 +1740,36 @@ var Editor = class {
1698
1740
  }
1699
1741
  }
1700
1742
  }
1743
+ #lineBackgroundColor(line) {
1744
+ const lineElement = this.#getLineElement(line);
1745
+ if (lineElement === void 0) return;
1746
+ const backgroundColor = getComputedStyle(lineElement, "::after").backgroundColor;
1747
+ return backgroundColor === "" || backgroundColor === "transparent" || backgroundColor === "rgba(0, 0, 0, 0)" ? void 0 : backgroundColor;
1748
+ }
1749
+ #getRenderedEditableLineRange() {
1750
+ const contentElement = this.#contentElement;
1751
+ if (contentElement === void 0) return;
1752
+ let first;
1753
+ let last;
1754
+ for (const child of contentElement.children) {
1755
+ const el = child;
1756
+ const lineType = el.dataset.lineType;
1757
+ const lineNumber = getLineNumberAttr(el);
1758
+ if (lineNumber === void 0 || lineType === void 0 || !isLineEditable(lineType)) continue;
1759
+ const line = lineNumber - 1;
1760
+ if (first === void 0 || line < first) first = line;
1761
+ if (last === void 0 || line > last) last = line;
1762
+ }
1763
+ return first === void 0 || last === void 0 ? void 0 : {
1764
+ first,
1765
+ last
1766
+ };
1767
+ }
1701
1768
  #getLineElement(line) {
1702
- const lastAccessed = this.#lastAccessedLineElement;
1703
- if (lastAccessed !== void 0 && lastAccessed[0] === line) return lastAccessed[1];
1769
+ let lineElement = this.#lineElementsCache.get(line);
1770
+ if (lineElement !== void 0) return lineElement ?? void 0;
1704
1771
  const contentElement = this.#contentElement;
1705
1772
  if (contentElement === void 0) return;
1706
- let lineElement = null;
1707
1773
  if (this.#renderRange !== void 0) {
1708
1774
  const { startingLine } = this.#renderRange;
1709
1775
  const { children } = contentElement;
@@ -1719,13 +1785,8 @@ var Editor = class {
1719
1785
  }
1720
1786
  }
1721
1787
  lineElement ??= contentElement.querySelector(`[data-line="${line + 1}"]` + (this.#diffSyle === "unified" ? ":not([data-line-type=\"change-deletion\"])" : ""));
1722
- if (lineElement !== null) {
1723
- if (lastAccessed !== void 0) {
1724
- lastAccessed[0] = line;
1725
- lastAccessed[1] = lineElement;
1726
- } else this.#lastAccessedLineElement = [line, lineElement];
1727
- return lineElement;
1728
- }
1788
+ if (lineElement !== void 0) this.#lineElementsCache.set(line, lineElement);
1789
+ return lineElement ?? void 0;
1729
1790
  }
1730
1791
  #getGutterWidth() {
1731
1792
  if (this.#gutterElement === void 0) return 0;
@@ -1863,11 +1924,7 @@ var Editor = class {
1863
1924
  #isLineVisible(line) {
1864
1925
  const lineCount = this.#textDocument?.lineCount ?? 0;
1865
1926
  if (line < 0 || line >= lineCount) return false;
1866
- if (this.#renderRange === void 0) return true;
1867
- const { startingLine, totalLines } = this.#renderRange;
1868
- if (line < startingLine) return false;
1869
- if (totalLines === Infinity) return true;
1870
- return line < startingLine + totalLines;
1927
+ return this.#getLineElement(line) !== void 0;
1871
1928
  }
1872
1929
  };
1873
1930
  //#endregion