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

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 (129) hide show
  1. package/dist/components/CodeView.d.ts +86 -4
  2. package/dist/components/CodeView.d.ts.map +1 -1
  3. package/dist/components/CodeView.js +248 -33
  4. package/dist/components/CodeView.js.map +1 -1
  5. package/dist/components/File.d.ts +1 -0
  6. package/dist/components/File.d.ts.map +1 -1
  7. package/dist/components/File.js +15 -4
  8. package/dist/components/File.js.map +1 -1
  9. package/dist/components/FileDiff.d.ts +2 -0
  10. package/dist/components/FileDiff.d.ts.map +1 -1
  11. package/dist/components/FileDiff.js +21 -6
  12. package/dist/components/FileDiff.js.map +1 -1
  13. package/dist/components/FileStream.d.ts.map +1 -1
  14. package/dist/components/FileStream.js +2 -1
  15. package/dist/components/FileStream.js.map +1 -1
  16. package/dist/components/VirtualizedFile.d.ts.map +1 -1
  17. package/dist/components/VirtualizedFile.js +3 -1
  18. package/dist/components/VirtualizedFile.js.map +1 -1
  19. package/dist/components/VirtualizedFileDiff.d.ts +3 -1
  20. package/dist/components/VirtualizedFileDiff.d.ts.map +1 -1
  21. package/dist/components/VirtualizedFileDiff.js +14 -6
  22. package/dist/components/VirtualizedFileDiff.js.map +1 -1
  23. package/dist/components/Virtualizer.d.ts +2 -0
  24. package/dist/components/Virtualizer.d.ts.map +1 -1
  25. package/dist/components/Virtualizer.js +18 -4
  26. package/dist/components/Virtualizer.js.map +1 -1
  27. package/dist/constants.d.ts +3 -1
  28. package/dist/constants.d.ts.map +1 -1
  29. package/dist/constants.js +3 -1
  30. package/dist/constants.js.map +1 -1
  31. package/dist/editor/command.d.ts +1 -1
  32. package/dist/editor/command.d.ts.map +1 -1
  33. package/dist/editor/command.js +8 -0
  34. package/dist/editor/command.js.map +1 -1
  35. package/dist/editor/editStack.d.ts.map +1 -1
  36. package/dist/editor/editStack.js +1 -1
  37. package/dist/editor/editStack.js.map +1 -1
  38. package/dist/editor/editor.d.ts +8 -1
  39. package/dist/editor/editor.d.ts.map +1 -1
  40. package/dist/editor/editor.js +188 -42
  41. package/dist/editor/editor.js.map +1 -1
  42. package/dist/editor/editor2.js +1 -1
  43. package/dist/editor/lineAnnotations.d.ts.map +1 -1
  44. package/dist/editor/lineAnnotations.js +84 -12
  45. package/dist/editor/lineAnnotations.js.map +1 -1
  46. package/dist/editor/marker.d.ts +5 -3
  47. package/dist/editor/marker.d.ts.map +1 -1
  48. package/dist/editor/marker.js +35 -12
  49. package/dist/editor/marker.js.map +1 -1
  50. package/dist/editor/matchBrackets.d.ts +8 -0
  51. package/dist/editor/matchBrackets.d.ts.map +1 -0
  52. package/dist/editor/matchBrackets.js +146 -0
  53. package/dist/editor/matchBrackets.js.map +1 -0
  54. package/dist/editor/popover.d.ts +45 -0
  55. package/dist/editor/popover.d.ts.map +1 -0
  56. package/dist/editor/popover.js +145 -0
  57. package/dist/editor/popover.js.map +1 -0
  58. package/dist/editor/searchPanel.d.ts +1 -0
  59. package/dist/editor/searchPanel.d.ts.map +1 -1
  60. package/dist/editor/searchPanel.js +6 -6
  61. package/dist/editor/searchPanel.js.map +1 -1
  62. package/dist/editor/selection.d.ts +13 -1
  63. package/dist/editor/selection.d.ts.map +1 -1
  64. package/dist/editor/selection.js +55 -4
  65. package/dist/editor/selection.js.map +1 -1
  66. package/dist/editor/selectionAction.d.ts +20 -3
  67. package/dist/editor/selectionAction.d.ts.map +1 -1
  68. package/dist/editor/selectionAction.js +41 -10
  69. package/dist/editor/selectionAction.js.map +1 -1
  70. package/dist/editor/textDocument.d.ts +2 -0
  71. package/dist/editor/textDocument.d.ts.map +1 -1
  72. package/dist/editor/textDocument.js +22 -6
  73. package/dist/editor/textDocument.js.map +1 -1
  74. package/dist/editor/tokenzier.d.ts +4 -7
  75. package/dist/editor/tokenzier.d.ts.map +1 -1
  76. package/dist/editor/tokenzier.js +76 -35
  77. package/dist/editor/tokenzier.js.map +1 -1
  78. package/dist/index.d.ts +7 -7
  79. package/dist/index.js +5 -5
  80. package/dist/managers/ResizeManager.d.ts +10 -2
  81. package/dist/managers/ResizeManager.d.ts.map +1 -1
  82. package/dist/managers/ResizeManager.js +33 -13
  83. package/dist/managers/ResizeManager.js.map +1 -1
  84. package/dist/managers/UniversalRenderingManager.d.ts +2 -1
  85. package/dist/managers/UniversalRenderingManager.d.ts.map +1 -1
  86. package/dist/managers/UniversalRenderingManager.js +6 -1
  87. package/dist/managers/UniversalRenderingManager.js.map +1 -1
  88. package/dist/react/CodeView.d.ts +25 -1
  89. package/dist/react/CodeView.d.ts.map +1 -1
  90. package/dist/react/CodeView.js +76 -17
  91. package/dist/react/CodeView.js.map +1 -1
  92. package/dist/react/EditorContext.d.ts +2 -2
  93. package/dist/react/EditorContext.d.ts.map +1 -1
  94. package/dist/react/EditorContext.js.map +1 -1
  95. package/dist/react/index.d.ts +2 -2
  96. package/dist/renderers/DiffHunksRenderer.d.ts +1 -1
  97. package/dist/renderers/DiffHunksRenderer.d.ts.map +1 -1
  98. package/dist/renderers/DiffHunksRenderer.js +24 -15
  99. package/dist/renderers/DiffHunksRenderer.js.map +1 -1
  100. package/dist/renderers/FileRenderer.d.ts +2 -1
  101. package/dist/renderers/FileRenderer.d.ts.map +1 -1
  102. package/dist/renderers/FileRenderer.js +58 -38
  103. package/dist/renderers/FileRenderer.js.map +1 -1
  104. package/dist/ssr/index.d.ts +2 -2
  105. package/dist/types.d.ts +42 -2
  106. package/dist/types.d.ts.map +1 -1
  107. package/dist/utils/applyLineTextWithNewline.d.ts +5 -0
  108. package/dist/utils/applyLineTextWithNewline.d.ts.map +1 -0
  109. package/dist/utils/applyLineTextWithNewline.js +11 -0
  110. package/dist/utils/applyLineTextWithNewline.js.map +1 -0
  111. package/dist/utils/areManagedSnapshotsEqual.d.ts +2 -2
  112. package/dist/utils/areManagedSnapshotsEqual.d.ts.map +1 -1
  113. package/dist/utils/areManagedSnapshotsEqual.js +5 -0
  114. package/dist/utils/areManagedSnapshotsEqual.js.map +1 -1
  115. package/dist/utils/createCodeViewHeaderFooterHostElement.d.ts +5 -0
  116. package/dist/utils/createCodeViewHeaderFooterHostElement.d.ts.map +1 -0
  117. package/dist/utils/createCodeViewHeaderFooterHostElement.js +19 -0
  118. package/dist/utils/createCodeViewHeaderFooterHostElement.js.map +1 -0
  119. package/dist/utils/updateDiffHunks.d.ts.map +1 -1
  120. package/dist/utils/updateDiffHunks.js +23 -1
  121. package/dist/utils/updateDiffHunks.js.map +1 -1
  122. package/dist/worker/WorkerPoolManager.d.ts.map +1 -1
  123. package/dist/worker/WorkerPoolManager.js +4 -2
  124. package/dist/worker/WorkerPoolManager.js.map +1 -1
  125. package/dist/worker/types.d.ts +4 -0
  126. package/dist/worker/types.d.ts.map +1 -1
  127. package/dist/worker/worker-portable.js.map +1 -1
  128. package/dist/worker/worker.js.map +1 -1
  129. package/package.json +4 -2
@@ -1,9 +1,11 @@
1
1
  import { DEFAULT_CODE_VIEW_FILE_METRICS, DEFAULT_CODE_VIEW_LAYOUT, DEFAULT_SMOOTH_SCROLL_SETTINGS, DEFAULT_THEMES, DIFFS_DEVELOPMENT_BUILD, DIFFS_TAG_NAME } from "../constants.js";
2
2
  import { dequeueRender, queueRender } from "../managers/UniversalRenderingManager.js";
3
+ import { areManagedSnapshotsEqual } from "../utils/areManagedSnapshotsEqual.js";
3
4
  import { areObjectsEqual } from "../utils/areObjectsEqual.js";
4
5
  import { areThemesEqual } from "../utils/areThemesEqual.js";
5
6
  import { areOptionsEqual } from "../utils/areOptionsEqual.js";
6
7
  import { areSelectionsEqual } from "../utils/areSelectionsEqual.js";
8
+ import { createCodeViewHeaderFooterHostElement } from "../utils/createCodeViewHeaderFooterHostElement.js";
7
9
  import { createWindowFromScrollPosition } from "../utils/createWindowFromScrollPosition.js";
8
10
  import { isStyleNode } from "../utils/isStyleNode.js";
9
11
  import { prefersReducedMotion } from "../utils/prefersReducedMotion.js";
@@ -62,6 +64,13 @@ const CODE_VIEW_FILE_OPTION_KEYS = [
62
64
  "controlledSelection",
63
65
  "disableErrorHandling"
64
66
  ];
67
+ const CODE_VIEW_EDIT_FORCED_OPTION_KEYS = /* @__PURE__ */ new Set([
68
+ "useTokenTransformer",
69
+ "enableGutterUtility",
70
+ "enableLineSelection",
71
+ "lineHoverHighlight",
72
+ "expandUnchanged"
73
+ ]);
65
74
  const CODE_VIEW_SHARED_CALLBACK_KEYS = [
66
75
  "renderCustomHeader",
67
76
  "renderHeaderPrefix",
@@ -131,6 +140,8 @@ var CodeView = class CodeView {
131
140
  items = [];
132
141
  idToItem = /* @__PURE__ */ new Map();
133
142
  selectedLines = null;
143
+ itemEditors = /* @__PURE__ */ new Map();
144
+ attachedEditors = /* @__PURE__ */ new Set();
134
145
  instanceToItem = /* @__PURE__ */ new Map();
135
146
  layoutDirtyIndex;
136
147
  pendingLayoutReset;
@@ -172,6 +183,16 @@ var CodeView = class CodeView {
172
183
  container = document.createElement("div");
173
184
  stickyContainer = document.createElement("div");
174
185
  stickyOffset = document.createElement("div");
186
+ header = {
187
+ element: void 0,
188
+ render: void 0,
189
+ height: 0
190
+ };
191
+ footer = {
192
+ element: void 0,
193
+ render: void 0,
194
+ height: 0
195
+ };
175
196
  elementPool = [];
176
197
  elementPoolVersion = 0;
177
198
  elementPoolTracker = /* @__PURE__ */ new WeakMap();
@@ -198,6 +219,9 @@ var CodeView = class CodeView {
198
219
  getLayout() {
199
220
  return this.options.layout ?? DEFAULT_CODE_VIEW_LAYOUT;
200
221
  }
222
+ getItemTopOffset() {
223
+ return this.getLayout().paddingTop + this.header.height;
224
+ }
201
225
  computeMetricsCache(itemMetrics) {
202
226
  this.itemMetricsCache = {
203
227
  hunkLineCount: itemMetrics?.hunkLineCount ?? DEFAULT_CODE_VIEW_FILE_METRICS.hunkLineCount,
@@ -300,6 +324,43 @@ var CodeView = class CodeView {
300
324
  this.container?.style.setProperty("margin-top", `${paddingTop}px`);
301
325
  this.container?.style.setProperty("margin-bottom", `${paddingBottom}px`);
302
326
  }
327
+ reconcileHeaderFooterHosts() {
328
+ const headerChanged = this.reconcileHost("header");
329
+ const footerChanged = this.reconcileHost("footer");
330
+ return headerChanged || footerChanged;
331
+ }
332
+ reconcileHost(type) {
333
+ const { root, container } = this;
334
+ if (root == null || container == null) return false;
335
+ const host = type === "header" ? this.header : this.footer;
336
+ const render = type === "header" ? this.options.renderCodeViewHeader : this.options.renderCodeViewFooter;
337
+ if (render == null) {
338
+ if (host.element == null) return false;
339
+ this.resizeObserver?.unobserve(host.element);
340
+ host.element.remove();
341
+ host.element = void 0;
342
+ host.render = void 0;
343
+ this.setHostHeight(host, 0);
344
+ return false;
345
+ }
346
+ if (host.element != null && render === host.render) return false;
347
+ const element = host.element ?? createCodeViewHeaderFooterHostElement(type, container, this.resizeObserver);
348
+ host.element = element;
349
+ const content = render();
350
+ if (content != null) element.replaceChildren(content);
351
+ else if (!this.isContainerManaged && element.children.length > 0) element.textContent = "";
352
+ host.render = render;
353
+ return true;
354
+ }
355
+ setHostHeight(host, height) {
356
+ if (host.height === height) return;
357
+ host.height = height;
358
+ this.scrollDirty = true;
359
+ }
360
+ measureMountedHosts() {
361
+ if (this.header.element != null) this.setHostHeight(this.header, this.header.element.getBoundingClientRect().height);
362
+ if (this.footer.element != null) this.setHostHeight(this.footer, this.footer.element.getBoundingClientRect().height);
363
+ }
303
364
  setup(root) {
304
365
  if (this.root != null) throw new Error("CodeView.setup: already setup");
305
366
  this.workerManager?.subscribeToThemeChanges(this);
@@ -339,9 +400,13 @@ var CodeView = class CodeView {
339
400
  };
340
401
  }
341
402
  reset() {
403
+ dequeueRender(this.computeRenderRangeAndEmit);
342
404
  this.clearReadySubscription();
343
405
  this.restoreScrollInteractions();
344
406
  this.cleanAllRenderedItems();
407
+ for (const record of this.itemEditors.values()) record.editor.cleanUp();
408
+ this.itemEditors.clear();
409
+ this.attachedEditors.clear();
345
410
  this.selectedLines = null;
346
411
  this.items.length = 0;
347
412
  this.idToItem.clear();
@@ -384,6 +449,14 @@ var CodeView = class CodeView {
384
449
  this.stickyOffset.remove();
385
450
  this.stickyContainer.remove();
386
451
  this.stickyContainer.textContent = "";
452
+ this.header.element?.remove();
453
+ this.header.element = void 0;
454
+ this.header.render = void 0;
455
+ this.header.height = 0;
456
+ this.footer.element?.remove();
457
+ this.footer.element = void 0;
458
+ this.footer.render = void 0;
459
+ this.footer.height = 0;
387
460
  this.root = void 0;
388
461
  this.container = void 0;
389
462
  }
@@ -418,6 +491,7 @@ var CodeView = class CodeView {
418
491
  const { element } = item;
419
492
  if (element != null && this.renderedItemOwnsFocus(element)) this.shouldFixContainerFocus = true;
420
493
  item.instance.cleanUp(true);
494
+ this.attachedEditors.delete(item.item.id);
421
495
  item.element = void 0;
422
496
  if (element == null) return;
423
497
  element.remove();
@@ -510,6 +584,14 @@ var CodeView = class CodeView {
510
584
  getItem(itemId) {
511
585
  return this.idToItem.get(itemId)?.item;
512
586
  }
587
+ /**
588
+ * Get the live editor for an item currently in edit mode. Use this to drive
589
+ * editor APIs CodeView does not wrap (applyEdits, undo, setMarkers, …).
590
+ * Returns undefined once the item leaves edit mode.
591
+ */
592
+ getEditor(itemId) {
593
+ return this.itemEditors.get(itemId)?.editor;
594
+ }
513
595
  updateItem(input) {
514
596
  const item = this.idToItem.get(input.id);
515
597
  if (item == null) {
@@ -521,6 +603,7 @@ var CodeView = class CodeView {
521
603
  this.scrollDirty = true;
522
604
  this.render();
523
605
  this.syncSelection();
606
+ this.syncItemEditors();
524
607
  return true;
525
608
  }
526
609
  updateItemId(oldId, newId) {
@@ -545,6 +628,13 @@ var CodeView = class CodeView {
545
628
  };
546
629
  this.options.onSelectedLinesChange?.(this.selectedLines);
547
630
  }
631
+ const editorRecord = this.itemEditors.get(oldId);
632
+ if (editorRecord != null) {
633
+ editorRecord.state.id = newId;
634
+ this.itemEditors.delete(oldId);
635
+ this.itemEditors.set(newId, editorRecord);
636
+ if (this.attachedEditors.delete(oldId)) this.attachedEditors.add(newId);
637
+ }
548
638
  this.renamePendingScrollTarget(oldId, newId);
549
639
  this.renamePendingLayoutAnchor(oldId, newId);
550
640
  this.render();
@@ -552,17 +642,25 @@ var CodeView = class CodeView {
552
642
  }
553
643
  addItem(input) {
554
644
  this.addItems([input]);
555
- this.syncSelection();
556
645
  }
557
646
  addItems(inputs) {
558
647
  this.appendItemsInternal(inputs);
559
648
  this.syncSelection();
649
+ this.syncItemEditors();
560
650
  }
561
651
  setItems(items) {
562
- if (items.length === 0) this.reset();
563
- else if (this.items.length === 0) this.appendItemsInternal(items);
652
+ if (items.length === 0) {
653
+ const completions = [];
654
+ for (const record of this.itemEditors.values()) {
655
+ const { lastChange } = record.state;
656
+ if (lastChange != null) completions.push(lastChange);
657
+ }
658
+ this.reset();
659
+ for (const { item, file, lineAnnotations } of completions) this.options.onItemEditComplete?.(item, file, lineAnnotations);
660
+ } else if (this.items.length === 0) this.appendItemsInternal(items);
564
661
  else if (!this.tryAppendItems(items)) this.reconcileItems(items);
565
662
  this.syncSelection();
663
+ this.syncItemEditors();
566
664
  }
567
665
  /**
568
666
  * Append new records to the viewer while preserving existing layout state.
@@ -624,7 +722,9 @@ var CodeView = class CodeView {
624
722
  this.scrollDirty = true;
625
723
  }
626
724
  if (!areOptionsEqual(prevOptions, options)) this.renderOptionsRevision++;
627
- if (!this.isContainerManaged && this.items.length > 0) this.render();
725
+ this.syncItemEditors();
726
+ const headerFooterChanged = prevOptions.renderCodeViewHeader !== options.renderCodeViewHeader || prevOptions.renderCodeViewFooter !== options.renderCodeViewFooter;
727
+ if (!this.isContainerManaged && (this.items.length > 0 || headerFooterChanged)) this.render();
628
728
  }
629
729
  capturePendingLayoutAnchor() {
630
730
  if (this.root == null || this.items.length === 0 || this.pendingScrollTarget != null) return;
@@ -668,6 +768,12 @@ var CodeView = class CodeView {
668
768
  getContainerElement() {
669
769
  return this.root;
670
770
  }
771
+ getHeaderElement() {
772
+ return this.header.element;
773
+ }
774
+ getFooterElement() {
775
+ return this.footer.element;
776
+ }
671
777
  getRenderedItems() {
672
778
  const { firstIndex, lastIndex } = this.renderState;
673
779
  if (firstIndex === -1 || lastIndex === -1 || lastIndex < firstIndex) return [];
@@ -701,7 +807,18 @@ var CodeView = class CodeView {
701
807
  return true;
702
808
  }
703
809
  getSlotSnapshot(coordinator) {
704
- return getSlotSnapshot(this.getRenderedItems(), coordinator);
810
+ return this.buildSlotSnapshot(coordinator);
811
+ }
812
+ buildSlotSnapshot(coordinator) {
813
+ const items = getSlotItems(this.getRenderedItems(), coordinator);
814
+ const { element: header } = this.header;
815
+ const { element: footer } = this.footer;
816
+ if (items == null && header == null && footer == null) return;
817
+ return {
818
+ items,
819
+ header,
820
+ footer
821
+ };
705
822
  }
706
823
  subscribeToScroll(listener) {
707
824
  this.scrollListeners.add(listener);
@@ -717,7 +834,7 @@ var CodeView = class CodeView {
717
834
  getTopForItem(id) {
718
835
  const item = this.idToItem.get(id);
719
836
  if (item == null) return;
720
- return item.top + this.getLayout().paddingTop;
837
+ return item.top + this.getItemTopOffset();
721
838
  }
722
839
  createItem(input, index, top) {
723
840
  const { itemMetricsCache: itemMetrics } = this;
@@ -764,6 +881,75 @@ var CodeView = class CodeView {
764
881
  }
765
882
  item.instance.setSelectedLines(this.selectedLines.range, { notify: false });
766
883
  }
884
+ isItemInEditMode(item) {
885
+ return this.options.createEditor != null && item.item.edit === true && item.item.collapsed !== true;
886
+ }
887
+ isReceiverEdited(receiver, mode) {
888
+ const state = getItemOptionsState(receiver);
889
+ if (state == null) return false;
890
+ const item = this.getItemOptions(state, mode);
891
+ return item != null && this.isItemInEditMode(item);
892
+ }
893
+ /**
894
+ * Attach (or lazily create) the editor for a mounted edit-mode item. Called
895
+ * from the render loop so every mounted item passes through it: fresh
896
+ * mounts, remounts after virtualization released the item, and items whose
897
+ * edit flag was just turned on. Editors persist across unmounts, so a
898
+ * remounted item re-attaches its existing editor and resumes the retained
899
+ * document; the renderers keep the host's file/diff data in sync with the
900
+ * session so the remount paints the edited text.
901
+ */
902
+ attachItemEditor(item) {
903
+ const { id } = item.item;
904
+ const { createEditor } = this.options;
905
+ if (createEditor == null || item.element == null || this.attachedEditors.has(id) || !this.isItemInEditMode(item)) return;
906
+ let record = this.itemEditors.get(id);
907
+ if (record == null) {
908
+ const state = { id };
909
+ const editor = createEditor({ onChange: (file, lineAnnotations) => {
910
+ const latest = this.idToItem.get(state.id);
911
+ if (latest == null) return;
912
+ state.lastChange = {
913
+ item: latest.item,
914
+ file,
915
+ lineAnnotations
916
+ };
917
+ this.options.onItemEditChange?.(latest.item, file, lineAnnotations);
918
+ } });
919
+ if (editor == null) return;
920
+ record = {
921
+ editor,
922
+ state
923
+ };
924
+ this.itemEditors.set(id, record);
925
+ }
926
+ if (this.selectedLines?.id === id) this.applySelectedLines(null, { notify: false });
927
+ record.editor.edit(item.instance);
928
+ this.attachedEditors.add(id);
929
+ }
930
+ /**
931
+ * Drop editors for items that can no longer be edited: removed, edit turned
932
+ * off, collapsed, or the createEditor option was unset. Attachment happens
933
+ * in the render loop via attachItemEditor, so this only reconciles editors
934
+ * CodeView is already holding.
935
+ */
936
+ syncItemEditors() {
937
+ if (this.itemEditors.size === 0) return;
938
+ const completions = [];
939
+ for (const [id, record] of this.itemEditors) {
940
+ const item = this.idToItem.get(id);
941
+ if (item != null && this.isItemInEditMode(item)) continue;
942
+ record.editor.cleanUp();
943
+ this.itemEditors.delete(id);
944
+ this.attachedEditors.delete(id);
945
+ const { lastChange } = record.state;
946
+ if (lastChange != null) completions.push(item == null ? lastChange : {
947
+ ...lastChange,
948
+ item: item.item
949
+ });
950
+ }
951
+ for (const { item, file, lineAnnotations } of completions) this.options.onItemEditComplete?.(item, file, lineAnnotations);
952
+ }
767
953
  renamePendingScrollTarget(oldId, newId) {
768
954
  const { pendingScrollTarget } = this;
769
955
  if (pendingScrollTarget == null || pendingScrollTarget.type === "position" || pendingScrollTarget.id !== oldId) return;
@@ -777,7 +963,14 @@ var CodeView = class CodeView {
777
963
  }
778
964
  createFileOptionsPrototype() {
779
965
  const prototype = {};
780
- for (const key of CODE_VIEW_FILE_OPTION_KEYS) defineItemOption(prototype, key, () => this.options[key]);
966
+ for (const key of CODE_VIEW_FILE_OPTION_KEYS) {
967
+ if (CODE_VIEW_EDIT_FORCED_OPTION_KEYS.has(key)) continue;
968
+ defineItemOption(prototype, key, () => this.options[key]);
969
+ }
970
+ defineItemOption(prototype, "useTokenTransformer", (receiver) => this.isReceiverEdited(receiver, "file") ? true : this.options.useTokenTransformer);
971
+ defineItemOption(prototype, "enableGutterUtility", (receiver) => this.isReceiverEdited(receiver, "file") ? false : this.options.enableGutterUtility);
972
+ defineItemOption(prototype, "enableLineSelection", (receiver) => this.isReceiverEdited(receiver, "file") ? false : this.options.enableLineSelection);
973
+ defineItemOption(prototype, "lineHoverHighlight", (receiver) => this.isReceiverEdited(receiver, "file") ? "disabled" : this.options.lineHoverHighlight);
781
974
  defineItemOption(prototype, "stickyHeader", () => this.options.stickyHeaders);
782
975
  defineItemOption(prototype, "collapsed", (receiver) => {
783
976
  const state = getItemOptionsState(receiver);
@@ -790,7 +983,15 @@ var CodeView = class CodeView {
790
983
  }
791
984
  createDiffOptionsPrototype() {
792
985
  const prototype = {};
793
- for (const key of CODE_VIEW_DIFF_OPTION_KEYS) defineItemOption(prototype, key, () => this.options[key]);
986
+ for (const key of CODE_VIEW_DIFF_OPTION_KEYS) {
987
+ if (CODE_VIEW_EDIT_FORCED_OPTION_KEYS.has(key)) continue;
988
+ defineItemOption(prototype, key, () => this.options[key]);
989
+ }
990
+ defineItemOption(prototype, "useTokenTransformer", (receiver) => this.isReceiverEdited(receiver, "diff") ? true : this.options.useTokenTransformer);
991
+ defineItemOption(prototype, "enableGutterUtility", (receiver) => this.isReceiverEdited(receiver, "diff") ? false : this.options.enableGutterUtility);
992
+ defineItemOption(prototype, "enableLineSelection", (receiver) => this.isReceiverEdited(receiver, "diff") ? false : this.options.enableLineSelection);
993
+ defineItemOption(prototype, "lineHoverHighlight", (receiver) => this.isReceiverEdited(receiver, "diff") ? "disabled" : this.options.lineHoverHighlight);
994
+ defineItemOption(prototype, "expandUnchanged", (receiver) => this.isReceiverEdited(receiver, "diff") ? true : this.options.expandUnchanged);
794
995
  defineItemOption(prototype, "stickyHeader", () => this.options.stickyHeaders);
795
996
  defineItemOption(prototype, "hunkSeparators", () => this.options.hunkSeparators);
796
997
  defineItemOption(prototype, "collapsed", (receiver) => {
@@ -846,6 +1047,8 @@ var CodeView = class CodeView {
846
1047
  if (this.options.enableLineSelection !== true) return;
847
1048
  const state = getItemOptionsState(receiver);
848
1049
  if (state == null) return;
1050
+ const item = this.getItemOptions(state, mode);
1051
+ if (item != null && this.isItemInEditMode(item)) return;
849
1052
  const callbackCache = state.callbackCache ??= {};
850
1053
  let wrapped = callbackCache[key];
851
1054
  if (wrapped == null) {
@@ -973,7 +1176,7 @@ var CodeView = class CodeView {
973
1176
  }
974
1177
  getMaxScrollTopForHeight(scrollHeight) {
975
1178
  const { paddingBottom, paddingTop } = this.getLayout();
976
- return Math.max(paddingTop + scrollHeight + paddingBottom - this.getHeight(), 0);
1179
+ return Math.max(paddingTop + this.header.height + scrollHeight + this.footer.height + paddingBottom - this.getHeight(), 0);
977
1180
  }
978
1181
  getMaxScrollTop() {
979
1182
  return this.getMaxScrollTopForHeight(this.getScrollHeight());
@@ -1085,7 +1288,7 @@ var CodeView = class CodeView {
1085
1288
  const rect = this.getScrollTargetRect(target);
1086
1289
  if (rect == null) return;
1087
1290
  const offset = target.offset ?? 0;
1088
- const targetTop = this.getLayout().paddingTop + rect.top;
1291
+ const targetTop = this.getItemTopOffset() + rect.top;
1089
1292
  const targetBottom = targetTop + rect.height;
1090
1293
  const currentTop = this.getScrollTop();
1091
1294
  const visibleTop = currentTop + (target.type === "line" || target.type === "range" ? this.getStickyHeaderOffset() : 0);
@@ -1137,7 +1340,7 @@ var CodeView = class CodeView {
1137
1340
  * and stickyOffset if necessary
1138
1341
  */
1139
1342
  resolveAlignedScrollPosition(targetTop, targetHeight, align, offset = 0, stickyOffset = 0) {
1140
- targetTop += this.getLayout().paddingTop;
1343
+ targetTop += this.getItemTopOffset();
1141
1344
  const viewportHeight = this.getHeight();
1142
1345
  if (align === "center" && targetHeight + offset < viewportHeight) return targetTop - (viewportHeight - targetHeight) / 2 + offset;
1143
1346
  if (align === "end") return targetTop - (viewportHeight - targetHeight) + offset;
@@ -1269,7 +1472,7 @@ var CodeView = class CodeView {
1269
1472
  const fitPerfectly = !computeScrollCorrection && (this.renderState.scrollTop === -1 || Math.abs(targetScrollTop - this.renderState.scrollTop) > viewportHeight + this.config.overscrollSize * 2);
1270
1473
  if (fitPerfectly) scrollAnchor = void 0;
1271
1474
  this.windowSpecs = createWindowFromScrollPosition({
1272
- scrollTop: targetScrollTop,
1475
+ scrollTop: targetScrollTop - this.header.height,
1273
1476
  height: viewportHeight,
1274
1477
  scrollHeight: this.getScrollHeight(),
1275
1478
  fitPerfectly,
@@ -1288,6 +1491,7 @@ var CodeView = class CodeView {
1288
1491
  if (item == null) throw new Error(`CodeView.computeRenderRangeAndEmit: No item at index: ${index}`);
1289
1492
  if (!(item.top > top - item.height && item.top <= bottom)) this.releaseRenderedItem(item);
1290
1493
  }
1494
+ const hostsChanged = this.reconcileHeaderFooterHosts();
1291
1495
  let prevElement;
1292
1496
  const updatedItems = /* @__PURE__ */ new Set();
1293
1497
  const startingIndex = this.findFirstVisibleIndex(top);
@@ -1313,11 +1517,13 @@ var CodeView = class CodeView {
1313
1517
  }
1314
1518
  prevElement = item.element;
1315
1519
  }
1520
+ if (item.item.edit === true) this.attachItemEditor(item);
1316
1521
  }
1317
1522
  this.renderState.firstIndex = startingIndex <= lastRenderedIndex ? startingIndex : -1;
1318
1523
  this.renderState.lastIndex = lastRenderedIndex;
1319
1524
  this.flushSlotCoordinator();
1320
1525
  this.flushManagers(updatedItems);
1526
+ if (hostsChanged) this.measureMountedHosts();
1321
1527
  this.reconcileRenderedItems(updatedItems);
1322
1528
  this.syncContainerHeight();
1323
1529
  this.updateStickyPositioning();
@@ -1456,6 +1662,25 @@ var CodeView = class CodeView {
1456
1662
  this.scrollAnimation = void 0;
1457
1663
  }
1458
1664
  }
1665
+ } else if (entry.target === this.header.element || entry.target === this.footer.element) {
1666
+ const host = entry.target === this.header.element ? this.header : this.footer;
1667
+ const blockSize = entry.borderBoxSize[0].blockSize;
1668
+ if (blockSize !== host.height) {
1669
+ const currentScrollTop = this.getScrollTop();
1670
+ const anchor = this.getScrollAnchor(currentScrollTop);
1671
+ this.setHostHeight(host, blockSize);
1672
+ const anchoredScrollTop = anchor != null ? this.resolveAnchoredScrollTop(anchor) : void 0;
1673
+ if (anchoredScrollTop != null) {
1674
+ const resizeAnchorDelta = anchoredScrollTop - currentScrollTop;
1675
+ this.applyScrollFix(anchoredScrollTop, currentScrollTop, this.windowSpecs);
1676
+ if (this.scrollAnimation != null) this.scrollAnimation.position += resizeAnchorDelta;
1677
+ }
1678
+ if (this.pendingScrollTarget != null && this.isPendingTargetSettled(this.pendingScrollTarget)) {
1679
+ this.pendingScrollTarget = void 0;
1680
+ this.scrollAnimation = void 0;
1681
+ }
1682
+ this.render();
1683
+ }
1459
1684
  } else {
1460
1685
  this.scrollDirty = true;
1461
1686
  this.heightDirty = true;
@@ -1478,6 +1703,7 @@ var CodeView = class CodeView {
1478
1703
  */
1479
1704
  getScrollAnchor(scrollTop) {
1480
1705
  if (this.pendingLayoutAnchor != null) return this.pendingLayoutAnchor;
1706
+ if (scrollTop <= 0) return;
1481
1707
  const { firstIndex, lastIndex, stickyTop, stickyBottom } = this.renderState;
1482
1708
  if (firstIndex === -1 || lastIndex === -1) return;
1483
1709
  const viewportHeight = this.getHeight();
@@ -1485,7 +1711,7 @@ var CodeView = class CodeView {
1485
1711
  for (let index = firstIndex; index <= lastIndex; index++) {
1486
1712
  const item = this.items[index];
1487
1713
  if (item == null) continue;
1488
- const absoluteItemTop = this.getLayout().paddingTop + item.top;
1714
+ const absoluteItemTop = this.getItemTopOffset() + item.top;
1489
1715
  if (absoluteItemTop + item.height <= scrollTop) continue;
1490
1716
  if (absoluteItemTop >= scrollTop + viewportHeight) break;
1491
1717
  if (absoluteItemTop >= scrollTop) return {
@@ -1517,14 +1743,14 @@ var CodeView = class CodeView {
1517
1743
  resolveAnchoredScrollTop(anchor) {
1518
1744
  const item = this.idToItem.get(anchor.id);
1519
1745
  if (item == null) return;
1520
- const { paddingTop } = this.getLayout();
1746
+ const itemTopOffset = this.getItemTopOffset();
1521
1747
  if (anchor.type === "item") {
1522
- const absoluteItemTop = paddingTop + item.top;
1748
+ const absoluteItemTop = itemTopOffset + item.top;
1523
1749
  return this.clampScrollTop(absoluteItemTop - anchor.viewportOffset);
1524
1750
  }
1525
1751
  const linePosition = item.type === "diff" ? item.instance.getLinePosition(anchor.lineNumber, anchor.side) : item.instance.getLinePosition(anchor.lineNumber);
1526
1752
  if (linePosition == null) return;
1527
- const absoluteLineTop = paddingTop + item.top + linePosition.top;
1753
+ const absoluteLineTop = itemTopOffset + item.top + linePosition.top;
1528
1754
  return this.clampScrollTop(absoluteLineTop - anchor.viewportOffset);
1529
1755
  }
1530
1756
  /**
@@ -1581,11 +1807,10 @@ var CodeView = class CodeView {
1581
1807
  }
1582
1808
  flushSlotCoordinator() {
1583
1809
  if (this.slotCoordinator == null) return;
1584
- const { onSnapshotChange } = this.slotCoordinator;
1585
- const slotSnapshot = getSlotSnapshot(this.getRenderedItems(), this.slotCoordinator);
1586
- if (areSlotSnapshotsEqual(this.slotSnapshot, slotSnapshot)) return;
1810
+ const slotSnapshot = this.buildSlotSnapshot(this.slotCoordinator);
1811
+ if (areManagedSnapshotsEqual(this.slotSnapshot, slotSnapshot)) return;
1587
1812
  this.slotSnapshot = slotSnapshot;
1588
- onSnapshotChange(slotSnapshot);
1813
+ this.slotCoordinator.onSnapshotChange(slotSnapshot);
1589
1814
  }
1590
1815
  notifyScroll() {
1591
1816
  if (this.scrollListeners.size === 0) return;
@@ -1656,7 +1881,7 @@ var CodeView = class CodeView {
1656
1881
  item.top = runningTop;
1657
1882
  if (item.type === "diff") {
1658
1883
  const fileDiff = item.instance.consumeCodeViewLayoutChanges(item.item.fileDiff);
1659
- if (fileDiff != null) item.item.fileDiff = fileDiff;
1884
+ if (fileDiff != null) Object.assign(item.item.fileDiff, fileDiff);
1660
1885
  item.height = item.instance.prepareCodeViewItem(item.item.fileDiff, runningTop, reset, item.item.annotations ?? []);
1661
1886
  } else item.height = item.instance.prepareCodeViewItem(item.item.file, runningTop, reset, item.item.annotations ?? []);
1662
1887
  runningTop += item.height;
@@ -1736,7 +1961,7 @@ function syncRenderedItemOrder(container, element, prevElement) {
1736
1961
  function hasAnnotations(item) {
1737
1962
  return (item.annotations?.length ?? 0) > 0;
1738
1963
  }
1739
- function getSlotSnapshot(renderedItems, { hasHeaderRenderers, hasAnnotationRenderer, hasGutterRenderer }) {
1964
+ function getSlotItems(renderedItems, { hasHeaderRenderers, hasAnnotationRenderer, hasGutterRenderer }) {
1740
1965
  if (renderedItems.length === 0) return;
1741
1966
  if (hasHeaderRenderers || hasGutterRenderer) return renderedItems;
1742
1967
  if (!hasAnnotationRenderer) return;
@@ -1744,17 +1969,7 @@ function getSlotSnapshot(renderedItems, { hasHeaderRenderers, hasAnnotationRende
1744
1969
  for (const renderedItem of renderedItems) if (hasAnnotations(renderedItem.item)) slotSnapshot.push(renderedItem);
1745
1970
  return slotSnapshot.length > 0 ? slotSnapshot : void 0;
1746
1971
  }
1747
- function areSlotSnapshotsEqual(previous, next) {
1748
- if (previous == null || next == null) return previous === next;
1749
- if (previous.length !== next.length) return false;
1750
- for (let index = 0; index < previous.length; index++) {
1751
- const previousItem = previous[index];
1752
- const nextItem = next[index];
1753
- if (previousItem == null || nextItem == null || previousItem.id !== nextItem.id || previousItem.type !== nextItem.type || previousItem.element !== nextItem.element || previousItem.version !== nextItem.version) return false;
1754
- }
1755
- return true;
1756
- }
1757
1972
  //#endregion
1758
- export { CodeView };
1973
+ export { CODE_VIEW_DIFF_OPTION_KEYS, CODE_VIEW_FILE_OPTION_KEYS, CodeView };
1759
1974
 
1760
1975
  //# sourceMappingURL=CodeView.js.map