@pierre/diffs 1.3.6 → 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 (254) 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 +1103 -383
  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.js +1 -1
  67. package/dist/editor/searchPanel.js.map +1 -1
  68. package/dist/editor/selection.d.ts +32 -23
  69. package/dist/editor/selection.d.ts.map +1 -1
  70. package/dist/editor/selection.js +3 -3
  71. package/dist/editor/selection.js.map +1 -1
  72. package/dist/editor/selectionAction.d.ts +3 -3
  73. package/dist/editor/selectionAction.d.ts.map +1 -1
  74. package/dist/editor/selectionAction.js.map +1 -1
  75. package/dist/editor/textDocument.d.ts +11 -8
  76. package/dist/editor/textDocument.d.ts.map +1 -1
  77. package/dist/editor/textDocument.js +28 -5
  78. package/dist/editor/textDocument.js.map +1 -1
  79. package/dist/editor/textDocumentChangeTransaction.d.ts +15 -0
  80. package/dist/editor/textDocumentChangeTransaction.d.ts.map +1 -0
  81. package/dist/editor/textDocumentChangeTransaction.js +12 -0
  82. package/dist/editor/textDocumentChangeTransaction.js.map +1 -0
  83. package/dist/editor/textMeasure.d.ts +5 -0
  84. package/dist/editor/textMeasure.d.ts.map +1 -1
  85. package/dist/editor/textMeasure.js +10 -0
  86. package/dist/editor/textMeasure.js.map +1 -1
  87. package/dist/editor/tokenizer.d.ts +1 -1
  88. package/dist/editor/tokenizer.js.map +1 -1
  89. package/dist/editor/types.d.ts +267 -0
  90. package/dist/editor/types.d.ts.map +1 -0
  91. package/dist/editor/types.js +0 -0
  92. package/dist/editor/utils.d.ts +2 -1
  93. package/dist/editor/utils.d.ts.map +1 -1
  94. package/dist/editor/utils.js +4 -1
  95. package/dist/editor/utils.js.map +1 -1
  96. package/dist/index.d.ts +8 -6
  97. package/dist/index.js +9 -8
  98. package/dist/managers/InteractionManager.d.ts.map +1 -1
  99. package/dist/managers/InteractionManager.js +7 -0
  100. package/dist/managers/InteractionManager.js.map +1 -1
  101. package/dist/react/CodeView.d.ts +36 -25
  102. package/dist/react/CodeView.d.ts.map +1 -1
  103. package/dist/react/CodeView.js +15 -14
  104. package/dist/react/CodeView.js.map +1 -1
  105. package/dist/react/EditContext.d.ts +8 -11
  106. package/dist/react/EditContext.d.ts.map +1 -1
  107. package/dist/react/EditContext.js +2 -9
  108. package/dist/react/EditContext.js.map +1 -1
  109. package/dist/react/File.d.ts +10 -6
  110. package/dist/react/File.d.ts.map +1 -1
  111. package/dist/react/File.js +8 -4
  112. package/dist/react/File.js.map +1 -1
  113. package/dist/react/FileDiff.d.ts +10 -5
  114. package/dist/react/FileDiff.d.ts.map +1 -1
  115. package/dist/react/FileDiff.js +8 -4
  116. package/dist/react/FileDiff.js.map +1 -1
  117. package/dist/react/MultiFileDiff.d.ts +8 -5
  118. package/dist/react/MultiFileDiff.d.ts.map +1 -1
  119. package/dist/react/MultiFileDiff.js +8 -12
  120. package/dist/react/MultiFileDiff.js.map +1 -1
  121. package/dist/react/PatchDiff.d.ts +7 -4
  122. package/dist/react/PatchDiff.d.ts.map +1 -1
  123. package/dist/react/PatchDiff.js +8 -4
  124. package/dist/react/PatchDiff.js.map +1 -1
  125. package/dist/react/UnresolvedFile.d.ts +3 -3
  126. package/dist/react/UnresolvedFile.d.ts.map +1 -1
  127. package/dist/react/UnresolvedFile.js.map +1 -1
  128. package/dist/react/index.d.ts +8 -5
  129. package/dist/react/types.d.ts +46 -9
  130. package/dist/react/types.d.ts.map +1 -1
  131. package/dist/react/utils/renderDiffChildren.d.ts +14 -12
  132. package/dist/react/utils/renderDiffChildren.d.ts.map +1 -1
  133. package/dist/react/utils/renderDiffChildren.js +2 -2
  134. package/dist/react/utils/renderDiffChildren.js.map +1 -1
  135. package/dist/react/utils/renderFileChildren.d.ts +14 -12
  136. package/dist/react/utils/renderFileChildren.d.ts.map +1 -1
  137. package/dist/react/utils/renderFileChildren.js +2 -2
  138. package/dist/react/utils/renderFileChildren.js.map +1 -1
  139. package/dist/react/utils/useFileDiffInstance.d.ts +22 -10
  140. package/dist/react/utils/useFileDiffInstance.d.ts.map +1 -1
  141. package/dist/react/utils/useFileDiffInstance.js +112 -22
  142. package/dist/react/utils/useFileDiffInstance.js.map +1 -1
  143. package/dist/react/utils/useFileInstance.d.ts +15 -9
  144. package/dist/react/utils/useFileInstance.d.ts.map +1 -1
  145. package/dist/react/utils/useFileInstance.js +84 -25
  146. package/dist/react/utils/useFileInstance.js.map +1 -1
  147. package/dist/renderers/DiffHunksRenderer.d.ts +30 -15
  148. package/dist/renderers/DiffHunksRenderer.d.ts.map +1 -1
  149. package/dist/renderers/DiffHunksRenderer.js +172 -108
  150. package/dist/renderers/DiffHunksRenderer.js.map +1 -1
  151. package/dist/renderers/FileRenderer.d.ts +27 -11
  152. package/dist/renderers/FileRenderer.d.ts.map +1 -1
  153. package/dist/renderers/FileRenderer.js +138 -64
  154. package/dist/renderers/FileRenderer.js.map +1 -1
  155. package/dist/renderers/UnresolvedFileHunksRenderer.d.ts +2 -2
  156. package/dist/renderers/UnresolvedFileHunksRenderer.d.ts.map +1 -1
  157. package/dist/renderers/UnresolvedFileHunksRenderer.js +2 -2
  158. package/dist/renderers/UnresolvedFileHunksRenderer.js.map +1 -1
  159. package/dist/shiki-stream/tokenizer.d.ts.map +1 -1
  160. package/dist/shiki-stream/tokenizer.js +2 -1
  161. package/dist/shiki-stream/tokenizer.js.map +1 -1
  162. package/dist/ssr/index.d.ts +2 -2
  163. package/dist/ssr/preloadDiffs.d.ts +21 -21
  164. package/dist/ssr/preloadDiffs.d.ts.map +1 -1
  165. package/dist/ssr/preloadDiffs.js +1 -1
  166. package/dist/ssr/preloadDiffs.js.map +1 -1
  167. package/dist/ssr/preloadFile.d.ts +6 -6
  168. package/dist/ssr/preloadFile.d.ts.map +1 -1
  169. package/dist/ssr/preloadFile.js.map +1 -1
  170. package/dist/ssr/preloadPatchFile.d.ts +4 -4
  171. package/dist/ssr/preloadPatchFile.d.ts.map +1 -1
  172. package/dist/ssr/preloadPatchFile.js.map +1 -1
  173. package/dist/style.js +1 -1
  174. package/dist/types.d.ts +13 -263
  175. package/dist/types.d.ts.map +1 -1
  176. package/dist/utils/appendItems.d.ts +5 -0
  177. package/dist/utils/appendItems.d.ts.map +1 -0
  178. package/dist/utils/appendItems.js +8 -0
  179. package/dist/utils/appendItems.js.map +1 -0
  180. package/dist/utils/areDiffTargetsEqual.js +1 -1
  181. package/dist/utils/areDiffTargetsEqual.js.map +1 -1
  182. package/dist/utils/areFileTargetsEqual.d.ts +7 -0
  183. package/dist/utils/areFileTargetsEqual.d.ts.map +1 -0
  184. package/dist/utils/areFileTargetsEqual.js +8 -0
  185. package/dist/utils/areFileTargetsEqual.js.map +1 -0
  186. package/dist/utils/areManagedSnapshotsEqual.d.ts +1 -1
  187. package/dist/utils/areManagedSnapshotsEqual.d.ts.map +1 -1
  188. package/dist/utils/areManagedSnapshotsEqual.js.map +1 -1
  189. package/dist/utils/areOptionsEqual.d.ts +3 -3
  190. package/dist/utils/areOptionsEqual.d.ts.map +1 -1
  191. package/dist/utils/areOptionsEqual.js.map +1 -1
  192. package/dist/utils/cloneFileDiffMetadata.d.ts +3 -2
  193. package/dist/utils/cloneFileDiffMetadata.d.ts.map +1 -1
  194. package/dist/utils/cloneFileDiffMetadata.js +8 -5
  195. package/dist/utils/cloneFileDiffMetadata.js.map +1 -1
  196. package/dist/utils/composeCacheKey.d.ts +6 -0
  197. package/dist/utils/composeCacheKey.d.ts.map +1 -0
  198. package/dist/utils/composeCacheKey.js +10 -0
  199. package/dist/utils/composeCacheKey.js.map +1 -0
  200. package/dist/utils/editSessionAnnotations.d.ts +69 -0
  201. package/dist/utils/editSessionAnnotations.d.ts.map +1 -0
  202. package/dist/utils/editSessionAnnotations.js +64 -0
  203. package/dist/utils/editSessionAnnotations.js.map +1 -0
  204. package/dist/utils/editSessionHunks.d.ts +5 -3
  205. package/dist/utils/editSessionHunks.d.ts.map +1 -1
  206. package/dist/utils/editSessionHunks.js +7 -5
  207. package/dist/utils/editSessionHunks.js.map +1 -1
  208. package/dist/utils/getDiffHunksRendererOptions.d.ts +1 -1
  209. package/dist/utils/getDiffHunksRendererOptions.d.ts.map +1 -1
  210. package/dist/utils/getDiffHunksRendererOptions.js.map +1 -1
  211. package/dist/utils/getFileRendererOptions.d.ts +1 -1
  212. package/dist/utils/getFileRendererOptions.d.ts.map +1 -1
  213. package/dist/utils/getFileRendererOptions.js.map +1 -1
  214. package/dist/utils/hydratePartialDiff.d.ts.map +1 -1
  215. package/dist/utils/hydratePartialDiff.js +2 -1
  216. package/dist/utils/hydratePartialDiff.js.map +1 -1
  217. package/dist/utils/lineAnnotationIdentity.d.ts +16 -0
  218. package/dist/utils/lineAnnotationIdentity.d.ts.map +1 -0
  219. package/dist/utils/lineAnnotationIdentity.js +17 -0
  220. package/dist/utils/lineAnnotationIdentity.js.map +1 -0
  221. package/dist/utils/parseDiffFromFile.d.ts +2 -2
  222. package/dist/utils/parseDiffFromFile.d.ts.map +1 -1
  223. package/dist/utils/parseDiffFromFile.js +6 -6
  224. package/dist/utils/parseDiffFromFile.js.map +1 -1
  225. package/dist/utils/parsePatchFiles.d.ts +6 -3
  226. package/dist/utils/parsePatchFiles.d.ts.map +1 -1
  227. package/dist/utils/parsePatchFiles.js +34 -9
  228. package/dist/utils/parsePatchFiles.js.map +1 -1
  229. package/dist/utils/renderDiffWithHighlighter.d.ts.map +1 -1
  230. package/dist/utils/renderDiffWithHighlighter.js +6 -5
  231. package/dist/utils/renderDiffWithHighlighter.js.map +1 -1
  232. package/dist/utils/renderFileWithHighlighter.d.ts.map +1 -1
  233. package/dist/utils/renderFileWithHighlighter.js +7 -4
  234. package/dist/utils/renderFileWithHighlighter.js.map +1 -1
  235. package/dist/utils/trimPatchContext.d.ts.map +1 -1
  236. package/dist/utils/trimPatchContext.js +3 -2
  237. package/dist/utils/trimPatchContext.js.map +1 -1
  238. package/dist/utils/updateDiffHunks.js +1 -1
  239. package/dist/utils/virtualDiffLayout.js +1 -1
  240. package/dist/worker/WorkerPoolManager.d.ts +4 -3
  241. package/dist/worker/WorkerPoolManager.d.ts.map +1 -1
  242. package/dist/worker/WorkerPoolManager.js +33 -4
  243. package/dist/worker/WorkerPoolManager.js.map +1 -1
  244. package/dist/worker/types.d.ts +5 -0
  245. package/dist/worker/types.d.ts.map +1 -1
  246. package/dist/worker/worker-portable.js +14 -6
  247. package/dist/worker/worker-portable.js.map +1 -1
  248. package/dist/worker/worker.js +14 -6
  249. package/dist/worker/worker.js.map +1 -1
  250. package/package.json +9 -1
  251. package/dist/editor/stateStorage.d.ts +0 -15
  252. package/dist/editor/stateStorage.d.ts.map +0 -1
  253. package/dist/editor/stateStorage.js +0 -65
  254. package/dist/editor/stateStorage.js.map +0 -1
@@ -1,16 +1,13 @@
1
1
  import { CUSTOM_HEADER_SLOT_ID, DEFAULT_THEMES, EMPTY_RENDER_RANGE, HEADER_FILENAME_SUFFIX_SLOT_ID, HEADER_METADATA_SLOT_ID, HEADER_PREFIX_SLOT_ID } from "../constants.js";
2
2
  import { dequeueRender, queueRender } from "../managers/UniversalRenderingManager.js";
3
3
  import { areThemesEqual } from "../utils/areThemesEqual.js";
4
- import { getHunkSideStartBoundary } from "../utils/getHunkSideBoundaries.js";
5
- import { parseDiffFromFile } from "../utils/parseDiffFromFile.js";
6
- import { getExpandedRegion, getHunkAdditionLineRange, getNearestRenderableAdditionLine, getTrailingExpandedRegion, isAdditionLineRenderable } from "../utils/virtualDiffLayout.js";
7
- import { captureExpansionAnchors, finishEditSessionForDiff, rebuildExpansionFromAnchors } from "../utils/editSessionHunks.js";
8
4
  import { isStyleNode } from "../utils/isStyleNode.js";
9
- import { areFilesEqual } from "../utils/areFilesEqual.js";
10
5
  import { InteractionManager, pluckInteractionOptions } from "../managers/InteractionManager.js";
11
6
  import { ResizeManager } from "../managers/ResizeManager.js";
12
7
  import { areRenderRangesEqual } from "../utils/areRenderRangesEqual.js";
8
+ import { getFiletypeFromFileName } from "../utils/getFiletypeFromFileName.js";
13
9
  import { getLineAnnotationName } from "../utils/getLineAnnotationName.js";
10
+ import { isDefaultRenderRange } from "../utils/isDefaultRenderRange.js";
14
11
  import { SVGSpriteSheet } from "../sprite.js";
15
12
  import { arePrePropertiesEqual } from "../utils/arePrePropertiesEqual.js";
16
13
  import { createAnnotationWrapperNode } from "../utils/createAnnotationWrapperNode.js";
@@ -18,6 +15,7 @@ import { createGutterUtilityContentNode } from "../utils/createGutterUtilityCont
18
15
  import { createUnsafeCSSStyleNode } from "../utils/createUnsafeCSSStyleNode.js";
19
16
  import { getMeasuredScrollbarGutter } from "../utils/scrollbarGutter.js";
20
17
  import { patchScrollbarGutterSize, wrapThemeCSS, wrapUnsafeCSS } from "../utils/cssWrappers.js";
18
+ import { adoptEditSessionAnnotations, resolveEditSessionSlotName, writeEditSessionAnnotations } from "../utils/editSessionAnnotations.js";
21
19
  import { getOrCreateCodeNode } from "../utils/getOrCreateCodeNode.js";
22
20
  import { guardWebKitScrollDuringRebuild } from "../utils/guardWebKitScrollDuringRebuild.js";
23
21
  import { upsertHostThemeStyle } from "../utils/hostTheme.js";
@@ -25,12 +23,20 @@ import { isSafari } from "../utils/platform.js";
25
23
  import { prerenderHTMLIfNecessary } from "../utils/prerenderHTMLIfNecessary.js";
26
24
  import { setPreNodeProperties } from "../utils/setWrapperNodeProps.js";
27
25
  import "./web-components.js";
26
+ import { areDiffTargetsEqual } from "../utils/areDiffTargetsEqual.js";
27
+ import { areFilesEqual } from "../utils/areFilesEqual.js";
28
28
  import { awaitWithTimeout } from "../utils/awaitWithTimeout.js";
29
+ import { getHunkSideStartBoundary } from "../utils/getHunkSideBoundaries.js";
30
+ import { getExpandedRegion, getHunkAdditionLineRange, getNearestRenderableAdditionLine, getTrailingExpandedRegion, isAdditionLineRenderable } from "../utils/virtualDiffLayout.js";
29
31
  import { getDiffFileInput } from "../utils/getDiffFileInput.js";
32
+ import { cloneFileDiffMetadata, cloneHunks } from "../utils/cloneFileDiffMetadata.js";
33
+ import { splitFileContents } from "../utils/splitFileContents.js";
30
34
  import { hydratePartialDiff } from "../utils/hydratePartialDiff.js";
31
35
  import { iterateOverDiff } from "../utils/iterateOverDiff.js";
36
+ import { parseDiffFromFile } from "../utils/parseDiffFromFile.js";
32
37
  import { ScrollSyncManager } from "../managers/ScrollSyncManager.js";
33
- import { isDefaultRenderRange } from "../utils/isDefaultRenderRange.js";
38
+ import { recomputeDiffRenderLineCounts } from "../utils/updateDiffHunks.js";
39
+ import { captureExpansionAnchors, finishEditSessionForDiff, rebuildExpansionFromAnchors } from "../utils/editSessionHunks.js";
34
40
  import { isDiffPlainText } from "../utils/isDiffPlainText.js";
35
41
  import { DiffHunksRenderer } from "../renderers/DiffHunksRenderer.js";
36
42
  import { areDiffLineAnnotationsEqual } from "../utils/areDiffLineAnnotationsEqual.js";
@@ -41,6 +47,28 @@ import { toHtml } from "hast-util-to-html";
41
47
  function canHydrateDiff(fileDiff) {
42
48
  return fileDiff.isPartial && (fileDiff.type === "change" || fileDiff.type === "rename-changed" || fileDiff.type === "rename-pure");
43
49
  }
50
+ function createEditSessionDiff(fileDiff) {
51
+ const editSessionDiff = { ...fileDiff };
52
+ delete editSessionDiff.cacheKey;
53
+ return editSessionDiff;
54
+ }
55
+ function shouldResetUndoState(prevDiff, nextDiff) {
56
+ if (prevDiff.isPartial || nextDiff.isPartial) throw new Error("FileDiff.shouldResetEditorForExternalDiff: diffs must be fully hydrated");
57
+ const prevLanguage = prevDiff.lang ?? getFiletypeFromFileName(prevDiff.name);
58
+ const nextLanguage = nextDiff.lang ?? getFiletypeFromFileName(nextDiff.name);
59
+ const prevHasOldFile = prevDiff.type !== "new";
60
+ const nextHasOldFile = nextDiff.type !== "new";
61
+ if (prevDiff.name !== nextDiff.name || prevLanguage !== nextLanguage || prevHasOldFile !== nextHasOldFile || prevDiff.deletionLines.length !== nextDiff.deletionLines.length) return true;
62
+ return prevDiff.deletionLines.some((line, index) => line !== nextDiff.deletionLines[index]);
63
+ }
64
+ function areLinesEqual(first, second) {
65
+ return first.length === second.length && first.every((line, index) => line === second[index]);
66
+ }
67
+ function canRestoreDiffSession(snapshot, externalDiff) {
68
+ const { oldFile } = snapshot;
69
+ if (oldFile == null) return externalDiff.type === "new";
70
+ return externalDiff.type !== "new" && oldFile.name === (externalDiff.prevName ?? externalDiff.name) && areLinesEqual(oldFile.lines, externalDiff.deletionLines);
71
+ }
44
72
  let instanceId = -1;
45
73
  var FileDiff = class {
46
74
  options;
@@ -81,11 +109,18 @@ var FileDiff = class {
81
109
  deletionFile;
82
110
  additionFile;
83
111
  fileDiff;
112
+ editSessionDiff;
113
+ editSessionAnnotations;
114
+ outgoingSessionDiff;
115
+ renderedDiff;
84
116
  renderRange;
85
117
  pendingFiles;
86
118
  appliedPreAttributes;
87
- lastRenderedHeaderHTML;
88
- cachedHeaderHTML;
119
+ headerCache = {
120
+ lastRenderedHTML: void 0,
121
+ html: void 0,
122
+ fileDiff: void 0
123
+ };
89
124
  lastRowCount;
90
125
  mounted = false;
91
126
  enabled = true;
@@ -112,10 +147,15 @@ var FileDiff = class {
112
147
  return getDiffHunksRendererOptions(options);
113
148
  }
114
149
  createHunksRenderer(options) {
115
- return new DiffHunksRenderer(this.getHunksRendererOptions(options), this.handleHighlightRender, this.workerManager);
150
+ return new DiffHunksRenderer(this.getHunksRendererOptions(options), this.getAnnotationSlotName, this.handleHighlightRender, this.workerManager);
116
151
  }
117
152
  getLineIndex = (lineNumber, side = "additions") => {
118
- const fileDiff = this.fileDiffCache;
153
+ return this.getLineIndexForDiff(this.getDiffForLineIndex(), lineNumber, side);
154
+ };
155
+ getDiffForLineIndex() {
156
+ return this.getRenderedDiff();
157
+ }
158
+ getLineIndexForDiff(fileDiff, lineNumber, side) {
119
159
  if (fileDiff == null) return;
120
160
  const lastHunk = fileDiff.hunks.at(-1);
121
161
  let targetUnifiedIndex;
@@ -168,11 +208,11 @@ var FileDiff = class {
168
208
  }
169
209
  if (targetUnifiedIndex == null || targetSplitIndex == null) return;
170
210
  return [targetUnifiedIndex, targetSplitIndex];
171
- };
211
+ }
172
212
  setOptions(options) {
173
213
  if (options == null) return;
174
214
  this.options = options;
175
- this.cachedHeaderHTML = void 0;
215
+ this.clearReusableHeader();
176
216
  this.hunksRenderer.setOptions(this.getHunksRendererOptions(options));
177
217
  this.syncInteractionOptions();
178
218
  }
@@ -203,8 +243,34 @@ var FileDiff = class {
203
243
  getHoveredLine = () => {
204
244
  return this.interactionManager.getHoveredLine();
205
245
  };
246
+ getAnnotationSlotName = (annotation) => {
247
+ return resolveEditSessionSlotName(this.editSessionAnnotations, annotation, getLineAnnotationName);
248
+ };
249
+ getLatestAnnotations() {
250
+ return this.editSessionAnnotations?.current ?? this.lineAnnotations;
251
+ }
252
+ isNewAnnotations(lineAnnotations) {
253
+ const { editSessionAnnotations: session, lineAnnotations: externalAnnotations } = this;
254
+ if (lineAnnotations === externalAnnotations) return false;
255
+ return session == null || lineAnnotations !== session.provided && lineAnnotations !== session.current;
256
+ }
206
257
  setLineAnnotations(lineAnnotations) {
258
+ const { editSessionAnnotations: sessionAnnotations } = this;
259
+ if (sessionAnnotations == null) {
260
+ this.lineAnnotations = lineAnnotations;
261
+ return;
262
+ }
263
+ if (!this.isNewAnnotations(lineAnnotations)) return;
207
264
  this.lineAnnotations = lineAnnotations;
265
+ writeEditSessionAnnotations(sessionAnnotations, lineAnnotations, getLineAnnotationName);
266
+ }
267
+ syncEditSessionAnnotationsFromEditor(lineAnnotations) {
268
+ const { editSessionAnnotations: session } = this;
269
+ if (session == null || lineAnnotations === session.current) return false;
270
+ session.current = lineAnnotations;
271
+ this.hunksRenderer.setLineAnnotations(lineAnnotations);
272
+ this.renderAnnotations();
273
+ return true;
208
274
  }
209
275
  canPartiallyRender(forceRender, annotationsChanged, didContentChange) {
210
276
  if (forceRender || annotationsChanged || didContentChange || typeof this.options.hunkSeparators === "function") return false;
@@ -246,7 +312,7 @@ var FileDiff = class {
246
312
  }
247
313
  shouldApplyColumnVariables(overflow) {
248
314
  if (typeof this.options.hunkSeparators === "function") return true;
249
- return overflow === "scroll" && (this.lineAnnotations.length > 0 || this.pre?.hasAttribute("data-has-merge-conflict") === true);
315
+ return overflow === "scroll" && (this.getLatestAnnotations().length > 0 || this.pre?.hasAttribute("data-has-merge-conflict") === true);
250
316
  }
251
317
  getCodeScrollLeft() {
252
318
  return Math.max(this.codeUnified?.scrollLeft ?? 0, this.codeDeletions?.scrollLeft ?? 0, this.codeAdditions?.scrollLeft ?? 0);
@@ -263,17 +329,18 @@ var FileDiff = class {
263
329
  };
264
330
  }
265
331
  cleanUp(recycle = false) {
332
+ const { editor } = this;
266
333
  dequeueRender(this.handleEditSessionRender);
267
334
  this.emitPostRender(true);
268
- this.editor?.cleanUp(recycle);
269
- this.editor = void 0;
335
+ editor?.cleanUp(recycle ? "recycle" : "discard");
336
+ if (!recycle) this.editor = void 0;
270
337
  this.resizeManager.cleanUp();
271
338
  this.interactionManager.cleanUp();
272
339
  this.scrollSyncManager.cleanUp();
273
340
  this.managersDirty = false;
274
341
  this.workerManager?.unsubscribeToThemeChanges(this);
275
342
  this.renderRange = void 0;
276
- this.pendingFiles = void 0;
343
+ if (!recycle) this.pendingFiles = void 0;
277
344
  if (!this.isContainerManaged) this.fileContainer?.remove();
278
345
  this.fileContainer = void 0;
279
346
  this.mounted = false;
@@ -296,8 +363,8 @@ var FileDiff = class {
296
363
  this.headerCustom = void 0;
297
364
  this.placeHolder?.remove();
298
365
  this.placeHolder = void 0;
299
- this.lastRenderedHeaderHTML = void 0;
300
- if (!recycle) this.cachedHeaderHTML = void 0;
366
+ this.headerCache.lastRenderedHTML = void 0;
367
+ if (!recycle) this.clearReusableHeader();
301
368
  this.errorWrapper?.remove();
302
369
  this.errorWrapper = void 0;
303
370
  this.spriteSVG = void 0;
@@ -312,6 +379,10 @@ var FileDiff = class {
312
379
  this.hunksRenderer.cleanUp();
313
380
  this.workerManager = void 0;
314
381
  this.fileDiff = void 0;
382
+ this.editSessionDiff = void 0;
383
+ this.editSessionAnnotations = void 0;
384
+ this.outgoingSessionDiff = void 0;
385
+ this.renderedDiff = void 0;
315
386
  this.deletionFile = void 0;
316
387
  this.additionFile = void 0;
317
388
  }
@@ -335,7 +406,8 @@ var FileDiff = class {
335
406
  const oldFile = fileInput?.oldFile;
336
407
  const newFile = fileInput?.newFile;
337
408
  this.hydrateElements(fileContainer, prerenderedHTML);
338
- if (shouldRenderCode(this.pre, hasDiffContent({
409
+ const forceEditorRender = this.editor != null;
410
+ if (forceEditorRender || shouldRenderCode(this.pre, hasDiffContent({
339
411
  fileDiff,
340
412
  oldFile,
341
413
  newFile
@@ -348,6 +420,7 @@ var FileDiff = class {
348
420
  fileContainer,
349
421
  lineAnnotations,
350
422
  fileDiff,
423
+ forceRender: forceEditorRender || fileInputProps.forceRender,
351
424
  preventEmit: true
352
425
  });
353
426
  else this.hydrationSetup({
@@ -405,6 +478,7 @@ var FileDiff = class {
405
478
  if (this.pre == null) return;
406
479
  this.syncInteractionOptions();
407
480
  this.hunksRenderer.hydrate(this.fileDiff);
481
+ this.renderedDiff = this.fileDiff;
408
482
  this.renderAnnotations();
409
483
  this.renderGutterUtility();
410
484
  this.injectUnsafeCSS();
@@ -433,10 +507,15 @@ var FileDiff = class {
433
507
  loadFilesIfNecessary() {
434
508
  const { fileDiff, options: { loadDiffFiles } } = this;
435
509
  if (fileDiff == null || loadDiffFiles == null || !canHydrateDiff(fileDiff) || this.pendingFiles?.fileDiff === fileDiff) return;
436
- this.pendingFiles = {
510
+ const promise = this.loadFilesForDiff(fileDiff, loadDiffFiles);
511
+ const pendingFiles = this.pendingFiles = {
437
512
  fileDiff,
438
- promise: this.loadFilesForDiff(fileDiff, loadDiffFiles)
513
+ promise
439
514
  };
515
+ const clearPendingFiles = () => {
516
+ if (this.pendingFiles === pendingFiles) this.pendingFiles = void 0;
517
+ };
518
+ pendingFiles.promise = promise.finally(clearPendingFiles);
440
519
  }
441
520
  async loadFilesForDiff(fileDiff, loadDiffFiles) {
442
521
  try {
@@ -446,18 +525,71 @@ var FileDiff = class {
446
525
  } catch (error) {
447
526
  if (this.options.disableErrorHandling === true) throw error;
448
527
  console.error(error);
449
- } finally {
450
- if (this.pendingFiles?.fileDiff === fileDiff) this.pendingFiles = void 0;
451
528
  }
452
529
  }
453
530
  async handleFilesLoaded(expectedDiff, files) {
454
531
  if (this.fileDiff !== expectedDiff || !expectedDiff.isPartial) return;
455
532
  hydratePartialDiff("merge", expectedDiff, files);
456
533
  this.setHydratedState(files);
534
+ if (this.startHydratedEditSession(expectedDiff)) {
535
+ this.rerender();
536
+ return;
537
+ }
457
538
  await awaitWithTimeout(() => this.primeHighlightCache(expectedDiff));
458
539
  if (!this.enabled || this.fileDiff !== expectedDiff) return;
459
540
  this.rerender();
460
541
  }
542
+ startHydratedEditSession(expectedDiff) {
543
+ if (expectedDiff.isPartial) throw new Error("FileDiff.startHydratedEditSession: diffs cannot be partial for editing");
544
+ if (this.fileDiff !== expectedDiff) return false;
545
+ const { editor } = this;
546
+ if (this.outgoingSessionDiff != null) {
547
+ this.installEditSession(expectedDiff);
548
+ return true;
549
+ }
550
+ if (editor == null || this.editSessionDiff != null) return false;
551
+ this.installEditSession(expectedDiff, editor.__getDocumentContents(getAdditionFile(expectedDiff)), editor.__getDocumentSessionState());
552
+ return true;
553
+ }
554
+ updateExternalDiff(incomingExternalDiff, lineAnnotations) {
555
+ if (areDiffTargetsEqual(this.fileDiff, incomingExternalDiff)) return false;
556
+ const editSessionDiff = this.outgoingSessionDiff ?? this.editSessionDiff;
557
+ this.fileDiff = incomingExternalDiff;
558
+ this.outgoingSessionDiff = void 0;
559
+ if (editSessionDiff != null) {
560
+ this.outgoingSessionDiff = editSessionDiff;
561
+ if (incomingExternalDiff.isPartial) this.loadFilesIfNecessary();
562
+ else this.installEditSession(incomingExternalDiff);
563
+ } else if (this.editor != null) if (incomingExternalDiff.isPartial) this.loadFilesIfNecessary();
564
+ else this.installEditSession(incomingExternalDiff, this.editor.__getDocumentContents(getAdditionFile(incomingExternalDiff)), this.editor.__getDocumentSessionState());
565
+ if (this.editSessionAnnotations != null && lineAnnotations != null) {
566
+ this.lineAnnotations = lineAnnotations;
567
+ this.editSessionAnnotations = adoptEditSessionAnnotations(lineAnnotations, getLineAnnotationName, this.editSessionAnnotations);
568
+ }
569
+ return true;
570
+ }
571
+ installEditSession(externalDiff, retainedDocument, retainedSession) {
572
+ const externalContents = externalDiff.additionLines.join("");
573
+ const retainedLines = retainedDocument != null ? splitFileContents(retainedDocument.contents) : void 0;
574
+ const restoreRetainedSession = retainedSession != null && canRestoreDiffSession(retainedSession, externalDiff);
575
+ if (retainedSession != null && !restoreRetainedSession) throw new Error("FileDiff: retained session cannot resume against a different old file");
576
+ if (retainedDocument != null && retainedDocument.contents !== externalContents && !restoreRetainedSession) throw new Error("FileDiff: retained edits are missing their diff session state");
577
+ const usesExternalDocument = retainedDocument == null || retainedDocument.name === externalDiff.name && retainedDocument.lang === externalDiff.lang && retainedDocument.contents === externalContents;
578
+ const sessionDiff = createEditSessionDiff(externalDiff);
579
+ if (retainedDocument != null && retainedLines != null && !usesExternalDocument) {
580
+ sessionDiff.name = retainedDocument.name;
581
+ sessionDiff.lang = retainedDocument.lang;
582
+ }
583
+ if (restoreRetainedSession && retainedSession != null && retainedLines != null) {
584
+ sessionDiff.additionLines = retainedLines;
585
+ sessionDiff.type = retainedSession.type;
586
+ sessionDiff.hunks = retainedSession.hunks;
587
+ sessionDiff.editSessionDirty = true;
588
+ recomputeDiffRenderLineCounts(sessionDiff);
589
+ }
590
+ this.editSessionDiff = sessionDiff;
591
+ this.hunksRenderer.beginEditSession(sessionDiff, usesExternalDocument && !restoreRetainedSession ? externalDiff : void 0);
592
+ }
461
593
  setHydratedState(files) {
462
594
  this.deletionFile = files.oldFile;
463
595
  this.additionFile = files.newFile;
@@ -465,20 +597,19 @@ var FileDiff = class {
465
597
  this.hunksRenderer.clearRenderCache();
466
598
  }
467
599
  render({ fileDiff, deferManagers = false, forceRender = false, preventEmit = false, lineAnnotations, fileContainer, containerWrapper, renderRange, ...fileInputProps }) {
600
+ if (!this.enabled) throw new Error("FileDiff.render: attempting to call render after cleaned up");
468
601
  const fileInput = getDiffFileInput(fileInputProps, "FileDiff.render");
469
602
  const oldFile = fileInput?.oldFile;
470
603
  const newFile = fileInput?.newFile;
471
- if (!this.enabled) throw new Error("FileDiff.render: attempting to call render after cleaned up");
472
- if (fileDiff != null && fileDiff.cacheKey === void 0) fileDiff.cacheKey = fileDiff.prevName != null ? fileDiff.prevName + ":" + fileDiff.name : fileDiff.name;
473
604
  this.editor?.__postponeBgTokenizeToNextFrame();
474
605
  const { collapsed = false, themeType = "system", expandUnchanged = false } = this.options;
475
606
  const nextRenderRange = collapsed ? void 0 : renderRange;
476
607
  const themeChanged = this.hasThemeChanged();
477
608
  const hasFileInput = fileInput != null;
478
609
  const filesDidChange = hasFileInput && (!areOptionalFilesEqual(oldFile, this.deletionFile) || !areOptionalFilesEqual(newFile, this.additionFile));
479
- let diffDidChange = fileDiff != null && fileDiff !== this.fileDiff;
480
- const annotationsChanged = lineAnnotations != null && (lineAnnotations.length > 0 || this.lineAnnotations.length > 0) ? lineAnnotations !== this.lineAnnotations : false;
481
- if (!collapsed && areRenderRangesEqual(nextRenderRange, this.renderRange) && !forceRender && !annotationsChanged && !themeChanged && (fileDiff != null && fileDiff === this.fileDiff || fileDiff == null && !filesDidChange)) return this.applyCachedThemeState(themeType);
610
+ let diffDidChange = fileDiff != null && !areDiffTargetsEqual(fileDiff, this.fileDiff);
611
+ const annotationsChanged = lineAnnotations != null && (lineAnnotations.length > 0 || this.getLatestAnnotations().length > 0) ? this.isNewAnnotations(lineAnnotations) : false;
612
+ if (!collapsed && areRenderRangesEqual(nextRenderRange, this.renderRange) && !forceRender && !annotationsChanged && !themeChanged && (fileDiff != null && !diffDidChange || fileDiff == null && !filesDidChange)) return this.applyCachedThemeState(themeType);
482
613
  let nextParsedFileDiff;
483
614
  if (fileDiff == null && hasFileInput && (filesDidChange || this.fileDiff == null)) nextParsedFileDiff = parseDiffFromFile(fileInput.oldFile, fileInput.newFile, this.options.parseDiffOptions);
484
615
  const { renderRange: previousRenderRange } = this;
@@ -490,28 +621,29 @@ var FileDiff = class {
490
621
  this.deletionFile = void 0;
491
622
  this.additionFile = void 0;
492
623
  }
493
- if (fileDiff != null) this.fileDiff = fileDiff;
624
+ if (fileDiff != null && diffDidChange) this.updateExternalDiff(fileDiff, lineAnnotations);
494
625
  else if (nextParsedFileDiff != null) {
495
626
  diffDidChange = true;
496
- this.fileDiff = nextParsedFileDiff;
627
+ this.updateExternalDiff(nextParsedFileDiff, lineAnnotations);
497
628
  }
498
- if (diffDidChange) this.cachedHeaderHTML = void 0;
629
+ if (diffDidChange) this.clearReusableHeader();
499
630
  if (lineAnnotations != null) this.setLineAnnotations(lineAnnotations);
500
- if (this.fileDiff == null) return false;
501
- if (this.fileDiff.editSessionDirty === true && this.shouldSelfHealEditSession()) {
502
- finishEditSessionForDiff(this.fileDiff, this.options.parseDiffOptions);
631
+ const latestDiff = this.getLatestDiff();
632
+ if (latestDiff == null) return false;
633
+ if (latestDiff.editSessionDirty === true && this.shouldSelfHealEditSession()) {
634
+ finishEditSessionForDiff(latestDiff, this.options.parseDiffOptions);
503
635
  this.hunksRenderer.refreshHighlightedResult();
504
636
  }
505
637
  if (expandUnchanged) this.loadFilesIfNecessary();
506
638
  this.hunksRenderer.setOptions(this.getHunksRendererOptions(this.options));
507
639
  this.syncInteractionOptions();
508
- this.hunksRenderer.setLineAnnotations(this.lineAnnotations);
640
+ this.hunksRenderer.setLineAnnotations(this.getLatestAnnotations());
509
641
  const { disableErrorHandling = false, disableFileHeader = false } = this.options;
510
642
  if (disableFileHeader) {
511
643
  if (this.headerElement != null) {
512
644
  this.headerElement.remove();
513
645
  this.headerElement = void 0;
514
- this.lastRenderedHeaderHTML = void 0;
646
+ this.headerCache.lastRenderedHTML = void 0;
515
647
  }
516
648
  this.clearHeaderSlots();
517
649
  }
@@ -521,10 +653,11 @@ var FileDiff = class {
521
653
  this.removeRenderedCode();
522
654
  this.clearAuxiliaryNodes();
523
655
  try {
524
- const hunksResult = this.hunksRenderer.renderDiff(this.fileDiff, EMPTY_RENDER_RANGE);
656
+ const hunksResult = this.hunksRenderer.renderDiff(latestDiff, EMPTY_RENDER_RANGE);
525
657
  if (hunksResult != null) this.applyThemeState(fileContainer, hunksResult.themeStyles, themeType, hunksResult.baseThemeType);
526
- if (hunksResult?.headerElement != null) this.applyHeaderToDOM(hunksResult.headerElement, fileContainer);
658
+ if (hunksResult?.headerElement != null) this.applyHeaderToDOM(hunksResult.headerElement, fileContainer, hunksResult.fileDiff);
527
659
  this.renderSeparators([]);
660
+ this.renderedDiff = hunksResult?.fileDiff ?? latestDiff;
528
661
  this.injectUnsafeCSS();
529
662
  } catch (error) {
530
663
  if (disableErrorHandling) throw error;
@@ -536,23 +669,25 @@ var FileDiff = class {
536
669
  }
537
670
  try {
538
671
  const pre = this.getOrCreatePreNode(fileContainer);
539
- if (!(this.canPartiallyRender(forceRender, annotationsChanged, filesDidChange || diffDidChange || themeChanged) && this.applyPartialRender({
672
+ if (!(this.canPartiallyRender(forceRender, annotationsChanged, filesDidChange || diffDidChange || themeChanged || !areDiffTargetsEqual(this.renderedDiff, latestDiff)) && this.applyPartialRender({
673
+ fileDiff: latestDiff,
540
674
  previousRenderRange,
541
675
  renderRange: nextRenderRange
542
676
  }))) {
543
- const hunksResult = this.hunksRenderer.renderDiff(this.fileDiff, nextRenderRange);
677
+ const hunksResult = this.hunksRenderer.renderDiff(latestDiff, nextRenderRange);
544
678
  if (hunksResult == null) {
545
- if (this.workerManager?.isInitialized() === false) this.workerManager.initialize().then(() => this.rerender());
679
+ if (this.workerManager?.isInitialized() === false && this.workerManager.isWorkingPool()) this.workerManager.initialize().catch(() => {}).then(() => this.rerender());
546
680
  return false;
547
681
  }
548
682
  this.applyThemeState(fileContainer, hunksResult.themeStyles, themeType, hunksResult.baseThemeType);
549
- if (hunksResult.headerElement != null) this.applyHeaderToDOM(hunksResult.headerElement, fileContainer);
683
+ if (hunksResult.headerElement != null) this.applyHeaderToDOM(hunksResult.headerElement, fileContainer, hunksResult.fileDiff);
550
684
  if (hunksResult.additionsContentAST != null || hunksResult.deletionsContentAST != null || hunksResult.unifiedContentAST != null) this.applyHunksToDOM(pre, hunksResult);
551
685
  else if (this.pre != null) {
552
686
  this.pre.remove();
553
687
  this.pre = void 0;
554
688
  }
555
689
  this.renderSeparators(hunksResult.hunkData);
690
+ this.renderedDiff = hunksResult.fileDiff;
556
691
  }
557
692
  this.applyBuffers(pre, nextRenderRange);
558
693
  this.injectUnsafeCSS();
@@ -583,22 +718,37 @@ var FileDiff = class {
583
718
  this.mounted = true;
584
719
  onPostRender?.(fileContainer, this, phase);
585
720
  }
586
- get fileDiffCache() {
587
- return this.hunksRenderer.diffCache ?? this.fileDiff;
721
+ getLatestDiff(fileDiff = this.fileDiff) {
722
+ return this.editSessionDiff ?? fileDiff;
723
+ }
724
+ getRenderedDiff() {
725
+ return this.renderedDiff;
588
726
  }
589
727
  syncRenderViewToEditor() {
590
- const editor = this.editor;
591
- const fileContainer = this.fileContainer;
592
- const fileDiff = this.fileDiffCache;
593
- const lineAnnotations = this.lineAnnotations;
728
+ const { editor, fileContainer } = this;
729
+ const lineAnnotations = this.getLatestAnnotations();
594
730
  const renderRange = this.computeEditorRenderRange(this.renderRange);
595
- if (editor != null && fileContainer != null && fileDiff != null && !fileDiff.isPartial) this.hunksRenderer.initializeHighlighter().then((highlighter) => {
596
- if (!this.enabled || this.editor !== editor || this.fileContainer !== fileContainer || this.fileDiffCache !== fileDiff) return;
597
- editor.__syncRenderView(highlighter, fileContainer, fileDiff, lineAnnotations, renderRange);
731
+ const fileDiff = this.getLatestDiff();
732
+ if (editor == null || fileContainer == null || fileDiff == null || fileDiff.isPartial) return;
733
+ this.hunksRenderer.initializeHighlighter().then((highlighter) => {
734
+ if (!this.enabled || this.editor !== editor || this.fileContainer !== fileContainer || this.getLatestDiff() !== fileDiff) return;
735
+ const { outgoingSessionDiff: replacement, fileDiff: externalDiff } = this;
736
+ const externalDocument = replacement != null && externalDiff != null && replacement !== fileDiff;
737
+ const resetHistory = externalDocument ? shouldResetUndoState(replacement, externalDiff) : false;
738
+ if (externalDocument) this.outgoingSessionDiff = void 0;
739
+ editor.__syncRenderView({
740
+ highlighter,
741
+ fileContainer,
742
+ fileDiff,
743
+ lineAnnotations,
744
+ renderRange,
745
+ externalDocument,
746
+ resetHistory
747
+ });
598
748
  });
599
749
  }
600
750
  computeEditorRenderRange(renderRange) {
601
- const fileDiff = this.fileDiffCache;
751
+ const fileDiff = this.getLatestDiff();
602
752
  if (renderRange == null || fileDiff == null || isDefaultRenderRange(renderRange)) return renderRange;
603
753
  const { diffStyle = "split", expandUnchanged = false, collapsedContextThreshold = 1 } = this.options;
604
754
  let firstLineNumber;
@@ -628,37 +778,166 @@ var FileDiff = class {
628
778
  totalLines: lastLineNumber - firstLineNumber + 1
629
779
  };
630
780
  }
631
- attachEditor(editor) {
632
- if (this.type !== "file-diff") throw new Error(`FileDiff.attachEditor: cannot attach an editor to a "${this.type}" diff`);
633
- this.editor?.cleanUp();
634
- this.editor = editor;
635
- this.hunksRenderer.beginEditSession();
636
- if (this.fileDiff?.isPartial === true) this.loadFilesIfNecessary();
637
- if (this.hunksRenderer.editorRenderReady()) this.syncRenderViewToEditor();
638
- else this.rerender();
639
- return (recycle) => {
781
+ emitEditChange(event) {
782
+ const { lineAnnotations } = event;
783
+ if (lineAnnotations != null) this.syncEditSessionAnnotationsFromEditor(lineAnnotations);
784
+ const { onEditChange } = this.options;
785
+ onEditChange?.(event);
786
+ }
787
+ /**
788
+ * @internal Capture the current diff session, or return `undefined` when no
789
+ * complete compatible session exists.
790
+ *
791
+ * When `clone` is true, the returned lines and hunks are copied.
792
+ */
793
+ __captureDocumentSessionState(clone = true) {
794
+ let { outgoingSessionDiff, fileDiff, editSessionDiff: sessionDiff } = this;
795
+ if (outgoingSessionDiff != null && fileDiff != null) {
796
+ if (!fileDiff.isPartial && shouldResetUndoState(outgoingSessionDiff, fileDiff)) return;
797
+ sessionDiff = outgoingSessionDiff;
798
+ }
799
+ if (sessionDiff == null || sessionDiff.isPartial) return;
800
+ return {
801
+ diffSession: {
802
+ oldFile: sessionDiff.type !== "new" ? {
803
+ name: sessionDiff.prevName ?? sessionDiff.name,
804
+ lines: clone ? [...sessionDiff.deletionLines] : sessionDiff.deletionLines
805
+ } : null,
806
+ type: sessionDiff.type,
807
+ hunks: clone ? cloneHunks(sessionDiff.hunks) : sessionDiff.hunks
808
+ },
809
+ hasChanges: sessionDiff.editSessionDirty === true
810
+ };
811
+ }
812
+ /** @internal Associate this component with its editor for a render lifecycle. */
813
+ __attachEditor(editor) {
814
+ if (this.type !== "file-diff") throw new Error(`FileDiff.__attachEditor: cannot attach an editor to a "${this.type}" diff`);
815
+ if (this.editor != null) throw new Error("FileDiff.__attachEditor: an editor is already attached");
816
+ const detach = () => {
640
817
  this.editor = void 0;
641
- if (recycle !== true) this.finishEditSession();
818
+ this.finishEditSession();
642
819
  };
820
+ try {
821
+ this.resumeEditorRendering(editor);
822
+ return detach;
823
+ } catch (error) {
824
+ detach();
825
+ throw error;
826
+ }
827
+ }
828
+ /** @internal Resume rendering for the editor already associated with this component. */
829
+ __resumeEditor(editor) {
830
+ if (this.editor !== editor) throw new Error("FileDiff.__resumeEditor: editor association changed");
831
+ this.resumeEditorRendering(editor);
832
+ }
833
+ resumeEditorRendering(editor) {
834
+ this.editSessionAnnotations ??= adoptEditSessionAnnotations(this.lineAnnotations, getLineAnnotationName);
835
+ const { fileDiff: externalDiff, outgoingSessionDiff: pendingReplacement } = this;
836
+ if (pendingReplacement != null && externalDiff != null && !externalDiff.isPartial && this.editSessionDiff === pendingReplacement) this.installEditSession(externalDiff);
837
+ const initialExternalDiff = this.editSessionDiff == null && externalDiff != null && !externalDiff.isPartial ? externalDiff : void 0;
838
+ if (initialExternalDiff != null) this.installEditSession(initialExternalDiff, editor.__getDocumentContents(getAdditionFile(initialExternalDiff)), editor.__getDocumentSessionState());
839
+ else this.hunksRenderer.beginEditSession(this.editSessionDiff);
840
+ this.editor = editor;
841
+ if (this.fileDiff?.isPartial === true) this.loadFilesIfNecessary();
842
+ if (this.hunksRenderer.editorRenderReady()) {
843
+ const { editSessionDiff } = this;
844
+ if (editSessionDiff != null && this.hunksRenderer.diffCache === editSessionDiff) this.renderedDiff = editSessionDiff;
845
+ this.syncRenderViewToEditor();
846
+ } else this.rerender();
643
847
  }
644
848
  finishEditSession() {
645
849
  this.hunksRenderer.endEditSession();
646
- this.completeEditSession();
850
+ this.finalizeEditSessionHunks();
647
851
  }
648
852
  /**
649
- * Run the genuine session-end recompute: restore recompute-shaped hunks (a
853
+ * @internal
854
+ *
855
+ * Ends the edit session and settles which diff this component renders.
856
+ * Requires the editor to be detached first. Does nothing when no session
857
+ * exists, so callers can invoke it again safely after it has settled.
858
+ *
859
+ * `onEditComplete` receives the completed diff, current external diff,
860
+ * complete file pair, and both annotation collections even when the final
861
+ * text is unchanged. In `install` mode, accepting installs the completed diff
862
+ * and its annotations; rejecting or having no handler restores the external
863
+ * values. `discard` mode always restores the external values. An accepted
864
+ * diff cannot reuse the replaced diff's `cacheKey`.
865
+ */
866
+ __completeEditSession(editor, mode) {
867
+ this.settleEditSession(mode === "install", editor);
868
+ }
869
+ settleEditSession(installResult, editor) {
870
+ const { editSessionDiff, editSessionAnnotations, fileDiff: externalDiff, lineAnnotations: externalAnnotations } = this;
871
+ if (editSessionDiff == null || externalDiff == null) return;
872
+ if (this.editor != null) throw new Error("FileDiff.__completeEditSession: detach the editor before completing the session");
873
+ this.hunksRenderer.endEditSession();
874
+ this.finalizeEditSessionHunks();
875
+ const sessionAnnotationsCurrent = editSessionAnnotations?.current;
876
+ let acceptedDiff;
877
+ let acceptedOldFile = null;
878
+ let acceptedNewFile = null;
879
+ let failed = false;
880
+ let failure;
881
+ if (editor == null) throw new Error("FileDiff.__completeEditSession: editor is required for completion");
882
+ const completedDiff = cloneFileDiffMetadata(editSessionDiff);
883
+ const newFile = {
884
+ name: completedDiff.name,
885
+ contents: completedDiff.additionLines.join("")
886
+ };
887
+ if (completedDiff.lang != null) newFile.lang = completedDiff.lang;
888
+ const event = {
889
+ fileDiff: completedDiff,
890
+ editor,
891
+ originalFileDiff: externalDiff,
892
+ oldFile: completedDiff.type === "new" ? null : {
893
+ name: completedDiff.prevName ?? completedDiff.name,
894
+ contents: completedDiff.deletionLines.join("")
895
+ },
896
+ newFile,
897
+ lineAnnotations: sessionAnnotationsCurrent,
898
+ originalLineAnnotations: externalAnnotations
899
+ };
900
+ Object.freeze(event);
901
+ try {
902
+ editor.__emitEditComplete(event);
903
+ if (this.options.onEditComplete?.(event) === "accept") {
904
+ if (completedDiff.cacheKey != null && completedDiff.cacheKey === externalDiff.cacheKey) throw new Error("FileDiff.__completeEditSession: an accepted diff must not reuse the replaced diff cacheKey");
905
+ acceptedDiff = completedDiff;
906
+ acceptedOldFile = event.oldFile;
907
+ acceptedNewFile = event.newFile;
908
+ }
909
+ } catch (error) {
910
+ failed = true;
911
+ failure = error;
912
+ }
913
+ if (installResult && acceptedDiff != null) {
914
+ this.fileDiff = acceptedDiff;
915
+ if (this.additionFile != null) {
916
+ this.deletionFile = acceptedOldFile;
917
+ this.additionFile = acceptedNewFile;
918
+ }
919
+ if (sessionAnnotationsCurrent != null) this.lineAnnotations = sessionAnnotationsCurrent;
920
+ }
921
+ this.editSessionDiff = void 0;
922
+ this.editSessionAnnotations = void 0;
923
+ this.outgoingSessionDiff = void 0;
924
+ if (installResult && this.fileContainer != null) this.rerender();
925
+ if (failed) throw failure;
926
+ }
927
+ /**
928
+ * Run the session-end recompute: restore recompute-shaped hunks (a
650
929
  * context-only region collapses away, boundaries re-derive), preserve
651
930
  * expansion state best-effort via old-side anchors, and repaint through
652
931
  * the session render path — which also invalidates virtualized layout,
653
932
  * since nothing else does at exit now that editing does not flip
654
933
  * expandUnchanged. Marker-guarded and idempotent; CodeView also calls this
655
- * when reaping a session whose detach closure was consumed by a recycle.
934
+ * when ending a session whose detach closure was consumed by a recycle.
656
935
  * Safe on a cleaned-up instance: the recompute is pure metadata work and
657
936
  * the deferred rerender is enabled-guarded. Returns true when a recompute
658
937
  * ran.
659
938
  */
660
- completeEditSession() {
661
- const fileDiff = this.fileDiffCache;
939
+ finalizeEditSessionHunks() {
940
+ const fileDiff = this.getLatestDiff();
662
941
  if (fileDiff == null || fileDiff.editSessionDirty !== true) return false;
663
942
  const { collapsedContextThreshold = 1 } = this.options;
664
943
  const anchors = captureExpansionAnchors(fileDiff, this.hunksRenderer.getExpandedHunksMap(), collapsedContextThreshold);
@@ -669,22 +948,20 @@ var FileDiff = class {
669
948
  return true;
670
949
  }
671
950
  applyDocumentChange(textDocument, newLineAnnotations) {
951
+ const { editSessionDiff } = this;
952
+ if (editSessionDiff == null) throw new Error("FileDiff.applyDocumentChange: requires an active edit session");
953
+ this.detachAdditionLines();
954
+ this.hunksRenderer.beginEditSession(editSessionDiff);
672
955
  this.hunksRenderer.applyDocumentChange(textDocument);
673
- const fileDiff = this.hunksRenderer.diffCache;
674
- if (fileDiff != null) {
675
- const cacheKey = this.fileDiff?.cacheKey;
676
- if (cacheKey != null && fileDiff.cacheKey == null) fileDiff.cacheKey = cacheKey;
677
- this.fileDiff = fileDiff;
678
- }
679
- if (newLineAnnotations !== void 0 && newLineAnnotations !== this.lineAnnotations) {
680
- this.setLineAnnotations(newLineAnnotations);
681
- this.hunksRenderer.setLineAnnotations(this.lineAnnotations);
682
- this.renderAnnotations();
683
- }
956
+ if (newLineAnnotations != null) this.syncEditSessionAnnotationsFromEditor(newLineAnnotations);
684
957
  this.rerender();
685
958
  this.interactionManager.setSelectionDirty();
686
959
  }
687
960
  updateRenderCache(dirtyLines, themeType, options = {}) {
961
+ const { editSessionDiff } = this;
962
+ if (editSessionDiff == null) throw new Error("FileDiff.updateRenderCache: requires an active edit session");
963
+ this.detachAdditionLines();
964
+ this.hunksRenderer.beginEditSession(editSessionDiff);
688
965
  const { shouldRefreshDiffsView, lineCountChangeInFlight } = options;
689
966
  if (this.hunksRenderer.updateRenderCache(dirtyLines, themeType, lineCountChangeInFlight)) {
690
967
  if (this.refreshViewTimeout != null) {
@@ -706,8 +983,12 @@ var FileDiff = class {
706
983
  }, 150);
707
984
  }
708
985
  }
986
+ detachAdditionLines() {
987
+ const { editSessionDiff, fileDiff } = this;
988
+ if (editSessionDiff != null && (editSessionDiff.additionLines === fileDiff?.additionLines || editSessionDiff.additionLines === editSessionDiff.deletionLines)) editSessionDiff.additionLines = [...editSessionDiff.additionLines];
989
+ }
709
990
  isLineRenderable(lineNumber) {
710
- const fileDiff = this.fileDiffCache;
991
+ const fileDiff = this.getRenderedDiff();
711
992
  if (fileDiff == null) return true;
712
993
  const { expandUnchanged = false, collapsedContextThreshold = 1 } = this.options;
713
994
  return isAdditionLineRenderable({
@@ -718,7 +999,7 @@ var FileDiff = class {
718
999
  });
719
1000
  }
720
1001
  getNearestRenderableLine(lineNumber, direction) {
721
- const fileDiff = this.fileDiffCache;
1002
+ const fileDiff = this.getRenderedDiff();
722
1003
  if (fileDiff == null) return lineNumber;
723
1004
  const { expandUnchanged = false, collapsedContextThreshold = 1 } = this.options;
724
1005
  return getNearestRenderableAdditionLine({
@@ -730,7 +1011,7 @@ var FileDiff = class {
730
1011
  });
731
1012
  }
732
1013
  revealLine(lineNumber) {
733
- const fileDiff = this.fileDiffCache;
1014
+ const fileDiff = this.getRenderedDiff();
734
1015
  const { expandUnchanged = false, collapsedContextThreshold = 1, expansionLineCount = 100 } = this.options;
735
1016
  if (fileDiff == null || fileDiff.isPartial || expandUnchanged) return false;
736
1017
  const expandedHunks = this.hunksRenderer.getExpandedHunksMap();
@@ -865,7 +1146,7 @@ var FileDiff = class {
865
1146
  this.hasAdoptedThemeCSS = false;
866
1147
  this.unsafeCSSStyle = void 0;
867
1148
  this.appliedUnsafeCSS = void 0;
868
- this.lastRenderedHeaderHTML = void 0;
1149
+ this.headerCache.lastRenderedHTML = void 0;
869
1150
  this.lastRowCount = void 0;
870
1151
  this.mounted = false;
871
1152
  }
@@ -909,15 +1190,17 @@ var FileDiff = class {
909
1190
  }
910
1191
  const staleAnnotations = new Map(this.annotationCache);
911
1192
  const { renderAnnotation } = this.options;
912
- if (renderAnnotation != null && this.lineAnnotations.length > 0) for (const [index, annotation] of this.lineAnnotations.entries()) {
913
- const id = `${index}-${getLineAnnotationName(annotation)}`;
1193
+ const lineAnnotations = this.getLatestAnnotations();
1194
+ if (renderAnnotation != null && lineAnnotations.length > 0) for (const [index, annotation] of lineAnnotations.entries()) {
1195
+ const name = this.getAnnotationSlotName(annotation);
1196
+ const id = `${index}-${name}`;
914
1197
  let cache = this.annotationCache.get(id);
915
1198
  if (cache == null || !areDiffLineAnnotationsEqual(annotation, cache.annotation)) {
916
1199
  cache?.element.remove();
917
1200
  const content = renderAnnotation(annotation);
918
1201
  if (content == null) continue;
919
1202
  cache = {
920
- element: createAnnotationWrapperNode(getLineAnnotationName(annotation)),
1203
+ element: createAnnotationWrapperNode(name),
921
1204
  annotation
922
1205
  };
923
1206
  cache.element.appendChild(content);
@@ -958,7 +1241,7 @@ var FileDiff = class {
958
1241
  if (containerChanged) this.emitPostRender(true);
959
1242
  this.fileContainer = nextContainer;
960
1243
  if (previousContainer != null && containerChanged) {
961
- this.lastRenderedHeaderHTML = void 0;
1244
+ this.headerCache.lastRenderedHTML = void 0;
962
1245
  this.headerElement = void 0;
963
1246
  }
964
1247
  if (parentNode != null && this.fileContainer.parentNode !== parentNode) parentNode.appendChild(this.fileContainer);
@@ -1017,14 +1300,15 @@ var FileDiff = class {
1017
1300
  else if (child.hasAttribute("data-additions")) this.codeAdditions = child;
1018
1301
  }
1019
1302
  }
1020
- applyHeaderToDOM(headerAST, container) {
1303
+ applyHeaderToDOM(headerAST, container, fileDiff) {
1021
1304
  this.cleanupErrorWrapper();
1022
1305
  this.placeHolder?.remove();
1023
1306
  this.placeHolder = void 0;
1024
- const { fileDiff } = this;
1025
- const headerHTML = this.cachedHeaderHTML ?? toHtml(headerAST);
1026
- this.cachedHeaderHTML = headerHTML;
1027
- if (headerHTML !== this.lastRenderedHeaderHTML) {
1307
+ const { headerCache: { fileDiff: cachedHeaderDiff, html: cachedHeaderHTML, lastRenderedHTML }, editSessionDiff } = this;
1308
+ const headerHTML = (fileDiff !== editSessionDiff && areDiffTargetsEqual(cachedHeaderDiff, fileDiff) ? cachedHeaderHTML : void 0) ?? toHtml(headerAST);
1309
+ this.headerCache.html = headerHTML;
1310
+ this.headerCache.fileDiff = fileDiff;
1311
+ if (headerHTML !== lastRenderedHTML) {
1028
1312
  const tempDiv = document.createElement("div");
1029
1313
  tempDiv.innerHTML = headerHTML;
1030
1314
  const newHeader = tempDiv.firstElementChild;
@@ -1032,9 +1316,9 @@ var FileDiff = class {
1032
1316
  if (this.headerElement != null) container.shadowRoot?.replaceChild(newHeader, this.headerElement);
1033
1317
  else container.shadowRoot?.prepend(newHeader);
1034
1318
  this.headerElement = newHeader;
1035
- this.lastRenderedHeaderHTML = headerHTML;
1319
+ this.headerCache.lastRenderedHTML = headerHTML;
1036
1320
  }
1037
- if (this.isContainerManaged || fileDiff == null) return;
1321
+ if (this.isContainerManaged) return;
1038
1322
  const { renderCustomHeader, renderHeaderPrefix, renderHeaderFilenameSuffix, renderHeaderMetadata } = this.options;
1039
1323
  if (renderCustomHeader != null) {
1040
1324
  const content = renderCustomHeader(fileDiff) ?? void 0;
@@ -1056,6 +1340,10 @@ var FileDiff = class {
1056
1340
  this.headerCustom?.remove();
1057
1341
  this.headerCustom = void 0;
1058
1342
  }
1343
+ clearReusableHeader() {
1344
+ this.headerCache.html = void 0;
1345
+ this.headerCache.fileDiff = void 0;
1346
+ }
1059
1347
  clearHeaderSlots() {
1060
1348
  this.headerPrefix?.remove();
1061
1349
  this.headerFilenameSuffix?.remove();
@@ -1235,7 +1523,7 @@ var FileDiff = class {
1235
1523
  else if (shouldReplace) pre.replaceChildren(...codeElements);
1236
1524
  this.lastRowCount = result.rowCount;
1237
1525
  }
1238
- applyPartialRender({ previousRenderRange, renderRange }) {
1526
+ applyPartialRender({ fileDiff, previousRenderRange, renderRange }) {
1239
1527
  const { pre, codeUnified, codeAdditions, codeDeletions, options: { diffStyle = "split" } } = this;
1240
1528
  if (pre == null || previousRenderRange == null || renderRange == null || !Number.isFinite(previousRenderRange.totalLines) || !Number.isFinite(renderRange.totalLines) || this.lastRowCount == null) return false;
1241
1529
  const codeElements = this.getCodeColumns(diffStyle, codeUnified, codeDeletions, codeAdditions);
@@ -1262,8 +1550,8 @@ var FileDiff = class {
1262
1550
  if (this.lastRowCount < trimResult) throw new Error("FileDiff.applyPartialRender: trimmed beyond DOM row count");
1263
1551
  let rowCount = this.lastRowCount - trimResult;
1264
1552
  const renderChunk = (startingLine, totalLines) => {
1265
- if (totalLines <= 0 || this.fileDiff == null) return;
1266
- return this.hunksRenderer.renderDiff(this.fileDiff, {
1553
+ if (totalLines <= 0) return;
1554
+ return this.hunksRenderer.renderDiff(fileDiff, {
1267
1555
  startingLine,
1268
1556
  totalLines,
1269
1557
  bufferBefore: 0,
@@ -1280,6 +1568,7 @@ var FileDiff = class {
1280
1568
  else if (diffStyle === "split" && Array.isArray(codeElements)) this.insertPartialHTML(diffStyle, codeElements, result, insertPosition);
1281
1569
  else throw new Error("FileDiff.applyPartialRender.applyChunk: invalid chunk application");
1282
1570
  rowCount += result.rowCount;
1571
+ this.renderedDiff = result.fileDiff;
1283
1572
  };
1284
1573
  this.cleanupErrorWrapper();
1285
1574
  applyChunk(prependResult, "afterbegin");
@@ -1302,8 +1591,9 @@ var FileDiff = class {
1302
1591
  } else throw new Error("FileDiff.insertPartialHTML: Invalid argument composition");
1303
1592
  }
1304
1593
  refreshSplitDiffView() {
1305
- if (this.options.diffStyle !== "split") return;
1306
- const hunksResult = this.hunksRenderer.renderDiff(this.fileDiff, this.renderRange);
1594
+ const fileDiff = this.getLatestDiff();
1595
+ if (this.options.diffStyle !== "split" || fileDiff == null) return;
1596
+ const hunksResult = this.hunksRenderer.renderDiff(fileDiff, this.renderRange);
1307
1597
  if (hunksResult == null) return;
1308
1598
  const columns = this.getCodeColumns("split", this.codeUnified, this.codeDeletions, this.codeAdditions);
1309
1599
  if (!Array.isArray(columns)) return;
@@ -1320,10 +1610,12 @@ var FileDiff = class {
1320
1610
  };
1321
1611
  applyLineType("deletions", columns[0]);
1322
1612
  applyLineType("additions", columns[1]);
1613
+ this.renderedDiff = hunksResult.fileDiff;
1323
1614
  }
1324
1615
  refreshUnifiedDiffView() {
1325
- if (this.options.diffStyle !== "unified") return;
1326
- const hunksResult = this.hunksRenderer.renderDiff(this.fileDiff, this.renderRange);
1616
+ const fileDiff = this.getLatestDiff();
1617
+ if (this.options.diffStyle !== "unified" || fileDiff == null) return;
1618
+ const hunksResult = this.hunksRenderer.renderDiff(fileDiff, this.renderRange);
1327
1619
  if (hunksResult == null) return;
1328
1620
  const columns = this.getCodeColumns("unified", this.codeUnified, this.codeDeletions, this.codeAdditions);
1329
1621
  if (columns == null || Array.isArray(columns)) return;
@@ -1336,6 +1628,7 @@ var FileDiff = class {
1336
1628
  this.applyRowSpan("unified", columns, hunksResult.rowCount);
1337
1629
  this.lastRowCount = hunksResult.rowCount;
1338
1630
  }
1631
+ this.renderedDiff = hunksResult.fileDiff;
1339
1632
  };
1340
1633
  if (this.shouldGuardRebuildScroll()) guardWebKitScrollDuringRebuild(this.pre, applyColumns);
1341
1634
  else applyColumns();
@@ -1626,6 +1919,13 @@ var FileDiff = class {
1626
1919
  this.errorWrapper = void 0;
1627
1920
  }
1628
1921
  };
1922
+ function getAdditionFile(fileDiff) {
1923
+ return {
1924
+ name: fileDiff.name,
1925
+ lang: fileDiff.lang,
1926
+ contents: fileDiff.additionLines.join("")
1927
+ };
1928
+ }
1629
1929
  function areOptionalFilesEqual(fileA, fileB) {
1630
1930
  if (fileA == null || fileB == null) return fileA == null && fileB == null;
1631
1931
  return areFilesEqual(fileA, fileB);