@pierre/diffs 1.3.5 → 1.4.0

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 (257) hide show
  1. package/dist/components/CodeView.d.ts +113 -68
  2. package/dist/components/CodeView.d.ts.map +1 -1
  3. package/dist/components/CodeView.js +153 -58
  4. package/dist/components/CodeView.js.map +1 -1
  5. package/dist/components/File.d.ts +75 -15
  6. package/dist/components/File.d.ts.map +1 -1
  7. package/dist/components/File.js +223 -62
  8. package/dist/components/File.js.map +1 -1
  9. package/dist/components/FileDiff.d.ts +97 -21
  10. package/dist/components/FileDiff.d.ts.map +1 -1
  11. package/dist/components/FileDiff.js +400 -100
  12. package/dist/components/FileDiff.js.map +1 -1
  13. package/dist/components/UnresolvedFile.d.ts +2 -2
  14. package/dist/components/UnresolvedFile.d.ts.map +1 -1
  15. package/dist/components/UnresolvedFile.js +2 -2
  16. package/dist/components/UnresolvedFile.js.map +1 -1
  17. package/dist/components/VirtualizedFile.d.ts +16 -7
  18. package/dist/components/VirtualizedFile.d.ts.map +1 -1
  19. package/dist/components/VirtualizedFile.js +140 -51
  20. package/dist/components/VirtualizedFile.js.map +1 -1
  21. package/dist/components/VirtualizedFileDiff.d.ts +14 -8
  22. package/dist/components/VirtualizedFileDiff.d.ts.map +1 -1
  23. package/dist/components/VirtualizedFileDiff.js +183 -93
  24. package/dist/components/VirtualizedFileDiff.js.map +1 -1
  25. package/dist/components/VirtulizerDevelopment.d.ts +1 -1
  26. package/dist/components/VirtulizerDevelopment.d.ts.map +1 -1
  27. package/dist/edit/index.d.ts +7 -4
  28. package/dist/edit/index.js +5 -1
  29. package/dist/editor/EditStateManager.d.ts +56 -0
  30. package/dist/editor/EditStateManager.d.ts.map +1 -0
  31. package/dist/editor/EditStateManager.js +135 -0
  32. package/dist/editor/EditStateManager.js.map +1 -0
  33. package/dist/editor/cloneRetainedDiffSessionSnapshot.d.ts +7 -0
  34. package/dist/editor/cloneRetainedDiffSessionSnapshot.d.ts.map +1 -0
  35. package/dist/editor/cloneRetainedDiffSessionSnapshot.js +16 -0
  36. package/dist/editor/cloneRetainedDiffSessionSnapshot.js.map +1 -0
  37. package/dist/editor/editPrediction.d.ts +76 -0
  38. package/dist/editor/editPrediction.d.ts.map +1 -0
  39. package/dist/editor/editPrediction.js +365 -0
  40. package/dist/editor/editPrediction.js.map +1 -0
  41. package/dist/editor/editStack.d.ts +19 -40
  42. package/dist/editor/editStack.d.ts.map +1 -1
  43. package/dist/editor/editStack.js +67 -4
  44. package/dist/editor/editStack.js.map +1 -1
  45. package/dist/editor/editor.d.ts +118 -29
  46. package/dist/editor/editor.d.ts.map +1 -1
  47. package/dist/editor/editor.js +1196 -403
  48. package/dist/editor/editor.js.map +1 -1
  49. package/dist/editor/editor2.js +1 -1
  50. package/dist/editor/languages.d.ts +3 -3
  51. package/dist/editor/languages.d.ts.map +1 -1
  52. package/dist/editor/languages.js.map +1 -1
  53. package/dist/editor/lineAnnotations.d.ts +3 -3
  54. package/dist/editor/lineAnnotations.d.ts.map +1 -1
  55. package/dist/editor/lineAnnotations.js +16 -7
  56. package/dist/editor/lineAnnotations.js.map +1 -1
  57. package/dist/editor/marker.d.ts +2 -2
  58. package/dist/editor/marker.d.ts.map +1 -1
  59. package/dist/editor/marker.js.map +1 -1
  60. package/dist/editor/matchBrackets.d.ts +2 -2
  61. package/dist/editor/matchBrackets.d.ts.map +1 -1
  62. package/dist/editor/matchBrackets.js.map +1 -1
  63. package/dist/editor/pieceTable.d.ts +1 -1
  64. package/dist/editor/pieceTable.js.map +1 -1
  65. package/dist/editor/searchPanel.d.ts +2 -2
  66. package/dist/editor/searchPanel.d.ts.map +1 -1
  67. package/dist/editor/searchPanel.js +3 -2
  68. package/dist/editor/searchPanel.js.map +1 -1
  69. package/dist/editor/selection.d.ts +33 -23
  70. package/dist/editor/selection.d.ts.map +1 -1
  71. package/dist/editor/selection.js +3 -3
  72. package/dist/editor/selection.js.map +1 -1
  73. package/dist/editor/selectionAction.d.ts +3 -3
  74. package/dist/editor/selectionAction.d.ts.map +1 -1
  75. package/dist/editor/selectionAction.js.map +1 -1
  76. package/dist/editor/textDocument.d.ts +11 -8
  77. package/dist/editor/textDocument.d.ts.map +1 -1
  78. package/dist/editor/textDocument.js +28 -5
  79. package/dist/editor/textDocument.js.map +1 -1
  80. package/dist/editor/textDocumentChangeTransaction.d.ts +15 -0
  81. package/dist/editor/textDocumentChangeTransaction.d.ts.map +1 -0
  82. package/dist/editor/textDocumentChangeTransaction.js +12 -0
  83. package/dist/editor/textDocumentChangeTransaction.js.map +1 -0
  84. package/dist/editor/textMeasure.d.ts +5 -0
  85. package/dist/editor/textMeasure.d.ts.map +1 -1
  86. package/dist/editor/textMeasure.js +10 -0
  87. package/dist/editor/textMeasure.js.map +1 -1
  88. package/dist/editor/tokenizer.d.ts +1 -1
  89. package/dist/editor/tokenizer.d.ts.map +1 -1
  90. package/dist/editor/tokenizer.js +6 -3
  91. package/dist/editor/tokenizer.js.map +1 -1
  92. package/dist/editor/types.d.ts +267 -0
  93. package/dist/editor/types.d.ts.map +1 -0
  94. package/dist/editor/types.js +0 -0
  95. package/dist/editor/utils.d.ts +2 -1
  96. package/dist/editor/utils.d.ts.map +1 -1
  97. package/dist/editor/utils.js +4 -1
  98. package/dist/editor/utils.js.map +1 -1
  99. package/dist/index.d.ts +8 -6
  100. package/dist/index.js +9 -8
  101. package/dist/managers/InteractionManager.d.ts.map +1 -1
  102. package/dist/managers/InteractionManager.js +7 -0
  103. package/dist/managers/InteractionManager.js.map +1 -1
  104. package/dist/react/CodeView.d.ts +36 -25
  105. package/dist/react/CodeView.d.ts.map +1 -1
  106. package/dist/react/CodeView.js +15 -14
  107. package/dist/react/CodeView.js.map +1 -1
  108. package/dist/react/EditContext.d.ts +8 -11
  109. package/dist/react/EditContext.d.ts.map +1 -1
  110. package/dist/react/EditContext.js +2 -9
  111. package/dist/react/EditContext.js.map +1 -1
  112. package/dist/react/File.d.ts +10 -6
  113. package/dist/react/File.d.ts.map +1 -1
  114. package/dist/react/File.js +8 -4
  115. package/dist/react/File.js.map +1 -1
  116. package/dist/react/FileDiff.d.ts +10 -5
  117. package/dist/react/FileDiff.d.ts.map +1 -1
  118. package/dist/react/FileDiff.js +8 -4
  119. package/dist/react/FileDiff.js.map +1 -1
  120. package/dist/react/MultiFileDiff.d.ts +8 -5
  121. package/dist/react/MultiFileDiff.d.ts.map +1 -1
  122. package/dist/react/MultiFileDiff.js +8 -12
  123. package/dist/react/MultiFileDiff.js.map +1 -1
  124. package/dist/react/PatchDiff.d.ts +7 -4
  125. package/dist/react/PatchDiff.d.ts.map +1 -1
  126. package/dist/react/PatchDiff.js +8 -4
  127. package/dist/react/PatchDiff.js.map +1 -1
  128. package/dist/react/UnresolvedFile.d.ts +3 -3
  129. package/dist/react/UnresolvedFile.d.ts.map +1 -1
  130. package/dist/react/UnresolvedFile.js.map +1 -1
  131. package/dist/react/index.d.ts +8 -5
  132. package/dist/react/types.d.ts +46 -9
  133. package/dist/react/types.d.ts.map +1 -1
  134. package/dist/react/utils/renderDiffChildren.d.ts +14 -12
  135. package/dist/react/utils/renderDiffChildren.d.ts.map +1 -1
  136. package/dist/react/utils/renderDiffChildren.js +2 -2
  137. package/dist/react/utils/renderDiffChildren.js.map +1 -1
  138. package/dist/react/utils/renderFileChildren.d.ts +14 -12
  139. package/dist/react/utils/renderFileChildren.d.ts.map +1 -1
  140. package/dist/react/utils/renderFileChildren.js +2 -2
  141. package/dist/react/utils/renderFileChildren.js.map +1 -1
  142. package/dist/react/utils/useFileDiffInstance.d.ts +22 -10
  143. package/dist/react/utils/useFileDiffInstance.d.ts.map +1 -1
  144. package/dist/react/utils/useFileDiffInstance.js +112 -22
  145. package/dist/react/utils/useFileDiffInstance.js.map +1 -1
  146. package/dist/react/utils/useFileInstance.d.ts +15 -9
  147. package/dist/react/utils/useFileInstance.d.ts.map +1 -1
  148. package/dist/react/utils/useFileInstance.js +84 -25
  149. package/dist/react/utils/useFileInstance.js.map +1 -1
  150. package/dist/renderers/DiffHunksRenderer.d.ts +30 -15
  151. package/dist/renderers/DiffHunksRenderer.d.ts.map +1 -1
  152. package/dist/renderers/DiffHunksRenderer.js +172 -108
  153. package/dist/renderers/DiffHunksRenderer.js.map +1 -1
  154. package/dist/renderers/FileRenderer.d.ts +27 -11
  155. package/dist/renderers/FileRenderer.d.ts.map +1 -1
  156. package/dist/renderers/FileRenderer.js +138 -64
  157. package/dist/renderers/FileRenderer.js.map +1 -1
  158. package/dist/renderers/UnresolvedFileHunksRenderer.d.ts +2 -2
  159. package/dist/renderers/UnresolvedFileHunksRenderer.d.ts.map +1 -1
  160. package/dist/renderers/UnresolvedFileHunksRenderer.js +2 -2
  161. package/dist/renderers/UnresolvedFileHunksRenderer.js.map +1 -1
  162. package/dist/shiki-stream/tokenizer.d.ts.map +1 -1
  163. package/dist/shiki-stream/tokenizer.js +2 -1
  164. package/dist/shiki-stream/tokenizer.js.map +1 -1
  165. package/dist/ssr/index.d.ts +2 -2
  166. package/dist/ssr/preloadDiffs.d.ts +21 -21
  167. package/dist/ssr/preloadDiffs.d.ts.map +1 -1
  168. package/dist/ssr/preloadDiffs.js +1 -1
  169. package/dist/ssr/preloadDiffs.js.map +1 -1
  170. package/dist/ssr/preloadFile.d.ts +6 -6
  171. package/dist/ssr/preloadFile.d.ts.map +1 -1
  172. package/dist/ssr/preloadFile.js.map +1 -1
  173. package/dist/ssr/preloadPatchFile.d.ts +4 -4
  174. package/dist/ssr/preloadPatchFile.d.ts.map +1 -1
  175. package/dist/ssr/preloadPatchFile.js.map +1 -1
  176. package/dist/style.js +1 -1
  177. package/dist/types.d.ts +13 -263
  178. package/dist/types.d.ts.map +1 -1
  179. package/dist/utils/appendItems.d.ts +5 -0
  180. package/dist/utils/appendItems.d.ts.map +1 -0
  181. package/dist/utils/appendItems.js +8 -0
  182. package/dist/utils/appendItems.js.map +1 -0
  183. package/dist/utils/areDiffTargetsEqual.js +1 -1
  184. package/dist/utils/areDiffTargetsEqual.js.map +1 -1
  185. package/dist/utils/areFileTargetsEqual.d.ts +7 -0
  186. package/dist/utils/areFileTargetsEqual.d.ts.map +1 -0
  187. package/dist/utils/areFileTargetsEqual.js +8 -0
  188. package/dist/utils/areFileTargetsEqual.js.map +1 -0
  189. package/dist/utils/areManagedSnapshotsEqual.d.ts +1 -1
  190. package/dist/utils/areManagedSnapshotsEqual.d.ts.map +1 -1
  191. package/dist/utils/areManagedSnapshotsEqual.js.map +1 -1
  192. package/dist/utils/areOptionsEqual.d.ts +3 -3
  193. package/dist/utils/areOptionsEqual.d.ts.map +1 -1
  194. package/dist/utils/areOptionsEqual.js.map +1 -1
  195. package/dist/utils/cloneFileDiffMetadata.d.ts +3 -2
  196. package/dist/utils/cloneFileDiffMetadata.d.ts.map +1 -1
  197. package/dist/utils/cloneFileDiffMetadata.js +8 -5
  198. package/dist/utils/cloneFileDiffMetadata.js.map +1 -1
  199. package/dist/utils/composeCacheKey.d.ts +6 -0
  200. package/dist/utils/composeCacheKey.d.ts.map +1 -0
  201. package/dist/utils/composeCacheKey.js +10 -0
  202. package/dist/utils/composeCacheKey.js.map +1 -0
  203. package/dist/utils/editSessionAnnotations.d.ts +69 -0
  204. package/dist/utils/editSessionAnnotations.d.ts.map +1 -0
  205. package/dist/utils/editSessionAnnotations.js +64 -0
  206. package/dist/utils/editSessionAnnotations.js.map +1 -0
  207. package/dist/utils/editSessionHunks.d.ts +5 -3
  208. package/dist/utils/editSessionHunks.d.ts.map +1 -1
  209. package/dist/utils/editSessionHunks.js +7 -5
  210. package/dist/utils/editSessionHunks.js.map +1 -1
  211. package/dist/utils/getDiffHunksRendererOptions.d.ts +1 -1
  212. package/dist/utils/getDiffHunksRendererOptions.d.ts.map +1 -1
  213. package/dist/utils/getDiffHunksRendererOptions.js.map +1 -1
  214. package/dist/utils/getFileRendererOptions.d.ts +1 -1
  215. package/dist/utils/getFileRendererOptions.d.ts.map +1 -1
  216. package/dist/utils/getFileRendererOptions.js.map +1 -1
  217. package/dist/utils/hydratePartialDiff.d.ts.map +1 -1
  218. package/dist/utils/hydratePartialDiff.js +2 -1
  219. package/dist/utils/hydratePartialDiff.js.map +1 -1
  220. package/dist/utils/lineAnnotationIdentity.d.ts +16 -0
  221. package/dist/utils/lineAnnotationIdentity.d.ts.map +1 -0
  222. package/dist/utils/lineAnnotationIdentity.js +17 -0
  223. package/dist/utils/lineAnnotationIdentity.js.map +1 -0
  224. package/dist/utils/parseDiffFromFile.d.ts +2 -2
  225. package/dist/utils/parseDiffFromFile.d.ts.map +1 -1
  226. package/dist/utils/parseDiffFromFile.js +6 -6
  227. package/dist/utils/parseDiffFromFile.js.map +1 -1
  228. package/dist/utils/parsePatchFiles.d.ts +6 -3
  229. package/dist/utils/parsePatchFiles.d.ts.map +1 -1
  230. package/dist/utils/parsePatchFiles.js +34 -9
  231. package/dist/utils/parsePatchFiles.js.map +1 -1
  232. package/dist/utils/renderDiffWithHighlighter.d.ts.map +1 -1
  233. package/dist/utils/renderDiffWithHighlighter.js +6 -5
  234. package/dist/utils/renderDiffWithHighlighter.js.map +1 -1
  235. package/dist/utils/renderFileWithHighlighter.d.ts.map +1 -1
  236. package/dist/utils/renderFileWithHighlighter.js +7 -4
  237. package/dist/utils/renderFileWithHighlighter.js.map +1 -1
  238. package/dist/utils/trimPatchContext.d.ts.map +1 -1
  239. package/dist/utils/trimPatchContext.js +3 -2
  240. package/dist/utils/trimPatchContext.js.map +1 -1
  241. package/dist/utils/updateDiffHunks.js +1 -1
  242. package/dist/utils/virtualDiffLayout.js +1 -1
  243. package/dist/worker/WorkerPoolManager.d.ts +4 -3
  244. package/dist/worker/WorkerPoolManager.d.ts.map +1 -1
  245. package/dist/worker/WorkerPoolManager.js +33 -4
  246. package/dist/worker/WorkerPoolManager.js.map +1 -1
  247. package/dist/worker/types.d.ts +5 -0
  248. package/dist/worker/types.d.ts.map +1 -1
  249. package/dist/worker/worker-portable.js +14 -6
  250. package/dist/worker/worker-portable.js.map +1 -1
  251. package/dist/worker/worker.js +14 -6
  252. package/dist/worker/worker.js.map +1 -1
  253. package/package.json +9 -1
  254. package/dist/editor/stateStorage.d.ts +0 -15
  255. package/dist/editor/stateStorage.d.ts.map +0 -1
  256. package/dist/editor/stateStorage.js +0 -65
  257. package/dist/editor/stateStorage.js.map +0 -1
@@ -7,7 +7,6 @@ import { areOptionsEqual } from "../utils/areOptionsEqual.js";
7
7
  import { areSelectionsEqual } from "../utils/areSelectionsEqual.js";
8
8
  import { createCodeViewHeaderFooterHostElement } from "../utils/createCodeViewHeaderFooterHostElement.js";
9
9
  import { createWindowFromScrollPosition } from "../utils/createWindowFromScrollPosition.js";
10
- import { finishEditSessionForDiff } from "../utils/editSessionHunks.js";
11
10
  import { isStyleNode } from "../utils/isStyleNode.js";
12
11
  import { prefersReducedMotion } from "../utils/prefersReducedMotion.js";
13
12
  import { roundToDevicePixel } from "../utils/roundToDevicePixel.js";
@@ -402,13 +401,31 @@ var CodeView = class CodeView {
402
401
  this.clearReadySubscription();
403
402
  this.restoreScrollInteractions();
404
403
  this.cleanAllRenderedItems();
405
- for (const record of this.itemEditors.values()) record.editor.cleanUp();
404
+ const teardownSessions = [...this.itemEditors.values()].map((record) => {
405
+ const item = this.idToItem.get(record.state.id);
406
+ if (item != null) record.state.removedItem = item.item;
407
+ return {
408
+ record,
409
+ instance: item?.instance
410
+ };
411
+ });
406
412
  this.itemEditors.clear();
407
413
  this.attachedEditors.clear();
408
414
  this.selectedLines = null;
409
415
  this.items.length = 0;
410
416
  this.idToItem.clear();
411
417
  this.instanceToItem.clear();
418
+ let failed = false;
419
+ let failure;
420
+ for (const { record, instance } of teardownSessions) try {
421
+ record.editor.cleanUp("discard");
422
+ instance?.cleanUp();
423
+ } catch (error) {
424
+ if (!failed) {
425
+ failed = true;
426
+ failure = error;
427
+ }
428
+ }
412
429
  this.layoutDirtyIndex = void 0;
413
430
  this.pendingLayoutReset = void 0;
414
431
  this.stickyContainer.textContent = "";
@@ -429,9 +446,17 @@ var CodeView = class CodeView {
429
446
  this.heightDirty = true;
430
447
  this.resetRenderState();
431
448
  if (!this.isContainerManaged) this.flushSlotCoordinator();
449
+ if (failed) throw failure;
432
450
  }
433
451
  cleanUp() {
434
- this.reset();
452
+ let resetFailed = false;
453
+ let resetFailure;
454
+ try {
455
+ this.reset();
456
+ } catch (error) {
457
+ resetFailed = true;
458
+ resetFailure = error;
459
+ }
435
460
  this.clearElementPool();
436
461
  this.restoreScrollInteractions();
437
462
  this.workerManager?.unsubscribeToThemeChanges(this);
@@ -457,6 +482,7 @@ var CodeView = class CodeView {
457
482
  this.footer.height = 0;
458
483
  this.root = void 0;
459
484
  this.container = void 0;
485
+ if (resetFailed) throw resetFailure;
460
486
  }
461
487
  cleanAllRenderedItems() {
462
488
  if (this.renderState.firstIndex === -1) return;
@@ -585,7 +611,8 @@ var CodeView = class CodeView {
585
611
  /**
586
612
  * Get the live editor for an item currently in edit mode. Use this to drive
587
613
  * editor APIs CodeView does not wrap (applyEdits, undo, setMarkers, …).
588
- * Returns undefined once the item leaves edit mode.
614
+ * Returns undefined once the item's session ends (edit off or removal); a
615
+ * collapsed item keeps its suspended editor.
589
616
  */
590
617
  getEditor(itemId) {
591
618
  return this.itemEditors.get(itemId)?.editor;
@@ -628,7 +655,6 @@ var CodeView = class CodeView {
628
655
  }
629
656
  const editorRecord = this.itemEditors.get(oldId);
630
657
  if (editorRecord != null) {
631
- editorRecord.state.id = newId;
632
658
  this.itemEditors.delete(oldId);
633
659
  this.itemEditors.set(newId, editorRecord);
634
660
  if (this.attachedEditors.delete(oldId)) this.attachedEditors.add(newId);
@@ -888,58 +914,63 @@ var CodeView = class CodeView {
888
914
  return item.item.edit === true && item.item.collapsed !== true;
889
915
  }
890
916
  /**
891
- * Attach (or lazily create) the editor for a mounted edit-mode item. Called
917
+ * Lazily create and attach the editor for a mounted edit-mode item. Called
892
918
  * from the render loop so every mounted item passes through it: fresh
893
919
  * mounts, remounts after virtualization released the item, and items whose
894
920
  * edit flag was just turned on. Editors persist across unmounts, so a
895
- * remounted item re-attaches its existing editor and resumes the retained
896
- * document; the renderers keep the host's file/diff data in sync with the
897
- * session so the remount paints the edited text.
921
+ * remounted item resumes its existing editor and retained document; the
922
+ * instance retains its private session model so the remount
923
+ * paints the edited text without changing the host input.
898
924
  */
899
925
  attachItemEditor(item) {
900
926
  const { id } = item.item;
901
927
  const { createEditor } = this.options;
902
928
  if (item.element == null || this.attachedEditors.has(id) || !this.isItemInEditMode(item)) return;
903
- let record = this.itemEditors.get(id);
904
- let createdEditor = false;
929
+ const record = this.itemEditors.get(id);
930
+ let createdEditor;
905
931
  try {
906
932
  if (record == null) {
907
933
  assertEditorFactory(createEditor);
908
- const state = { id };
909
- const editor = createEditor({ onChange: (file, lineAnnotations) => {
934
+ const state = getItemOptionsState(item.instance.options);
935
+ if (state == null) throw new Error("CodeView.attachItemEditor: instance options are missing their state");
936
+ const onChange = (event) => {
910
937
  const latest = this.idToItem.get(state.id);
911
938
  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
939
+ this.options.onItemEditChange?.(event, latest.item);
923
940
  };
924
- this.itemEditors.set(id, record);
925
- createdEditor = true;
926
- }
927
- record.editor.edit(item.instance);
941
+ const editStateKey = this.options.getEditStateKey?.(item.item);
942
+ if (item.type === "diff") {
943
+ const editor = createEditor("file-diff", { onChange }, editStateKey);
944
+ createdEditor = editor;
945
+ this.itemEditors.set(id, {
946
+ editor,
947
+ state,
948
+ dispose: editor.edit(item.instance)
949
+ });
950
+ } else {
951
+ const editor = createEditor("file", { onChange }, editStateKey);
952
+ createdEditor = editor;
953
+ this.itemEditors.set(id, {
954
+ editor,
955
+ state,
956
+ dispose: editor.edit(item.instance)
957
+ });
958
+ }
959
+ } else if (item.type === "diff") record.dispose = record.editor.edit(item.instance);
960
+ else record.dispose = record.editor.edit(item.instance);
928
961
  this.attachedEditors.add(id);
929
962
  } catch (error) {
930
- if (createdEditor && record != null) {
931
- this.itemEditors.delete(id);
932
- record.editor.cleanUp();
933
- }
963
+ createdEditor?.cleanUp();
934
964
  this.releaseRenderedItem(item);
935
965
  throw error;
936
966
  }
937
967
  }
938
968
  /**
939
- * Drop editors for items that can no longer be edited: removed, edit turned
940
- * off, or collapsed. Attachment happens in the render loop via
941
- * attachItemEditor, so this only reconciles editors CodeView is already
942
- * holding.
969
+ * Reconcile the editors CodeView is holding: complete sessions for items
970
+ * whose edit turned off or that were removed, and suspend sessions for
971
+ * collapsed items (the editor tears down, the record and the instance's
972
+ * session stay for the next expand). Attachment happens in the render loop
973
+ * via attachItemEditor.
943
974
  */
944
975
  syncItemEditors(removedItems) {
945
976
  if (this.itemEditors.size === 0) return;
@@ -947,25 +978,77 @@ var CodeView = class CodeView {
947
978
  for (const [id, record] of this.itemEditors) {
948
979
  const item = this.idToItem.get(id);
949
980
  const removedItem = removedItems?.get(id);
950
- if (removedItem == null && item != null && this.isItemInEditMode(item)) continue;
951
- record.editor.cleanUp();
981
+ if (removedItem == null && item != null) {
982
+ const { edit = false, collapsed = false } = item.item;
983
+ if (edit) {
984
+ if (collapsed && this.attachedEditors.delete(id)) record.editor.cleanUp("recycle");
985
+ continue;
986
+ }
987
+ } else if (removedItem != null) record.state.removedItem = removedItem.item;
952
988
  this.itemEditors.delete(id);
953
989
  this.attachedEditors.delete(id);
954
- const { lastChange } = record.state;
955
- const itemSnapshot = removedItem == null ? item?.item ?? lastChange?.item : lastChange?.item ?? removedItem.item;
956
- if (itemSnapshot?.type === "diff") {
957
- if (removedItem == null && item != null && item.type === "diff" && item.instance.completeEditSession()) {
958
- this.markItemLayoutDirty(item);
959
- this.render();
990
+ completions.push(record);
991
+ }
992
+ if (completions.length === 0) return;
993
+ let failed = false;
994
+ let failure;
995
+ for (const record of completions) {
996
+ try {
997
+ record.dispose();
998
+ } catch (error) {
999
+ if (!failed) {
1000
+ failed = true;
1001
+ failure = error;
960
1002
  }
961
- finishEditSessionForDiff(itemSnapshot.fileDiff);
962
1003
  }
963
- if (lastChange != null) completions.push(removedItem != null || item == null ? lastChange : {
964
- ...lastChange,
965
- item: item.item
966
- });
1004
+ const item = this.idToItem.get(record.state.id);
1005
+ if (item != null) this.markItemLayoutDirty(item);
967
1006
  }
968
- for (const { item, file, lineAnnotations } of completions) this.options.onItemEditComplete?.(item, file, lineAnnotations);
1007
+ this.render();
1008
+ if (failed) throw failure;
1009
+ }
1010
+ requireItemFromState(state) {
1011
+ const item = this.idToItem.get(state.id)?.item ?? state.removedItem;
1012
+ if (item == null) throw new Error(`CodeView.onItemEditComplete: unknown item "${state.id}"`);
1013
+ return item;
1014
+ }
1015
+ /**
1016
+ * Item-instance `onEditComplete` adapter for file items: builds the
1017
+ * accepted next item, hands it to `onItemEditComplete` alongside the event
1018
+ * and the owning item, and translates the identity of the returned item to
1019
+ * the component return contract.
1020
+ */
1021
+ completeFileItemEdit(state, event) {
1022
+ const item = this.requireItemFromState(state);
1023
+ if (item.type !== "file") throw new Error(`CodeView.onItemEditComplete: item "${state.id}" is not a file item`);
1024
+ const nextItem = {
1025
+ ...item,
1026
+ file: event.file,
1027
+ annotations: event.lineAnnotations,
1028
+ edit: false,
1029
+ version: (item.version ?? 0) + 1
1030
+ };
1031
+ if ((this.options.onItemEditComplete?.(event, item, nextItem) ?? "reject") === "reject") return "reject";
1032
+ if (this.idToItem.has(item.id)) this.updateItem(nextItem);
1033
+ return "accept";
1034
+ }
1035
+ /**
1036
+ * Item-instance `onEditComplete` adapter for diff items; see
1037
+ * completeFileItemEdit.
1038
+ */
1039
+ completeDiffItemEdit(state, event) {
1040
+ const item = this.requireItemFromState(state);
1041
+ if (item.type !== "diff") throw new Error(`CodeView.onItemEditComplete: item "${state.id}" is not a diff item`);
1042
+ const nextItem = {
1043
+ ...item,
1044
+ fileDiff: event.fileDiff,
1045
+ annotations: event.lineAnnotations,
1046
+ edit: false,
1047
+ version: (item.version ?? 0) + 1
1048
+ };
1049
+ if ((this.options.onItemEditComplete?.(event, item, nextItem) ?? "reject") === "reject") return "reject";
1050
+ if (this.idToItem.has(item.id)) this.updateItem(nextItem);
1051
+ return "accept";
969
1052
  }
970
1053
  renamePendingScrollTarget(oldId, newId) {
971
1054
  const { pendingScrollTarget } = this;
@@ -987,6 +1070,12 @@ var CodeView = class CodeView {
987
1070
  if (state == null) return;
988
1071
  return this.getItemOptions(state, "file")?.item.collapsed;
989
1072
  });
1073
+ defineItemOption(prototype, "onEditComplete", (receiver) => {
1074
+ if (this.options.onItemEditComplete == null) return;
1075
+ const state = getItemOptionsState(receiver);
1076
+ if (state == null) return;
1077
+ return (event) => this.completeFileItemEdit(state, event);
1078
+ });
990
1079
  for (const key of CODE_VIEW_SHARED_CALLBACK_KEYS) this.defineItemSharedCallback(prototype, "file", key);
991
1080
  for (const key of CODE_VIEW_SELECTION_CALLBACK_KEYS) this.defineItemSelectionCallback(prototype, "file", key);
992
1081
  return prototype;
@@ -1001,6 +1090,12 @@ var CodeView = class CodeView {
1001
1090
  if (state == null) return;
1002
1091
  return this.getItemOptions(state, "diff")?.item.collapsed;
1003
1092
  });
1093
+ defineItemOption(prototype, "onEditComplete", (receiver) => {
1094
+ if (this.options.onItemEditComplete == null) return;
1095
+ const state = getItemOptionsState(receiver);
1096
+ if (state == null) return;
1097
+ return (event) => this.completeDiffItemEdit(state, event);
1098
+ });
1004
1099
  for (const key of CODE_VIEW_SHARED_CALLBACK_KEYS) this.defineItemSharedCallback(prototype, "diff", key);
1005
1100
  for (const key of CODE_VIEW_SELECTION_CALLBACK_KEYS) this.defineItemSelectionCallback(prototype, "diff", key);
1006
1101
  return prototype;
@@ -1598,7 +1693,10 @@ var CodeView = class CodeView {
1598
1693
  syncPagedScrollScaffolding(windowSpecs) {
1599
1694
  this.syncContainerHeight();
1600
1695
  const stickyBounds = this.getStickyBounds(windowSpecs);
1601
- if (stickyBounds == null) return;
1696
+ if (stickyBounds == null) {
1697
+ this.stickyOffset.style.height = `${this.getPagedLayoutTop(windowSpecs.top)}px`;
1698
+ return;
1699
+ }
1602
1700
  this.applyStickyPositioning(stickyBounds);
1603
1701
  }
1604
1702
  reconcileRenderedItems(updatedItems) {
@@ -1910,11 +2008,8 @@ var CodeView = class CodeView {
1910
2008
  const item = this.items[index];
1911
2009
  if (item == null) throw new Error("CodeView.recomputeLayout: invalid item index");
1912
2010
  item.top = runningTop;
1913
- if (item.type === "diff") {
1914
- const fileDiff = item.instance.consumeCodeViewLayoutChanges(item.item.fileDiff);
1915
- if (fileDiff != null) Object.assign(item.item.fileDiff, fileDiff);
1916
- item.height = item.instance.prepareCodeViewItem(item.item.fileDiff, runningTop, reset, item.item.annotations ?? []);
1917
- } else item.height = item.instance.prepareCodeViewItem(item.item.file, runningTop, reset, item.item.annotations ?? []);
2011
+ if (item.type === "diff") item.height = item.instance.updateCodeViewLayout(item.item.fileDiff, runningTop, reset, item.item.annotations ?? []);
2012
+ else item.height = item.instance.updateCodeViewLayout(item.item.file, runningTop, reset, item.item.annotations ?? []);
1918
2013
  runningTop += item.height;
1919
2014
  if (index < this.items.length - 1) runningTop += layout.gap;
1920
2015
  }
@@ -1935,8 +2030,8 @@ var CodeView = class CodeView {
1935
2030
  };
1936
2031
  function prepareItemInstance(item) {
1937
2032
  item.instance.cleanUp(true);
1938
- if (item.type === "diff") return item.instance.prepareCodeViewItem(item.item.fileDiff, item.top, void 0, item.item.annotations ?? []);
1939
- else return item.instance.prepareCodeViewItem(item.item.file, item.top, void 0, item.item.annotations ?? []);
2033
+ if (item.type === "diff") return item.instance.updateCodeViewLayout(item.item.fileDiff, item.top, void 0, item.item.annotations ?? []);
2034
+ else return item.instance.updateCodeViewLayout(item.item.file, item.top, void 0, item.item.annotations ?? []);
1940
2035
  }
1941
2036
  function shouldClearPool(previousOptions, nextOptions) {
1942
2037
  return !areThemesEqual(previousOptions.theme ?? DEFAULT_THEMES, nextOptions.theme ?? DEFAULT_THEMES) || (previousOptions.themeType ?? "system") !== (nextOptions.themeType ?? "system") || previousOptions.unsafeCSS !== nextOptions.unsafeCSS;