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

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 (705) hide show
  1. package/README.md +15 -15
  2. package/dist/components/CodeView.d.ts +103 -15
  3. package/dist/components/CodeView.d.ts.map +1 -1
  4. package/dist/components/CodeView.js +335 -51
  5. package/dist/components/CodeView.js.map +1 -1
  6. package/dist/components/File.d.ts +12 -8
  7. package/dist/components/File.d.ts.map +1 -1
  8. package/dist/components/File.js +103 -40
  9. package/dist/components/File.js.map +1 -1
  10. package/dist/components/FileDiff.d.ts +82 -36
  11. package/dist/components/FileDiff.d.ts.map +1 -1
  12. package/dist/components/FileDiff.js +382 -96
  13. package/dist/components/FileDiff.js.map +1 -1
  14. package/dist/components/FileStream.d.ts +0 -1
  15. package/dist/components/FileStream.d.ts.map +1 -1
  16. package/dist/components/FileStream.js +10 -7
  17. package/dist/components/FileStream.js.map +1 -1
  18. package/dist/components/UnresolvedFile.d.ts +3 -3
  19. package/dist/components/UnresolvedFile.d.ts.map +1 -1
  20. package/dist/components/UnresolvedFile.js +8 -6
  21. package/dist/components/UnresolvedFile.js.map +1 -1
  22. package/dist/components/VirtualizedFile.d.ts +8 -4
  23. package/dist/components/VirtualizedFile.d.ts.map +1 -1
  24. package/dist/components/VirtualizedFile.js +118 -44
  25. package/dist/components/VirtualizedFile.js.map +1 -1
  26. package/dist/components/VirtualizedFileDiff.d.ts +36 -9
  27. package/dist/components/VirtualizedFileDiff.d.ts.map +1 -1
  28. package/dist/components/VirtualizedFileDiff.js +371 -120
  29. package/dist/components/VirtualizedFileDiff.js.map +1 -1
  30. package/dist/components/Virtualizer.d.ts +4 -1
  31. package/dist/components/Virtualizer.d.ts.map +1 -1
  32. package/dist/components/Virtualizer.js +47 -29
  33. package/dist/components/Virtualizer.js.map +1 -1
  34. package/dist/components/VirtulizerDevelopment.d.ts.map +1 -1
  35. package/dist/components/web-components.d.ts.map +1 -1
  36. package/dist/components/web-components.js +2 -3
  37. package/dist/components/web-components.js.map +1 -1
  38. package/dist/constants.d.ts +5 -2
  39. package/dist/constants.d.ts.map +1 -1
  40. package/dist/constants.js +5 -2
  41. package/dist/constants.js.map +1 -1
  42. package/dist/editor/command.d.ts +3 -2
  43. package/dist/editor/command.d.ts.map +1 -1
  44. package/dist/editor/command.js +29 -6
  45. package/dist/editor/command.js.map +1 -1
  46. package/dist/editor/editStack.d.ts +12 -2
  47. package/dist/editor/editStack.d.ts.map +1 -1
  48. package/dist/editor/editStack.js +57 -16
  49. package/dist/editor/editStack.js.map +1 -1
  50. package/dist/editor/editor.d.ts +91 -8
  51. package/dist/editor/editor.d.ts.map +1 -1
  52. package/dist/editor/editor.js +1951 -709
  53. package/dist/editor/editor.js.map +1 -1
  54. package/dist/editor/editor2.js +6 -0
  55. package/dist/editor/editor2.js.map +1 -0
  56. package/dist/editor/index.d.ts +4 -2
  57. package/dist/editor/index.js +1 -2
  58. package/dist/editor/languages.d.ts +26 -0
  59. package/dist/editor/languages.d.ts.map +1 -0
  60. package/dist/editor/languages.js +363 -0
  61. package/dist/editor/languages.js.map +1 -0
  62. package/dist/editor/lineAnnotations.d.ts +2 -1
  63. package/dist/editor/lineAnnotations.d.ts.map +1 -1
  64. package/dist/editor/lineAnnotations.js +193 -13
  65. package/dist/editor/lineAnnotations.js.map +1 -1
  66. package/dist/editor/marker.d.ts +38 -0
  67. package/dist/editor/marker.d.ts.map +1 -0
  68. package/dist/editor/marker.js +245 -0
  69. package/dist/editor/marker.js.map +1 -0
  70. package/dist/editor/matchBrackets.d.ts +9 -0
  71. package/dist/editor/matchBrackets.d.ts.map +1 -0
  72. package/dist/editor/matchBrackets.js +138 -0
  73. package/dist/editor/matchBrackets.js.map +1 -0
  74. package/dist/editor/pieceTable.d.ts +15 -7
  75. package/dist/editor/pieceTable.d.ts.map +1 -1
  76. package/dist/editor/pieceTable.js +306 -190
  77. package/dist/editor/pieceTable.js.map +1 -1
  78. package/dist/editor/platform.d.ts +8 -1
  79. package/dist/editor/platform.d.ts.map +1 -1
  80. package/dist/editor/platform.js +18 -5
  81. package/dist/editor/platform.js.map +1 -1
  82. package/dist/editor/popover.d.ts +65 -0
  83. package/dist/editor/popover.d.ts.map +1 -0
  84. package/dist/editor/popover.js +191 -0
  85. package/dist/editor/popover.js.map +1 -0
  86. package/dist/editor/searchPanel.d.ts +17 -7
  87. package/dist/editor/searchPanel.d.ts.map +1 -1
  88. package/dist/editor/searchPanel.js +268 -169
  89. package/dist/editor/searchPanel.js.map +1 -1
  90. package/dist/editor/selection.d.ts +101 -16
  91. package/dist/editor/selection.d.ts.map +1 -1
  92. package/dist/editor/selection.js +863 -137
  93. package/dist/editor/selection.js.map +1 -1
  94. package/dist/editor/selectionAction.d.ts +46 -0
  95. package/dist/editor/selectionAction.d.ts.map +1 -0
  96. package/dist/editor/selectionAction.js +64 -0
  97. package/dist/editor/selectionAction.js.map +1 -0
  98. package/dist/editor/sprite.d.ts +8 -0
  99. package/dist/editor/sprite.d.ts.map +1 -0
  100. package/dist/editor/sprite.js +45 -0
  101. package/dist/editor/sprite.js.map +1 -0
  102. package/dist/editor/stateStorage.d.ts +15 -0
  103. package/dist/editor/stateStorage.d.ts.map +1 -0
  104. package/dist/editor/stateStorage.js +65 -0
  105. package/dist/editor/stateStorage.js.map +1 -0
  106. package/dist/editor/textDocument.d.ts +21 -83
  107. package/dist/editor/textDocument.d.ts.map +1 -1
  108. package/dist/editor/textDocument.js +117 -48
  109. package/dist/editor/textDocument.js.map +1 -1
  110. package/dist/editor/textMeasure.d.ts +31 -2
  111. package/dist/editor/textMeasure.d.ts.map +1 -1
  112. package/dist/editor/textMeasure.js +122 -21
  113. package/dist/editor/textMeasure.js.map +1 -1
  114. package/dist/editor/{tokenzier.d.ts → tokenizer.d.ts} +16 -12
  115. package/dist/editor/tokenizer.d.ts.map +1 -0
  116. package/dist/editor/tokenizer.js +518 -0
  117. package/dist/editor/tokenizer.js.map +1 -0
  118. package/dist/editor/utils.d.ts +6 -1
  119. package/dist/editor/utils.d.ts.map +1 -1
  120. package/dist/editor/utils.js +34 -3
  121. package/dist/editor/utils.js.map +1 -1
  122. package/dist/highlighter/languages/areLanguagesAttached.d.ts.map +1 -1
  123. package/dist/highlighter/languages/areLanguagesAttached.js +1 -2
  124. package/dist/highlighter/languages/areLanguagesAttached.js.map +1 -1
  125. package/dist/highlighter/languages/attachResolvedLanguages.d.ts +0 -2
  126. package/dist/highlighter/languages/attachResolvedLanguages.d.ts.map +1 -1
  127. package/dist/highlighter/languages/attachResolvedLanguages.js +1 -2
  128. package/dist/highlighter/languages/attachResolvedLanguages.js.map +1 -1
  129. package/dist/highlighter/languages/cleanUpResolvedLanguages.d.ts.map +1 -1
  130. package/dist/highlighter/languages/cleanUpResolvedLanguages.js +1 -2
  131. package/dist/highlighter/languages/cleanUpResolvedLanguages.js.map +1 -1
  132. package/dist/highlighter/languages/constants.d.ts +0 -1
  133. package/dist/highlighter/languages/constants.d.ts.map +1 -1
  134. package/dist/highlighter/languages/constants.js +1 -1
  135. package/dist/highlighter/languages/constants.js.map +1 -1
  136. package/dist/highlighter/languages/getResolvedLanguages.d.ts +0 -2
  137. package/dist/highlighter/languages/getResolvedLanguages.d.ts.map +1 -1
  138. package/dist/highlighter/languages/getResolvedLanguages.js +1 -2
  139. package/dist/highlighter/languages/getResolvedLanguages.js.map +1 -1
  140. package/dist/highlighter/languages/getResolvedOrResolveLanguage.d.ts +0 -2
  141. package/dist/highlighter/languages/getResolvedOrResolveLanguage.d.ts.map +1 -1
  142. package/dist/highlighter/languages/getResolvedOrResolveLanguage.js +1 -2
  143. package/dist/highlighter/languages/getResolvedOrResolveLanguage.js.map +1 -1
  144. package/dist/highlighter/languages/hasResolvedLanguages.d.ts.map +1 -1
  145. package/dist/highlighter/languages/hasResolvedLanguages.js +1 -2
  146. package/dist/highlighter/languages/hasResolvedLanguages.js.map +1 -1
  147. package/dist/highlighter/languages/registerCustomLanguage.d.ts +0 -1
  148. package/dist/highlighter/languages/registerCustomLanguage.d.ts.map +1 -1
  149. package/dist/highlighter/languages/registerCustomLanguage.js +1 -2
  150. package/dist/highlighter/languages/registerCustomLanguage.js.map +1 -1
  151. package/dist/highlighter/languages/resolveLanguage.d.ts +0 -2
  152. package/dist/highlighter/languages/resolveLanguage.d.ts.map +1 -1
  153. package/dist/highlighter/languages/resolveLanguage.js +4 -5
  154. package/dist/highlighter/languages/resolveLanguage.js.map +1 -1
  155. package/dist/highlighter/languages/resolveLanguages.d.ts +0 -2
  156. package/dist/highlighter/languages/resolveLanguages.d.ts.map +1 -1
  157. package/dist/highlighter/languages/resolveLanguages.js +1 -2
  158. package/dist/highlighter/languages/resolveLanguages.js.map +1 -1
  159. package/dist/highlighter/shared_highlighter.d.ts.map +1 -1
  160. package/dist/highlighter/shared_highlighter.js +6 -33
  161. package/dist/highlighter/shared_highlighter.js.map +1 -1
  162. package/dist/highlighter/themes/areThemesAttached.d.ts.map +1 -1
  163. package/dist/highlighter/themes/areThemesAttached.js +1 -2
  164. package/dist/highlighter/themes/areThemesAttached.js.map +1 -1
  165. package/dist/highlighter/themes/attachResolvedThemes.d.ts.map +1 -1
  166. package/dist/highlighter/themes/attachResolvedThemes.js +5 -5
  167. package/dist/highlighter/themes/attachResolvedThemes.js.map +1 -1
  168. package/dist/highlighter/themes/cleanUpResolvedThemes.d.ts.map +1 -1
  169. package/dist/highlighter/themes/cleanUpResolvedThemes.js +4 -4
  170. package/dist/highlighter/themes/cleanUpResolvedThemes.js.map +1 -1
  171. package/dist/highlighter/themes/constants.d.ts +1 -7
  172. package/dist/highlighter/themes/constants.d.ts.map +1 -1
  173. package/dist/highlighter/themes/constants.js +2 -5
  174. package/dist/highlighter/themes/constants.js.map +1 -1
  175. package/dist/highlighter/themes/getResolvedOrResolveTheme.d.ts.map +1 -1
  176. package/dist/highlighter/themes/getResolvedOrResolveTheme.js +3 -4
  177. package/dist/highlighter/themes/getResolvedOrResolveTheme.js.map +1 -1
  178. package/dist/highlighter/themes/getResolvedThemes.d.ts.map +1 -1
  179. package/dist/highlighter/themes/getResolvedThemes.js +3 -10
  180. package/dist/highlighter/themes/getResolvedThemes.js.map +1 -1
  181. package/dist/highlighter/themes/hasResolvedThemes.d.ts.map +1 -1
  182. package/dist/highlighter/themes/hasResolvedThemes.js +3 -5
  183. package/dist/highlighter/themes/hasResolvedThemes.js.map +1 -1
  184. package/dist/highlighter/themes/registerCustomCSSVariableTheme.d.ts.map +1 -1
  185. package/dist/highlighter/themes/registerCustomCSSVariableTheme.js +2 -3
  186. package/dist/highlighter/themes/registerCustomCSSVariableTheme.js.map +1 -1
  187. package/dist/highlighter/themes/registerCustomTheme.d.ts +5 -3
  188. package/dist/highlighter/themes/registerCustomTheme.d.ts.map +1 -1
  189. package/dist/highlighter/themes/registerCustomTheme.js +16 -7
  190. package/dist/highlighter/themes/registerCustomTheme.js.map +1 -1
  191. package/dist/highlighter/themes/resolveTheme.d.ts.map +1 -1
  192. package/dist/highlighter/themes/resolveTheme.js +7 -29
  193. package/dist/highlighter/themes/resolveTheme.js.map +1 -1
  194. package/dist/highlighter/themes/resolveThemes.d.ts.map +1 -1
  195. package/dist/highlighter/themes/resolveThemes.js +6 -14
  196. package/dist/highlighter/themes/resolveThemes.js.map +1 -1
  197. package/dist/highlighter/themes/themeResolution.d.ts +8 -0
  198. package/dist/highlighter/themes/themeResolution.d.ts.map +1 -0
  199. package/dist/highlighter/themes/themeResolution.js +21 -0
  200. package/dist/highlighter/themes/themeResolution.js.map +1 -0
  201. package/dist/highlighter/themes/themeResolver.d.ts +8 -0
  202. package/dist/highlighter/themes/themeResolver.d.ts.map +1 -0
  203. package/dist/highlighter/themes/themeResolver.js +7 -0
  204. package/dist/highlighter/themes/themeResolver.js.map +1 -0
  205. package/dist/index.d.ts +16 -14
  206. package/dist/index.js +13 -12
  207. package/dist/managers/InteractionManager.d.ts +20 -2
  208. package/dist/managers/InteractionManager.d.ts.map +1 -1
  209. package/dist/managers/InteractionManager.js +159 -83
  210. package/dist/managers/InteractionManager.js.map +1 -1
  211. package/dist/managers/ResizeManager.d.ts +10 -2
  212. package/dist/managers/ResizeManager.d.ts.map +1 -1
  213. package/dist/managers/ResizeManager.js +35 -15
  214. package/dist/managers/ResizeManager.js.map +1 -1
  215. package/dist/managers/ScrollSyncManager.d.ts.map +1 -1
  216. package/dist/managers/ScrollSyncManager.js +1 -1
  217. package/dist/managers/ScrollSyncManager.js.map +1 -1
  218. package/dist/managers/UniversalRenderingManager.d.ts +2 -1
  219. package/dist/managers/UniversalRenderingManager.d.ts.map +1 -1
  220. package/dist/managers/UniversalRenderingManager.js +8 -3
  221. package/dist/managers/UniversalRenderingManager.js.map +1 -1
  222. package/dist/node_modules/.pnpm/@types_hast@3.0.4/node_modules/@types/hast/index.d.ts +228 -0
  223. package/dist/node_modules/.pnpm/@types_hast@3.0.4/node_modules/@types/hast/index.d.ts.map +1 -0
  224. package/dist/node_modules/.pnpm/@types_unist@3.0.3/node_modules/@types/unist/index.d.ts +84 -0
  225. package/dist/node_modules/.pnpm/@types_unist@3.0.3/node_modules/@types/unist/index.d.ts.map +1 -0
  226. package/dist/react/CodeView.d.ts +26 -2
  227. package/dist/react/CodeView.d.ts.map +1 -1
  228. package/dist/react/CodeView.js +90 -30
  229. package/dist/react/CodeView.js.map +1 -1
  230. package/dist/react/EditContext.d.ts +15 -0
  231. package/dist/react/EditContext.d.ts.map +1 -0
  232. package/dist/react/EditContext.js +23 -0
  233. package/dist/react/EditContext.js.map +1 -0
  234. package/dist/react/File.d.ts +1 -0
  235. package/dist/react/File.d.ts.map +1 -1
  236. package/dist/react/File.js +4 -6
  237. package/dist/react/File.js.map +1 -1
  238. package/dist/react/FileDiff.d.ts +1 -0
  239. package/dist/react/FileDiff.d.ts.map +1 -1
  240. package/dist/react/FileDiff.js +4 -6
  241. package/dist/react/FileDiff.js.map +1 -1
  242. package/dist/react/MultiFileDiff.d.ts +4 -4
  243. package/dist/react/MultiFileDiff.d.ts.map +1 -1
  244. package/dist/react/MultiFileDiff.js +4 -6
  245. package/dist/react/MultiFileDiff.js.map +1 -1
  246. package/dist/react/PatchDiff.d.ts +1 -0
  247. package/dist/react/PatchDiff.d.ts.map +1 -1
  248. package/dist/react/PatchDiff.js +4 -6
  249. package/dist/react/PatchDiff.js.map +1 -1
  250. package/dist/react/UnresolvedFile.d.ts +2 -1
  251. package/dist/react/UnresolvedFile.d.ts.map +1 -1
  252. package/dist/react/UnresolvedFile.js +4 -6
  253. package/dist/react/UnresolvedFile.js.map +1 -1
  254. package/dist/react/Virtualizer.d.ts.map +1 -1
  255. package/dist/react/Virtualizer.js +2 -5
  256. package/dist/react/Virtualizer.js.map +1 -1
  257. package/dist/react/WorkerPoolContext.d.ts +0 -1
  258. package/dist/react/WorkerPoolContext.d.ts.map +1 -1
  259. package/dist/react/WorkerPoolContext.js +2 -5
  260. package/dist/react/WorkerPoolContext.js.map +1 -1
  261. package/dist/react/constants.d.ts.map +1 -1
  262. package/dist/react/constants.js +1 -1
  263. package/dist/react/constants.js.map +1 -1
  264. package/dist/react/index.d.ts +3 -3
  265. package/dist/react/index.js +2 -3
  266. package/dist/react/jsx.d.ts +0 -1
  267. package/dist/react/jsx.d.ts.map +1 -1
  268. package/dist/react/types.d.ts +2 -0
  269. package/dist/react/types.d.ts.map +1 -1
  270. package/dist/react/types.js +1 -0
  271. package/dist/react/utils/renderDiffChildren.d.ts +2 -0
  272. package/dist/react/utils/renderDiffChildren.d.ts.map +1 -1
  273. package/dist/react/utils/renderDiffChildren.js +18 -11
  274. package/dist/react/utils/renderDiffChildren.js.map +1 -1
  275. package/dist/react/utils/renderFileChildren.d.ts +2 -0
  276. package/dist/react/utils/renderFileChildren.d.ts.map +1 -1
  277. package/dist/react/utils/renderFileChildren.js +18 -11
  278. package/dist/react/utils/renderFileChildren.js.map +1 -1
  279. package/dist/react/utils/templateRender.d.ts.map +1 -1
  280. package/dist/react/utils/templateRender.js +1 -2
  281. package/dist/react/utils/templateRender.js.map +1 -1
  282. package/dist/react/utils/useFileDiffInstance.d.ts.map +1 -1
  283. package/dist/react/utils/useFileDiffInstance.js +10 -18
  284. package/dist/react/utils/useFileDiffInstance.js.map +1 -1
  285. package/dist/react/utils/useFileInstance.d.ts.map +1 -1
  286. package/dist/react/utils/useFileInstance.js +3 -7
  287. package/dist/react/utils/useFileInstance.js.map +1 -1
  288. package/dist/react/utils/useStableCallback.d.ts.map +1 -1
  289. package/dist/react/utils/useStableCallback.js +1 -2
  290. package/dist/react/utils/useStableCallback.js.map +1 -1
  291. package/dist/react/utils/useUnresolvedFileInstance.d.ts.map +1 -1
  292. package/dist/react/utils/useUnresolvedFileInstance.js +10 -11
  293. package/dist/react/utils/useUnresolvedFileInstance.js.map +1 -1
  294. package/dist/renderers/DiffHunksRenderer.d.ts +30 -4
  295. package/dist/renderers/DiffHunksRenderer.d.ts.map +1 -1
  296. package/dist/renderers/DiffHunksRenderer.js +313 -45
  297. package/dist/renderers/DiffHunksRenderer.js.map +1 -1
  298. package/dist/renderers/FileRenderer.d.ts +7 -6
  299. package/dist/renderers/FileRenderer.d.ts.map +1 -1
  300. package/dist/renderers/FileRenderer.js +113 -56
  301. package/dist/renderers/FileRenderer.js.map +1 -1
  302. package/dist/renderers/UnresolvedFileHunksRenderer.d.ts +1 -2
  303. package/dist/renderers/UnresolvedFileHunksRenderer.d.ts.map +1 -1
  304. package/dist/renderers/UnresolvedFileHunksRenderer.js +1 -2
  305. package/dist/renderers/UnresolvedFileHunksRenderer.js.map +1 -1
  306. package/dist/shiki-stream/index.js +1 -2
  307. package/dist/shiki-stream/stream.d.ts +0 -1
  308. package/dist/shiki-stream/stream.d.ts.map +1 -1
  309. package/dist/shiki-stream/stream.js +1 -2
  310. package/dist/shiki-stream/stream.js.map +1 -1
  311. package/dist/shiki-stream/tokenizer.d.ts.map +1 -1
  312. package/dist/shiki-stream/tokenizer.js +1 -1
  313. package/dist/shiki-stream/tokenizer.js.map +1 -1
  314. package/dist/shiki-stream/types.d.ts +0 -1
  315. package/dist/shiki-stream/types.d.ts.map +1 -1
  316. package/dist/sprite.d.ts.map +1 -1
  317. package/dist/sprite.js +1 -1
  318. package/dist/ssr/FileDiffReact.d.ts.map +1 -1
  319. package/dist/ssr/FileDiffReact.js +4 -7
  320. package/dist/ssr/FileDiffReact.js.map +1 -1
  321. package/dist/ssr/index.d.ts +2 -2
  322. package/dist/ssr/index.js +1 -2
  323. package/dist/ssr/preloadDiffs.d.ts +12 -11
  324. package/dist/ssr/preloadDiffs.d.ts.map +1 -1
  325. package/dist/ssr/preloadDiffs.js +16 -9
  326. package/dist/ssr/preloadDiffs.js.map +1 -1
  327. package/dist/ssr/preloadFile.d.ts.map +1 -1
  328. package/dist/ssr/preloadFile.js +1 -2
  329. package/dist/ssr/preloadFile.js.map +1 -1
  330. package/dist/ssr/preloadPatchFile.d.ts.map +1 -1
  331. package/dist/ssr/preloadPatchFile.js +2 -3
  332. package/dist/ssr/preloadPatchFile.js.map +1 -1
  333. package/dist/ssr/renderHTML.d.ts +1 -1
  334. package/dist/ssr/renderHTML.d.ts.map +1 -1
  335. package/dist/ssr/renderHTML.js +1 -2
  336. package/dist/ssr/renderHTML.js.map +1 -1
  337. package/dist/string-import.d.ts +4 -0
  338. package/dist/string-import.d.ts.map +1 -1
  339. package/dist/style.js +3 -3
  340. package/dist/style.js.map +1 -1
  341. package/dist/types.d.ts +278 -31
  342. package/dist/types.d.ts.map +1 -1
  343. package/dist/utils/applyLineTextWithNewline.d.ts +5 -0
  344. package/dist/utils/applyLineTextWithNewline.d.ts.map +1 -0
  345. package/dist/utils/applyLineTextWithNewline.js +11 -0
  346. package/dist/utils/applyLineTextWithNewline.js.map +1 -0
  347. package/dist/utils/areDiffLineAnnotationsEqual.d.ts.map +1 -1
  348. package/dist/utils/areDiffLineAnnotationsEqual.js +1 -1
  349. package/dist/utils/areDiffLineAnnotationsEqual.js.map +1 -1
  350. package/dist/utils/areDiffRenderOptionsEqual.d.ts.map +1 -1
  351. package/dist/utils/areDiffRenderOptionsEqual.js +1 -2
  352. package/dist/utils/areDiffRenderOptionsEqual.js.map +1 -1
  353. package/dist/utils/areDiffTargetsEqual.d.ts.map +1 -1
  354. package/dist/utils/areDiffTargetsEqual.js +1 -1
  355. package/dist/utils/areDiffTargetsEqual.js.map +1 -1
  356. package/dist/utils/areFileRenderOptionsEqual.d.ts.map +1 -1
  357. package/dist/utils/areFileRenderOptionsEqual.js +1 -2
  358. package/dist/utils/areFileRenderOptionsEqual.js.map +1 -1
  359. package/dist/utils/areFilesEqual.d.ts.map +1 -1
  360. package/dist/utils/areFilesEqual.js +1 -1
  361. package/dist/utils/areFilesEqual.js.map +1 -1
  362. package/dist/utils/areHunkDataEqual.d.ts.map +1 -1
  363. package/dist/utils/areHunkDataEqual.js +2 -2
  364. package/dist/utils/areHunkDataEqual.js.map +1 -1
  365. package/dist/utils/areLineAnnotationsEqual.d.ts.map +1 -1
  366. package/dist/utils/areLineAnnotationsEqual.js +1 -1
  367. package/dist/utils/areLineAnnotationsEqual.js.map +1 -1
  368. package/dist/utils/areManagedSnapshotsEqual.d.ts +2 -2
  369. package/dist/utils/areManagedSnapshotsEqual.d.ts.map +1 -1
  370. package/dist/utils/areManagedSnapshotsEqual.js +6 -1
  371. package/dist/utils/areManagedSnapshotsEqual.js.map +1 -1
  372. package/dist/utils/areMergeConflictActionsEqual.d.ts.map +1 -1
  373. package/dist/utils/areMergeConflictActionsEqual.js +1 -1
  374. package/dist/utils/areMergeConflictActionsEqual.js.map +1 -1
  375. package/dist/utils/areObjectsEqual.d.ts.map +1 -1
  376. package/dist/utils/areObjectsEqual.js +1 -1
  377. package/dist/utils/areObjectsEqual.js.map +1 -1
  378. package/dist/utils/areOptionsEqual.d.ts +0 -2
  379. package/dist/utils/areOptionsEqual.d.ts.map +1 -1
  380. package/dist/utils/areOptionsEqual.js +1 -2
  381. package/dist/utils/areOptionsEqual.js.map +1 -1
  382. package/dist/utils/arePrePropertiesEqual.d.ts.map +1 -1
  383. package/dist/utils/arePrePropertiesEqual.js +1 -1
  384. package/dist/utils/arePrePropertiesEqual.js.map +1 -1
  385. package/dist/utils/areRenderRangesEqual.d.ts.map +1 -1
  386. package/dist/utils/areRenderRangesEqual.js +1 -1
  387. package/dist/utils/areRenderRangesEqual.js.map +1 -1
  388. package/dist/utils/areSelectionPointsEqual.d.ts.map +1 -1
  389. package/dist/utils/areSelectionPointsEqual.js +1 -1
  390. package/dist/utils/areSelectionPointsEqual.js.map +1 -1
  391. package/dist/utils/areSelectionsEqual.d.ts.map +1 -1
  392. package/dist/utils/areSelectionsEqual.js +1 -1
  393. package/dist/utils/areSelectionsEqual.js.map +1 -1
  394. package/dist/utils/areThemesEqual.d.ts.map +1 -1
  395. package/dist/utils/areThemesEqual.js +1 -1
  396. package/dist/utils/areThemesEqual.js.map +1 -1
  397. package/dist/utils/areVirtualWindowSpecsEqual.d.ts.map +1 -1
  398. package/dist/utils/areVirtualWindowSpecsEqual.js +1 -1
  399. package/dist/utils/areVirtualWindowSpecsEqual.js.map +1 -1
  400. package/dist/utils/areWorkerStatsEqual.d.ts +0 -2
  401. package/dist/utils/areWorkerStatsEqual.d.ts.map +1 -1
  402. package/dist/utils/areWorkerStatsEqual.js +1 -1
  403. package/dist/utils/areWorkerStatsEqual.js.map +1 -1
  404. package/dist/utils/awaitWithTimeout.d.ts +5 -0
  405. package/dist/utils/awaitWithTimeout.d.ts.map +1 -0
  406. package/dist/utils/awaitWithTimeout.js +15 -0
  407. package/dist/utils/awaitWithTimeout.js.map +1 -0
  408. package/dist/utils/cleanLastNewline.d.ts.map +1 -1
  409. package/dist/utils/cleanLastNewline.js +1 -1
  410. package/dist/utils/cleanLastNewline.js.map +1 -1
  411. package/dist/utils/cloneFileDiffMetadata.d.ts +7 -0
  412. package/dist/utils/cloneFileDiffMetadata.d.ts.map +1 -0
  413. package/dist/utils/cloneFileDiffMetadata.js +16 -0
  414. package/dist/utils/cloneFileDiffMetadata.js.map +1 -0
  415. package/dist/utils/computeEstimatedDiffHeights.d.ts +3 -1
  416. package/dist/utils/computeEstimatedDiffHeights.d.ts.map +1 -1
  417. package/dist/utils/computeEstimatedDiffHeights.js +18 -23
  418. package/dist/utils/computeEstimatedDiffHeights.js.map +1 -1
  419. package/dist/utils/computeFileOffsets.d.ts +9 -1
  420. package/dist/utils/computeFileOffsets.d.ts.map +1 -1
  421. package/dist/utils/computeFileOffsets.js +51 -4
  422. package/dist/utils/computeFileOffsets.js.map +1 -1
  423. package/dist/utils/computeVirtualFileMetrics.d.ts.map +1 -1
  424. package/dist/utils/computeVirtualFileMetrics.js +1 -2
  425. package/dist/utils/computeVirtualFileMetrics.js.map +1 -1
  426. package/dist/utils/createAnnotationElement.d.ts +1 -1
  427. package/dist/utils/createAnnotationElement.d.ts.map +1 -1
  428. package/dist/utils/createAnnotationElement.js +1 -2
  429. package/dist/utils/createAnnotationElement.js.map +1 -1
  430. package/dist/utils/createAnnotationWrapperNode.d.ts.map +1 -1
  431. package/dist/utils/createAnnotationWrapperNode.js +1 -1
  432. package/dist/utils/createAnnotationWrapperNode.js.map +1 -1
  433. package/dist/utils/createCodeViewHeaderFooterHostElement.d.ts +5 -0
  434. package/dist/utils/createCodeViewHeaderFooterHostElement.d.ts.map +1 -0
  435. package/dist/utils/createCodeViewHeaderFooterHostElement.js +19 -0
  436. package/dist/utils/createCodeViewHeaderFooterHostElement.js.map +1 -0
  437. package/dist/utils/createContentColumn.d.ts +1 -1
  438. package/dist/utils/createContentColumn.d.ts.map +1 -1
  439. package/dist/utils/createContentColumn.js +1 -2
  440. package/dist/utils/createContentColumn.js.map +1 -1
  441. package/dist/utils/createEmptyRowBuffer.d.ts +1 -1
  442. package/dist/utils/createEmptyRowBuffer.d.ts.map +1 -1
  443. package/dist/utils/createEmptyRowBuffer.js +1 -2
  444. package/dist/utils/createEmptyRowBuffer.js.map +1 -1
  445. package/dist/utils/createFileHeaderElement.d.ts +1 -1
  446. package/dist/utils/createFileHeaderElement.d.ts.map +1 -1
  447. package/dist/utils/createFileHeaderElement.js +6 -3
  448. package/dist/utils/createFileHeaderElement.js.map +1 -1
  449. package/dist/utils/createGutterUtilityContentNode.d.ts.map +1 -1
  450. package/dist/utils/createGutterUtilityContentNode.js +1 -1
  451. package/dist/utils/createGutterUtilityContentNode.js.map +1 -1
  452. package/dist/utils/createGutterUtilityElement.d.ts +1 -1
  453. package/dist/utils/createGutterUtilityElement.d.ts.map +1 -1
  454. package/dist/utils/createGutterUtilityElement.js +1 -2
  455. package/dist/utils/createGutterUtilityElement.js.map +1 -1
  456. package/dist/utils/createNoNewlineElement.d.ts +1 -1
  457. package/dist/utils/createNoNewlineElement.d.ts.map +1 -1
  458. package/dist/utils/createNoNewlineElement.js +1 -2
  459. package/dist/utils/createNoNewlineElement.js.map +1 -1
  460. package/dist/utils/createPreElement.d.ts +1 -1
  461. package/dist/utils/createPreElement.d.ts.map +1 -1
  462. package/dist/utils/createPreElement.js +1 -3
  463. package/dist/utils/createPreElement.js.map +1 -1
  464. package/dist/utils/createRowNodes.d.ts.map +1 -1
  465. package/dist/utils/createRowNodes.js +1 -1
  466. package/dist/utils/createRowNodes.js.map +1 -1
  467. package/dist/utils/createSeparator.d.ts +1 -1
  468. package/dist/utils/createSeparator.d.ts.map +1 -1
  469. package/dist/utils/createSeparator.js +1 -2
  470. package/dist/utils/createSeparator.js.map +1 -1
  471. package/dist/utils/createSpanNodeFromToken.d.ts.map +1 -1
  472. package/dist/utils/createSpanNodeFromToken.js +1 -2
  473. package/dist/utils/createSpanNodeFromToken.js.map +1 -1
  474. package/dist/utils/createStyleElement.d.ts +1 -1
  475. package/dist/utils/createStyleElement.d.ts.map +1 -1
  476. package/dist/utils/createStyleElement.js +1 -2
  477. package/dist/utils/createStyleElement.js.map +1 -1
  478. package/dist/utils/createTransformerWithState.d.ts.map +1 -1
  479. package/dist/utils/createTransformerWithState.js +1 -2
  480. package/dist/utils/createTransformerWithState.js.map +1 -1
  481. package/dist/utils/createUnsafeCSSStyleNode.d.ts.map +1 -1
  482. package/dist/utils/createUnsafeCSSStyleNode.js +1 -2
  483. package/dist/utils/createUnsafeCSSStyleNode.js.map +1 -1
  484. package/dist/utils/createWindowFromScrollPosition.d.ts.map +1 -1
  485. package/dist/utils/createWindowFromScrollPosition.js +5 -5
  486. package/dist/utils/createWindowFromScrollPosition.js.map +1 -1
  487. package/dist/utils/cssWrappers.d.ts.map +1 -1
  488. package/dist/utils/cssWrappers.js +2 -3
  489. package/dist/utils/cssWrappers.js.map +1 -1
  490. package/dist/utils/detachString.d.ts.map +1 -1
  491. package/dist/utils/detachString.js +1 -1
  492. package/dist/utils/detachString.js.map +1 -1
  493. package/dist/utils/diffAcceptRejectHunk.d.ts.map +1 -1
  494. package/dist/utils/diffAcceptRejectHunk.js +1 -2
  495. package/dist/utils/diffAcceptRejectHunk.js.map +1 -1
  496. package/dist/utils/editSessionHunks.d.ts +84 -0
  497. package/dist/utils/editSessionHunks.d.ts.map +1 -0
  498. package/dist/utils/editSessionHunks.js +366 -0
  499. package/dist/utils/editSessionHunks.js.map +1 -0
  500. package/dist/utils/formatCSSVariablePrefix.d.ts.map +1 -1
  501. package/dist/utils/formatCSSVariablePrefix.js +1 -1
  502. package/dist/utils/formatCSSVariablePrefix.js.map +1 -1
  503. package/dist/utils/getDiffFileInput.d.ts +14 -0
  504. package/dist/utils/getDiffFileInput.d.ts.map +1 -0
  505. package/dist/utils/getDiffFileInput.js +24 -0
  506. package/dist/utils/getDiffFileInput.js.map +1 -0
  507. package/dist/utils/getDiffHunksRendererOptions.d.ts.map +1 -1
  508. package/dist/utils/getDiffHunksRendererOptions.js +2 -1
  509. package/dist/utils/getDiffHunksRendererOptions.js.map +1 -1
  510. package/dist/utils/getFileRendererOptions.d.ts.map +1 -1
  511. package/dist/utils/getFileRendererOptions.js +1 -1
  512. package/dist/utils/getFileRendererOptions.js.map +1 -1
  513. package/dist/utils/getFiletypeFromFileName.d.ts.map +1 -1
  514. package/dist/utils/getFiletypeFromFileName.js +3 -1
  515. package/dist/utils/getFiletypeFromFileName.js.map +1 -1
  516. package/dist/utils/getHighlighterOptions.d.ts.map +1 -1
  517. package/dist/utils/getHighlighterOptions.js +1 -2
  518. package/dist/utils/getHighlighterOptions.js.map +1 -1
  519. package/dist/utils/getHighlighterThemeStyles.d.ts.map +1 -1
  520. package/dist/utils/getHighlighterThemeStyles.js +17 -14
  521. package/dist/utils/getHighlighterThemeStyles.js.map +1 -1
  522. package/dist/utils/getHunkSeparatorSlotName.d.ts.map +1 -1
  523. package/dist/utils/getHunkSeparatorSlotName.js +1 -1
  524. package/dist/utils/getHunkSeparatorSlotName.js.map +1 -1
  525. package/dist/utils/getIconForType.d.ts.map +1 -1
  526. package/dist/utils/getIconForType.js +1 -1
  527. package/dist/utils/getIconForType.js.map +1 -1
  528. package/dist/utils/getLineAnnotationName.d.ts.map +1 -1
  529. package/dist/utils/getLineAnnotationName.js +1 -1
  530. package/dist/utils/getLineAnnotationName.js.map +1 -1
  531. package/dist/utils/getLineEndingType.d.ts.map +1 -1
  532. package/dist/utils/getLineEndingType.js +1 -1
  533. package/dist/utils/getLineEndingType.js.map +1 -1
  534. package/dist/utils/getLineNodes.d.ts +1 -1
  535. package/dist/utils/getLineNodes.d.ts.map +1 -1
  536. package/dist/utils/getLineNodes.js +1 -1
  537. package/dist/utils/getLineNodes.js.map +1 -1
  538. package/dist/utils/getMergeConflictActionSlotName.d.ts.map +1 -1
  539. package/dist/utils/getMergeConflictActionSlotName.js +1 -1
  540. package/dist/utils/getMergeConflictActionSlotName.js.map +1 -1
  541. package/dist/utils/getMergeConflictLineTypes.d.ts.map +1 -1
  542. package/dist/utils/getMergeConflictLineTypes.js +1 -2
  543. package/dist/utils/getMergeConflictLineTypes.js.map +1 -1
  544. package/dist/utils/getOrCreateCodeNode.d.ts.map +1 -1
  545. package/dist/utils/getOrCreateCodeNode.js +1 -1
  546. package/dist/utils/getOrCreateCodeNode.js.map +1 -1
  547. package/dist/utils/getSingularPatch.d.ts.map +1 -1
  548. package/dist/utils/getSingularPatch.js +1 -2
  549. package/dist/utils/getSingularPatch.js.map +1 -1
  550. package/dist/utils/getThemes.d.ts.map +1 -1
  551. package/dist/utils/getThemes.js +1 -2
  552. package/dist/utils/getThemes.js.map +1 -1
  553. package/dist/utils/getTotalLineCountFromHunks.d.ts.map +1 -1
  554. package/dist/utils/getTotalLineCountFromHunks.js +1 -1
  555. package/dist/utils/getTotalLineCountFromHunks.js.map +1 -1
  556. package/dist/utils/hast_utils.d.ts +1 -1
  557. package/dist/utils/hast_utils.d.ts.map +1 -1
  558. package/dist/utils/hast_utils.js +1 -1
  559. package/dist/utils/hast_utils.js.map +1 -1
  560. package/dist/utils/hostTheme.d.ts.map +1 -1
  561. package/dist/utils/hostTheme.js +1 -2
  562. package/dist/utils/hostTheme.js.map +1 -1
  563. package/dist/utils/hydratePartialDiff.d.ts +10 -0
  564. package/dist/utils/hydratePartialDiff.d.ts.map +1 -0
  565. package/dist/utils/hydratePartialDiff.js +140 -0
  566. package/dist/utils/hydratePartialDiff.js.map +1 -0
  567. package/dist/utils/includesFileAnnotations.d.ts +17 -0
  568. package/dist/utils/includesFileAnnotations.d.ts.map +1 -0
  569. package/dist/utils/includesFileAnnotations.js +19 -0
  570. package/dist/utils/includesFileAnnotations.js.map +1 -0
  571. package/dist/utils/isDefaultRenderRange.d.ts.map +1 -1
  572. package/dist/utils/isDefaultRenderRange.js +1 -1
  573. package/dist/utils/isDefaultRenderRange.js.map +1 -1
  574. package/dist/utils/isDiffPlainText.d.ts.map +1 -1
  575. package/dist/utils/isDiffPlainText.js +1 -2
  576. package/dist/utils/isDiffPlainText.js.map +1 -1
  577. package/dist/utils/isFilePlainText.d.ts.map +1 -1
  578. package/dist/utils/isFilePlainText.js +1 -2
  579. package/dist/utils/isFilePlainText.js.map +1 -1
  580. package/dist/utils/isGutterUtilityPath.d.ts +5 -0
  581. package/dist/utils/isGutterUtilityPath.d.ts.map +1 -0
  582. package/dist/utils/isGutterUtilityPath.js +12 -0
  583. package/dist/utils/isGutterUtilityPath.js.map +1 -0
  584. package/dist/utils/isStyleNode.d.ts.map +1 -1
  585. package/dist/utils/isStyleNode.js +1 -1
  586. package/dist/utils/isStyleNode.js.map +1 -1
  587. package/dist/utils/isWorkerContext.d.ts.map +1 -1
  588. package/dist/utils/isWorkerContext.js +1 -1
  589. package/dist/utils/isWorkerContext.js.map +1 -1
  590. package/dist/utils/iterateOverDiff.d.ts.map +1 -1
  591. package/dist/utils/iterateOverDiff.js +178 -214
  592. package/dist/utils/iterateOverDiff.js.map +1 -1
  593. package/dist/utils/normalizeDiffResolution.d.ts.map +1 -1
  594. package/dist/utils/normalizeDiffResolution.js +1 -1
  595. package/dist/utils/normalizeDiffResolution.js.map +1 -1
  596. package/dist/utils/parseDiffDecorations.d.ts.map +1 -1
  597. package/dist/utils/parseDiffDecorations.js +1 -2
  598. package/dist/utils/parseDiffDecorations.js.map +1 -1
  599. package/dist/utils/parseDiffFromFile.d.ts +1 -2
  600. package/dist/utils/parseDiffFromFile.d.ts.map +1 -1
  601. package/dist/utils/parseDiffFromFile.js +27 -7
  602. package/dist/utils/parseDiffFromFile.js.map +1 -1
  603. package/dist/utils/parseLineType.d.ts.map +1 -1
  604. package/dist/utils/parseLineType.js +1 -1
  605. package/dist/utils/parseLineType.js.map +1 -1
  606. package/dist/utils/parseMergeConflictDiffFromFile.d.ts.map +1 -1
  607. package/dist/utils/parseMergeConflictDiffFromFile.js +5 -5
  608. package/dist/utils/parseMergeConflictDiffFromFile.js.map +1 -1
  609. package/dist/utils/parsePatchFiles.d.ts.map +1 -1
  610. package/dist/utils/parsePatchFiles.js +101 -11
  611. package/dist/utils/parsePatchFiles.js.map +1 -1
  612. package/dist/utils/prefersReducedMotion.d.ts.map +1 -1
  613. package/dist/utils/prefersReducedMotion.js +1 -1
  614. package/dist/utils/prefersReducedMotion.js.map +1 -1
  615. package/dist/utils/prerenderHTMLIfNecessary.d.ts.map +1 -1
  616. package/dist/utils/prerenderHTMLIfNecessary.js +1 -1
  617. package/dist/utils/prerenderHTMLIfNecessary.js.map +1 -1
  618. package/dist/utils/processLine.d.ts +1 -1
  619. package/dist/utils/processLine.d.ts.map +1 -1
  620. package/dist/utils/processLine.js +1 -2
  621. package/dist/utils/processLine.js.map +1 -1
  622. package/dist/utils/realignChangeContent.d.ts +28 -0
  623. package/dist/utils/realignChangeContent.d.ts.map +1 -0
  624. package/dist/utils/realignChangeContent.js +142 -0
  625. package/dist/utils/realignChangeContent.js.map +1 -0
  626. package/dist/utils/renderDiffWithHighlighter.d.ts.map +1 -1
  627. package/dist/utils/renderDiffWithHighlighter.js +9 -8
  628. package/dist/utils/renderDiffWithHighlighter.js.map +1 -1
  629. package/dist/utils/renderFileWithHighlighter.d.ts.map +1 -1
  630. package/dist/utils/renderFileWithHighlighter.js +5 -4
  631. package/dist/utils/renderFileWithHighlighter.js.map +1 -1
  632. package/dist/utils/resolveConflict.d.ts.map +1 -1
  633. package/dist/utils/resolveConflict.js +1 -2
  634. package/dist/utils/resolveConflict.js.map +1 -1
  635. package/dist/utils/resolveRegion.d.ts.map +1 -1
  636. package/dist/utils/resolveRegion.js +1 -1
  637. package/dist/utils/resolveRegion.js.map +1 -1
  638. package/dist/utils/roundToDevicePixel.d.ts.map +1 -1
  639. package/dist/utils/roundToDevicePixel.js +1 -1
  640. package/dist/utils/roundToDevicePixel.js.map +1 -1
  641. package/dist/utils/scrollbarGutter.d.ts.map +1 -1
  642. package/dist/utils/scrollbarGutter.js +1 -2
  643. package/dist/utils/scrollbarGutter.js.map +1 -1
  644. package/dist/utils/setLanguageOverride.d.ts.map +1 -1
  645. package/dist/utils/setLanguageOverride.js +1 -1
  646. package/dist/utils/setLanguageOverride.js.map +1 -1
  647. package/dist/utils/setWrapperNodeProps.d.ts.map +1 -1
  648. package/dist/utils/setWrapperNodeProps.js +1 -2
  649. package/dist/utils/setWrapperNodeProps.js.map +1 -1
  650. package/dist/utils/shouldUseTokenTransformer.d.ts.map +1 -1
  651. package/dist/utils/shouldUseTokenTransformer.js +1 -1
  652. package/dist/utils/shouldUseTokenTransformer.js.map +1 -1
  653. package/dist/utils/splitFileContents.d.ts.map +1 -1
  654. package/dist/utils/splitFileContents.js +1 -2
  655. package/dist/utils/splitFileContents.js.map +1 -1
  656. package/dist/utils/trimPatchContext.d.ts.map +1 -1
  657. package/dist/utils/trimPatchContext.js +1 -2
  658. package/dist/utils/trimPatchContext.js.map +1 -1
  659. package/dist/utils/updateDiffHunks.d.ts +24 -0
  660. package/dist/utils/updateDiffHunks.d.ts.map +1 -0
  661. package/dist/utils/updateDiffHunks.js +235 -0
  662. package/dist/utils/updateDiffHunks.js.map +1 -0
  663. package/dist/utils/virtualDiffLayout.d.ts +62 -2
  664. package/dist/utils/virtualDiffLayout.d.ts.map +1 -1
  665. package/dist/utils/virtualDiffLayout.js +137 -3
  666. package/dist/utils/virtualDiffLayout.js.map +1 -1
  667. package/dist/utils/wrapTokenFragments.d.ts +1 -1
  668. package/dist/utils/wrapTokenFragments.d.ts.map +1 -1
  669. package/dist/utils/wrapTokenFragments.js +1 -2
  670. package/dist/utils/wrapTokenFragments.js.map +1 -1
  671. package/dist/worker/WorkerPoolManager.d.ts +7 -2
  672. package/dist/worker/WorkerPoolManager.d.ts.map +1 -1
  673. package/dist/worker/WorkerPoolManager.js +88 -23
  674. package/dist/worker/WorkerPoolManager.js.map +1 -1
  675. package/dist/worker/getOrCreateWorkerPoolSingleton.d.ts.map +1 -1
  676. package/dist/worker/getOrCreateWorkerPoolSingleton.js +1 -2
  677. package/dist/worker/getOrCreateWorkerPoolSingleton.js.map +1 -1
  678. package/dist/worker/index.d.ts +2 -2
  679. package/dist/worker/index.js +1 -2
  680. package/dist/worker/types.d.ts +11 -1
  681. package/dist/worker/types.d.ts.map +1 -1
  682. package/dist/worker/wasm-B9ZqxnKj.js +8 -0
  683. package/dist/worker/wasm-B9ZqxnKj.js.map +1 -0
  684. package/dist/worker/worker-portable.js +3361 -6211
  685. package/dist/worker/worker-portable.js.map +1 -1
  686. package/dist/worker/worker.js +321 -314
  687. package/dist/worker/worker.js.map +1 -1
  688. package/package.json +29 -32
  689. package/dist/editor/css.d.ts +0 -6
  690. package/dist/editor/css.d.ts.map +0 -1
  691. package/dist/editor/css.js +0 -218
  692. package/dist/editor/css.js.map +0 -1
  693. package/dist/editor/quickEdit.d.ts +0 -29
  694. package/dist/editor/quickEdit.d.ts.map +0 -1
  695. package/dist/editor/quickEdit.js +0 -81
  696. package/dist/editor/quickEdit.js.map +0 -1
  697. package/dist/editor/tokenzier.d.ts.map +0 -1
  698. package/dist/editor/tokenzier.js +0 -348
  699. package/dist/editor/tokenzier.js.map +0 -1
  700. package/dist/react/EditorContext.d.ts +0 -16
  701. package/dist/react/EditorContext.d.ts.map +0 -1
  702. package/dist/react/EditorContext.js +0 -26
  703. package/dist/react/EditorContext.js.map +0 -1
  704. package/dist/worker/wasm-D4DU5jgR.js +0 -10
  705. package/dist/worker/wasm-D4DU5jgR.js.map +0 -1
@@ -1,256 +1,459 @@
1
+ import { dequeueRender, queueRender } from "../managers/UniversalRenderingManager.js";
2
+ import { isGutterUtilityPath } from "../utils/isGutterUtilityPath.js";
1
3
  import { getFiletypeFromFileName } from "../utils/getFiletypeFromFileName.js";
2
4
  import { isMoveCursorShortcut, isPrimaryModifier, isSafari } from "./platform.js";
3
- import { resolveEditorCommandFromKeyboardEvent } from "./command.js";
4
- import { editorCSS, editorGlobalCSS } from "./css.js";
5
- import { applyDocumentChangeToLineAnnotations } from "./lineAnnotations.js";
6
- import { DirectionBackward, DirectionForward, DirectionNone, applyDeleteHardLineForwardToSelections, applyTextChangeToSelections, applyTextReplaceToSelections, applyTransposeToSelections, comparePosition, convertSelection, createSelectionFrom, createSelectionFromAnchorAndFocusOffsets, expandCollapsedSelectionToWord, extendSelection, extendSelections, findNexMatch, getCaretPosition, getDocumentBoundarySelection, getDocumentFullSelection, getSelectionAnchor, getSelectionText, isCollapsedSelection, isLineEditable, mapCursorMove, mapSelectionShift, mergeOverlappingSelections, resolveIndentEdits, selectionIntersects } from "./selection.js";
7
- import { TextDocument } from "./textDocument.js";
8
- import { addEventListener, debounce, extend, h, round } from "./utils.js";
9
- import { QuickEditWidget } from "./quickEdit.js";
5
+ import { resolveEditorCommandFromKeyboardEvent, resolveFindAgainShortcut } from "./command.js";
6
+ import { EditStack } from "./editStack.js";
7
+ import editor_default from "./editor2.js";
8
+ import { resolveBlockCommentEdits, resolveCommentConfig, resolveLineCommentEdits } from "./languages.js";
9
+ import { addEventListener, clampDomOffset, extend, getLineNumberAttr, h, round } from "./utils.js";
10
+ import { applyDocumentChangeToLineAnnotations, renderLineAnnotations } from "./lineAnnotations.js";
11
+ import { PopoverManager } from "./popover.js";
12
+ import { applyDeleteCharacterToSelections, applyDeleteHardLineForwardToSelections, applyDeleteSoftLineBackwardToSelections, applyDeleteWordBackwardToSelections, applyTextChangeToSelections, applyTextReplaceToSelections, applyTransposeToSelections, comparePosition, convertSelection, createSelectionFrom, createSelectionFromAnchorAndFocusOffsets, expandCollapsedSelectionToWord, extendSelection, extendSelections, findNextMatch, getAutoSurroundReplacementTexts, getCaretPosition, getDocumentBoundarySelection, getDocumentFullSelection, getSelectedLineBlocks, getSelectionAnchor, getSelectionClipboardTexts, getSelectionText, isCollapsedSelection, isLineEditable, mapCursorMove, mapSelectionShift, mergeOverlappingSelections, remapSelectionsAfterEdits, resolveIndentEdits, resolveSelectionCut, selectionIntersects, shiftSelectionLines } from "./selection.js";
13
+ import { MarkerRenderer, markerSeverityDatasetKey } from "./marker.js";
14
+ import { findBracketMatchRanges } from "./matchBrackets.js";
15
+ import { createSpriteElement } from "./sprite.js";
10
16
  import { SearchPanelWidget } from "./searchPanel.js";
17
+ import { SelectionActionWidget } from "./selectionAction.js";
18
+ import { cloneEditorState, createStateStorage } from "./stateStorage.js";
19
+ import { TextDocument } from "./textDocument.js";
11
20
  import { Metrics, getExpandedAsciiTextColumns, getUnicodeMeasurementOffsets, snapTextOffsetToUnicodeBoundary } from "./textMeasure.js";
12
- import { EditorTokenizer, renderLineTokens } from "./tokenzier.js";
13
-
21
+ import { EditorTokenizer, renderLineTokens } from "./tokenizer.js";
14
22
  //#region src/editor/editor.ts
15
- function clampDomOffset(node, offset) {
16
- if (node.nodeType === 3) {
17
- const length = node.textContent?.length ?? 0;
18
- return Math.max(0, Math.min(offset, length));
19
- }
20
- if (node.nodeType === 1) return Math.max(0, Math.min(offset, node.childNodes.length));
21
- return 0;
23
+ function getShadowRootRange(shadowRoot) {
24
+ const selection = shadowRoot.getSelection?.();
25
+ if (selection == null || selection.rangeCount === 0) return;
26
+ const range = selection.getRangeAt(0);
27
+ return {
28
+ collapsed: range.collapsed,
29
+ startContainer: range.startContainer,
30
+ startOffset: range.startOffset,
31
+ endContainer: range.endContainer,
32
+ endOffset: range.endOffset
33
+ };
34
+ }
35
+ function requirePersistedCacheKey(file) {
36
+ if (typeof file.cacheKey !== "string" || file.cacheKey.length === 0) throw new Error(`Editor persistState requires a non-empty file.cacheKey for "${file.name}". Provide a unique, stable cacheKey for every editable file.`);
37
+ return file.cacheKey;
22
38
  }
39
+ function isPromise(value) {
40
+ return typeof value === "object" && value !== null && "then" in value && typeof value.then === "function";
41
+ }
42
+ const MAX_EDIT_WIDEN_WINDOW_MULTIPLE = 2;
43
+ const SELECTION_ACTION_POPOVER_PLACEMENT_KEY = "selection-action";
44
+ const MULTI_SELECTION_CLIPBOARD_TYPE = "application/vnd.pierre.diffs-selections+json";
23
45
  var Editor = class {
24
46
  #options;
25
- #editMode = "simple";
26
- #wrap = false;
27
47
  #metrics = new Metrics();
28
48
  #tokenizer;
49
+ #popoverManager;
50
+ #textDocumentCache = /* @__PURE__ */ new Map();
51
+ #stateStorage;
52
+ #stateStorageOption;
53
+ #pendingStateWrites = /* @__PURE__ */ new Map();
54
+ #pendingStateRestore;
55
+ #stateRestoreGeneration = 0;
56
+ #restoreStateOnNextSync = false;
29
57
  #editorEventDisposes;
30
58
  #globalEventDisposes;
31
- #mouseUpDisposes;
59
+ #selectEventDisposes;
32
60
  #detach;
33
- #component;
34
- #fileContents;
35
- #lineAnnotations;
36
- #textDocument;
37
- #renderRange;
38
- #codePaddingTop = 0;
61
+ #contentOffset;
39
62
  #gutterWidthCache;
40
63
  #contentWidthCache;
41
64
  #lineYCache = /* @__PURE__ */ new Map();
42
65
  #wrapLineOffsetsCache = /* @__PURE__ */ new Map();
43
- #lastCharX;
66
+ #lineElementsCache = /* @__PURE__ */ new Map();
67
+ #lastAccessedCharX;
44
68
  #globalStyleElement;
45
69
  #editorStyleElement;
46
70
  #themeStyleElement;
47
- #componentContainer;
71
+ #spriteElement;
72
+ #fileContainer;
73
+ #gutterElement;
48
74
  #contentElement;
49
75
  #overlayElement;
76
+ #overlayElements;
50
77
  #primaryCaretElement;
51
- #selectionElements;
52
- #quickEdit;
53
- #searchPanel;
54
78
  #resizeObserver;
79
+ #fileInstance;
80
+ #fileInfo;
81
+ #lineAnnotations;
82
+ #textDocument;
83
+ #renderRange;
84
+ #viewportWindowLines;
85
+ #markerRenderer;
86
+ #searchPanel;
87
+ #selectionAction;
55
88
  #shouldIgnoreSelectionChange = false;
89
+ #suppressNativeSelectionSync = false;
90
+ #contentHasFocus = false;
91
+ #isComposing = false;
56
92
  #isGutterMouseDown = false;
57
93
  #isContentMouseDown = false;
58
94
  #shiftKeyPressed = false;
59
95
  #selectionStart;
96
+ #deletedSelectionText = "";
60
97
  #reservedSelections;
61
- #selections;
62
98
  #initSelections;
99
+ #selections;
100
+ #matches;
63
101
  #scrollingToLine;
64
102
  #scrollingToLineChar;
103
+ #scrollingToLineFixed = false;
104
+ #scrollingToLineNoFocus = false;
65
105
  #retainSearchPanelFocus = false;
66
- #emitChange = debounce((fileContents, lineAnnotations) => {
67
- this.#options.onChange?.(fileContents, lineAnnotations);
68
- }, 500);
106
+ #fontRemeasureScheduled = false;
107
+ #themeSelectionRefreshFrame;
69
108
  #onDeferTokenize = (lines, themeType) => {
70
- this.#component?.applyLineChange?.(lines, themeType);
109
+ this.#fileInstance?.updateRenderCache(lines, themeType, false, false);
71
110
  if (this.#renderRange !== void 0 && this.#renderRange.totalLines !== Infinity) {
72
111
  const { startingLine, totalLines } = this.#renderRange;
73
112
  const endLine = Math.min(startingLine + totalLines, this.#textDocument?.lineCount ?? 0);
74
113
  for (const [line, tokens] of lines) if (line >= startingLine && line < endLine) {
75
114
  const lineElement = this.#getLineElement(line);
76
- if (lineElement !== void 0) lineElement.replaceChildren(...renderLineTokens(tokens, themeType));
115
+ if (lineElement !== void 0) lineElement.replaceChildren(...renderLineTokens(tokens));
77
116
  }
78
117
  }
79
118
  };
80
119
  constructor(options = {}) {
81
120
  this.#options = options;
82
121
  }
83
- edit(component) {
84
- const { useTokenTransformer, enableGutterUtility, enableLineSelection, expandUnchanged, lineHoverHighlight,...rest } = component.options;
85
- if (useTokenTransformer !== true || enableGutterUtility === true || enableLineSelection === true || expandUnchanged !== true && Object.hasOwn(component, "fileDiff") || lineHoverHighlight !== "disabled") {
86
- component.setOptions({
87
- ...rest,
88
- useTokenTransformer: true,
89
- enableGutterUtility: false,
90
- enableLineSelection: false,
91
- expandUnchanged: true,
92
- lineHoverHighlight: "disabled"
122
+ setOptions(options) {
123
+ const previousStorageOption = this.#options.persistStateStorage ?? "inMemory";
124
+ const nextOptions = {
125
+ ...this.#options,
126
+ ...options
127
+ };
128
+ if (nextOptions.persistState === true && this.#fileInstance?.type === "file") {
129
+ const file = this.#fileInstance.__getCurrentFile?.() ?? this.#fileInfo;
130
+ if (file !== void 0) requirePersistedCacheKey(file);
131
+ }
132
+ this.#options = nextOptions;
133
+ if (this.#options.persistState !== true) {
134
+ this.#textDocumentCache.clear();
135
+ this.#stateRestoreGeneration++;
136
+ this.#restoreStateOnNextSync = false;
137
+ }
138
+ if ((this.#options.persistStateStorage ?? "inMemory") !== previousStorageOption) {
139
+ this.#stateRestoreGeneration++;
140
+ this.#stateStorage = void 0;
141
+ this.#stateStorageOption = void 0;
142
+ this.#pendingStateWrites.clear();
143
+ }
144
+ }
145
+ edit(fileInstance) {
146
+ if (this.#options.persistState === true && fileInstance.type === "file") {
147
+ const file = fileInstance.__getCurrentFile?.();
148
+ if (file !== void 0) requirePersistedCacheKey(file);
149
+ }
150
+ if (fileInstance.options.useTokenTransformer !== true) {
151
+ fileInstance.setOptions({
152
+ ...fileInstance.options,
153
+ useTokenTransformer: true
93
154
  });
94
- component.rerender();
155
+ fileInstance.rerender();
95
156
  }
96
- this.#component = component;
157
+ this.#fileInstance = fileInstance;
97
158
  this.#initialize();
98
- this.#detach = component.attachEditor(this);
159
+ this.#detach = fileInstance.attachEditor(this);
99
160
  return () => this.cleanUp();
100
161
  }
101
- setSelections(selections) {
162
+ /**
163
+ * Apply edits to current attached file. Every edit joins the undo timeline:
164
+ * a programmatic edit must leave the document and its history exactly as
165
+ * the same edit typed by the user would (history equivalence — see
166
+ * TextDocument.applyResolvedEdits), so it is undoable like any other edit.
167
+ *
168
+ * @param updateHistory Whether to record caller selection snapshots for
169
+ * exact undo/redo restoration. Defaults to true. When false, live selections
170
+ * are remapped during replay and the text edit still joins the undo timeline.
171
+ */
172
+ applyEdits(edits, updateHistory = true) {
102
173
  const textDocument = this.#textDocument;
103
- if (textDocument !== void 0) {
104
- const resolvedSelections = selections.map((selection) => {
105
- const start = textDocument.normalizePosition(selection.start);
106
- const end = textDocument.normalizePosition(selection.end);
107
- return {
108
- direction: selection.direction === "none" ? DirectionNone : selection.direction === "backward" ? DirectionBackward : DirectionForward,
109
- start,
110
- end
111
- };
174
+ if (textDocument == null) throw new Error("Editor is not attached");
175
+ const wasFocused = this.#contentHasFocus;
176
+ const selectionsBefore = this.#selections;
177
+ const selectionOffsetsBefore = selectionsBefore?.map((selection) => [textDocument.offsetAt(selection.start), textDocument.offsetAt(selection.end)]);
178
+ const resolvedEditOffsets = selectionsBefore === void 0 ? void 0 : textDocument.resolveEdits(edits).sort((a, b) => a.start - b.start);
179
+ const change = textDocument.applyEdits(edits, updateHistory, selectionsBefore);
180
+ if (change === void 0) return;
181
+ let nextSelections;
182
+ if (selectionsBefore !== void 0 && selectionOffsetsBefore !== void 0 && resolvedEditOffsets !== void 0) {
183
+ nextSelections = remapSelectionsAfterEdits(textDocument, selectionsBefore, selectionOffsetsBefore, resolvedEditOffsets);
184
+ if (updateHistory) textDocument.setLastUndoSelectionsAfter(nextSelections);
185
+ }
186
+ this.#applyChange(change, nextSelections, this.#applyChangeToLineAnnotations(change), { skipFocus: !wasFocused });
187
+ }
188
+ /** Whether there is an edit to undo. */
189
+ get canUndo() {
190
+ return this.#textDocument?.canUndo ?? false;
191
+ }
192
+ /** Whether there is an undone edit to redo. */
193
+ get canRedo() {
194
+ return this.#textDocument?.canRedo ?? false;
195
+ }
196
+ /** Undo the last edit. Does nothing when there is nothing to undo. */
197
+ undo() {
198
+ this.#runCommand("undo");
199
+ }
200
+ /** Redo the last undone edit. Does nothing when there is nothing to redo. */
201
+ redo() {
202
+ this.#runCommand("redo");
203
+ }
204
+ getFile() {
205
+ const fileInfo = this.#fileInfo;
206
+ const textDocument = this.#textDocument;
207
+ if (fileInfo === void 0 || textDocument === void 0) return;
208
+ const file = { ...fileInfo };
209
+ Object.defineProperty(file, "contents", {
210
+ enumerable: true,
211
+ get: () => textDocument.getText()
212
+ });
213
+ return file;
214
+ }
215
+ getText() {
216
+ return this.#textDocument?.getText() ?? "";
217
+ }
218
+ getState() {
219
+ const scrollContainer = this.#fileInstance?.getScrollContainer?.();
220
+ return {
221
+ selections: this.#selections,
222
+ view: scrollContainer !== void 0 ? {
223
+ scrollLeft: scrollContainer.scrollLeft,
224
+ scrollTop: scrollContainer.scrollTop
225
+ } : void 0
226
+ };
227
+ }
228
+ setState({ selections, view }) {
229
+ if (this.#fileInstance === void 0 || this.#textDocument === void 0) throw new Error("Editor is not attached");
230
+ this.#updateSelections(selections ?? []);
231
+ if (view !== void 0) {
232
+ const scrollContainer = this.#fileInstance.getScrollContainer?.();
233
+ if (scrollContainer !== void 0) scrollContainer.scrollTo({
234
+ left: view.scrollLeft,
235
+ top: view.scrollTop,
236
+ behavior: "instant"
112
237
  });
113
- this.#updateSelections(resolvedSelections);
114
- this.#scrollToPrimaryCaret();
115
- } else this.#initSelections = selections;
238
+ return;
239
+ }
240
+ this.#scrollToPrimaryCaret();
241
+ }
242
+ setSelections(selections) {
243
+ const textDocument = this.#textDocument;
244
+ if (textDocument === void 0) throw new Error("Text document is not initialized");
245
+ const resolvedSelections = selections.map((selection) => {
246
+ let start = textDocument.normalizePosition(selection.start);
247
+ let end = textDocument.normalizePosition(selection.end);
248
+ let direction = selection.direction === "none" ? 0 : selection.direction === "backward" ? -1 : 1;
249
+ if (comparePosition(start, end) > 0) {
250
+ [start, end] = [end, start];
251
+ if (direction !== 0) direction = direction === 1 ? -1 : 1;
252
+ }
253
+ return {
254
+ direction,
255
+ start,
256
+ end
257
+ };
258
+ });
259
+ this.#updateSelections(resolvedSelections);
260
+ const primarySelection = resolvedSelections.at(-1);
261
+ if (primarySelection !== void 0) this.#revealLineIfCollapsed(getCaretPosition(primarySelection).line);
262
+ this.#scrollToPrimaryCaret();
263
+ }
264
+ setMarkers(markers) {
265
+ const textDocument = this.#textDocument;
266
+ if (textDocument === void 0) throw new Error("Text document is not initialized");
267
+ if (markers.length === 0) {
268
+ this.#markerRenderer?.cleanup();
269
+ this.#markerRenderer = void 0;
270
+ this.#updateSelections(this.#selections ?? []);
271
+ return;
272
+ }
273
+ this.#markerRenderer ??= new MarkerRenderer({
274
+ popoverManager: this.#getPopoverManager(),
275
+ getLineHeight: () => this.#metrics.lineHeight,
276
+ getOverlayElement: () => this.#overlayElement,
277
+ getGutterWidth: () => this.#getGutterWidth(),
278
+ getCharX: (line, character) => this.#getCharX(line, character),
279
+ getLineY: (line) => this.#getLineY(line),
280
+ isMouseDown: () => this.#isContentMouseDown || this.#isGutterMouseDown
281
+ });
282
+ this.#markerRenderer.setMarkers(markers, textDocument);
283
+ if (this.#contentElement !== void 0) this.#markerRenderer.listenHover(this.#contentElement);
284
+ this.#updateSelections(this.#selections ?? []);
116
285
  }
117
286
  focus(options) {
118
287
  const preventScroll = options?.preventScroll ?? false;
119
288
  const primarySelection = this.#selections?.at(-1);
120
289
  if (primarySelection !== void 0) {
121
- const pos = primarySelection.direction === DirectionBackward ? primarySelection.end : primarySelection.start;
290
+ const pos = primarySelection.direction === -1 ? primarySelection.end : primarySelection.start;
122
291
  this.#focus(pos, preventScroll);
123
292
  } else this.#focus(void 0, preventScroll);
124
293
  }
125
- cleanUp() {
294
+ blur() {
295
+ this.#contentElement?.blur();
296
+ }
297
+ cleanUp(recycle = false) {
298
+ const shouldRestoreState = this.#isStatePersistenceEnabled;
299
+ this.#stateRestoreGeneration++;
300
+ this.#persistCurrentState();
301
+ this.#restoreStateOnNextSync = shouldRestoreState;
302
+ dequeueRender(this.#handleCustomPasteEvent);
126
303
  this.#tokenizer?.cleanUp();
127
304
  this.#tokenizer = void 0;
305
+ if (!recycle) {
306
+ this.#textDocument = void 0;
307
+ this.#fileInfo = void 0;
308
+ }
128
309
  this.#globalEventDisposes?.forEach((dispose) => dispose());
129
310
  this.#globalEventDisposes = void 0;
130
311
  this.#editorEventDisposes?.forEach((dispose) => dispose());
131
312
  this.#editorEventDisposes = void 0;
132
- this.#detach?.();
313
+ this.#selectEventDisposes?.forEach((dispose) => dispose());
314
+ this.#selectEventDisposes = void 0;
315
+ this.#detach?.(recycle);
133
316
  this.#detach = void 0;
134
- this.#component?.setSelectedLines(null);
135
- this.#component = void 0;
136
- this.#fileContents = void 0;
137
- this.#lineAnnotations = void 0;
138
- this.#textDocument = void 0;
139
- this.#renderRange = void 0;
140
317
  this.#gutterWidthCache = void 0;
141
318
  this.#contentWidthCache = void 0;
142
319
  this.#lineYCache.clear();
143
320
  this.#wrapLineOffsetsCache.clear();
144
- this.#lastCharX = void 0;
321
+ this.#lineElementsCache.clear();
322
+ this.#lastAccessedCharX = void 0;
145
323
  this.#globalStyleElement?.remove();
146
324
  this.#globalStyleElement = void 0;
147
325
  this.#editorStyleElement?.remove();
148
326
  this.#editorStyleElement = void 0;
149
327
  this.#themeStyleElement?.remove();
150
328
  this.#themeStyleElement = void 0;
151
- this.#componentContainer = void 0;
329
+ this.#spriteElement?.remove();
330
+ this.#spriteElement = void 0;
331
+ this.#fileContainer = void 0;
332
+ this.#popoverManager?.cleanUp();
333
+ this.#popoverManager = void 0;
334
+ this.#gutterElement = void 0;
152
335
  this.#contentElement?.removeAttribute("contentEditable");
153
336
  this.#contentElement = void 0;
337
+ this.#contentHasFocus = false;
154
338
  this.#overlayElement?.remove();
155
339
  this.#overlayElement = void 0;
156
- this.#primaryCaretElement?.remove();
157
- this.#primaryCaretElement = void 0;
158
- this.#selectionElements?.forEach((el) => el.remove());
159
- this.#selectionElements?.clear();
160
- this.#selectionElements = void 0;
161
- this.#searchPanel?.cleanup();
162
- this.#searchPanel = void 0;
163
- this.#quickEdit?.cleanup();
164
- this.#quickEdit = void 0;
165
340
  this.#resizeObserver?.disconnect();
166
341
  this.#resizeObserver = void 0;
167
- this.#shouldIgnoreSelectionChange = false;
168
- this.#selectionStart = void 0;
169
- this.#selections = void 0;
170
- this.#reservedSelections = void 0;
342
+ this.#fontRemeasureScheduled = false;
343
+ if (this.#themeSelectionRefreshFrame !== void 0) {
344
+ cancelAnimationFrame(this.#themeSelectionRefreshFrame);
345
+ this.#themeSelectionRefreshFrame = void 0;
346
+ }
347
+ this.#resetState();
348
+ }
349
+ /** @internal Capture outgoing state and substitute cached text before render. */
350
+ __prepareFile(file) {
351
+ if (this.#options.persistState !== true) return file;
352
+ const cacheKey = requirePersistedCacheKey(file);
353
+ const fileInfo = this.#fileInfo;
354
+ const languageId = file.lang ?? getFiletypeFromFileName(file.name);
355
+ if (fileInfo !== void 0 && (requirePersistedCacheKey(fileInfo) !== cacheKey || fileInfo.name !== file.name || this.#textDocument?.languageId !== languageId)) {
356
+ this.#stateRestoreGeneration++;
357
+ this.#persistCurrentState();
358
+ }
359
+ const textDocument = this.#getCachedTextDocument(file, cacheKey);
360
+ if (textDocument === void 0 || textDocument.getText() === file.contents) return file;
361
+ return {
362
+ ...file,
363
+ contents: textDocument.getText()
364
+ };
365
+ }
366
+ /** @internal */
367
+ __postponeBgTokenizeToNextFrame() {
368
+ const tokenizer = this.#tokenizer;
369
+ if (tokenizer !== void 0) {
370
+ tokenizer.pauseBackgroundTokenize();
371
+ requestAnimationFrame(() => {
372
+ tokenizer.resumeBackgroundTokenize();
373
+ });
374
+ }
171
375
  }
172
- syncWithRender(highlighter, fileContainer, fileContents, lineAnnotations, renderRange, editMode) {
376
+ /** @internal */
377
+ __syncRenderView = (highlighter, fileContainer, fileOrDiff, lineAnnotations, renderRange) => {
173
378
  const shadowRoot = fileContainer.shadowRoot;
174
379
  if (shadowRoot == null) {
175
380
  console.error("[editor] Could not find the shadow root.");
176
381
  return;
177
382
  }
178
383
  let codeElement;
384
+ let gutterEl;
385
+ let contentEl;
179
386
  for (const el of shadowRoot.querySelectorAll("[data-code]")) if (el.dataset.deletions === void 0) {
180
387
  codeElement = el;
181
- break;
182
- }
183
- if (codeElement === void 0) return;
184
- const contentEl = codeElement.children[1];
185
- if (contentEl === void 0) return;
186
- this.#editMode = editMode ?? "simple";
187
- this.#wrap = this.#component?.options.overflow === "wrap";
188
- if (editMode === "advanced" || (lineAnnotations?.length ?? 0) > 0) {
189
- let startingLine;
190
- let endLine;
191
- for (const child of contentEl.children) {
388
+ for (const child of el.children) {
192
389
  const el = child;
193
- const line = el.dataset.line;
194
- const lineType = el.dataset.lineType;
195
- if (line !== void 0) {
196
- const lineIndex = Number(line) - 1;
197
- startingLine ??= lineIndex;
198
- endLine = lineIndex;
199
- }
200
- if (lineType === void 0 || !isLineEditable(lineType)) el.contentEditable = "false";
201
- }
202
- if (endLine !== void 0 && renderRange !== void 0) {
203
- const { startingLine: startingLine$1, totalLines } = renderRange;
204
- endLine = Math.max(endLine, startingLine$1 + totalLines);
390
+ const { gutter, content } = el.dataset;
391
+ if (gutter !== void 0) gutterEl = el;
392
+ else if (content !== void 0) contentEl = el;
205
393
  }
206
- if (startingLine !== void 0 && endLine !== void 0) renderRange = {
207
- startingLine,
208
- totalLines: endLine - startingLine,
209
- bufferBefore: 0,
210
- bufferAfter: 0
211
- };
394
+ break;
212
395
  }
213
- if (this.#componentContainer !== fileContainer) {
214
- this.#componentContainer = fileContainer;
215
- this.#codePaddingTop = Number(getComputedStyle(codeElement).paddingTop.slice(0, -2));
396
+ if (codeElement === void 0 || contentEl === void 0) return;
397
+ this.#getPopoverManager().setViewportElements(fileContainer, codeElement);
398
+ if (this.#fileContainer !== fileContainer) {
399
+ this.#fileContainer = fileContainer;
216
400
  if (this.#globalStyleElement !== void 0) fileContainer.appendChild(this.#globalStyleElement);
217
401
  if (this.#editorStyleElement !== void 0) shadowRoot.appendChild(this.#editorStyleElement);
218
402
  if (this.#themeStyleElement !== void 0) shadowRoot.appendChild(this.#themeStyleElement);
403
+ if (this.#spriteElement !== void 0) shadowRoot.prepend(this.#spriteElement);
219
404
  }
220
- if (this.#textDocument === void 0 || this.#fileContents === void 0 || this.#fileContents.name !== fileContents.name) {
221
- const textDocument = new TextDocument(fileContents.name, fileContents.contents, fileContents.lang ?? getFiletypeFromFileName(fileContents.name));
222
- this.#fileContents = fileContents;
405
+ const shouldRebuildDocument = this.#textDocument === void 0 || this.#fileInfo === void 0 || this.#fileInfo.name !== fileOrDiff.name || this.#fileInfo.lang !== fileOrDiff.lang || this.#fileInfo.cacheKey !== fileOrDiff.cacheKey;
406
+ const persistedCacheKey = this.#isStatePersistenceEnabled ? requirePersistedCacheKey(fileOrDiff) : void 0;
407
+ let persistedStateTarget;
408
+ if (shouldRebuildDocument) {
409
+ let contents = "";
410
+ if ("contents" in fileOrDiff) contents = fileOrDiff.contents;
411
+ else contents = fileOrDiff.additionLines.join("");
412
+ const editStack = new EditStack({ maxEntries: this.#options.historyMaxEntries });
413
+ const { name, lang, cacheKey } = fileOrDiff;
414
+ const languageId = lang ?? getFiletypeFromFileName(fileOrDiff.name);
415
+ const textDocument = (persistedCacheKey !== void 0 ? this.#getCachedTextDocument(fileOrDiff, persistedCacheKey) : void 0) ?? new TextDocument(fileOrDiff.name, contents, languageId, 0, editStack);
416
+ this.#fileInfo = {
417
+ name,
418
+ lang,
419
+ cacheKey
420
+ };
223
421
  this.#textDocument = textDocument;
422
+ if (persistedCacheKey !== void 0) {
423
+ this.#textDocumentCache.set(persistedCacheKey, textDocument);
424
+ persistedStateTarget = {
425
+ cacheKey: persistedCacheKey,
426
+ textDocument
427
+ };
428
+ }
224
429
  this.#tokenizer?.cleanUp();
225
- this.#tokenizer = new EditorTokenizer({
226
- highlighter,
227
- textDocument,
228
- codeOptions: this.#component?.options ?? {},
229
- onDeferTokenize: this.#onDeferTokenize,
230
- setStyle: (css) => {
231
- this.#themeStyleElement.textContent = css;
232
- }
430
+ this.#tokenizer = void 0;
431
+ this.#resetState();
432
+ this.#selections = this.#initSelections;
433
+ requestAnimationFrame(() => {
434
+ this.#options.onAttach?.(this, this.#fileInstance);
233
435
  });
234
- this.#shouldIgnoreSelectionChange = false;
235
- this.#selectionElements?.forEach((el) => el.remove());
236
- this.#selectionElements?.clear();
237
- this.#component?.setSelectedLines(null);
238
- this.#selectionElements = void 0;
239
- this.#selections = void 0;
240
- this.#scrollingToLine = void 0;
241
- this.#reservedSelections = void 0;
242
- this.#searchPanel?.cleanup();
243
- this.#searchPanel = void 0;
244
- this.#quickEdit?.cleanup();
245
- this.#quickEdit = void 0;
436
+ if (this.#textDocument !== void 0 && this.#options.__debug === true) console.log("[diffs/editor] text document rebuilt from", fileOrDiff.name);
246
437
  }
438
+ if (persistedStateTarget === void 0 && this.#restoreStateOnNextSync && persistedCacheKey !== void 0 && this.#textDocument !== void 0) persistedStateTarget = {
439
+ cacheKey: persistedCacheKey,
440
+ textDocument: this.#textDocument
441
+ };
442
+ const textDocument = this.#textDocument;
443
+ if (this.#tokenizer == null && textDocument != null) this.#tokenizer = new EditorTokenizer({
444
+ highlighter,
445
+ textDocument,
446
+ codeOptions: this.#fileInstance?.options ?? {},
447
+ matchBrackets: this.#options.matchBrackets,
448
+ onDeferTokenize: this.#onDeferTokenize,
449
+ onThemeChange: () => this.#scheduleThemeSelectionRefresh(),
450
+ setStyle: (css) => {
451
+ this.#themeStyleElement.textContent = css;
452
+ },
453
+ __debug: this.#options.__debug
454
+ });
247
455
  if (this.#contentElement !== contentEl) {
248
- const guttterEl = contentEl.previousElementSibling;
249
- const targetIsContentElement = (e) => {
250
- const target = e.composedPath()[0];
251
- return target === contentEl || contentEl.contains(target);
252
- };
253
- this.#metrics.init(contentEl);
456
+ this.#gutterElement = gutterEl;
254
457
  this.#contentElement = extend(contentEl, {
255
458
  contentEditable: "true",
256
459
  role: "textbox",
@@ -262,207 +465,224 @@ var Editor = class {
262
465
  translate: false
263
466
  });
264
467
  if (this.#overlayElement !== void 0) contentEl.after(this.#overlayElement);
265
- this.#editorEventDisposes?.forEach((dispose) => dispose());
266
- this.#editorEventDisposes = [
267
- addEventListener(contentEl, "pointerdown", (e) => {
268
- if (e.pointerType !== "mouse") return;
269
- if (isSafari() && this.#lineAnnotations !== void 0 && this.#lineAnnotations.length > 0) this.#mouseUpDisposes = [...contentEl.querySelectorAll("[data-line-annotation]")].map((el) => [addEventListener(el, "mouseenter", () => {
270
- this.#shouldIgnoreSelectionChange = true;
271
- }), addEventListener(el, "mouseleave", () => {
272
- this.#shouldIgnoreSelectionChange = false;
273
- })]).flat();
274
- this.#isContentMouseDown = true;
275
- this.#selectionStart = void 0;
276
- if (e.button === 0 && isPrimaryModifier(e)) this.#reservedSelections = this.#selections?.map((selection) => ({ ...selection }));
277
- if (e.shiftKey) {
278
- const primarySelection = this.#selections?.at(-1);
279
- if (primarySelection !== void 0) {
280
- const pos = primarySelection.direction === DirectionBackward ? primarySelection.end : primarySelection.start;
281
- this.#updateWindowSelection({
282
- start: pos,
283
- end: pos,
284
- direction: DirectionNone
285
- });
286
- }
287
- this.#shiftKeyPressed = true;
288
- }
289
- }, { passive: true }),
290
- addEventListener(contentEl, "keydown", (e) => {
291
- if (e.key === "Escape") {
292
- e.preventDefault();
293
- this.#searchPanel?.cleanup();
294
- this.#searchPanel = void 0;
295
- this.#retainSearchPanelFocus = false;
296
- this.#quickEdit?.cleanup();
297
- this.#quickEdit = void 0;
298
- if (this.#selections !== void 0 && this.#selections.length > 0) {
299
- const primarySelection = this.#selections.at(-1);
300
- if (!isCollapsedSelection(primarySelection) || this.#selections.length > 1) {
301
- const pos = getCaretPosition(primarySelection);
302
- this.#updateSelections([{
303
- start: pos,
304
- end: pos,
305
- direction: DirectionNone
306
- }]);
307
- this.#focus(pos);
308
- }
309
- }
310
- return;
311
- }
312
- if (!targetIsContentElement(e)) return;
313
- const mvShortcut = isMoveCursorShortcut(e);
314
- const textDocument = this.#textDocument;
315
- if (this.#selections !== void 0 && this.#selections.length > 0 && mvShortcut !== void 0 && textDocument !== void 0) {
316
- if (e.shiftKey) this.#updateSelections(mapSelectionShift(textDocument, this.#selections, mvShortcut));
317
- else this.#updateSelections(mapCursorMove(textDocument, this.#selections, mvShortcut));
318
- this.#scrollToPrimaryCaret();
319
- e.preventDefault();
320
- return;
321
- }
322
- const command = resolveEditorCommandFromKeyboardEvent(e);
323
- if (command !== void 0) {
324
- e.preventDefault();
325
- this.#runCommand(command);
326
- }
327
- }),
328
- addEventListener(contentEl, "copy", (e) => {
329
- if (!targetIsContentElement(e)) return;
330
- e.preventDefault();
331
- e.clipboardData?.setData("text", this.#getSelectionText());
332
- }),
333
- addEventListener(contentEl, "cut", (e) => {
334
- if (!targetIsContentElement(e)) return;
335
- e.preventDefault();
336
- e.clipboardData?.setData("text", this.#getSelectionText());
337
- this.#replaceSelectionText("");
338
- }),
339
- addEventListener(contentEl, "paste", (e) => {
340
- if (!targetIsContentElement(e)) return;
341
- e.preventDefault();
342
- const text = e.clipboardData?.getData("text");
343
- if (text !== void 0) this.#replaceSelectionText(text);
344
- }),
345
- addEventListener(contentEl, "beforeinput", (e) => {
346
- if (!targetIsContentElement(e)) return;
347
- e.preventDefault();
348
- this.#handleInput(e.inputType, e.data);
349
- }),
350
- addEventListener(contentEl, "compositionstart", (e) => {
351
- if (!targetIsContentElement(e)) return;
352
- this.#shouldIgnoreSelectionChange = true;
353
- }, { passive: true }),
354
- addEventListener(contentEl, "compositionend", (e) => {
355
- if (!targetIsContentElement(e)) return;
356
- this.#shouldIgnoreSelectionChange = false;
357
- this.#handleInput("insertText", e.data);
358
- }, { passive: true })
359
- ];
360
- if (guttterEl !== null && guttterEl.dataset.gutter !== void 0) this.#editorEventDisposes.push(addEventListener(guttterEl, "pointerdown", (e) => {
361
- let target = e.composedPath()[0];
362
- if (target?.dataset.lineNumberContent !== void 0) target = target.parentElement ?? void 0;
363
- const textDocument = this.#textDocument;
364
- if (target === void 0 || textDocument === void 0) return;
365
- const lineNumber = target.dataset.columnNumber;
366
- const lineType = target.dataset.lineType;
367
- if (lineNumber === void 0 || lineType === void 0 || !isLineEditable(lineType)) return;
368
- const lineIndex = Number(lineNumber) - 1;
369
- const selection = {
370
- start: {
371
- line: lineIndex,
372
- character: 0
373
- },
374
- end: {
375
- line: lineIndex,
376
- character: textDocument.getLineText(lineIndex).length
377
- },
378
- direction: DirectionForward
379
- };
380
- this.#isGutterMouseDown = true;
381
- this.#selectionStart = selection;
382
- this.#updateSelections([selection]);
383
- this.#focus(selection.end);
384
- this.#mouseUpDisposes = [addEventListener(document, "mousemove", (e$1) => {
385
- let target$1 = e$1.composedPath()[0];
386
- if (target$1?.dataset.lineNumberContent !== void 0) target$1 = target$1?.parentElement ?? void 0;
387
- else if (target$1?.tagName === "SPAN") target$1 = target$1?.closest("[data-line]");
388
- if (target$1 === void 0) return;
389
- const lineNumber$1 = target$1.dataset.columnNumber ?? target$1.dataset.line;
390
- const lineType$1 = target$1.dataset.lineType;
391
- if (this.#isGutterMouseDown && this.#textDocument !== void 0 && lineNumber$1 !== void 0 && lineType$1 !== void 0 && isLineEditable(lineType$1)) {
392
- const lineIndex$1 = Number(lineNumber$1) - 1;
393
- let selection$1 = {
394
- start: {
395
- line: lineIndex$1,
396
- character: 0
397
- },
398
- end: {
399
- line: lineIndex$1,
400
- character: this.#textDocument.getLineText(lineIndex$1).length
401
- },
402
- direction: DirectionForward
403
- };
404
- if (this.#selectionStart !== void 0) selection$1 = createSelectionFrom(this.#selectionStart, selection$1);
405
- else this.#selectionStart = selection$1;
406
- this.#updateSelections([selection$1]);
407
- this.#focus(selection$1.end);
408
- }
409
- }, { passive: true })];
410
- }, { passive: true }));
411
- this.#resizeObserver?.disconnect();
412
- this.#resizeObserver = new ResizeObserver(() => {
413
- requestAnimationFrame(() => {
414
- this.#handleLayoutResize();
415
- });
416
- });
417
- this.#resizeObserver.observe(contentEl);
418
- this.#resizeObserver.observe(contentEl.parentElement);
468
+ this.#metrics.init(contentEl);
469
+ this.#remeasureMetricsOnFontLoad();
470
+ this.#listenContentElement(contentEl, gutterEl);
471
+ if (this.#contentElement !== void 0 && this.#options.__debug === true) console.log("[diffs/editor] full re-render triggered !!!");
419
472
  }
420
- this.#lineYCache.clear();
421
- this.#wrapLineOffsetsCache.clear();
422
- this.#lastCharX = void 0;
473
+ if (contentEl.ariaLabel !== fileOrDiff.name) contentEl.ariaLabel = fileOrDiff.name;
474
+ if (lineAnnotations !== void 0 && lineAnnotations.length > 0 || this.#isDiff) for (const child of this.#contentElement.children) {
475
+ const el = child;
476
+ const { lineAnnotation, lineType, separator } = el.dataset;
477
+ if (lineAnnotation !== void 0 || separator !== void 0 || lineType === "change-deletion") el.setAttribute("contenteditable", "false");
478
+ }
479
+ this.#resetCache();
480
+ this.#tokenizer?.syncTheme(this.#fileInstance?.options ?? {});
423
481
  this.#lineAnnotations = lineAnnotations;
424
482
  this.#renderRange = renderRange;
425
- this.#tokenizer?.prebuildStateStackMap(renderRange);
426
- if (this.#initSelections !== void 0) {
427
- this.setSelections(this.#initSelections);
428
- this.#scrollToPrimaryCaret();
483
+ this.#viewportWindowLines = renderRange?.totalLines;
484
+ this.#tokenizer?.prebuildStateStack(renderRange);
485
+ this.#markerRenderer?.removePopover();
486
+ if (this.#selections !== void 0 || this.#matches !== void 0 || this.#markerRenderer !== void 0) this.#updateSelections(this.#selections ?? []);
487
+ if (this.#initSelections !== void 0 && this.#primaryCaretElement !== void 0) {
429
488
  this.#initSelections = void 0;
430
- } else if (this.#selections !== void 0 && this.#selections.length > 0) this.#updateSelections(this.#selections);
489
+ this.#scrollToPrimaryCaret(false, "center");
490
+ } else if (this.#scrollingToLine !== void 0) this.#scrollToLine(this.#scrollingToLine, this.#scrollingToLineChar, this.#scrollingToLineNoFocus);
491
+ else if (this.#selections !== void 0 && this.#selections.length > 0 && !this.#retainSearchPanelFocus) this.focus({ preventScroll: true });
492
+ if (this.#retainSearchPanelFocus) this.#searchPanel?.focus();
431
493
  if (this.#options.__debug === true && renderRange !== void 0) {
432
494
  const { startingLine, totalLines } = renderRange;
433
- console.log("[diffs/editor] render file:", fileContents.name, "RenderRange:", startingLine + "-" + (startingLine + totalLines), "of", this.#textDocument.lineCount, "lines");
495
+ console.log("[diffs/editor] render file:", fileOrDiff.name, "RenderRange:", startingLine + "-" + (startingLine + totalLines), "of", this.#textDocument?.lineCount, "lines");
434
496
  }
435
- if (this.#scrollingToLine !== void 0) {
436
- this.#scrollToLine(this.#scrollingToLine, this.#scrollingToLineChar);
437
- this.#scrollingToLine = void 0;
438
- this.#scrollingToLineChar = void 0;
439
- } else if (this.#selections !== void 0 && this.#selections.length > 0) this.focus({ preventScroll: true });
440
- if (this.#retainSearchPanelFocus) {
441
- this.#retainSearchPanelFocus = false;
442
- requestAnimationFrame(() => {
443
- this.#searchPanel?.focus();
497
+ if (persistedStateTarget !== void 0) {
498
+ this.#restoreStateOnNextSync = false;
499
+ this.#restorePersistedState(persistedStateTarget.cacheKey, persistedStateTarget.textDocument);
500
+ }
501
+ };
502
+ get #isStatePersistenceEnabled() {
503
+ return this.#options.persistState === true && this.#fileInstance?.type === "file";
504
+ }
505
+ #getCachedTextDocument(file, cacheKey) {
506
+ const textDocument = this.#textDocumentCache.get(cacheKey);
507
+ const languageId = file.lang ?? getFiletypeFromFileName(file.name);
508
+ return textDocument?.languageId === languageId ? textDocument : void 0;
509
+ }
510
+ #getStateStorage() {
511
+ const option = this.#options.persistStateStorage ?? "inMemory";
512
+ if (this.#stateStorage === void 0 || this.#stateStorageOption !== option) {
513
+ this.#stateStorage = createStateStorage(option);
514
+ this.#stateStorageOption = option;
515
+ }
516
+ return this.#stateStorage;
517
+ }
518
+ #persistCurrentState() {
519
+ const fileInfo = this.#fileInfo;
520
+ const textDocument = this.#textDocument;
521
+ if (!this.#isStatePersistenceEnabled || fileInfo === void 0 || textDocument === void 0) return;
522
+ const cacheKey = requirePersistedCacheKey(fileInfo);
523
+ this.#textDocumentCache.set(cacheKey, textDocument);
524
+ let storage;
525
+ try {
526
+ storage = this.#getStateStorage();
527
+ } catch {
528
+ return;
529
+ }
530
+ const state = cloneEditorState(this.getState());
531
+ const pendingRestore = this.#pendingStateRestore;
532
+ if (pendingRestore?.cacheKey === cacheKey && pendingRestore.textDocument === textDocument) {
533
+ this.#pendingStateRestore = void 0;
534
+ if (textDocument.version === pendingRestore.documentVersion && this.#selections === pendingRestore.selections && state.view?.scrollLeft === pendingRestore.view?.scrollLeft && state.view?.scrollTop === pendingRestore.view?.scrollTop) return;
535
+ this.#writeState(storage, cacheKey, state, pendingRestore.completion);
536
+ return;
537
+ }
538
+ this.#writeState(storage, cacheKey, state);
539
+ }
540
+ #writeState(storage, cacheKey, state, waitFor) {
541
+ const previousWrite = this.#pendingStateWrites.get(cacheKey);
542
+ if (waitFor !== void 0 || previousWrite !== void 0) {
543
+ let pending = waitFor ?? Promise.resolve();
544
+ if (previousWrite !== void 0) pending = pending.then(() => previousWrite);
545
+ this.#trackStateWrite(cacheKey, pending.then(() => storage.set(cacheKey, state)));
546
+ return;
547
+ }
548
+ let result;
549
+ try {
550
+ result = storage.set(cacheKey, state);
551
+ } catch {
552
+ return;
553
+ }
554
+ if (!isPromise(result)) return;
555
+ this.#trackStateWrite(cacheKey, result);
556
+ }
557
+ #trackStateWrite(cacheKey, result) {
558
+ const pending = result.catch(() => {});
559
+ this.#pendingStateWrites.set(cacheKey, pending);
560
+ pending.finally(() => {
561
+ if (this.#pendingStateWrites.get(cacheKey) === pending) this.#pendingStateWrites.delete(cacheKey);
562
+ });
563
+ }
564
+ #restorePersistedState(cacheKey, textDocument) {
565
+ const generation = ++this.#stateRestoreGeneration;
566
+ const documentVersion = textDocument.version;
567
+ const selections = this.#selections;
568
+ const view = this.getState().view;
569
+ const applyState = (state) => {
570
+ const currentView = this.getState().view;
571
+ if (state === void 0 || generation !== this.#stateRestoreGeneration || this.#textDocument !== textDocument || textDocument.version !== documentVersion || this.#selections !== selections || currentView?.scrollLeft !== view?.scrollLeft || currentView?.scrollTop !== view?.scrollTop || this.#fileInfo === void 0 || requirePersistedCacheKey(this.#fileInfo) !== cacheKey) return;
572
+ this.setState(cloneEditorState(state));
573
+ };
574
+ const readState = () => {
575
+ let result;
576
+ try {
577
+ result = this.#getStateStorage().get(cacheKey);
578
+ } catch {
579
+ return;
580
+ }
581
+ if (isPromise(result)) return result.then(applyState).catch(() => {});
582
+ else try {
583
+ applyState(result);
584
+ } catch {}
585
+ };
586
+ const pendingWrite = this.#pendingStateWrites.get(cacheKey);
587
+ const result = pendingWrite === void 0 ? readState() : pendingWrite.then(readState);
588
+ if (isPromise(result)) {
589
+ const pendingRestore = {
590
+ cacheKey,
591
+ textDocument,
592
+ documentVersion,
593
+ selections,
594
+ view,
595
+ completion: result.catch(() => {})
596
+ };
597
+ this.#pendingStateRestore = pendingRestore;
598
+ pendingRestore.completion.finally(() => {
599
+ if (this.#pendingStateRestore === pendingRestore) this.#pendingStateRestore = void 0;
444
600
  });
445
601
  }
446
- if (this.#quickEdit !== void 0 && this.#isLineVisible(this.#quickEdit.line) && this.#contentElement !== void 0) this.#quickEdit.render(this.#contentElement);
602
+ }
603
+ #isLineRenderable(line) {
604
+ return this.#fileInstance?.isLineRenderable?.(line + 1) ?? true;
605
+ }
606
+ get #resolveRenderableLine() {
607
+ const fileInstance = this.#fileInstance;
608
+ if (fileInstance?.getNearestRenderableLine == null) return;
609
+ return (line, direction) => {
610
+ const nearest = fileInstance.getNearestRenderableLine(line + 1, direction);
611
+ return nearest == null ? void 0 : nearest - 1;
612
+ };
613
+ }
614
+ #revealLineIfCollapsed(line) {
615
+ if (!this.#isLineRenderable(line)) this.#fileInstance?.revealLine?.(line + 1);
616
+ }
617
+ get #diffSyle() {
618
+ return this.#fileInstance?.options.diffStyle ?? "split";
619
+ }
620
+ get #isDiff() {
621
+ return this.#fileInstance?.type === "file-diff";
622
+ }
623
+ get #isWrap() {
624
+ return this.#fileInstance?.options.overflow === "wrap";
625
+ }
626
+ #getPopoverManager() {
627
+ return this.#popoverManager ??= new PopoverManager({
628
+ hasActivePopover: () => this.#selectionAction !== void 0 || this.#markerRenderer?.isPopoverVisible() === true,
629
+ updateActivePopover: () => {
630
+ this.#updateSelectionActionPopover();
631
+ this.#markerRenderer?.updatePopoverPosition();
632
+ }
633
+ });
634
+ }
635
+ #resetCache() {
636
+ this.#lineYCache.clear();
637
+ this.#wrapLineOffsetsCache.clear();
638
+ this.#lineElementsCache.clear();
639
+ this.#lastAccessedCharX = void 0;
640
+ }
641
+ #resetState() {
642
+ this.#setEditorActiveLineSafe(null);
643
+ this.#gutterWidthCache = void 0;
644
+ this.#contentWidthCache = void 0;
645
+ this.#shouldIgnoreSelectionChange = false;
646
+ this.#suppressNativeSelectionSync = false;
647
+ this.#overlayElements?.forEach((el) => el.remove());
648
+ this.#overlayElements = void 0;
649
+ this.#selections = void 0;
650
+ this.#reservedSelections = void 0;
651
+ this.#scrollingToLine = void 0;
652
+ this.#markerRenderer?.cleanup();
653
+ this.#markerRenderer = void 0;
654
+ this.#searchPanel?.cleanup();
655
+ this.#searchPanel = void 0;
656
+ this.#selectionAction?.cleanup();
657
+ this.#selectionAction = void 0;
447
658
  }
448
659
  #initialize() {
660
+ this.#globalStyleElement = h("style", {
661
+ dataset: "editorGlobalCss",
662
+ textContent: `
663
+ [data-annotation-slot] {
664
+ user-select: none;
665
+ -webkit-user-select: none;
666
+ }
667
+ `
668
+ });
449
669
  this.#editorStyleElement = h("style", {
450
670
  dataset: "editorCss",
451
- textContent: editorCSS
671
+ textContent: editor_default
452
672
  });
453
673
  this.#themeStyleElement = h("style", { dataset: "editorThemeCss" });
454
- this.#globalStyleElement = h("style", {
455
- dataset: "editorGlobalCss",
456
- textContent: editorGlobalCSS
457
- });
674
+ this.#spriteElement = createSpriteElement();
458
675
  this.#overlayElement = h("div", { dataset: "editorOverlay" });
459
676
  this.#globalEventDisposes = [
460
677
  addEventListener(document, "selectionchange", () => {
461
- const shadowRoot = this.#componentContainer?.shadowRoot;
462
- if (this.#shouldIgnoreSelectionChange || shadowRoot == null) return;
463
- const composedRange = document.getSelection()?.getComposedRanges({ shadowRoots: [shadowRoot] })?.[0];
678
+ const shadowRoot = this.#fileContainer?.shadowRoot;
679
+ if (this.#shouldIgnoreSelectionChange || this.#suppressNativeSelectionSync || shadowRoot == null || !this.#contentHasFocus) return;
680
+ if (this.#selections !== void 0 && this.#selections.length > 1 && !this.#isContentMouseDown) return;
681
+ const selectionRaw = document.getSelection();
682
+ if (selectionRaw == null) return;
683
+ const composedRange = typeof selectionRaw.getComposedRanges === "function" ? selectionRaw.getComposedRanges({ shadowRoots: [shadowRoot] })?.[0] : getShadowRootRange(shadowRoot);
464
684
  if (composedRange === void 0 || !this.#rangeBelongsToEditor(composedRange)) return;
465
- let selection = convertSelection(composedRange, DirectionNone);
685
+ let selection = convertSelection(composedRange, 0);
466
686
  if (selection === void 0) return;
467
687
  if (this.#isContentMouseDown && this.#shiftKeyPressed && this.#selections !== void 0 && this.#selections.length > 0) {
468
688
  const primarySelection = this.#selections.at(-1);
@@ -472,13 +692,17 @@ var Editor = class {
472
692
  if (this.#isContentMouseDown) if (this.#selectionStart !== void 0) selection = createSelectionFrom(this.#selectionStart, selection);
473
693
  else this.#selectionStart = selection;
474
694
  else if (this.#selectionStart !== void 0) selection.direction = createSelectionFrom(this.#selectionStart, selection).direction;
695
+ else if (this.#selections !== void 0 && this.#selections.length === 1) {
696
+ const previous = this.#selections[0];
697
+ if (comparePosition(previous.start, selection.start) === 0 && comparePosition(previous.end, selection.end) === 0) selection.direction = previous.direction;
698
+ }
475
699
  if (this.#reservedSelections !== void 0) this.#updateSelections([...this.#reservedSelections.filter((reservedSelection) => !selectionIntersects(reservedSelection, selection)), selection]);
476
700
  else this.#updateSelections([selection]);
477
701
  }, { passive: true }),
478
702
  addEventListener(document, "pointerup", (e) => {
479
703
  if (e.pointerType !== "mouse") return;
480
- this.#mouseUpDisposes?.forEach((dispose) => dispose());
481
- this.#mouseUpDisposes = void 0;
704
+ this.#selectEventDisposes?.forEach((dispose) => dispose());
705
+ this.#selectEventDisposes = void 0;
482
706
  if (this.#isGutterMouseDown) {
483
707
  this.#isGutterMouseDown = false;
484
708
  this.#focus();
@@ -488,9 +712,7 @@ var Editor = class {
488
712
  this.#shiftKeyPressed = false;
489
713
  this.#selectionStart = void 0;
490
714
  this.#reservedSelections = void 0;
491
- this.#selectionElements?.forEach((el, key) => {
492
- if (key.startsWith("quickEditIcon-")) el.dataset.visible = "true";
493
- });
715
+ if (this.#options.enabledSelectionAction === true && this.#selections !== void 0 && this.#selections.length > 0 && !isCollapsedSelection(this.#selections.at(-1))) this.#updateSelections(this.#selections);
494
716
  }, { passive: true }),
495
717
  addEventListener(document, "keydown", (e) => {
496
718
  if (e.key === "Shift") this.#selectionStart = this.#selections?.at(-1);
@@ -500,66 +722,458 @@ var Editor = class {
500
722
  }, { passive: true })
501
723
  ];
502
724
  }
725
+ #replaceSelectEventListeners(disposes) {
726
+ this.#selectEventDisposes?.forEach((dispose) => dispose());
727
+ this.#selectEventDisposes = disposes;
728
+ }
729
+ #isLineSelectionEnabled() {
730
+ return this.#fileInstance?.options.enableLineSelection === true;
731
+ }
732
+ #preserveEditorSelectionsForGutterGesture() {
733
+ this.#suppressNativeSelectionSync = this.#selections !== void 0;
734
+ }
735
+ #listenContentElement(contentEl, gutterEl) {
736
+ const { onFocus, onBlur } = this.#options;
737
+ const targetIsContentElement = (e) => {
738
+ const target = e.composedPath()[0];
739
+ return target !== void 0 && (target === contentEl || contentEl.contains(target));
740
+ };
741
+ this.#editorEventDisposes?.forEach((dispose) => dispose());
742
+ this.#editorEventDisposes = [
743
+ addEventListener(contentEl, "focus", () => {
744
+ this.#contentHasFocus = true;
745
+ onFocus?.();
746
+ if (!this.#isContentMouseDown && !this.#shouldIgnoreSelectionChange && this.#selections !== void 0 && this.#selections.length > 0) this.#setWindowSelection(this.#selections.at(-1));
747
+ }, { passive: true }),
748
+ addEventListener(contentEl, "blur", () => {
749
+ this.#contentHasFocus = false;
750
+ onBlur?.();
751
+ }, { passive: true }),
752
+ addEventListener(contentEl, "pointerdown", (e) => {
753
+ this.#suppressNativeSelectionSync = false;
754
+ if (e.pointerType !== "mouse") return;
755
+ if (this.#isDeletedLineTarget(e)) {
756
+ this.#setDeletedTextSelectionActive(true);
757
+ if (this.#selections !== void 0) this.#updateSelections([]);
758
+ return;
759
+ }
760
+ this.#setDeletedTextSelectionActive(false);
761
+ this.#markerRenderer?.removePopover();
762
+ if (isSafari() && this.#lineAnnotations !== void 0 && this.#lineAnnotations.length > 0) {
763
+ const annotationDisposes = [...contentEl.querySelectorAll("[data-line-annotation]")].map((el) => [addEventListener(el, "mouseenter", () => {
764
+ this.#shouldIgnoreSelectionChange = true;
765
+ }), addEventListener(el, "mouseleave", () => {
766
+ this.#shouldIgnoreSelectionChange = false;
767
+ })]).flat();
768
+ this.#replaceSelectEventListeners(annotationDisposes);
769
+ }
770
+ this.#isContentMouseDown = true;
771
+ this.#selectionStart = void 0;
772
+ if (e.button === 0 && isPrimaryModifier(e)) this.#reservedSelections = this.#selections?.map((selection) => ({ ...selection }));
773
+ if (e.shiftKey) {
774
+ const primarySelection = this.#selections?.at(-1);
775
+ if (primarySelection !== void 0) {
776
+ const pos = primarySelection.direction === -1 ? primarySelection.end : primarySelection.start;
777
+ this.#setWindowSelection({
778
+ start: pos,
779
+ end: pos,
780
+ direction: 0
781
+ });
782
+ }
783
+ this.#shiftKeyPressed = true;
784
+ }
785
+ }, { passive: true }),
786
+ addEventListener(contentEl, "keydown", (e) => {
787
+ if (e.key === "Escape") {
788
+ e.preventDefault();
789
+ this.#searchPanel?.close();
790
+ this.#searchPanel = void 0;
791
+ this.#retainSearchPanelFocus = false;
792
+ this.#selectionAction?.cleanup();
793
+ this.#selectionAction = void 0;
794
+ this.#runCommand("simplifySelection");
795
+ return;
796
+ }
797
+ if (!targetIsContentElement(e)) return;
798
+ this.#suppressNativeSelectionSync = false;
799
+ const mvShortcut = isMoveCursorShortcut(e);
800
+ const textDocument = this.#textDocument;
801
+ if (this.#selections !== void 0 && this.#selections.length > 0 && mvShortcut !== void 0 && textDocument !== void 0) {
802
+ const cursorMoveOptions = {
803
+ getSoftLineOffsets: this.#isWrap ? (line) => this.#wrapLineText(line) : void 0,
804
+ resolveRenderableLine: this.#resolveRenderableLine
805
+ };
806
+ if (e.shiftKey) this.#updateSelections(mapSelectionShift(textDocument, this.#selections, mvShortcut, cursorMoveOptions));
807
+ else this.#updateSelections(mapCursorMove(textDocument, this.#selections, mvShortcut, cursorMoveOptions));
808
+ this.#scrollToPrimaryCaret();
809
+ e.preventDefault();
810
+ return;
811
+ }
812
+ if ((e.key.length === 1 ? e.key.toLowerCase() : e.key) === "v" && isPrimaryModifier(e)) {
813
+ if (e.repeat && this.#isDiff) {
814
+ e.preventDefault();
815
+ return;
816
+ }
817
+ if (this.#options.clipboard !== void 0) {
818
+ e.preventDefault();
819
+ queueRender(this.#handleCustomPasteEvent);
820
+ return;
821
+ }
822
+ }
823
+ if (this.#searchPanel !== void 0) {
824
+ const findAgain = resolveFindAgainShortcut(e);
825
+ if (findAgain !== void 0) {
826
+ e.preventDefault();
827
+ this.#searchPanel.navigate(findAgain === "previous");
828
+ return;
829
+ }
830
+ }
831
+ const command = resolveEditorCommandFromKeyboardEvent(e);
832
+ if (command !== void 0) {
833
+ e.preventDefault();
834
+ this.#runCommand(command);
835
+ }
836
+ }),
837
+ addEventListener(contentEl, "copy", (e) => {
838
+ if (!targetIsContentElement(e)) return;
839
+ e.preventDefault();
840
+ if (this.#isDeletedTextSelectionActive()) e.clipboardData?.setData("text", this.#deletedTextForClipboard());
841
+ else this.#writeSelectionClipboardData(e.clipboardData, this.#getSelectionText(), this.#getSelectionClipboardTexts());
842
+ }),
843
+ addEventListener(contentEl, "cut", (e) => {
844
+ if (!targetIsContentElement(e)) return;
845
+ e.preventDefault();
846
+ if (this.#isDeletedTextSelectionActive()) e.clipboardData?.setData("text", this.#deletedTextForClipboard());
847
+ else {
848
+ const selectionTexts = this.#getSelectionClipboardTexts();
849
+ this.#writeSelectionClipboardData(e.clipboardData, this.#cutSelectionText(), selectionTexts);
850
+ }
851
+ }),
852
+ addEventListener(contentEl, "paste", (e) => {
853
+ if (!targetIsContentElement(e)) return;
854
+ e.preventDefault();
855
+ const clipboardData = e.clipboardData;
856
+ const textDocument = this.#textDocument;
857
+ if (clipboardData === null || textDocument === void 0) return;
858
+ let text = clipboardData.getData("text");
859
+ const selectionCount = this.#selections?.length ?? 0;
860
+ if (selectionCount > 1) {
861
+ const multiSelectionText = clipboardData.getData(MULTI_SELECTION_CLIPBOARD_TYPE);
862
+ if (multiSelectionText !== void 0) try {
863
+ const selectionTexts = JSON.parse(multiSelectionText);
864
+ if (Array.isArray(selectionTexts) && selectionTexts.length === selectionCount) text = selectionTexts;
865
+ } catch {}
866
+ }
867
+ this.#replaceSelectionText(Array.isArray(text) ? text.map((t) => textDocument.normalizeEol(t)) : textDocument.normalizeEol(text), void 0, true, "document");
868
+ }),
869
+ addEventListener(contentEl, "beforeinput", (e) => {
870
+ if (!targetIsContentElement(e)) return;
871
+ if (e.inputType === "insertCompositionText") return;
872
+ e.preventDefault();
873
+ this.#handleInput(e.inputType, e.data);
874
+ }),
875
+ addEventListener(contentEl, "drop", (e) => {
876
+ if (!targetIsContentElement(e)) return;
877
+ e.preventDefault();
878
+ }),
879
+ addEventListener(contentEl, "compositionstart", (e) => {
880
+ if (!targetIsContentElement(e)) return;
881
+ this.#isComposing = true;
882
+ this.#shouldIgnoreSelectionChange = true;
883
+ }, { passive: true }),
884
+ addEventListener(contentEl, "compositionend", (e) => {
885
+ if (!targetIsContentElement(e)) return;
886
+ this.#shouldIgnoreSelectionChange = false;
887
+ const wasComposing = this.#isComposing;
888
+ this.#isComposing = false;
889
+ if (e.data !== "" || !wasComposing) this.#handleInput("insertText", e.data);
890
+ }, { passive: true })
891
+ ];
892
+ const deletionsCode = this.#fileContainer?.shadowRoot?.querySelector("[data-deletions]");
893
+ if (deletionsCode != null) this.#editorEventDisposes.push(addEventListener(deletionsCode, "pointerdown", (e) => {
894
+ const path = e.composedPath();
895
+ if (isGutterUtilityPath(path)) {
896
+ this.#preserveEditorSelectionsForGutterGesture();
897
+ return;
898
+ }
899
+ const target = path[0];
900
+ const gutterRow = target instanceof HTMLElement ? target.closest("[data-column-number]") : null;
901
+ if (gutterRow instanceof HTMLElement) {
902
+ if (this.#isLineSelectionEnabled()) {
903
+ this.#preserveEditorSelectionsForGutterGesture();
904
+ return;
905
+ }
906
+ if (this.#beginDeletionGutterSelection(gutterRow, deletionsCode, e.pointerType === "mouse")) return;
907
+ }
908
+ this.#setDeletedTextSelectionActive(true);
909
+ if (this.#selections !== void 0) this.#updateSelections([]);
910
+ }, { passive: true }));
911
+ if (gutterEl !== void 0) {
912
+ const resolveGutterTarget = (eventTarget, includeContentLine = false) => {
913
+ let target = eventTarget;
914
+ if (target?.dataset.lineNumberContent !== void 0) target = target.parentElement ?? void 0;
915
+ else if (includeContentLine && target?.tagName === "SPAN") target = target.closest("[data-line]");
916
+ return target;
917
+ };
918
+ const resolveEditableLine = (target) => {
919
+ if (target === void 0) return;
920
+ const lineType = target.dataset.lineType;
921
+ const lineNumber = getLineNumberAttr(target) ?? getLineNumberAttr(target, "columnNumber");
922
+ if (lineNumber === void 0 || lineType === void 0 || !isLineEditable(lineType)) return;
923
+ return lineNumber - 1;
924
+ };
925
+ this.#editorEventDisposes.push(addEventListener(gutterEl, "pointerdown", (e) => {
926
+ const path = e.composedPath();
927
+ if (isGutterUtilityPath(path)) {
928
+ this.#preserveEditorSelectionsForGutterGesture();
929
+ return;
930
+ }
931
+ const gutterRow = resolveGutterTarget(path[0]);
932
+ if (gutterRow !== void 0 && this.#isLineSelectionEnabled()) {
933
+ this.#preserveEditorSelectionsForGutterGesture();
934
+ return;
935
+ }
936
+ if (gutterRow?.dataset.lineType === "change-deletion") {
937
+ const code = gutterRow.closest("[data-code]");
938
+ if (code != null) this.#beginDeletionGutterSelection(gutterRow, code, e.pointerType === "mouse");
939
+ return;
940
+ }
941
+ if (e.pointerType !== "mouse") return;
942
+ const textDocument = this.#textDocument;
943
+ const lineIndex = resolveEditableLine(gutterRow);
944
+ if (lineIndex === void 0 || textDocument === void 0) return;
945
+ this.#markerRenderer?.removePopover();
946
+ const selection = this.#spanLineSelection(lineIndex, lineIndex, textDocument);
947
+ this.#isGutterMouseDown = true;
948
+ this.#selectionStart = selection;
949
+ this.#updateSelections([selection]);
950
+ this.#setWindowSelection(selection);
951
+ this.#focus();
952
+ this.#replaceSelectEventListeners([addEventListener(document, "mousemove", (e) => {
953
+ if (!this.#isGutterMouseDown) return;
954
+ const textDocument = this.#textDocument;
955
+ const lineIndex = resolveEditableLine(resolveGutterTarget(e.composedPath()[0], true));
956
+ if (lineIndex === void 0 || textDocument === void 0) return;
957
+ const anchorLine = this.#selectionStart?.start.line ?? lineIndex;
958
+ const selection = this.#spanLineSelection(anchorLine, lineIndex, textDocument);
959
+ this.#selectionStart ??= selection;
960
+ this.#updateSelections([selection]);
961
+ this.#focus(selection.direction === -1 ? selection.start : selection.end);
962
+ }, { passive: true })]);
963
+ }, { passive: true }));
964
+ }
965
+ this.#markerRenderer?.listenHover(contentEl);
966
+ this.#resizeObserver?.disconnect();
967
+ this.#resizeObserver = new ResizeObserver(this.#handleLayoutResize);
968
+ this.#resizeObserver.observe(contentEl);
969
+ this.#resizeObserver.observe(contentEl.parentElement);
970
+ this.#computeContentOffset(contentEl);
971
+ }
972
+ #handleCustomPasteEvent = async () => {
973
+ const clipboard = this.#options.clipboard;
974
+ if (clipboard !== void 0) {
975
+ let text = await clipboard.readText();
976
+ const selectionCount = this.#selections?.length ?? 0;
977
+ if (selectionCount > 1) {
978
+ const multiSelectionText = await clipboard.readText(MULTI_SELECTION_CLIPBOARD_TYPE);
979
+ try {
980
+ const selectionTexts = JSON.parse(multiSelectionText);
981
+ if (Array.isArray(selectionTexts) && selectionTexts.length === selectionCount) text = selectionTexts;
982
+ } catch {}
983
+ }
984
+ const textDocument = this.#textDocument;
985
+ if (textDocument !== void 0) this.#replaceSelectionText(Array.isArray(text) ? text.map((t) => textDocument.normalizeEol(t)) : textDocument.normalizeEol(text), void 0, true, "document");
986
+ }
987
+ };
988
+ #computeContentOffset(contentEl) {
989
+ if (this.#isDiff && this.#diffSyle === "split" && this.#isWrap) {
990
+ this.#contentOffset = {
991
+ top: contentEl.offsetTop,
992
+ left: contentEl.offsetLeft - this.#getGutterWidth()
993
+ };
994
+ if (this.#options.__debug === true) console.log("[diffs/editor] content offset:", this.#contentOffset);
995
+ }
996
+ }
997
+ get #activeContentOffset() {
998
+ if (this.#isDiff && this.#diffSyle === "split" && this.#isWrap) return this.#contentOffset;
999
+ }
503
1000
  #runCommand(command) {
504
1001
  const textDocument = this.#textDocument;
505
1002
  if (textDocument === void 0) return;
506
1003
  switch (command) {
507
1004
  case "openSearchPanel":
508
- this.#renderSearchPanel();
1005
+ this.#openSearchPanel("find");
1006
+ break;
1007
+ case "openSearchReplacePanel":
1008
+ this.#openSearchPanel("replace");
509
1009
  break;
510
1010
  case "findNextMatch": {
511
1011
  const selections = this.#selections;
512
- const textDocument$1 = this.#textDocument;
513
- if (selections === void 0 || textDocument$1 === void 0) break;
1012
+ if (selections === void 0) break;
514
1013
  if (selections.some(isCollapsedSelection)) {
515
1014
  const expanded = selections.map((sel) => {
516
- if (isCollapsedSelection(sel)) return expandCollapsedSelectionToWord(textDocument$1, sel);
1015
+ if (isCollapsedSelection(sel)) return expandCollapsedSelectionToWord(textDocument, sel);
517
1016
  return sel;
518
1017
  });
519
1018
  this.#updateSelections(expanded);
520
1019
  this.focus();
521
1020
  } else {
522
- const nextMatch = findNexMatch(textDocument$1, selections);
1021
+ const nextMatch = findNextMatch(textDocument, selections);
523
1022
  if (nextMatch !== void 0) {
524
1023
  this.#updateSelections(nextMatch);
1024
+ const primaryMatch = nextMatch.at(-1);
1025
+ if (primaryMatch !== void 0) this.#revealLineIfCollapsed(getCaretPosition(primaryMatch).line);
525
1026
  this.#scrollToPrimaryCaret();
526
1027
  }
527
1028
  }
528
1029
  break;
529
1030
  }
1031
+ case "moveLineUp":
1032
+ case "moveLineDown":
1033
+ this.#moveSelectedLines(command === "moveLineUp" ? -1 : 1);
1034
+ break;
1035
+ case "copyLineUp":
1036
+ case "copyLineDown":
1037
+ this.#copySelectedLines(command === "copyLineUp" ? -1 : 1);
1038
+ break;
1039
+ case "simplifySelection": {
1040
+ const selections = this.#selections;
1041
+ const primarySelection = selections?.at(-1);
1042
+ if (selections === void 0 || primarySelection === void 0) break;
1043
+ if (selections.length > 1) {
1044
+ this.#updateSelections([primarySelection]);
1045
+ this.#focus(getCaretPosition(primarySelection));
1046
+ } else if (!isCollapsedSelection(primarySelection)) {
1047
+ const caret = getCaretPosition(primarySelection);
1048
+ this.#updateSelections([{
1049
+ start: caret,
1050
+ end: caret,
1051
+ direction: 0
1052
+ }]);
1053
+ this.#focus(caret);
1054
+ }
1055
+ break;
1056
+ }
1057
+ case "insertBlankLine":
1058
+ this.#insertBlankLine();
1059
+ break;
1060
+ case "deleteHardLineForward":
1061
+ this.#deleteHardLineForward();
1062
+ break;
1063
+ case "toggleComment":
1064
+ case "toggleBlockComment": {
1065
+ const selections = this.#selections;
1066
+ if (selections === void 0) break;
1067
+ const { lineComment, blockComment } = resolveCommentConfig(textDocument.languageId, this.#options.languageCommentConfig);
1068
+ if (command === "toggleComment" && lineComment !== null) {
1069
+ this.#applyCommandEdits(resolveLineCommentEdits(textDocument, selections, lineComment));
1070
+ break;
1071
+ }
1072
+ const linewise = command === "toggleComment";
1073
+ const result = resolveBlockCommentEdits(textDocument, selections, blockComment, linewise);
1074
+ if (result !== void 0) this.#applyCommandEdits(result.edits, linewise ? void 0 : (document) => result.nextSelectionOffsets.map(([start, end, direction]) => ({
1075
+ start: document.positionAt(start),
1076
+ end: document.positionAt(end),
1077
+ direction
1078
+ })));
1079
+ break;
1080
+ }
530
1081
  case "indent":
531
1082
  case "outdent":
1083
+ case "indentLess":
1084
+ case "indentMore":
532
1085
  if (this.#selections !== void 0) {
533
1086
  const edits = [];
534
1087
  const nextSelections = [];
1088
+ const editedLines = /* @__PURE__ */ new Set();
1089
+ const sameLineIndents = [];
535
1090
  for (const selection of this.#selections) {
536
1091
  const startLine = selection.start.line;
537
- const outdent = command === "outdent";
538
- if (startLine !== selection.end.line || outdent) {
1092
+ const outdent = command === "outdent" || command === "indentLess";
1093
+ const lineBased = command === "indentLess" || command === "indentMore";
1094
+ if (startLine !== selection.end.line || outdent || lineBased) {
539
1095
  const ret = resolveIndentEdits(textDocument, selection, this.#metrics.tabSize, outdent);
540
- edits.push(...ret[0]);
1096
+ for (const edit of ret[0]) {
1097
+ const line = edit.range.start.line;
1098
+ if (!editedLines.has(line)) {
1099
+ editedLines.add(line);
1100
+ edits.push(edit);
1101
+ }
1102
+ }
541
1103
  nextSelections.push(ret[1]);
542
1104
  } else {
543
- const lineChar0 = textDocument.charAt({
1105
+ const text = textDocument.charAt({
544
1106
  line: startLine,
545
1107
  character: 0
1108
+ }) === " " ? " " : " ".repeat(this.#metrics.tabSize);
1109
+ edits.push({
1110
+ range: selection,
1111
+ newText: text
546
1112
  });
547
- this.#replaceSelectionText(lineChar0 === " " ? " " : " ".repeat(this.#metrics.tabSize));
1113
+ sameLineIndents.push({
1114
+ line: startLine,
1115
+ startCharacter: selection.start.character,
1116
+ addedLength: text.length - (selection.end.character - selection.start.character),
1117
+ selectionIndex: nextSelections.length
1118
+ });
1119
+ const nextPosition = {
1120
+ line: selection.start.line,
1121
+ character: selection.start.character + text.length
1122
+ };
1123
+ nextSelections.push({
1124
+ start: nextPosition,
1125
+ end: nextPosition,
1126
+ direction: 0
1127
+ });
1128
+ }
1129
+ }
1130
+ for (const indent of sameLineIndents) {
1131
+ let shift = 0;
1132
+ for (const other of sameLineIndents) if (other.line === indent.line && other.startCharacter < indent.startCharacter) shift += other.addedLength;
1133
+ if (shift !== 0) {
1134
+ const current = nextSelections[indent.selectionIndex];
1135
+ const position = {
1136
+ line: indent.line,
1137
+ character: current.start.character + shift
1138
+ };
1139
+ nextSelections[indent.selectionIndex] = {
1140
+ start: position,
1141
+ end: position,
1142
+ direction: 0
1143
+ };
548
1144
  }
549
1145
  }
550
1146
  const change = textDocument.applyEdits(edits, true, this.#selections, nextSelections);
551
1147
  if (change !== void 0) this.#applyChange(change, nextSelections);
552
1148
  }
553
1149
  break;
554
- case "selectAll":
555
- this.#updateSelections([getDocumentFullSelection(textDocument)]);
1150
+ case "selectAll": {
1151
+ const fullSelection = getDocumentFullSelection(textDocument);
1152
+ this.#updateSelections([fullSelection]);
556
1153
  this.focus();
1154
+ const renderedLines = this.#getRenderedEditableLineRange();
1155
+ if (renderedLines !== void 0) {
1156
+ this.#suppressNativeSelectionSync = true;
1157
+ this.#setWindowSelection({
1158
+ start: {
1159
+ line: renderedLines.first,
1160
+ character: 0
1161
+ },
1162
+ end: {
1163
+ line: renderedLines.last,
1164
+ character: textDocument.getLineLength(renderedLines.last)
1165
+ },
1166
+ direction: 1
1167
+ });
1168
+ }
557
1169
  break;
1170
+ }
558
1171
  case "moveCursorToDocStart":
559
1172
  case "moveCursorToDocEnd":
560
1173
  {
561
- const atEnd = command === "moveCursorToDocEnd";
562
- this.#updateSelections([getDocumentBoundarySelection(textDocument, atEnd)]);
1174
+ const boundarySelection = getDocumentBoundarySelection(textDocument, command === "moveCursorToDocEnd", this.#isDiff);
1175
+ this.#updateSelections([boundarySelection]);
1176
+ this.#revealLineIfCollapsed(getCaretPosition(boundarySelection).line);
563
1177
  this.#scrollToPrimaryCaret();
564
1178
  }
565
1179
  break;
@@ -569,26 +1183,248 @@ var Editor = class {
569
1183
  const atEnd = command === "expandSelectionDocEnd";
570
1184
  const selections = this.#selections;
571
1185
  if (selections !== void 0) {
572
- this.#updateSelections(extendSelections(selections, getDocumentBoundarySelection(textDocument, atEnd)));
1186
+ const boundarySelection = getDocumentBoundarySelection(textDocument, atEnd, this.#isDiff);
1187
+ this.#updateSelections(extendSelections(selections, boundarySelection));
1188
+ this.#revealLineIfCollapsed(getCaretPosition(boundarySelection).line);
573
1189
  this.#scrollToPrimaryCaret();
574
1190
  }
575
1191
  }
576
1192
  break;
577
1193
  case "undo":
578
- if (this.#textDocument?.canUndo === true) {
579
- const undoResult = this.#textDocument.undo();
580
- if (undoResult !== void 0) this.#applyChange(...undoResult);
581
- }
582
- break;
583
1194
  case "redo":
584
- if (this.#textDocument?.canRedo === true) {
585
- const redoResult = this.#textDocument.redo();
586
- if (redoResult !== void 0) this.#applyChange(...redoResult);
587
- }
1195
+ this.#applyHistoryChange(command);
588
1196
  break;
589
1197
  }
590
1198
  }
591
- #handleLayoutResize() {
1199
+ #applyHistoryChange(command) {
1200
+ const textDocument = this.#textDocument;
1201
+ if (textDocument === void 0) return;
1202
+ if (command === "undo" && !textDocument.canUndo || command === "redo" && !textDocument.canRedo) return;
1203
+ const selections = this.#selections;
1204
+ const selectionOffsets = selections?.map((selection) => [textDocument.offsetAt(selection.start), textDocument.offsetAt(selection.end)]);
1205
+ const result = command === "undo" ? textDocument.undo() : textDocument.redo();
1206
+ if (result === void 0) return;
1207
+ const [change, recordedSelections, lineAnnotations, selectionEdits] = result;
1208
+ const nextSelections = recordedSelections ?? (selections !== void 0 && selectionOffsets !== void 0 && selectionEdits !== void 0 ? remapSelectionsAfterEdits(textDocument, selections, selectionOffsets, selectionEdits) : void 0);
1209
+ this.#applyChange(change, nextSelections, lineAnnotations);
1210
+ }
1211
+ /** Applies one undoable command batch and records its resulting selections. */
1212
+ #applyCommandEdits(edits, resolveNextSelections) {
1213
+ const textDocument = this.#textDocument;
1214
+ const selections = this.#selections;
1215
+ if (textDocument === void 0 || selections === void 0) return;
1216
+ const remapSelections = resolveNextSelections === void 0;
1217
+ const selectionOffsets = remapSelections ? selections.map((selection) => [textDocument.offsetAt(selection.start), textDocument.offsetAt(selection.end)]) : void 0;
1218
+ const resolvedEdits = remapSelections ? edits.map((edit) => {
1219
+ const start = textDocument.offsetAt(edit.range.start);
1220
+ const end = textDocument.offsetAt(edit.range.end);
1221
+ return {
1222
+ start: Math.min(start, end),
1223
+ end: Math.max(start, end),
1224
+ text: edit.newText
1225
+ };
1226
+ }).sort((a, b) => {
1227
+ const startOrder = a.start - b.start;
1228
+ return startOrder !== 0 ? startOrder : a.end - b.end;
1229
+ }) : void 0;
1230
+ const change = textDocument.applyEdits(edits, true, selections, void 0, true);
1231
+ if (change === void 0) return;
1232
+ const nextSelections = remapSelections ? remapSelectionsAfterEdits(textDocument, selections, selectionOffsets, resolvedEdits) : resolveNextSelections(textDocument);
1233
+ textDocument.setLastUndoSelectionsAfter(nextSelections);
1234
+ this.#applyChange(change, nextSelections, this.#applyChangeToLineAnnotations(change));
1235
+ }
1236
+ /** Copies selected line blocks and keeps the selection in the requested copy. */
1237
+ #copySelectedLines(direction) {
1238
+ const textDocument = this.#textDocument;
1239
+ const selections = this.#selections;
1240
+ if (textDocument === void 0 || selections === void 0) return;
1241
+ const blocks = getSelectedLineBlocks(selections);
1242
+ if (blocks.length === 0) return;
1243
+ const copiedLinesBefore = [];
1244
+ let copiedLineCount = 0;
1245
+ const edits = [];
1246
+ for (const block of blocks) {
1247
+ copiedLinesBefore.push(copiedLineCount);
1248
+ const blockLineCount = block.endLine - block.startLine + 1;
1249
+ copiedLineCount += blockLineCount;
1250
+ const text = textDocument.getText({
1251
+ start: {
1252
+ line: block.startLine,
1253
+ character: 0
1254
+ },
1255
+ end: {
1256
+ line: block.endLine,
1257
+ character: textDocument.getLineLength(block.endLine)
1258
+ }
1259
+ });
1260
+ if (direction > 0) {
1261
+ const position = {
1262
+ line: block.startLine,
1263
+ character: 0
1264
+ };
1265
+ edits.push({
1266
+ range: {
1267
+ start: position,
1268
+ end: position
1269
+ },
1270
+ newText: text + textDocument.eol
1271
+ });
1272
+ } else if (block.endLine < textDocument.lineCount - 1) {
1273
+ const position = {
1274
+ line: block.endLine + 1,
1275
+ character: 0
1276
+ };
1277
+ edits.push({
1278
+ range: {
1279
+ start: position,
1280
+ end: position
1281
+ },
1282
+ newText: text + textDocument.eol
1283
+ });
1284
+ } else {
1285
+ const position = {
1286
+ line: block.endLine,
1287
+ character: textDocument.getLineLength(block.endLine)
1288
+ };
1289
+ edits.push({
1290
+ range: {
1291
+ start: position,
1292
+ end: position
1293
+ },
1294
+ newText: textDocument.eol + text
1295
+ });
1296
+ }
1297
+ }
1298
+ const nextSelections = selections.map((selection) => {
1299
+ const line = selection.start.line;
1300
+ let low = 0;
1301
+ let high = blocks.length - 1;
1302
+ while (low <= high) {
1303
+ const middle = low + high >>> 1;
1304
+ const block = blocks[middle];
1305
+ if (line < block.startLine) high = middle - 1;
1306
+ else if (line > block.endLine) low = middle + 1;
1307
+ else {
1308
+ low = middle;
1309
+ break;
1310
+ }
1311
+ }
1312
+ const blockIndex = Math.max(0, low <= high ? low : high);
1313
+ const block = blocks[blockIndex];
1314
+ const shift = copiedLinesBefore[blockIndex] + (direction > 0 ? block.endLine - block.startLine + 1 : 0);
1315
+ return {
1316
+ start: {
1317
+ ...selection.start,
1318
+ line: selection.start.line + shift
1319
+ },
1320
+ end: {
1321
+ ...selection.end,
1322
+ line: selection.end.line + shift
1323
+ },
1324
+ direction: selection.direction
1325
+ };
1326
+ });
1327
+ this.#applyCommandEdits(edits, () => nextSelections);
1328
+ }
1329
+ /** Inserts an indented blank line after each selection's final line. */
1330
+ #insertBlankLine() {
1331
+ const textDocument = this.#textDocument;
1332
+ const selections = this.#selections;
1333
+ if (textDocument === void 0 || selections === void 0) return;
1334
+ const selectionLines = selections.map((selection) => getCaretPosition(selection).line);
1335
+ const targetLines = Array.from(new Set(selectionLines)).sort((a, b) => a - b);
1336
+ const targetIndex = /* @__PURE__ */ new Map();
1337
+ const indents = /* @__PURE__ */ new Map();
1338
+ const edits = [];
1339
+ for (let index = 0; index < targetLines.length; index++) {
1340
+ const line = targetLines[index];
1341
+ const lineText = textDocument.getLineText(line);
1342
+ const indent = /^\s*/.exec(lineText)?.[0] ?? "";
1343
+ targetIndex.set(line, index);
1344
+ indents.set(line, indent);
1345
+ const position = {
1346
+ line,
1347
+ character: textDocument.getLineLength(line)
1348
+ };
1349
+ edits.push({
1350
+ range: {
1351
+ start: position,
1352
+ end: position
1353
+ },
1354
+ newText: textDocument.eol + indent
1355
+ });
1356
+ }
1357
+ const nextSelections = selections.map((_, index) => {
1358
+ const line = selectionLines[index];
1359
+ const position = {
1360
+ line: line + 1 + targetIndex.get(line),
1361
+ character: indents.get(line).length
1362
+ };
1363
+ return {
1364
+ start: position,
1365
+ end: position,
1366
+ direction: 0
1367
+ };
1368
+ });
1369
+ this.#applyCommandEdits(edits, () => nextSelections);
1370
+ }
1371
+ #moveSelectedLines(direction) {
1372
+ const textDocument = this.#textDocument;
1373
+ const selections = this.#selections;
1374
+ if (textDocument === void 0 || selections === void 0) return;
1375
+ const blocks = getSelectedLineBlocks(selections);
1376
+ if (blocks.length === 0 || direction < 0 && blocks[0].startLine === 0 || direction > 0 && blocks.at(-1).endLine >= textDocument.lineCount - 1) return;
1377
+ const lineCount = textDocument.lineCount;
1378
+ const lineRangeEnd = (line) => line < lineCount - 1 ? {
1379
+ line: line + 1,
1380
+ character: 0
1381
+ } : {
1382
+ line,
1383
+ character: textDocument.getLineLength(line)
1384
+ };
1385
+ const getLinesText = (lines, appendFinalLineBreak) => {
1386
+ const text = lines.map((line) => textDocument.getLineText(line)).join(textDocument.eol);
1387
+ return appendFinalLineBreak ? text + textDocument.eol : text;
1388
+ };
1389
+ const edits = [];
1390
+ if (direction < 0) for (const block of blocks) {
1391
+ const previousLine = block.startLine - 1;
1392
+ const blockLines = [];
1393
+ for (let line = block.startLine; line <= block.endLine; line++) blockLines.push(line);
1394
+ edits.push({
1395
+ range: {
1396
+ start: {
1397
+ line: previousLine,
1398
+ character: 0
1399
+ },
1400
+ end: lineRangeEnd(block.endLine)
1401
+ },
1402
+ newText: getLinesText([...blockLines, previousLine], block.endLine < lineCount - 1)
1403
+ });
1404
+ }
1405
+ else for (let index = blocks.length - 1; index >= 0; index--) {
1406
+ const block = blocks[index];
1407
+ const nextLine = block.endLine + 1;
1408
+ const blockLines = [];
1409
+ for (let line = block.startLine; line <= block.endLine; line++) blockLines.push(line);
1410
+ edits.push({
1411
+ range: {
1412
+ start: {
1413
+ line: block.startLine,
1414
+ character: 0
1415
+ },
1416
+ end: lineRangeEnd(nextLine)
1417
+ },
1418
+ newText: getLinesText([nextLine, ...blockLines], nextLine < lineCount - 1)
1419
+ });
1420
+ }
1421
+ const lastBlock = blocks.at(-1);
1422
+ const lastLineLengthAfterMove = direction > 0 && lastBlock.endLine === lineCount - 2 ? textDocument.getLineLength(lastBlock.endLine) : textDocument.getLineLength(lineCount - 1);
1423
+ const nextSelections = selections.map((selection) => shiftSelectionLines(selection, direction, lineCount, (line) => line === lineCount - 1 ? lastLineLengthAfterMove : textDocument.getLineLength(line)));
1424
+ const change = textDocument.applyEdits(edits, true, selections, nextSelections, true);
1425
+ if (change !== void 0) this.#applyChange(change, nextSelections);
1426
+ }
1427
+ #handleLayoutResize = () => {
592
1428
  const lineAnnotations = this.#lineAnnotations?.length ?? 0;
593
1429
  const prevGutterWidth = this.#gutterWidthCache;
594
1430
  const prevContentWidth = this.#contentWidthCache;
@@ -597,109 +1433,141 @@ var Editor = class {
597
1433
  const gutterWidthChanged = this.#getGutterWidth() !== prevGutterWidth;
598
1434
  const contentWidthChanged = this.#getContentWidth() !== prevContentWidth;
599
1435
  if (!gutterWidthChanged && !contentWidthChanged) return;
600
- this.#lastCharX = void 0;
601
- if (contentWidthChanged && (this.#wrap || lineAnnotations > 0)) {
1436
+ this.#lineElementsCache.clear();
1437
+ this.#lastAccessedCharX = void 0;
1438
+ this.#metrics.clearTextWidthCache();
1439
+ if (contentWidthChanged && (this.#isWrap || lineAnnotations > 0)) {
602
1440
  this.#lineYCache.clear();
603
1441
  this.#wrapLineOffsetsCache.clear();
604
1442
  }
605
- if (this.#selections !== void 0) {
606
- this.#updateSelections(this.#selections);
607
- this.focus();
1443
+ if (this.#selections !== void 0 || this.#matches !== void 0 || this.#markerRenderer !== void 0) {
1444
+ this.#updateSelections(this.#selections ?? []);
1445
+ if (this.#selections !== void 0) this.focus();
608
1446
  }
1447
+ this.#markerRenderer?.removePopover();
1448
+ this.#computeContentOffset(this.#contentElement);
1449
+ };
1450
+ #remeasureMetricsOnFontLoad() {
1451
+ if (this.#fontRemeasureScheduled) return;
1452
+ const fonts = document.fonts;
1453
+ if (fonts === void 0) return;
1454
+ this.#fontRemeasureScheduled = true;
1455
+ fonts.ready.then(() => {
1456
+ if (this.#contentElement === void 0 || !this.#metrics.remeasureCharacterWidth()) return;
1457
+ this.#gutterWidthCache = void 0;
1458
+ this.#contentWidthCache = void 0;
1459
+ this.#resetCache();
1460
+ if (this.#selections !== void 0 || this.#matches !== void 0 || this.#markerRenderer !== void 0) this.#updateSelections(this.#selections ?? []);
1461
+ this.#markerRenderer?.removePopover();
1462
+ });
609
1463
  }
610
1464
  #rerender(change, newLineAnnotations, renderRange = this.#renderRange, shouldUpdateBuffer) {
611
1465
  const tokenizer = this.#tokenizer;
612
- const component = this.#component;
613
- const fileContents = this.#fileContents;
1466
+ const fileInstance = this.#fileInstance;
614
1467
  const textDocument = this.#textDocument;
1468
+ const gutterEl = this.#gutterElement;
615
1469
  const contentEl = this.#contentElement;
616
- const gutterEl = this.#contentElement?.previousElementSibling ?? void 0;
617
- if (tokenizer === void 0 || component === void 0 || fileContents === void 0 || textDocument === void 0 || contentEl === void 0 || gutterEl === void 0 || !(gutterEl instanceof HTMLElement) || gutterEl.dataset.gutter === void 0) return;
1470
+ if (tokenizer === void 0 || fileInstance === void 0 || textDocument === void 0 || contentEl === void 0) return;
618
1471
  tokenizer.stopBackgroundTokenize();
619
1472
  const t = performance.now();
620
- const isAdvancedMode = this.#editMode === "advanced";
621
1473
  const dirtyLines = tokenizer.tokenize(change, renderRange);
622
1474
  const t2 = performance.now();
623
1475
  if (dirtyLines.size > 0) {
624
1476
  const children = contentEl.children;
625
- const dirtyLineIndexes = new Set(dirtyLines.keys());
626
- if (isAdvancedMode) for (const child of children) {
627
- const el = child;
628
- if (el.dataset.line !== void 0) {
629
- const lineIndex = Number(el.dataset.line) - 1;
630
- const tokens = dirtyLines.get(lineIndex);
631
- if (tokens !== void 0) {
632
- el.replaceChildren(...renderLineTokens(tokens, tokenizer.themeType));
1477
+ const dirtyLineIndexes = /* @__PURE__ */ new Set();
1478
+ for (const lineIndex of dirtyLines.keys()) if (this.#isLineRenderable(lineIndex)) dirtyLineIndexes.add(lineIndex);
1479
+ for (let i = 0; i < children.length; i++) {
1480
+ const child = children[i];
1481
+ if (child !== void 0) {
1482
+ const lineNumber = getLineNumberAttr(child);
1483
+ const lineType = child.dataset.lineType;
1484
+ if (lineNumber === void 0 || lineType === "change-deletion") continue;
1485
+ const lineIndex = lineNumber - 1;
1486
+ if (dirtyLineIndexes.has(lineIndex)) {
1487
+ const tokens = dirtyLines.get(lineIndex);
1488
+ child.replaceChildren(...renderLineTokens(tokens));
633
1489
  dirtyLineIndexes.delete(lineIndex);
634
1490
  if (dirtyLineIndexes.size === 0) break;
635
1491
  }
636
1492
  }
637
1493
  }
638
- else {
639
- const startingLine = renderRange?.startingLine ?? 0;
640
- for (let i = change.startLine - startingLine; i < children.length; i++) {
1494
+ if (dirtyLineIndexes.size > 0) {
1495
+ let lastRenderedLineNumber = 0;
1496
+ for (let i = children.length - 1; i >= 0; i--) {
641
1497
  const child = children[i];
642
- if (child?.dataset.line !== void 0) {
643
- const lineIndex = Number(child.dataset.line) - 1;
644
- if (dirtyLines.has(lineIndex)) {
645
- const tokens = dirtyLines.get(lineIndex);
646
- child.replaceChildren(...renderLineTokens(tokens, tokenizer.themeType));
647
- dirtyLineIndexes.delete(lineIndex);
648
- if (dirtyLineIndexes.size === 0) break;
649
- }
1498
+ const lineNumber = getLineNumberAttr(child);
1499
+ if (lineNumber !== void 0 && child.dataset.lineType !== "change-deletion") {
1500
+ lastRenderedLineNumber = lineNumber;
1501
+ break;
650
1502
  }
651
1503
  }
652
- }
653
- if (dirtyLineIndexes.size > 0) for (const lineIndex of dirtyLineIndexes) {
654
- const tokens = dirtyLines.get(lineIndex);
655
- const lineNumber = String(lineIndex + 1);
656
- h("div", {
657
- dataset: {
658
- line: lineNumber,
659
- lineType: "context",
660
- lineIndex: lineIndex.toString()
661
- },
662
- children: renderLineTokens(tokens, tokenizer.themeType)
663
- }, contentEl);
664
- h("div", {
665
- dataset: {
666
- lineType: "context",
667
- columnNumber: lineNumber,
668
- lineIndex: lineIndex.toString()
669
- },
670
- children: [h("span", {
671
- dataset: { lineNumberContent: "" },
672
- textContent: lineNumber
673
- })]
674
- }, gutterEl);
1504
+ for (const lineIndex of dirtyLineIndexes) {
1505
+ if (lineIndex < lastRenderedLineNumber) continue;
1506
+ const tokens = dirtyLines.get(lineIndex);
1507
+ const lineNumber = String(lineIndex + 1);
1508
+ h("div", {
1509
+ dataset: {
1510
+ line: lineNumber,
1511
+ lineType: "context",
1512
+ lineIndex: lineIndex.toString()
1513
+ },
1514
+ children: renderLineTokens(tokens)
1515
+ }, contentEl);
1516
+ if (gutterEl !== void 0) h("div", {
1517
+ dataset: {
1518
+ lineType: "context",
1519
+ columnNumber: lineNumber,
1520
+ lineIndex: lineIndex.toString()
1521
+ },
1522
+ children: [h("span", {
1523
+ dataset: { lineNumberContent: "" },
1524
+ textContent: lineNumber
1525
+ })]
1526
+ }, gutterEl);
1527
+ }
675
1528
  }
676
1529
  }
677
- if (change.lineDelta < 0) for (const parent of [contentEl, gutterEl]) {
678
- const children = parent.children;
679
- for (let i = children.length - 1; i >= 0; i--) {
680
- const child = children[i];
681
- const { lineIndex, lineAnnotation } = child.dataset;
682
- if (lineIndex !== void 0 || lineAnnotation !== void 0) {
683
- if (Number(lineAnnotation !== void 0 ? lineAnnotation.split(",")[1] : lineIndex) < change.lineCount) break;
684
- child.remove();
685
- }
1530
+ if (change.lineDelta < 0) for (const children of [contentEl.children, gutterEl?.children ?? []]) for (let i = children.length - 1; i >= 0; i--) {
1531
+ const child = children[i];
1532
+ const lineNumber = getLineNumberAttr(child) ?? getLineNumberAttr(child, "columnNumber");
1533
+ const lineType = child.dataset.lineType;
1534
+ if (lineNumber === void 0 || lineType === "change-deletion") continue;
1535
+ if (lineNumber - 1 < change.lineCount) break;
1536
+ child.remove();
1537
+ }
1538
+ const didLineCountChange = change.lineDelta !== 0;
1539
+ if (didLineCountChange) {
1540
+ let gridRow = contentEl.children.length;
1541
+ for (const child of contentEl.children) {
1542
+ const { bufferSize } = child.dataset;
1543
+ if (bufferSize !== void 0) gridRow += parseInt(bufferSize) - 1;
686
1544
  }
1545
+ contentEl.style.gridRow = "span " + gridRow;
1546
+ if (gutterEl !== void 0) gutterEl.style.gridRow = "span " + gridRow;
687
1547
  }
688
- if (change.lineDelta !== 0) {
689
- gutterEl.style.gridRow = "span " + gutterEl.children.length;
690
- contentEl.style.gridRow = "span " + contentEl.children.length;
1548
+ fileInstance.updateRenderCache(dirtyLines, tokenizer.themeType, !didLineCountChange, didLineCountChange);
1549
+ if (didLineCountChange) fileInstance.applyDocumentChange(textDocument, newLineAnnotations, shouldUpdateBuffer);
1550
+ if (this.#isDiff && (this.#diffSyle === "unified" || didLineCountChange)) this.#resetCache();
1551
+ if (newLineAnnotations !== void 0) {
1552
+ this.#lineAnnotations = newLineAnnotations;
1553
+ renderLineAnnotations(newLineAnnotations, contentEl, gutterEl);
691
1554
  }
692
- component.applyLineChange?.(dirtyLines, tokenizer.themeType);
693
- if (change.lineDelta !== 0 || isAdvancedMode) component.applyLayoutChange(textDocument, newLineAnnotations, shouldUpdateBuffer);
694
1555
  if (this.#options.__debug === true) console.log(`[diffs/editor] re-render in: ${round(performance.now() - t2)}ms,`, `tokenize in: ${round(t2 - t)}ms (${dirtyLines.size} dirty lines)`);
695
1556
  }
696
1557
  #handleInput(inputType, data) {
697
1558
  switch (inputType) {
698
- case "insertText":
699
- this.#replaceSelectionText(data ?? "");
1559
+ case "insertText": {
1560
+ const text = data ?? "";
1561
+ const textDocument = this.#textDocument;
1562
+ const selections = this.#selections;
1563
+ const autoSurroundTexts = textDocument !== void 0 && selections !== void 0 ? getAutoSurroundReplacementTexts(textDocument, selections, text, this.#options.autoSurround) : void 0;
1564
+ this.#replaceSelectionText(autoSurroundTexts ?? text);
700
1565
  break;
1566
+ }
1567
+ case "insertCompositionText": break;
1568
+ case "insertLineBreak":
701
1569
  case "insertParagraph":
702
- this.#replaceSelectionText("\n");
1570
+ this.#replaceSelectionText(this.#textDocument?.eol ?? "\n");
703
1571
  break;
704
1572
  case "deleteContentBackward":
705
1573
  this.#deleteSelectionText();
@@ -707,52 +1575,39 @@ var Editor = class {
707
1575
  case "deleteContentForward":
708
1576
  this.#deleteSelectionText(true);
709
1577
  break;
710
- case "deleteHardLineForward":
711
- this.#deleteHardLineForward();
1578
+ case "deleteSoftLineBackward":
1579
+ case "deleteHardLineBackward":
1580
+ this.#deleteSoftLineBackward();
1581
+ break;
1582
+ case "deleteWordBackward":
1583
+ this.#deleteWordBackward();
712
1584
  break;
713
1585
  case "insertTranspose":
714
1586
  this.#insertTranspose();
715
1587
  break;
716
1588
  default:
717
- console.warn(`[diffs] Unknown input type: ${inputType}`);
1589
+ console.warn(`[diffs] Unknown input type: ${inputType}`, data);
718
1590
  break;
719
1591
  }
720
1592
  }
721
- #updateSelections(selections) {
722
- if (selections.length === 0) return;
723
- const gutterBuffer = this.#contentElement?.previousElementSibling;
724
- const normalizedSelections = mergeOverlappingSelections(selections);
725
- const primarySelection = normalizedSelections.at(-1);
726
- this.#selections = normalizedSelections;
727
- this.#primaryCaretElement = void 0;
728
- this.#component?.setSelectedLines(null);
729
- gutterBuffer?.querySelectorAll("[data-active]").forEach((el) => el.removeAttribute("data-active"));
730
- if (isCollapsedSelection(primarySelection)) {
731
- const line = primarySelection.start.line + 1;
732
- this.#component?.setSelectedLines({
733
- start: line,
734
- end: line
1593
+ #focus(position, preventScroll = true) {
1594
+ this.#contentHasFocus = true;
1595
+ if (position !== void 0) {
1596
+ this.#shouldIgnoreSelectionChange = true;
1597
+ this.#setWindowSelection({
1598
+ start: position,
1599
+ end: position,
1600
+ direction: 0
735
1601
  });
736
- } else if (gutterBuffer !== void 0 && gutterBuffer instanceof HTMLElement) {
737
- const pos = getCaretPosition(primarySelection);
738
- gutterBuffer.querySelector(`[data-column-number="${pos.line + 1}"]`)?.setAttribute("data-active", "");
739
- }
740
- const fragment = document.createDocumentFragment();
741
- const renderCtx = {
742
- fragment,
743
- elements: /* @__PURE__ */ new Map()
744
- };
745
- for (const selection of normalizedSelections) {
746
- if (!isCollapsedSelection(selection)) this.#renderSelection(renderCtx, selection);
747
- this.#renderCaret(renderCtx, selection, selection === primarySelection);
748
- }
749
- if (this.#options.enabledQuickEdit === true && !isCollapsedSelection(primarySelection)) this.#renderQuickEditIcon(renderCtx, primarySelection);
750
- this.#overlayElement?.appendChild(fragment);
751
- this.#selectionElements?.forEach((el) => el.remove());
752
- this.#selectionElements?.clear();
753
- this.#selectionElements = renderCtx.elements;
1602
+ requestAnimationFrame(() => {
1603
+ this.#contentElement?.focus({ preventScroll });
1604
+ requestAnimationFrame(() => {
1605
+ this.#shouldIgnoreSelectionChange = false;
1606
+ });
1607
+ });
1608
+ } else this.#contentElement?.focus({ preventScroll });
754
1609
  }
755
- #updateWindowSelection(selection) {
1610
+ #setWindowSelection(selection) {
756
1611
  const winSelection = window.getSelection();
757
1612
  if (winSelection === null) return;
758
1613
  let { start, end, direction } = selection;
@@ -762,7 +1617,7 @@ var Editor = class {
762
1617
  if (startLineElement === void 0 || endLineElement === void 0) return;
763
1618
  let [anchorNode, anchorOffset] = getSelectionAnchor(startLineElement, start.character);
764
1619
  let [focusNode, focusOffset] = getSelectionAnchor(endLineElement, end.character);
765
- if (direction === DirectionBackward) [anchorNode, anchorOffset, focusNode, focusOffset] = [
1620
+ if (direction === -1) [anchorNode, anchorOffset, focusNode, focusOffset] = [
766
1621
  focusNode,
767
1622
  focusOffset,
768
1623
  anchorNode,
@@ -774,47 +1629,28 @@ var Editor = class {
774
1629
  console.error("[diffs/editor] failed to update window selection:", err);
775
1630
  }
776
1631
  }
777
- #focus(position, preventScroll = true) {
778
- if (position !== void 0) {
779
- this.#shouldIgnoreSelectionChange = true;
780
- this.#updateWindowSelection({
781
- start: position,
782
- end: position,
783
- direction: DirectionNone
784
- });
785
- requestAnimationFrame(() => {
786
- this.#contentElement?.focus({ preventScroll });
787
- requestAnimationFrame(() => {
788
- this.#shouldIgnoreSelectionChange = false;
789
- });
790
- });
791
- } else requestAnimationFrame(() => {
792
- this.#contentElement?.focus({ preventScroll });
793
- });
794
- }
795
- #scrollToPrimaryCaret() {
796
- const primaryCaretElement = this.#primaryCaretElement;
1632
+ #scrollToPrimaryCaret(noFocus = false, scrollPosition = "nearest") {
797
1633
  const primarySelection = this.#selections?.at(-1);
798
1634
  if (primarySelection === void 0) return;
1635
+ const primaryCaretElement = this.#primaryCaretElement;
799
1636
  if (primaryCaretElement !== void 0) {
800
1637
  primaryCaretElement.scrollIntoView({
801
- block: "nearest",
1638
+ block: scrollPosition,
802
1639
  inline: "nearest"
803
1640
  });
804
- this.#focus(primarySelection.direction === DirectionBackward ? primarySelection.end : primarySelection.start);
1641
+ if (!noFocus) this.#focus(primarySelection.direction === -1 ? primarySelection.end : primarySelection.start);
805
1642
  } else {
806
1643
  const pos = getCaretPosition(primarySelection);
807
- this.#scrollToLine(pos.line, pos.character);
1644
+ this.#scrollToLine(pos.line, pos.character, noFocus);
808
1645
  }
809
1646
  }
810
1647
  #getScrollMargin() {
811
- const componentTop = this.#component?.top ?? 0;
812
1648
  const top = this.#searchPanel !== void 0 ? 48 : 0;
813
1649
  const start = this.#getGutterWidth() + this.#metrics.ch;
814
- const end = this.#metrics.ch;
815
- return `${componentTop + top}px ${end}px 0 ${start}px`;
1650
+ return `${top}px ${this.#metrics.ch}px 0 ${start}px`;
816
1651
  }
817
- #scrollToLine(line, char = 0) {
1652
+ #scrollToLine(line, char = 0, noFocus = false) {
1653
+ this.__postponeBgTokenizeToNextFrame();
818
1654
  const virtualCaret = h("div", { style: {
819
1655
  position: "absolute",
820
1656
  left: "0",
@@ -832,111 +1668,372 @@ var Editor = class {
832
1668
  block: "center",
833
1669
  inline: "nearest"
834
1670
  });
835
- this.#focus({
1671
+ if (!noFocus) this.#focus({
836
1672
  line,
837
1673
  character: char
838
1674
  });
839
- requestAnimationFrame(() => virtualCaret.remove());
1675
+ this.#scrollingToLine = void 0;
1676
+ this.#scrollingToLineChar = void 0;
1677
+ this.#scrollingToLineFixed = false;
1678
+ this.#scrollingToLineNoFocus = false;
840
1679
  } else {
841
- const approximateLineY = ((this.#lineAnnotations ?? []).filter((annotation) => annotation.lineNumber < line).length + line) * this.#metrics.lineHeight;
842
- virtualCaret.style.top = approximateLineY + "px";
843
- this.#componentContainer?.shadowRoot?.appendChild(virtualCaret);
844
- this.#scrollingToLine = line;
845
- this.#scrollingToLineChar = char;
846
- virtualCaret.scrollIntoView({
847
- block: "center",
848
- inline: "nearest"
1680
+ const modelLinePosition = this.#fileInstance?.getLinePosition?.(line + 1);
1681
+ if (modelLinePosition !== void 0) {
1682
+ virtualCaret.style.top = modelLinePosition.top + "px";
1683
+ this.#fileContainer?.shadowRoot?.appendChild(virtualCaret);
1684
+ virtualCaret.scrollIntoView({
1685
+ block: "center",
1686
+ inline: "nearest"
1687
+ });
1688
+ if (modelLinePosition.height > 0 && this.#isLineRenderable(line)) {
1689
+ this.#scrollingToLine = line;
1690
+ this.#scrollingToLineChar = char;
1691
+ this.#scrollingToLineNoFocus = noFocus;
1692
+ } else {
1693
+ this.#scrollingToLine = void 0;
1694
+ this.#scrollingToLineChar = void 0;
1695
+ this.#scrollingToLineNoFocus = false;
1696
+ }
1697
+ } else {
1698
+ let yFix = 0;
1699
+ if (this.#scrollingToLine === line && this.#contentElement !== void 0) for (let i = this.#contentElement.childElementCount - 1; i >= 0; i--) {
1700
+ const child = this.#contentElement.children[i];
1701
+ const lineType = child.dataset.lineType;
1702
+ const lineNumber = getLineNumberAttr(child);
1703
+ if (lineType !== void 0 && isLineEditable(lineType) && lineNumber !== void 0) {
1704
+ yFix = (line - (lineNumber - 1)) * this.#metrics.lineHeight;
1705
+ break;
1706
+ }
1707
+ }
1708
+ const approximateLineY = ((this.#lineAnnotations ?? []).filter((annotation) => annotation.lineNumber < line).length + line) * this.#metrics.lineHeight + yFix;
1709
+ virtualCaret.style.top = approximateLineY + "px";
1710
+ this.#fileContainer?.shadowRoot?.appendChild(virtualCaret);
1711
+ virtualCaret.scrollIntoView({
1712
+ block: "center",
1713
+ inline: "nearest"
1714
+ });
1715
+ if (this.#scrollingToLine === line && (yFix === 0 || this.#scrollingToLineFixed) || !this.#isLineRenderable(line)) {
1716
+ this.#scrollingToLine = void 0;
1717
+ this.#scrollingToLineChar = void 0;
1718
+ this.#scrollingToLineFixed = false;
1719
+ this.#scrollingToLineNoFocus = false;
1720
+ } else {
1721
+ this.#scrollingToLine = line;
1722
+ this.#scrollingToLineChar = char;
1723
+ this.#scrollingToLineFixed = yFix !== 0;
1724
+ this.#scrollingToLineNoFocus = noFocus;
1725
+ }
1726
+ }
1727
+ }
1728
+ virtualCaret.remove();
1729
+ }
1730
+ #spanLineSelection(anchorLine, focusLine, textDocument) {
1731
+ const lineStart = (line) => ({
1732
+ line,
1733
+ character: 0
1734
+ });
1735
+ const lineEnd = (line) => ({
1736
+ line,
1737
+ character: textDocument.getLineText(line).length
1738
+ });
1739
+ if (focusLine < anchorLine) return {
1740
+ start: lineStart(focusLine),
1741
+ end: lineEnd(anchorLine),
1742
+ direction: -1
1743
+ };
1744
+ return {
1745
+ start: lineStart(anchorLine),
1746
+ end: lineEnd(focusLine),
1747
+ direction: 1
1748
+ };
1749
+ }
1750
+ #isDeletedLineTarget(event) {
1751
+ const target = event.composedPath()[0];
1752
+ return target instanceof HTMLElement && target.closest("[data-line]")?.getAttribute("data-line-type") === "change-deletion";
1753
+ }
1754
+ #selectDeletedLines(anchorContent, focusContent, deletionsCode) {
1755
+ const rows = [...deletionsCode.querySelectorAll("[data-content] > [data-line]")];
1756
+ const anchorIndex = rows.indexOf(anchorContent);
1757
+ const focusIndex = rows.indexOf(focusContent);
1758
+ const [topContent, bottomContent] = focusIndex < anchorIndex ? [focusContent, anchorContent] : [anchorContent, focusContent];
1759
+ const winSelection = window.getSelection();
1760
+ if (winSelection !== null) {
1761
+ const range = document.createRange();
1762
+ range.setStart(topContent, 0);
1763
+ range.setEnd(bottomContent, bottomContent.childNodes.length);
1764
+ winSelection.removeAllRanges();
1765
+ winSelection.addRange(range);
1766
+ }
1767
+ this.#setDeletedTextSelectionActive(true);
1768
+ this.#updateSelections([]);
1769
+ this.#setEditorActiveLineSafe(getLineNumberAttr(focusContent) ?? null, true, "deletions");
1770
+ const lo = Math.min(anchorIndex, focusIndex);
1771
+ const hi = Math.max(anchorIndex, focusIndex);
1772
+ this.#deletedSelectionText = lo < 0 ? "" : rows.slice(lo, hi + 1).filter((row) => row.getAttribute("data-line-type") === "change-deletion").map((row) => row.textContent ?? "").join("\n");
1773
+ }
1774
+ #contentRowForGutterRow(gutterRow, contentColumn) {
1775
+ const gutterColumn = gutterRow.parentElement;
1776
+ if (gutterColumn == null || contentColumn == null) return;
1777
+ const index = [...gutterColumn.children].indexOf(gutterRow);
1778
+ const row = contentColumn.children[index];
1779
+ return row instanceof HTMLElement ? row : void 0;
1780
+ }
1781
+ #beginDeletionGutterSelection(gutterRow, code, isMouse) {
1782
+ const contentColumn = code.querySelector("[data-content]");
1783
+ const anchorContent = this.#contentRowForGutterRow(gutterRow, contentColumn);
1784
+ if (anchorContent === void 0) return false;
1785
+ this.#selectDeletedLines(anchorContent, anchorContent, code);
1786
+ if (isMouse) this.#replaceSelectEventListeners([addEventListener(document, "mousemove", (moveEvent) => {
1787
+ const moveTarget = moveEvent.composedPath()[0];
1788
+ const moveGutter = moveTarget instanceof HTMLElement ? moveTarget.closest("[data-column-number]") : null;
1789
+ if (moveGutter instanceof HTMLElement && code.contains(moveGutter)) {
1790
+ const focusContent = this.#contentRowForGutterRow(moveGutter, contentColumn);
1791
+ if (focusContent !== void 0) this.#selectDeletedLines(anchorContent, focusContent, code);
1792
+ }
1793
+ }, { passive: true })]);
1794
+ return true;
1795
+ }
1796
+ #isDeletedTextSelectionActive() {
1797
+ return this.#fileContainer?.shadowRoot?.querySelector("pre")?.hasAttribute("data-deleted-text-selection") ?? false;
1798
+ }
1799
+ #deletedTextForClipboard() {
1800
+ return this.#deletedSelectionText !== "" ? this.#deletedSelectionText : window.getSelection()?.toString() ?? "";
1801
+ }
1802
+ #setDeletedTextSelectionActive(active) {
1803
+ const pre = this.#fileContainer?.shadowRoot?.querySelector("pre");
1804
+ if (pre == null) return;
1805
+ if (active) {
1806
+ pre.setAttribute("data-deleted-text-selection", "");
1807
+ this.#setEditorActiveLineSafe(null);
1808
+ this.#deletedSelectionText = "";
1809
+ } else {
1810
+ pre.removeAttribute("data-deleted-text-selection");
1811
+ this.#deletedSelectionText = "";
1812
+ }
1813
+ }
1814
+ #setEditorActiveLineSafe(lineNumber, lineNumberOnly = false, side = "additions") {
1815
+ try {
1816
+ this.#fileInstance?.setEditorActiveLine(lineNumber, {
1817
+ lineNumberOnly,
1818
+ side
849
1819
  });
850
- requestAnimationFrame(() => virtualCaret.remove());
1820
+ } catch {}
1821
+ }
1822
+ #scheduleThemeSelectionRefresh() {
1823
+ if (this.#themeSelectionRefreshFrame !== void 0) return;
1824
+ this.#themeSelectionRefreshFrame = requestAnimationFrame(() => {
1825
+ this.#themeSelectionRefreshFrame = void 0;
1826
+ if (this.#selections !== void 0 || this.#matches !== void 0 || this.#markerRenderer !== void 0) this.#updateSelections(this.#selections ?? []);
1827
+ });
1828
+ }
1829
+ #updateSelections(selections) {
1830
+ this.__postponeBgTokenizeToNextFrame();
1831
+ this.#primaryCaretElement = void 0;
1832
+ this.#setEditorActiveLineSafe(null);
1833
+ if (selections.length === 0 && this.#matches === void 0 && this.#markerRenderer === void 0) {
1834
+ this.#selections = void 0;
1835
+ this.#overlayElements?.forEach((el) => el.remove());
1836
+ this.#overlayElements?.clear();
1837
+ this.#selectionAction?.cleanup();
1838
+ this.#selectionAction = void 0;
1839
+ return;
1840
+ }
1841
+ const fragment = document.createDocumentFragment();
1842
+ const renderCtx = {
1843
+ fragment,
1844
+ elements: /* @__PURE__ */ new Map()
1845
+ };
1846
+ if (selections.length > 0) {
1847
+ const normalizedSelections = mergeOverlappingSelections(selections);
1848
+ const primarySelection = normalizedSelections.at(-1);
1849
+ this.#selections = normalizedSelections;
1850
+ const hasNonEmptySelection = normalizedSelections.some((selection) => !isCollapsedSelection(selection));
1851
+ const caretLine = getCaretPosition(primarySelection).line + 1;
1852
+ this.#setEditorActiveLineSafe(caretLine, hasNonEmptySelection);
1853
+ for (const selection of normalizedSelections) {
1854
+ if (!isCollapsedSelection(selection)) this.#renderSelection(renderCtx, "selection", selection);
1855
+ this.#renderCaret(renderCtx, selection, selection === primarySelection);
1856
+ }
1857
+ const bracketMatchRanges = this.#options.matchBrackets !== false && this.#textDocument !== void 0 && this.#tokenizer !== void 0 && isCollapsedSelection(primarySelection) ? findBracketMatchRanges(this.#textDocument, this.#tokenizer, primarySelection.start) : void 0;
1858
+ if (bracketMatchRanges !== void 0) for (const range of bracketMatchRanges) this.#renderSelection(renderCtx, "bracketMatch", range);
1859
+ }
1860
+ const textDocument = this.#textDocument;
1861
+ if (this.#matches !== void 0 && textDocument !== void 0) {
1862
+ const primarySelection = this.#selections?.at(-1);
1863
+ const primaryStartOffset = primarySelection !== void 0 ? textDocument.offsetAt(primarySelection.start) : -1;
1864
+ const primaryEndOffset = primarySelection !== void 0 ? textDocument.offsetAt(primarySelection.end) : -1;
1865
+ for (const [startOffset, endOffset] of this.#matches) {
1866
+ const range = {
1867
+ start: textDocument.positionAt(startOffset),
1868
+ end: textDocument.positionAt(endOffset)
1869
+ };
1870
+ const isFocused = primaryStartOffset === startOffset && primaryEndOffset === endOffset;
1871
+ this.#renderSelection(renderCtx, "match", range, isFocused ? "focus" : void 0);
1872
+ }
851
1873
  }
1874
+ if (this.#markerRenderer !== void 0 && textDocument !== void 0) for (const marker of this.#markerRenderer.markers) this.#renderSelection(renderCtx, "marker", marker, markerSeverityDatasetKey(marker.severity));
1875
+ this.#overlayElement?.appendChild(fragment);
1876
+ this.#overlayElements?.forEach((el) => el.remove());
1877
+ this.#overlayElements?.clear();
1878
+ this.#overlayElements = renderCtx.elements;
1879
+ this.#updateSelectionActionPopover();
852
1880
  }
853
- #renderSelection(renderCtx, selection) {
1881
+ #renderSelection(renderCtx, type, range, extraDataset) {
854
1882
  if (this.#textDocument === void 0) return;
855
- const { start, end } = selection;
856
- for (let ln = start.line; ln <= end.line; ln++) {
857
- if (!this.#isLineVisible(ln)) continue;
858
- const lineText = this.#textDocument.getLineText(ln);
859
- const startChar = ln === start.line ? start.character : 0;
860
- const endChar = ln === end.line ? end.character : lineText.length;
861
- if (this.#wrap) {
862
- const paddingInline = this.#metrics.ch;
1883
+ const { start, end } = range;
1884
+ for (let line = start.line; line <= end.line; line++) {
1885
+ if (!this.#isLineVisible(line)) continue;
1886
+ const isLastLine = line === end.line;
1887
+ const startChar = line === start.line ? start.character : 0;
1888
+ const endChar = isLastLine ? end.character : this.#textDocument.getLineLength(line);
1889
+ if (this.#isWrap) {
863
1890
  const contentWidth = this.#getContentWidth();
864
- if (2 * paddingInline + this.#metrics.measureTextWidth(lineText) > contentWidth) {
865
- this.#renderWrappedSelection(renderCtx, selection, ln, lineText, startChar, endChar, paddingInline);
1891
+ const lineText = this.#textDocument.getLineText(line);
1892
+ if (2 * this.#metrics.ch + this.#metrics.measureTextWidth(lineText) > contentWidth) {
1893
+ this.#renderWrappedSelection(renderCtx, line, lineText, startChar, endChar, isLastLine, type, extraDataset);
866
1894
  continue;
867
1895
  }
868
1896
  }
869
1897
  let left = 0;
870
1898
  let width = 0;
871
- if (startChar === endChar && startChar === 0) {
872
- left = this.#getGutterWidth() + this.#metrics.ch;
873
- width = ln === end.line ? 0 : this.#metrics.ch;
874
- } else {
875
- left = this.#getCharX(ln, startChar)[0];
876
- width = endChar === startChar ? 0 : this.#getCharX(ln, endChar)[0] - left;
877
- }
878
- this.#renderSelectionRange(renderCtx, selection, ln, 0, startChar, endChar, width, left);
1899
+ let paddingEnd = 0;
1900
+ if (startChar === 0) left = this.#getGutterWidth() + this.#metrics.ch + (this.#activeContentOffset?.left ?? 0);
1901
+ else left = this.#getCharX(line, startChar)[0];
1902
+ if (!isLastLine && type === "selection") paddingEnd = this.#metrics.ch;
1903
+ if (startChar === endChar) width = paddingEnd;
1904
+ else width = this.#getCharX(line, endChar)[0] - left + paddingEnd;
1905
+ this.#renderSelectionBlock(renderCtx, type, line, 0, left, width, extraDataset);
879
1906
  }
880
1907
  }
881
- #renderWrappedSelection(renderCtx, selection, line, lineText, startChar, endChar, paddingInline) {
1908
+ #renderWrappedSelection(renderCtx, line, lineText, startChar, endChar, isLastLine, type, extraDataset) {
882
1909
  const wrapOffsets = this.#wrapLineText(line);
883
1910
  const segmentCount = wrapOffsets.length - 1;
884
- const lastSegmentIndex = segmentCount - 1;
885
- const offsetLeft = this.#getGutterWidth() + paddingInline;
886
- for (let w = 0; w < segmentCount; w++) {
887
- const segmentStart = wrapOffsets[w];
888
- const segmentEnd = wrapOffsets[w + 1];
1911
+ const offsetLeft = this.#getGutterWidth() + this.#metrics.ch + (this.#activeContentOffset?.left ?? 0);
1912
+ for (let wrapLine = 0; wrapLine < segmentCount; wrapLine++) {
1913
+ const segmentStart = wrapOffsets[wrapLine];
1914
+ const segmentEnd = wrapOffsets[wrapLine + 1];
889
1915
  const wrapStartChar = Math.max(startChar, segmentStart);
890
1916
  const wrapEndChar = Math.min(endChar, segmentEnd);
891
1917
  if (wrapStartChar > wrapEndChar) continue;
892
- if (wrapStartChar === wrapEndChar) {
893
- const isAtLineStart = wrapStartChar === 0 && w === 0;
894
- const isAtLineEnd = wrapEndChar === lineText.length && w === lastSegmentIndex;
895
- if (!isAtLineStart && !isAtLineEnd) continue;
1918
+ const segmentStartWidth = this.#segmentTextWidth(lineText, segmentStart, wrapStartChar);
1919
+ const segmentLeft = offsetLeft + segmentStartWidth;
1920
+ let paddingEnd = 0;
1921
+ if (!isLastLine && wrapLine === segmentCount - 1 && type === "selection") paddingEnd = this.#metrics.ch;
1922
+ const segmentWidth = wrapStartChar === wrapEndChar ? paddingEnd : this.#segmentTextWidth(lineText, segmentStart, wrapEndChar) - segmentStartWidth + paddingEnd;
1923
+ this.#renderSelectionBlock(renderCtx, type, line, wrapLine, segmentLeft, segmentWidth, extraDataset);
1924
+ }
1925
+ }
1926
+ #segmentTextWidth(lineText, segmentStart, character) {
1927
+ if (character <= segmentStart) return 0;
1928
+ const segmentText = lineText.slice(segmentStart, character);
1929
+ const asciiColumns = getExpandedAsciiTextColumns(segmentText, this.#metrics.tabSize);
1930
+ return asciiColumns !== -1 ? asciiColumns * this.#metrics.ch : this.#metrics.measureTextWidth(segmentText);
1931
+ }
1932
+ #renderSelectionBlock(renderCtx, type, line, wrapLine, left, width, extraDataset) {
1933
+ if (width === 0) return;
1934
+ const { ch, lineHeight } = this.#metrics;
1935
+ const y = this.#getLineY(line) + wrapLine * lineHeight;
1936
+ const cacheKey = `${type}-${line}/${wrapLine}-${left}-${width} ${extraDataset ?? ""}`;
1937
+ const overlayEls = this.#overlayElements;
1938
+ const rounded = (this.#options.roundedSelection ?? true) && type === "selection";
1939
+ const addRoundedCorner = (line, wrapLine, left, radius) => {
1940
+ const top = this.#getLineY(line) + wrapLine * lineHeight;
1941
+ const lineElement = this.#getLineElement(line);
1942
+ let cornerBg = "initial";
1943
+ if (this.#isDiff && lineElement?.dataset.lineType === "change-addition") cornerBg = getComputedStyle(lineElement).getPropertyValue("--diffs-line-bg");
1944
+ const css = `width:${ch}px;transform:translateX(${left}px) translateY(${top}px);--diffs-selection-corner-bg:${cornerBg}`;
1945
+ const dataset = {
1946
+ selectionCorner: "",
1947
+ [radius]: ""
1948
+ };
1949
+ const cacheKeyPrefix = `${type}-block-${line}/${wrapLine}-${left}-1ch`;
1950
+ let cacheKey = cacheKeyPrefix + "-" + radius;
1951
+ if (radius === "rbl") {
1952
+ const prevCornerKey = cacheKeyPrefix + "-rtl";
1953
+ const prevCorner = renderCtx.elements.get(prevCornerKey);
1954
+ if (prevCorner !== void 0) {
1955
+ prevCorner.remove();
1956
+ renderCtx.elements.delete(prevCornerKey);
1957
+ cacheKey += "-rtl";
1958
+ dataset.rtl = "";
1959
+ }
896
1960
  }
897
- let segmentLeft;
898
- let segmentWidth;
899
- if (wrapStartChar === 0 && wrapEndChar === 0) {
900
- segmentLeft = offsetLeft;
901
- segmentWidth = line === selection.end.line ? 0 : paddingInline;
902
- } else {
903
- const prefixInSegment = lineText.slice(segmentStart, wrapStartChar);
904
- const prefixAsciiColumns = getExpandedAsciiTextColumns(prefixInSegment, this.#metrics.tabSize);
905
- segmentLeft = offsetLeft + (prefixAsciiColumns !== -1 ? prefixAsciiColumns * this.#metrics.ch : this.#metrics.measureTextWidth(prefixInSegment));
906
- if (wrapStartChar === wrapEndChar) segmentWidth = 0;
907
- else {
908
- const selectionInSegment = lineText.slice(wrapStartChar, wrapEndChar);
909
- const selectionAsciiWidth = getExpandedAsciiTextColumns(selectionInSegment, this.#metrics.tabSize);
910
- segmentWidth = selectionAsciiWidth !== -1 ? selectionAsciiWidth * this.#metrics.ch : this.#metrics.measureTextWidth(selectionInSegment);
1961
+ let cornerEl = renderCtx.elements.get(cacheKey);
1962
+ if (cornerEl !== void 0) return;
1963
+ if (overlayEls?.has(cacheKey) === true) {
1964
+ cornerEl = overlayEls.get(cacheKey);
1965
+ cornerEl.style.cssText = css;
1966
+ overlayEls.delete(cacheKey);
1967
+ } else cornerEl = h("div", {
1968
+ dataset: "selectionRange",
1969
+ style: { cssText: css },
1970
+ children: [h("div", { dataset })]
1971
+ }, renderCtx.fragment);
1972
+ renderCtx.elements.set(cacheKey, cornerEl);
1973
+ };
1974
+ const addRadiusStyle = (element) => {
1975
+ const end = left + width;
1976
+ const dataset = element.dataset;
1977
+ const previousSelectionRange = renderCtx.previousSelectionRange;
1978
+ if (previousSelectionRange === void 0 || previousSelectionRange.line !== line || previousSelectionRange.wrapLine !== wrapLine) renderCtx.previousSelectionRange = {
1979
+ element,
1980
+ line,
1981
+ wrapLine,
1982
+ left,
1983
+ width
1984
+ };
1985
+ if (previousSelectionRange === void 0 || end <= previousSelectionRange.left) [
1986
+ "rtl",
1987
+ "rtr",
1988
+ "rbl",
1989
+ "rbr"
1990
+ ].forEach((key) => {
1991
+ dataset[key] = "";
1992
+ });
1993
+ else {
1994
+ const prevLine = previousSelectionRange.line;
1995
+ const prevWrapLine = previousSelectionRange.wrapLine;
1996
+ const prevLeft = previousSelectionRange.left;
1997
+ const prevDataset = previousSelectionRange.element.dataset;
1998
+ const prevEnd = prevLeft + previousSelectionRange.width;
1999
+ if (prevLeft > left) addRoundedCorner(prevLine, prevWrapLine, prevLeft - ch, "rbr");
2000
+ delete prevDataset.rbl;
2001
+ delete dataset.rtl;
2002
+ delete dataset.rtr;
2003
+ if (end >= prevEnd) delete prevDataset.rbr;
2004
+ if (end > prevEnd) {
2005
+ addRoundedCorner(prevLine, prevWrapLine, prevEnd, "rbl");
2006
+ dataset.rtr = "";
911
2007
  }
2008
+ if (end < prevEnd) addRoundedCorner(line, wrapLine, end, "rtl");
2009
+ if (left < prevLeft) dataset.rtl = "";
2010
+ dataset.rbl = "";
2011
+ dataset.rbr = "";
912
2012
  }
913
- this.#renderSelectionRange(renderCtx, selection, line, w, wrapStartChar, wrapEndChar, segmentWidth, segmentLeft, w === lastSegmentIndex);
2013
+ };
2014
+ let rangeEl = renderCtx.elements.get(cacheKey);
2015
+ if (rangeEl !== void 0) {
2016
+ if (rounded) addRadiusStyle(rangeEl);
2017
+ return;
914
2018
  }
915
- }
916
- #renderSelectionRange(renderCtx, selection, ln, wrapLine, startChar, endChar, width, left, applyEolSpacing = true) {
917
- const css = `width:${width + (!applyEolSpacing || selection.end.line === ln || startChar === endChar && ln !== selection.start.line ? 0 : this.#metrics.ch)}px;transform:translateY(${this.#getLineY(ln) + wrapLine * this.#metrics.lineHeight}px) translateX(${left}px);`;
918
- const cacheKey = "selection-range-" + css;
919
- const selectionEls = this.#selectionElements;
920
- if (renderCtx.elements.has(cacheKey)) return;
921
- let rangeEl;
922
- if (selectionEls?.has(cacheKey) === true) {
923
- rangeEl = selectionEls.get(cacheKey);
924
- selectionEls.delete(cacheKey);
925
- } else rangeEl = h("div", {
926
- dataset: "selectionRange",
927
- style: { cssText: css }
928
- }, renderCtx.fragment);
2019
+ if (overlayEls?.has(cacheKey) === true) {
2020
+ rangeEl = overlayEls.get(cacheKey);
2021
+ overlayEls.delete(cacheKey);
2022
+ } else rangeEl = h("div", { dataset: extraDataset ? [type + "Range", extraDataset] : type + "Range" }, renderCtx.fragment);
2023
+ rangeEl.style.width = `${width}px`;
2024
+ rangeEl.style.transform = `translateX(${left}px) translateY(${y}px)`;
2025
+ if (rounded) addRadiusStyle(rangeEl);
929
2026
  renderCtx.elements.set(cacheKey, rangeEl);
930
2027
  }
931
2028
  #renderCaret(renderCtx, selection, isPrimary) {
932
2029
  const { line, character } = getCaretPosition(selection);
933
2030
  if (!this.#isLineVisible(line)) return;
934
2031
  const [left, wrapLine] = this.#getCharX(line, character);
935
- const cacheKey = "caret-" + line + "(" + wrapLine + ")-" + character;
2032
+ const cacheKey = "caret-" + line + "/" + wrapLine + ":" + character;
936
2033
  if (renderCtx.elements.has(cacheKey)) return;
937
2034
  const caretEl = h("div", {
938
2035
  dataset: "caret",
939
- style: { transform: `translateY(${this.#getLineY(line) + wrapLine * this.#metrics.lineHeight}px) translateX(${left - 1}px)` }
2036
+ style: { transform: `translateX(${left - 1}px) translateY(${this.#getLineY(line) + wrapLine * this.#metrics.lineHeight}px)` }
940
2037
  }, renderCtx.fragment);
941
2038
  renderCtx.elements.set(cacheKey, caretEl);
942
2039
  if (isPrimary) {
@@ -944,107 +2041,179 @@ var Editor = class {
944
2041
  this.#primaryCaretElement = caretEl;
945
2042
  }
946
2043
  }
947
- #renderQuickEditIcon(renderCtx, selection) {
948
- const line = getCaretPosition(selection).line;
949
- if (!this.#isLineVisible(line)) return;
950
- const [left, wrapLine] = this.#getCharX(line, 0);
951
- const cacheKey = "quickEditIcon-" + line + "(" + wrapLine + ")";
952
- if (renderCtx.elements.has(cacheKey)) return;
953
- const quickEditIcon = QuickEditWidget.renderIcon(left, this.#getLineY(line) + wrapLine * this.#metrics.lineHeight, renderCtx.fragment, () => {
954
- const cleanUpQuickEdit = () => {
955
- this.#quickEdit?.cleanup();
956
- this.#quickEdit = void 0;
957
- };
958
- const handleWidgetDomResize = () => {
959
- this.#lineYCache.clear();
960
- if (this.#selections !== void 0) this.#updateSelections(this.#selections);
961
- };
962
- cleanUpQuickEdit();
963
- const textDocument = this.#textDocument;
964
- const renderQuickEdit = this.#options.renderQuickEdit;
965
- const fileContainer = this.#componentContainer;
966
- if (textDocument === void 0 || renderQuickEdit === void 0 || fileContainer == null) return;
967
- const line$1 = selection.end.line;
968
- const lineText = textDocument.getLineText(line$1);
969
- const quickEditElement = renderQuickEdit({
2044
+ #updateSelectionActionPopover() {
2045
+ const primarySelection = this.#selections?.at(-1);
2046
+ const overlayElement = this.#overlayElement;
2047
+ const textDocument = this.#textDocument;
2048
+ const renderSelectionAction = this.#options.renderSelectionAction;
2049
+ const cleanup = () => {
2050
+ this.#selectionAction?.cleanup();
2051
+ this.#selectionAction = void 0;
2052
+ };
2053
+ if (this.#options.enabledSelectionAction !== true || renderSelectionAction === void 0 || primarySelection === void 0 || isCollapsedSelection(primarySelection) || this.#isContentMouseDown || overlayElement === void 0 || textDocument === void 0) {
2054
+ cleanup();
2055
+ return;
2056
+ }
2057
+ const head = getCaretPosition(primarySelection);
2058
+ if (!this.#isLineVisible(head.line)) {
2059
+ cleanup();
2060
+ return;
2061
+ }
2062
+ if (this.#selectionAction === void 0) {
2063
+ const getActiveSelection = () => this.#selections?.at(-1) ?? primarySelection;
2064
+ const selectionActionElement = renderSelectionAction({
970
2065
  textDocument,
971
- selection,
972
- applyEdits: (edits) => {
973
- const change = textDocument.applyEdits(edits, true, this.#selections);
974
- if (change !== void 0) this.#applyChange(change);
975
- },
976
- getSelectionText: () => {
977
- return this.#textDocument?.getText(selection) ?? "";
2066
+ get selection() {
2067
+ return getActiveSelection();
978
2068
  },
2069
+ applyEdits: (edits) => this.applyEdits(edits),
2070
+ getSelectionText: () => this.#textDocument?.getText(getActiveSelection()) ?? "",
979
2071
  replaceSelectionText: (text) => {
980
- this.#replaceSelectionText(text);
2072
+ this.#replaceSelectionText(text, [getActiveSelection()]);
981
2073
  },
982
2074
  close: () => {
983
- cleanUpQuickEdit();
984
- handleWidgetDomResize();
2075
+ cleanup();
985
2076
  this.#scrollToPrimaryCaret();
986
2077
  }
987
2078
  });
988
- let leadingWhitespaces = 0;
989
- for (let i = 0; i < lineText.length; i++) {
990
- const charCode = lineText.charCodeAt(i);
991
- if (charCode === 32) leadingWhitespaces++;
992
- else if (charCode === 9) leadingWhitespaces += this.#metrics.tabSize;
993
- else break;
994
- }
995
- this.#quickEdit = new QuickEditWidget(line$1, quickEditElement, fileContainer, leadingWhitespaces, handleWidgetDomResize);
996
- this.#updateSelections([selection]);
997
- if (this.#isLineVisible(line$1) && this.#contentElement !== void 0) this.#quickEdit.render(this.#contentElement);
998
- });
999
- renderCtx.elements.set(cacheKey, quickEditIcon);
2079
+ this.#selectionAction = new SelectionActionWidget(selectionActionElement, overlayElement, () => this.#updateSelectionActionPopover());
2080
+ this.#getPopoverManager().resetPlacement(SELECTION_ACTION_POPOVER_PLACEMENT_KEY);
2081
+ }
2082
+ const lineHeight = this.#metrics.lineHeight;
2083
+ const isBackward = primarySelection.direction === -1;
2084
+ const preferred = {
2085
+ placeAbove: isBackward,
2086
+ anchor: head
2087
+ };
2088
+ const fallback = isBackward ? {
2089
+ placeAbove: false,
2090
+ anchor: primarySelection.end
2091
+ } : {
2092
+ placeAbove: true,
2093
+ anchor: primarySelection.start
2094
+ };
2095
+ const popoverHeight = this.#selectionAction.height;
2096
+ const candidateGeometry = (candidate) => {
2097
+ const [left, candidateWrapLine] = this.#getCharX(candidate.anchor.line, candidate.anchor.character);
2098
+ const rowTop = this.#getLineY(candidate.anchor.line) + candidateWrapLine * lineHeight;
2099
+ const anchorTop = candidate.placeAbove ? rowTop : rowTop + lineHeight;
2100
+ const top = candidate.placeAbove ? anchorTop - popoverHeight : anchorTop;
2101
+ return {
2102
+ top,
2103
+ bottom: top + popoverHeight,
2104
+ left,
2105
+ anchorTop
2106
+ };
2107
+ };
2108
+ const preferredGeometry = candidateGeometry(preferred);
2109
+ const fallbackGeometry = candidateGeometry(fallback);
2110
+ const lineCount = textDocument.lineCount;
2111
+ const atDocumentEdge = isBackward ? head.line < 3 : head.line >= lineCount - 3;
2112
+ const canUseFallback = this.#isLineVisible(fallback.anchor.line);
2113
+ const popoverManager = this.#getPopoverManager();
2114
+ const viewport = popoverManager.getPlacementBounds();
2115
+ const useFallback = canUseFallback && popoverManager.choosePlacement({
2116
+ preferred: preferredGeometry,
2117
+ fallback: fallbackGeometry,
2118
+ viewport,
2119
+ popoverHeight,
2120
+ atDocumentEdge,
2121
+ placementKey: SELECTION_ACTION_POPOVER_PLACEMENT_KEY
2122
+ }) === "fallback";
2123
+ if (!canUseFallback) popoverManager.setPlacement("preferred", SELECTION_ACTION_POPOVER_PLACEMENT_KEY);
2124
+ const { placeAbove } = useFallback ? fallback : preferred;
2125
+ const { left, anchorTop } = useFallback ? fallbackGeometry : preferredGeometry;
2126
+ this.#selectionAction.reposition(left, anchorTop, this.#getGutterWidth(), placeAbove, viewport);
2127
+ }
2128
+ #openSearchPanel(mode) {
2129
+ if (this.#searchPanel !== void 0) {
2130
+ this.#searchPanel.setMode(mode);
2131
+ return;
2132
+ }
2133
+ this.#renderSearchPanel(mode);
1000
2134
  }
1001
- #renderSearchPanel() {
2135
+ #renderSearchPanel(mode) {
1002
2136
  this.#searchPanel?.cleanup();
1003
2137
  const textDocument = this.#textDocument;
1004
- const preElement = this.#componentContainer?.shadowRoot?.querySelector("pre");
2138
+ const preElement = this.#fileContainer?.shadowRoot?.querySelector("pre");
2139
+ const selections = this.#selections;
1005
2140
  if (textDocument === void 0 || preElement == null) return;
1006
2141
  let defaultQuery = "";
1007
2142
  let initialMatch = void 0;
1008
- const selections = this.#selections;
1009
2143
  if (selections !== void 0 && selections.length > 0) {
1010
2144
  let primarySelection = selections.at(-1);
1011
2145
  if (isCollapsedSelection(primarySelection)) {
1012
2146
  primarySelection = expandCollapsedSelectionToWord(textDocument, primarySelection);
1013
2147
  this.#updateSelections([...selections.slice(0, -1), primarySelection]);
1014
2148
  const selectionText = textDocument.getText(primarySelection);
1015
- if (!selectionText.includes("\n")) {
2149
+ if (selectionText !== "" && !selectionText.includes("\n")) {
1016
2150
  defaultQuery = selectionText;
1017
2151
  initialMatch = [textDocument.offsetAt(primarySelection.start), textDocument.offsetAt(primarySelection.end)];
1018
2152
  }
1019
2153
  }
1020
2154
  }
1021
- this.#searchPanel = new SearchPanelWidget({
2155
+ const scrollToMatch = ([startOffset, endOffset], retainFocus) => {
2156
+ const nextSelection = createSelectionFromAnchorAndFocusOffsets(textDocument, startOffset, endOffset);
2157
+ this.#updateSelections([nextSelection]);
2158
+ this.#revealLineIfCollapsed(getCaretPosition(nextSelection).line);
2159
+ this.#scrollToPrimaryCaret(true);
2160
+ this.#retainSearchPanelFocus = retainFocus;
2161
+ };
2162
+ const searchPanel = new SearchPanelWidget({
1022
2163
  textDocument,
1023
2164
  containerElement: preElement,
1024
2165
  defaultQuery,
2166
+ mode,
1025
2167
  initialMatch,
1026
- getCurrentSearchRange: () => this.#selections?.at(-1),
1027
- postSearch: (kind, [startOffset, endOffset], retainFocus) => {
1028
- if (kind === "findNext" || kind === "findPrevious" || kind === "replace") {
1029
- const nextSelection = createSelectionFromAnchorAndFocusOffsets(textDocument, startOffset, endOffset);
1030
- this.#updateSelections([nextSelection]);
1031
- this.#scrollToPrimaryCaret();
1032
- if (retainFocus === true) {
1033
- this.#retainSearchPanelFocus = true;
1034
- requestAnimationFrame(() => {
1035
- this.#searchPanel?.focus();
1036
- });
2168
+ scrollToMatch,
2169
+ applyReplace: (edits) => {
2170
+ if (edits.length === 0) return;
2171
+ const change = textDocument.applyEdits(edits.map((edit) => ({
2172
+ range: {
2173
+ start: textDocument.positionAt(edit.start),
2174
+ end: textDocument.positionAt(edit.end)
2175
+ },
2176
+ newText: edit.text
2177
+ })), true, this.#selections);
2178
+ if (change !== void 0) this.#applyChange(change, void 0, this.#applyChangeToLineAnnotations(change), { skipSearchRefresh: true });
2179
+ },
2180
+ onUpdate: (allMatches, options) => {
2181
+ if (allMatches.length === 0) {
2182
+ this.#matches = void 0;
2183
+ this.#updateSelections(this.#selections ?? []);
2184
+ return;
2185
+ }
2186
+ this.#matches = allMatches;
2187
+ if (options?.syncSelection === false) {
2188
+ this.#updateSelections(this.#selections ?? []);
2189
+ const primarySelection = this.#selections?.at(-1);
2190
+ if (primarySelection !== void 0) {
2191
+ const startOffset = textDocument.offsetAt(primarySelection.start);
2192
+ const endOffset = textDocument.offsetAt(primarySelection.end);
2193
+ for (const match of allMatches) if (match[0] === startOffset && match[1] === endOffset) return match;
1037
2194
  }
1038
- } else if (kind === "findAll" || kind === "replaceAll") {
1039
- const { line, character } = textDocument.positionAt(startOffset);
1040
- this.#scrollToLine(line, character);
2195
+ return;
1041
2196
  }
2197
+ const primarySelection = this.#selections?.at(-1);
2198
+ let searchOffset = 0;
2199
+ let nextMatch;
2200
+ if (primarySelection !== void 0) searchOffset = textDocument.offsetAt(primarySelection.start);
2201
+ for (const m of allMatches) if (m[0] >= searchOffset) {
2202
+ nextMatch = m;
2203
+ break;
2204
+ }
2205
+ if (nextMatch !== void 0) scrollToMatch(nextMatch, true);
2206
+ else this.#updateSelections(this.#selections ?? []);
2207
+ return nextMatch;
1042
2208
  },
1043
2209
  onClose: () => {
1044
2210
  this.#searchPanel = void 0;
1045
2211
  this.#retainSearchPanelFocus = false;
2212
+ this.#matches = void 0;
2213
+ this.#updateSelections(this.#selections ?? []);
1046
2214
  }
1047
2215
  });
2216
+ this.#searchPanel = searchPanel;
1048
2217
  this.#retainSearchPanelFocus = false;
1049
2218
  }
1050
2219
  #getSelectionText() {
@@ -1053,39 +2222,88 @@ var Editor = class {
1053
2222
  if (textDocument === void 0 || selections === void 0) return "";
1054
2223
  return getSelectionText(textDocument, selections);
1055
2224
  }
1056
- #replaceSelectionText(text) {
2225
+ #getSelectionClipboardTexts() {
2226
+ const textDocument = this.#textDocument;
2227
+ const selections = this.#selections;
2228
+ if (textDocument === void 0 || selections === void 0) return [];
2229
+ return getSelectionClipboardTexts(textDocument, selections);
2230
+ }
2231
+ /** Writes both the portable text and the selection pairing metadata. */
2232
+ #writeSelectionClipboardData(clipboardData, text, selectionTexts) {
2233
+ if (clipboardData === null) return;
2234
+ clipboardData.setData("text", text);
2235
+ if (selectionTexts.length > 1) clipboardData.setData(MULTI_SELECTION_CLIPBOARD_TYPE, JSON.stringify(selectionTexts));
2236
+ }
2237
+ #cutSelectionText() {
2238
+ const textDocument = this.#textDocument;
2239
+ const selections = this.#selections;
2240
+ if (textDocument === void 0 || selections === void 0 || selections.length === 0) return "";
2241
+ if (selections.some((selection) => isCollapsedSelection(selection))) {
2242
+ const cut = resolveSelectionCut(textDocument, selections);
2243
+ this.#applySelectionCutEdits(cut.edits, cut.nextSelectionOffsets);
2244
+ return cut.text;
2245
+ }
2246
+ const text = getSelectionText(textDocument, selections);
2247
+ this.#replaceSelectionText("", void 0, true);
2248
+ return text;
2249
+ }
2250
+ #applySelectionCutEdits(edits, nextSelectionOffsets) {
2251
+ const textDocument = this.#textDocument;
1057
2252
  const selections = this.#selections;
2253
+ if (textDocument === void 0 || selections === void 0 || edits.length === 0) return;
2254
+ const change = textDocument.applyResolvedEdits(edits, true, selections, void 0, true);
2255
+ if (change === void 0) return;
2256
+ const nextSelections = nextSelectionOffsets.map((offset) => {
2257
+ const caret = textDocument.positionAt(offset);
2258
+ return {
2259
+ start: caret,
2260
+ end: caret,
2261
+ direction: 0
2262
+ };
2263
+ });
2264
+ textDocument.setLastUndoSelectionsAfter(nextSelections);
2265
+ this.#applyChange(change, nextSelections, this.#applyChangeToLineAnnotations(change));
2266
+ }
2267
+ #replaceSelectionText(text, selections = this.#selections, undoBoundary = false, textOrder = "selection") {
1058
2268
  if (selections === void 0) return;
1059
2269
  const textDocument = this.#textDocument;
1060
2270
  const primarySelection = selections.at(-1);
1061
2271
  if (textDocument === void 0 || primarySelection === void 0) return;
1062
- const { nextSelections, change } = Array.isArray(text) && text.length === selections.length ? applyTextReplaceToSelections(textDocument, selections, text, this.#lineAnnotations) : applyTextChangeToSelections(textDocument, selections, {
2272
+ const { nextSelections, change } = Array.isArray(text) && text.length === selections.length ? applyTextReplaceToSelections(textDocument, selections, text, this.#lineAnnotations, undoBoundary, textOrder) : applyTextChangeToSelections(textDocument, selections, {
1063
2273
  start: textDocument.offsetAt(primarySelection.start),
1064
2274
  end: textDocument.offsetAt(primarySelection.end),
1065
- text: Array.isArray(text) ? text.join("\n") : text
1066
- }, this.#lineAnnotations);
2275
+ text: Array.isArray(text) ? text.join(textDocument.eol) : text
2276
+ }, this.#lineAnnotations, void 0, undoBoundary);
1067
2277
  if (change !== void 0) this.#applyChange(change, nextSelections, this.#applyChangeToLineAnnotations(change));
1068
2278
  }
1069
2279
  #deleteSelectionText(forward = false) {
1070
2280
  const selections = this.#selections;
1071
2281
  const textDocument = this.#textDocument;
1072
2282
  if (selections === void 0 || textDocument === void 0) return;
1073
- const primarySelection = selections.at(-1);
1074
- if (primarySelection === void 0) return;
1075
- const edit = isCollapsedSelection(primarySelection) ? (() => {
1076
- const offset = textDocument.offsetAt(primarySelection.start);
1077
- const nextOffset = forward ? Math.min(textDocument.getText().length, offset + 1) : Math.max(0, offset - 1);
1078
- return {
1079
- start: Math.min(offset, nextOffset),
1080
- end: Math.max(offset, nextOffset),
1081
- text: ""
1082
- };
1083
- })() : {
1084
- start: textDocument.offsetAt(primarySelection.start),
1085
- end: textDocument.offsetAt(primarySelection.end),
1086
- text: ""
1087
- };
1088
- this.#applyResolvedTextEdit(edit);
2283
+ const { nextSelections, change } = applyDeleteCharacterToSelections(textDocument, selections, forward, this.#lineAnnotations, this.#metrics.tabSize);
2284
+ if (change !== void 0) this.#applyChange(change, nextSelections, this.#applyChangeToLineAnnotations(change));
2285
+ }
2286
+ #deleteSoftLineBackward() {
2287
+ const selections = this.#selections;
2288
+ const textDocument = this.#textDocument;
2289
+ if (selections === void 0 || textDocument === void 0) return;
2290
+ const { nextSelections, change } = applyDeleteSoftLineBackwardToSelections(textDocument, selections, this.#isWrap ? (line, character) => {
2291
+ const wrapOffsets = this.#wrapLineText(line);
2292
+ for (let w = 0; w + 1 < wrapOffsets.length; w++) {
2293
+ const segmentStart = wrapOffsets[w];
2294
+ const segmentEnd = wrapOffsets[w + 1];
2295
+ if (character >= segmentStart && character <= segmentEnd) return segmentStart;
2296
+ }
2297
+ return 0;
2298
+ } : void 0, this.#lineAnnotations);
2299
+ if (change !== void 0) this.#applyChange(change, nextSelections, this.#applyChangeToLineAnnotations(change));
2300
+ }
2301
+ #deleteWordBackward() {
2302
+ const selections = this.#selections;
2303
+ const textDocument = this.#textDocument;
2304
+ if (selections === void 0 || textDocument === void 0) return;
2305
+ const { nextSelections, change } = applyDeleteWordBackwardToSelections(textDocument, selections, this.#lineAnnotations);
2306
+ if (change !== void 0) this.#applyChange(change, nextSelections, this.#applyChangeToLineAnnotations(change));
1089
2307
  }
1090
2308
  #deleteHardLineForward() {
1091
2309
  const selections = this.#selections;
@@ -1101,53 +2319,54 @@ var Editor = class {
1101
2319
  const { nextSelections, change } = applyTransposeToSelections(textDocument, selections, this.#lineAnnotations);
1102
2320
  if (change !== void 0) this.#applyChange(change, nextSelections, this.#applyChangeToLineAnnotations(change));
1103
2321
  }
1104
- #applyResolvedTextEdit(edit) {
1105
- if (this.#selections === void 0 || this.#textDocument === void 0) return;
1106
- const { nextSelections, change } = applyTextChangeToSelections(this.#textDocument, this.#selections, edit, this.#lineAnnotations, this.#metrics.tabSize);
1107
- if (change !== void 0) this.#applyChange(change, nextSelections, this.#applyChangeToLineAnnotations(change));
1108
- }
1109
- #applyChange(change, selections, newLineAnnotations) {
1110
- const fileContents = this.#fileContents;
1111
- const textDocument = this.#textDocument;
2322
+ #applyChange(change, newSelections, newLineAnnotations, options) {
2323
+ const fileRef = this.getFile();
1112
2324
  const onChange = this.#options.onChange;
1113
- if (fileContents !== void 0 && textDocument !== void 0 && onChange !== void 0) {
1114
- const { contents: _,...file } = fileContents;
1115
- let contents;
1116
- Object.defineProperty(file, "contents", { get: () => contents ??= textDocument.getText() });
1117
- this.#emitChange(file, newLineAnnotations ?? this.#lineAnnotations);
1118
- }
1119
- if (change.lineDelta !== 0) {
2325
+ if (fileRef !== void 0 && onChange !== void 0) onChange(fileRef, newLineAnnotations ?? this.#lineAnnotations);
2326
+ if (change.lineDelta !== 0 || this.#isWrap) {
1120
2327
  for (const line of this.#lineYCache.keys()) if (line >= change.startLine) this.#lineYCache.delete(line);
1121
2328
  }
1122
- if (this.#wrap) {
2329
+ if (this.#isWrap) {
1123
2330
  for (const line of this.#wrapLineOffsetsCache.keys()) if (line >= change.startLine) this.#wrapLineOffsetsCache.delete(line);
1124
2331
  }
1125
- this.#lastCharX = void 0;
2332
+ this.#lastAccessedCharX = void 0;
1126
2333
  let renderRange = this.#renderRange;
1127
2334
  let shouldUpdateBuffer;
1128
- if (renderRange !== void 0 && selections !== void 0 && selections.length > 0) {
1129
- const primarySelection = selections.at(-1);
2335
+ if (renderRange !== void 0 && newSelections !== void 0 && newSelections.length > 0) {
2336
+ const primarySelection = newSelections.at(-1);
1130
2337
  const renderRangeEndLine = renderRange.startingLine + renderRange.totalLines;
1131
- if (primarySelection.end.line === renderRangeEndLine) renderRange = {
1132
- ...renderRange,
1133
- totalLines: renderRange.totalLines + 1
1134
- };
1135
- else if (primarySelection.end.line > renderRangeEndLine) shouldUpdateBuffer = true;
2338
+ if (primarySelection.end.line >= renderRangeEndLine) {
2339
+ const widenedTotalLines = primarySelection.end.line - renderRange.startingLine + 1;
2340
+ const maxWidenLines = this.#viewportWindowLines === void 0 || this.#viewportWindowLines === Infinity ? Infinity : this.#viewportWindowLines * MAX_EDIT_WIDEN_WINDOW_MULTIPLE;
2341
+ if (change.startLine <= renderRangeEndLine && widenedTotalLines <= maxWidenLines && this.#isLineRenderable(primarySelection.end.line)) {
2342
+ if (primarySelection.end.line > renderRangeEndLine) shouldUpdateBuffer = true;
2343
+ renderRange = {
2344
+ ...renderRange,
2345
+ totalLines: widenedTotalLines
2346
+ };
2347
+ this.#renderRange = renderRange;
2348
+ } else shouldUpdateBuffer = true;
2349
+ }
1136
2350
  }
1137
2351
  this.#rerender(change, newLineAnnotations, renderRange, shouldUpdateBuffer);
1138
- if (selections !== void 0) {
1139
- this.#updateSelections(selections);
1140
- this.focus({ preventScroll: true });
1141
- requestAnimationFrame(() => {
1142
- if (this.#primaryCaretElement !== void 0) this.#primaryCaretElement.scrollIntoView({
1143
- block: "nearest",
1144
- inline: "nearest"
2352
+ if (options?.skipSearchRefresh !== true && this.#searchPanel !== void 0 && this.#matches !== void 0) this.#searchPanel.updateMatches({ syncSelection: false });
2353
+ if (newSelections !== void 0) {
2354
+ this.#updateSelections(newSelections);
2355
+ if (options?.skipFocus !== true) {
2356
+ const revealTarget = newSelections.at(-1);
2357
+ if (revealTarget !== void 0) this.#revealLineIfCollapsed(getCaretPosition(revealTarget).line);
2358
+ if (this.#primaryCaretElement !== void 0) requestAnimationFrame(() => {
2359
+ this.#primaryCaretElement?.scrollIntoView({
2360
+ block: "nearest",
2361
+ inline: "nearest"
2362
+ });
1145
2363
  });
1146
- else if (selections.length > 0) {
1147
- const pos = getCaretPosition(selections.at(-1));
2364
+ else if (newSelections.length > 0) {
2365
+ const pos = getCaretPosition(newSelections.at(-1));
1148
2366
  this.#scrollToLine(pos.line, pos.character);
1149
2367
  }
1150
- });
2368
+ this.focus({ preventScroll: true });
2369
+ }
1151
2370
  }
1152
2371
  }
1153
2372
  #applyChangeToLineAnnotations(change) {
@@ -1159,29 +2378,54 @@ var Editor = class {
1159
2378
  }
1160
2379
  }
1161
2380
  }
2381
+ #getRenderedEditableLineRange() {
2382
+ const contentElement = this.#contentElement;
2383
+ if (contentElement === void 0) return;
2384
+ let first;
2385
+ let last;
2386
+ for (const child of contentElement.children) {
2387
+ const el = child;
2388
+ const lineType = el.dataset.lineType;
2389
+ const lineNumber = getLineNumberAttr(el);
2390
+ if (lineNumber === void 0 || lineType === void 0 || !isLineEditable(lineType)) continue;
2391
+ const line = lineNumber - 1;
2392
+ if (first === void 0 || line < first) first = line;
2393
+ if (last === void 0 || line > last) last = line;
2394
+ }
2395
+ return first === void 0 || last === void 0 ? void 0 : {
2396
+ first,
2397
+ last
2398
+ };
2399
+ }
1162
2400
  #getLineElement(line) {
2401
+ let lineElement = this.#lineElementsCache.get(line);
2402
+ if (lineElement !== void 0) return lineElement ?? void 0;
1163
2403
  const contentElement = this.#contentElement;
1164
2404
  if (contentElement === void 0) return;
1165
- if (this.#renderRange !== void 0 && this.#editMode === "simple") {
2405
+ if (this.#renderRange !== void 0) {
1166
2406
  const { startingLine } = this.#renderRange;
1167
2407
  const { children } = contentElement;
1168
2408
  for (let i = line - startingLine; i <= children.length; i++) {
1169
2409
  const child = children[i];
1170
- const lineNumber = child?.dataset.line;
1171
- const lineType = child?.dataset.lineType;
1172
- if (lineNumber !== void 0 && lineType !== void 0 && isLineEditable(lineType) && Number(lineNumber) === line + 1) return child;
2410
+ if (child === void 0) break;
2411
+ const lineNumber = getLineNumberAttr(child);
2412
+ const lineType = child.dataset.lineType;
2413
+ if (lineNumber !== void 0 && lineNumber === line + 1 && lineType !== void 0 && isLineEditable(lineType)) {
2414
+ lineElement = child;
2415
+ break;
2416
+ }
1173
2417
  }
1174
2418
  }
1175
- if (this.#editMode === "advanced") return contentElement.querySelector(`[data-line="${line + 1}"]:not([data-line-type="change-deletion"])`) ?? void 0;
1176
- return contentElement.querySelector(`[data-line="${line + 1}"]`) ?? void 0;
2419
+ lineElement ??= contentElement.querySelector(`[data-line="${line + 1}"]` + (this.#diffSyle === "unified" ? ":not([data-line-type=\"change-deletion\"])" : ""));
2420
+ if (lineElement !== void 0) this.#lineElementsCache.set(line, lineElement);
2421
+ return lineElement ?? void 0;
1177
2422
  }
1178
2423
  #getGutterWidth() {
1179
- const gutterElement = this.#contentElement?.previousElementSibling;
1180
- if (gutterElement == null || !(gutterElement instanceof HTMLElement) || !gutterElement.hasAttribute("data-gutter")) return 0;
2424
+ if (this.#gutterElement === void 0) return 0;
1181
2425
  if (this.#gutterWidthCache === void 0) {
1182
2426
  const diffsColumnNumberWidth = this.#contentElement?.parentElement?.style.getPropertyValue("--diffs-column-number-width");
1183
- if (diffsColumnNumberWidth !== void 0 && diffsColumnNumberWidth.length > 2 && diffsColumnNumberWidth.endsWith("px")) this.#gutterWidthCache = Number(diffsColumnNumberWidth.slice(0, -2));
1184
- else this.#gutterWidthCache = gutterElement.offsetWidth;
2427
+ if (diffsColumnNumberWidth !== void 0 && diffsColumnNumberWidth.length > 2 && diffsColumnNumberWidth.endsWith("px")) this.#gutterWidthCache = parseInt(diffsColumnNumberWidth.slice(0, -2), 10);
2428
+ else this.#gutterWidthCache = this.#gutterElement.offsetWidth;
1185
2429
  }
1186
2430
  return this.#gutterWidthCache;
1187
2431
  }
@@ -1189,7 +2433,7 @@ var Editor = class {
1189
2433
  if (this.#contentElement === void 0) return 0;
1190
2434
  if (this.#contentWidthCache === void 0) {
1191
2435
  const diffsColumnContentWidth = this.#contentElement.parentElement?.style.getPropertyValue("--diffs-column-content-width");
1192
- if (diffsColumnContentWidth !== void 0 && diffsColumnContentWidth.length > 2 && diffsColumnContentWidth.endsWith("px")) this.#contentWidthCache = Number(diffsColumnContentWidth.slice(0, -2));
2436
+ if (diffsColumnContentWidth !== void 0 && diffsColumnContentWidth.length > 2 && diffsColumnContentWidth.endsWith("px")) this.#contentWidthCache = parseFloat(diffsColumnContentWidth.slice(0, -2));
1193
2437
  else this.#contentWidthCache = this.#contentElement.offsetWidth;
1194
2438
  }
1195
2439
  return this.#contentWidthCache;
@@ -1199,15 +2443,16 @@ var Editor = class {
1199
2443
  if (cachedY !== void 0) return cachedY;
1200
2444
  const lineElement = this.#getLineElement(line);
1201
2445
  if (lineElement === void 0) return -1;
1202
- const y = lineElement.offsetTop + this.#codePaddingTop;
2446
+ let y = lineElement.offsetTop + this.#metrics.paddingTop;
2447
+ y += this.#activeContentOffset?.top ?? 0;
1203
2448
  this.#lineYCache.set(line, y);
1204
2449
  return y;
1205
2450
  }
1206
2451
  #getCharX(line, char) {
1207
- if (this.#lastCharX !== void 0 && this.#lastCharX[0] === line && this.#lastCharX[1] === char) return [this.#lastCharX[2], this.#lastCharX[3]];
2452
+ if (this.#lastAccessedCharX !== void 0 && this.#lastAccessedCharX[0] === line && this.#lastAccessedCharX[1] === char) return [this.#lastAccessedCharX[2], this.#lastAccessedCharX[3]];
1208
2453
  const lineText = this.#textDocument?.getLineText(line);
1209
2454
  const offsetLeft = this.#getGutterWidth() + this.#metrics.ch;
1210
- if (lineText === void 0 || lineText.length === 0 || char <= 0) return [offsetLeft, 0];
2455
+ if (lineText === void 0 || lineText.length === 0 || char <= 0) return [offsetLeft + (this.#activeContentOffset?.left ?? 0), 0];
1211
2456
  const boundedCharacter = snapTextOffsetToUnicodeBoundary(lineText, Math.min(char, lineText.length));
1212
2457
  const textBeforeCharacter = lineText.slice(0, boundedCharacter);
1213
2458
  const asciiColumns = getExpandedAsciiTextColumns(textBeforeCharacter, this.#metrics.tabSize);
@@ -1215,7 +2460,7 @@ var Editor = class {
1215
2460
  let wrapLine = 0;
1216
2461
  if (asciiColumns !== -1) left = offsetLeft + asciiColumns * this.#metrics.ch;
1217
2462
  else left = offsetLeft + this.#metrics.measureTextWidth(textBeforeCharacter);
1218
- if (this.#wrap) {
2463
+ if (this.#isWrap) {
1219
2464
  const contentWidth = this.#getContentWidth();
1220
2465
  if (2 * this.#metrics.ch + this.#metrics.measureTextWidth(lineText) > contentWidth) {
1221
2466
  const wrapOffsets = this.#wrapLineText(line);
@@ -1231,13 +2476,14 @@ var Editor = class {
1231
2476
  }
1232
2477
  }
1233
2478
  }
2479
+ left += this.#activeContentOffset?.left ?? 0;
1234
2480
  }
1235
- if (this.#lastCharX !== void 0) {
1236
- this.#lastCharX[0] = line;
1237
- this.#lastCharX[1] = char;
1238
- this.#lastCharX[2] = left;
1239
- this.#lastCharX[3] = wrapLine;
1240
- } else this.#lastCharX = [
2481
+ if (this.#lastAccessedCharX !== void 0) {
2482
+ this.#lastAccessedCharX[0] = line;
2483
+ this.#lastAccessedCharX[1] = char;
2484
+ this.#lastAccessedCharX[2] = left;
2485
+ this.#lastAccessedCharX[3] = wrapLine;
2486
+ } else this.#lastAccessedCharX = [
1241
2487
  line,
1242
2488
  char,
1243
2489
  left,
@@ -1310,14 +2556,10 @@ var Editor = class {
1310
2556
  #isLineVisible(line) {
1311
2557
  const lineCount = this.#textDocument?.lineCount ?? 0;
1312
2558
  if (line < 0 || line >= lineCount) return false;
1313
- if (this.#renderRange === void 0) return true;
1314
- const { startingLine, totalLines } = this.#renderRange;
1315
- if (line < startingLine) return false;
1316
- if (totalLines === Infinity) return true;
1317
- return line < startingLine + totalLines;
2559
+ return this.#getLineElement(line) !== void 0;
1318
2560
  }
1319
2561
  };
1320
-
1321
2562
  //#endregion
1322
2563
  export { Editor };
2564
+
1323
2565
  //# sourceMappingURL=editor.js.map