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

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