jj-plus 0.10.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 (404) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +102 -0
  3. package/assets/jj-plus-icon.png +0 -0
  4. package/dist/_virtual/_rolldown/runtime.cjs +23 -0
  5. package/dist/bin.cjs +112 -0
  6. package/dist/bin.cjs.map +1 -0
  7. package/dist/cli/options.cjs +376 -0
  8. package/dist/cli/options.cjs.map +1 -0
  9. package/dist/cli/timeline-json.cjs +29 -0
  10. package/dist/cli/timeline-json.cjs.map +1 -0
  11. package/dist/extension/blame-codelens.cjs +228 -0
  12. package/dist/extension/blame-codelens.cjs.map +1 -0
  13. package/dist/extension/command-runner.cjs +99 -0
  14. package/dist/extension/command-runner.cjs.map +1 -0
  15. package/dist/extension/constants.cjs +56 -0
  16. package/dist/extension/constants.cjs.map +1 -0
  17. package/dist/extension/editor-extra-features.cjs +464 -0
  18. package/dist/extension/editor-extra-features.cjs.map +1 -0
  19. package/dist/extension/history-adapters.cjs +702 -0
  20. package/dist/extension/history-adapters.cjs.map +1 -0
  21. package/dist/extension/index.cjs +657 -0
  22. package/dist/extension/index.cjs.map +1 -0
  23. package/dist/extension/repo-timeline-panel.cjs +402 -0
  24. package/dist/extension/repo-timeline-panel.cjs.map +1 -0
  25. package/dist/extension/resolve-file-path.cjs +16 -0
  26. package/dist/extension/resolve-file-path.cjs.map +1 -0
  27. package/dist/extension/revision-diff-nav.cjs +169 -0
  28. package/dist/extension/revision-diff-nav.cjs.map +1 -0
  29. package/dist/extension/settings.cjs +41 -0
  30. package/dist/extension/settings.cjs.map +1 -0
  31. package/dist/extension/timeline-at-line.cjs +72 -0
  32. package/dist/extension/timeline-at-line.cjs.map +1 -0
  33. package/dist/extension/timeline-panel.cjs +1113 -0
  34. package/dist/extension/timeline-panel.cjs.map +1 -0
  35. package/dist/extension/timeline-service.cjs +1154 -0
  36. package/dist/extension/timeline-service.cjs.map +1 -0
  37. package/dist/extension/uri-utils.cjs +75 -0
  38. package/dist/extension/uri-utils.cjs.map +1 -0
  39. package/dist/package.cjs +11 -0
  40. package/dist/package.cjs.map +1 -0
  41. package/dist/shared/blame.cjs +211 -0
  42. package/dist/shared/blame.cjs.map +1 -0
  43. package/dist/shared/diff-content-search.cjs +23 -0
  44. package/dist/shared/diff-content-search.cjs.map +1 -0
  45. package/dist/shared/diff-helpers.cjs +12 -0
  46. package/dist/shared/diff-helpers.cjs.map +1 -0
  47. package/dist/shared/diff-stats.cjs +129 -0
  48. package/dist/shared/diff-stats.cjs.map +1 -0
  49. package/dist/shared/file-oplog.cjs +82 -0
  50. package/dist/shared/file-oplog.cjs.map +1 -0
  51. package/dist/shared/history-helpers.cjs +257 -0
  52. package/dist/shared/history-helpers.cjs.map +1 -0
  53. package/dist/shared/history-search.cjs +85 -0
  54. package/dist/shared/history-search.cjs.map +1 -0
  55. package/dist/shared/jj-revset-suggestions.cjs +41 -0
  56. package/dist/shared/jj-revset-suggestions.cjs.map +1 -0
  57. package/dist/shared/line-history.cjs +181 -0
  58. package/dist/shared/line-history.cjs.map +1 -0
  59. package/dist/shared/list-file-revisions.cjs +36 -0
  60. package/dist/shared/list-file-revisions.cjs.map +1 -0
  61. package/dist/shared/non-textual-details.cjs +43 -0
  62. package/dist/shared/non-textual-details.cjs.map +1 -0
  63. package/dist/shared/resolve-file-path.cjs +14 -0
  64. package/dist/shared/resolve-file-path.cjs.map +1 -0
  65. package/dist/shared/revision-diff-availability.cjs +18 -0
  66. package/dist/shared/revision-diff-availability.cjs.map +1 -0
  67. package/dist/shared/revision-diff-pair.cjs +42 -0
  68. package/dist/shared/revision-diff-pair.cjs.map +1 -0
  69. package/dist/shared/revset.cjs +16 -0
  70. package/dist/shared/revset.cjs.map +1 -0
  71. package/dist/shared/timeline-model.cjs +29 -0
  72. package/dist/shared/timeline-model.cjs.map +1 -0
  73. package/dist/standalone/server.cjs +1733 -0
  74. package/dist/standalone/server.cjs.map +1 -0
  75. package/dist/webview/timeline-template.cjs +214 -0
  76. package/dist/webview/timeline-template.cjs.map +1 -0
  77. package/package.json +320 -0
  78. package/webview-dist/assets/worker-DuV13XDT.js +161 -0
  79. package/webview-dist/chunks/abap-CLvhMVsD.js +1 -0
  80. package/webview-dist/chunks/actionscript-3-Cs6JJXT5.js +1 -0
  81. package/webview-dist/chunks/ada-C5qYipkI.js +1 -0
  82. package/webview-dist/chunks/ahk-CA9gdOdF.js +1 -0
  83. package/webview-dist/chunks/ahk2-_6rzW9BS.js +1 -0
  84. package/webview-dist/chunks/andromeeda-vGVdxbeo.js +1 -0
  85. package/webview-dist/chunks/angular-html-DTpR04n4.js +1 -0
  86. package/webview-dist/chunks/angular-ts-BCtbMvbl.js +1 -0
  87. package/webview-dist/chunks/apache-U0d_L8uA.js +1 -0
  88. package/webview-dist/chunks/apex-KFGFyKwG.js +1 -0
  89. package/webview-dist/chunks/apl-BMZuN1Ql.js +1 -0
  90. package/webview-dist/chunks/applescript-CCn79oCD.js +1 -0
  91. package/webview-dist/chunks/ara-4CJ0cIlV.js +1 -0
  92. package/webview-dist/chunks/asciidoc-SCjQUq34.js +1 -0
  93. package/webview-dist/chunks/asm-Cmm7eHzH.js +1 -0
  94. package/webview-dist/chunks/astro-DrbV4Z7r.js +1 -0
  95. package/webview-dist/chunks/aurora-x-CDeNXAV0.js +1 -0
  96. package/webview-dist/chunks/awk-BWXHIvNe.js +1 -0
  97. package/webview-dist/chunks/ayu-dark-DluEY0Gj.js +1 -0
  98. package/webview-dist/chunks/ayu-light-C3h-C4tm.js +1 -0
  99. package/webview-dist/chunks/ayu-mirage-Bqwy1Gya.js +1 -0
  100. package/webview-dist/chunks/ballerina-B7ZEbQpA.js +1 -0
  101. package/webview-dist/chunks/bat-qdxAdBWQ.js +1 -0
  102. package/webview-dist/chunks/beancount-D-usSTwE.js +1 -0
  103. package/webview-dist/chunks/berry-DKpUyyne.js +1 -0
  104. package/webview-dist/chunks/bibtex-Ci_nEsc7.js +1 -0
  105. package/webview-dist/chunks/bicep-CUHmPFLl.js +1 -0
  106. package/webview-dist/chunks/bird2-CYIUgYqB.js +1 -0
  107. package/webview-dist/chunks/blade-oPV8S6rR.js +1 -0
  108. package/webview-dist/chunks/bsl-_VjlB9mv.js +1 -0
  109. package/webview-dist/chunks/c-DYf-3tob.js +1 -0
  110. package/webview-dist/chunks/c3-D0apG41V.js +1 -0
  111. package/webview-dist/chunks/cadence-CQ2zXKGN.js +1 -0
  112. package/webview-dist/chunks/cairo-DLTphjLi.js +1 -0
  113. package/webview-dist/chunks/catppuccin-frappe-C9Q5zVZY.js +1 -0
  114. package/webview-dist/chunks/catppuccin-latte-CtsyrtPq.js +1 -0
  115. package/webview-dist/chunks/catppuccin-macchiato-R8nAf1vR.js +1 -0
  116. package/webview-dist/chunks/catppuccin-mocha-DjuaAJKi.js +1 -0
  117. package/webview-dist/chunks/chapel-DY-WYB1D.js +1 -0
  118. package/webview-dist/chunks/clarity-CtfBBspg.js +1 -0
  119. package/webview-dist/chunks/clojure-DqKBuwfJ.js +1 -0
  120. package/webview-dist/chunks/cmake-Bj61d0ZC.js +1 -0
  121. package/webview-dist/chunks/cobol-DvdX_6CO.js +1 -0
  122. package/webview-dist/chunks/codeowners-C8r90Shi.js +1 -0
  123. package/webview-dist/chunks/codeql-oeQT6MSM.js +1 -0
  124. package/webview-dist/chunks/coffee-C1kO7jr_.js +1 -0
  125. package/webview-dist/chunks/common-lisp-Cv5bFMCO.js +1 -0
  126. package/webview-dist/chunks/coq-DuBRPxYg.js +1 -0
  127. package/webview-dist/chunks/cpp-CoSarUrI.js +1 -0
  128. package/webview-dist/chunks/crystal-SLJeZ5EP.js +1 -0
  129. package/webview-dist/chunks/csharp-oqKa8noW.js +1 -0
  130. package/webview-dist/chunks/css-cfScyrSP.js +1 -0
  131. package/webview-dist/chunks/csv-Dx-8-gkx.js +1 -0
  132. package/webview-dist/chunks/cue-CE9AQfxI.js +1 -0
  133. package/webview-dist/chunks/cypher-ClKdZ_lG.js +1 -0
  134. package/webview-dist/chunks/d-qD-0Kul2.js +1 -0
  135. package/webview-dist/chunks/dark-plus-Cs2F2srj.js +1 -0
  136. package/webview-dist/chunks/dart-CnvKMtbv.js +1 -0
  137. package/webview-dist/chunks/dax-BkyTk9wS.js +1 -0
  138. package/webview-dist/chunks/desktop-Dlh5hvp9.js +1 -0
  139. package/webview-dist/chunks/diff-woXpYk--.js +1 -0
  140. package/webview-dist/chunks/docker-IyjqRm3v.js +1 -0
  141. package/webview-dist/chunks/dotenv-_5a1GRtc.js +1 -0
  142. package/webview-dist/chunks/dracula-BHWKrbxM.js +1 -0
  143. package/webview-dist/chunks/dracula-soft-5eyTD99u.js +1 -0
  144. package/webview-dist/chunks/dream-maker-DW3nJb8Q.js +1 -0
  145. package/webview-dist/chunks/edge-lvBr3t3s.js +1 -0
  146. package/webview-dist/chunks/elixir-BLoPe0KG.js +1 -0
  147. package/webview-dist/chunks/elm-BveBINBn.js +1 -0
  148. package/webview-dist/chunks/emacs-lisp-c_oH4hRZ.js +1 -0
  149. package/webview-dist/chunks/erb-Bmf8z4ph.js +1 -0
  150. package/webview-dist/chunks/erlang-Cphh6RMH.js +1 -0
  151. package/webview-dist/chunks/everforest-dark-sB-x3p7T.js +1 -0
  152. package/webview-dist/chunks/everforest-light-Df2xbC6M.js +1 -0
  153. package/webview-dist/chunks/fennel-DQxkIbk2.js +1 -0
  154. package/webview-dist/chunks/fish-BJitypiv.js +1 -0
  155. package/webview-dist/chunks/fluent-C03EYrpw.js +1 -0
  156. package/webview-dist/chunks/fortran-fixed-form-DEKoE2YW.js +1 -0
  157. package/webview-dist/chunks/fortran-free-form-CYNrtFtB.js +1 -0
  158. package/webview-dist/chunks/fsharp-D13ZGOAj.js +1 -0
  159. package/webview-dist/chunks/gdresource-xMC7jr7x.js +1 -0
  160. package/webview-dist/chunks/gdscript-DYvRD3hg.js +1 -0
  161. package/webview-dist/chunks/gdshader-CBce3t8t.js +1 -0
  162. package/webview-dist/chunks/genie-CV2tkWYe.js +1 -0
  163. package/webview-dist/chunks/gherkin-DExj1W_8.js +1 -0
  164. package/webview-dist/chunks/git-commit-BSykSTBG.js +1 -0
  165. package/webview-dist/chunks/git-rebase-BBii7GBM.js +1 -0
  166. package/webview-dist/chunks/github-dark-C-LZuMrd.js +1 -0
  167. package/webview-dist/chunks/github-dark-default-DXG-b-1a.js +1 -0
  168. package/webview-dist/chunks/github-dark-dimmed-Bx1FflLF.js +1 -0
  169. package/webview-dist/chunks/github-dark-high-contrast-B_tTalzw.js +1 -0
  170. package/webview-dist/chunks/github-light-EUqPIrTm.js +1 -0
  171. package/webview-dist/chunks/github-light-default-BXViO-2h.js +1 -0
  172. package/webview-dist/chunks/github-light-high-contrast-B68TUdTA.js +1 -0
  173. package/webview-dist/chunks/gleam-CSRkHgEL.js +1 -0
  174. package/webview-dist/chunks/glimmer-js-CuCPna-X.js +1 -0
  175. package/webview-dist/chunks/glimmer-ts-DNAjZNDK.js +1 -0
  176. package/webview-dist/chunks/glsl-COQvRxdz.js +1 -0
  177. package/webview-dist/chunks/gn-ilITqXS6.js +1 -0
  178. package/webview-dist/chunks/gnuplot-7GGW24-e.js +1 -0
  179. package/webview-dist/chunks/go-rLFTqkRN.js +1 -0
  180. package/webview-dist/chunks/graphql-1cKCVreZ.js +1 -0
  181. package/webview-dist/chunks/groovy-CacY0gHj.js +1 -0
  182. package/webview-dist/chunks/gruvbox-dark-hard-C820rvS2.js +1 -0
  183. package/webview-dist/chunks/gruvbox-dark-medium-BPjhmG05.js +1 -0
  184. package/webview-dist/chunks/gruvbox-dark-soft-MrdJrrXF.js +1 -0
  185. package/webview-dist/chunks/gruvbox-light-hard-BC_s9l72.js +1 -0
  186. package/webview-dist/chunks/gruvbox-light-medium-BAWPOn9u.js +1 -0
  187. package/webview-dist/chunks/gruvbox-light-soft-BSMLrYjP.js +1 -0
  188. package/webview-dist/chunks/hack-7CXYxWGO.js +1 -0
  189. package/webview-dist/chunks/haml-CeE16iG9.js +1 -0
  190. package/webview-dist/chunks/handlebars-CLm7Miue.js +1 -0
  191. package/webview-dist/chunks/haskell-D8IpX4py.js +1 -0
  192. package/webview-dist/chunks/haxe-C8oCnwJJ.js +1 -0
  193. package/webview-dist/chunks/hcl-Dh228itO.js +1 -0
  194. package/webview-dist/chunks/hjson-CxZEssPk.js +1 -0
  195. package/webview-dist/chunks/hlsl-Cvrh5tZx.js +1 -0
  196. package/webview-dist/chunks/horizon-CE9ld1lL.js +1 -0
  197. package/webview-dist/chunks/horizon-bright-DSNQnXHK.js +1 -0
  198. package/webview-dist/chunks/houston-CsvMBhTu.js +1 -0
  199. package/webview-dist/chunks/html-EbCri-_j.js +1 -0
  200. package/webview-dist/chunks/html-derivative-DGcE2kQi.js +1 -0
  201. package/webview-dist/chunks/http-DpnqgCg2.js +1 -0
  202. package/webview-dist/chunks/hurl-B6NGpamo.js +1 -0
  203. package/webview-dist/chunks/hxml-Dcm88srW.js +1 -0
  204. package/webview-dist/chunks/hy-CZbG8q4J.js +1 -0
  205. package/webview-dist/chunks/imba-DsUTQ-LC.js +1 -0
  206. package/webview-dist/chunks/ini-B5eOa1yu.js +1 -0
  207. package/webview-dist/chunks/java-ZkUoUSJy.js +1 -0
  208. package/webview-dist/chunks/javascript-DLd0EIw7.js +1 -0
  209. package/webview-dist/chunks/jinja-WhIqNp3q.js +1 -0
  210. package/webview-dist/chunks/jison-CIn1t7S8.js +1 -0
  211. package/webview-dist/chunks/json-AHG_JuKN.js +1 -0
  212. package/webview-dist/chunks/json5-BR5RXkoi.js +1 -0
  213. package/webview-dist/chunks/jsonc-CYpm1nAK.js +1 -0
  214. package/webview-dist/chunks/jsonl-CmCQp5Yx.js +1 -0
  215. package/webview-dist/chunks/jsonnet-CJTPZ8u_.js +1 -0
  216. package/webview-dist/chunks/jssm-DXw9l8Rf.js +1 -0
  217. package/webview-dist/chunks/jsx-BLy2KGb2.js +1 -0
  218. package/webview-dist/chunks/julia-XrhdGMY0.js +1 -0
  219. package/webview-dist/chunks/just-CiO9rOBq.js +1 -0
  220. package/webview-dist/chunks/kanagawa-dragon-Bozd7klA.js +1 -0
  221. package/webview-dist/chunks/kanagawa-lotus-BmuOG9ZW.js +1 -0
  222. package/webview-dist/chunks/kanagawa-wave-BML5mF2J.js +1 -0
  223. package/webview-dist/chunks/kdl-CsD5j6eV.js +1 -0
  224. package/webview-dist/chunks/kotlin-DhhofPvG.js +1 -0
  225. package/webview-dist/chunks/kusto-C7mF5XQf.js +1 -0
  226. package/webview-dist/chunks/laserwave-C_8bwKvT.js +1 -0
  227. package/webview-dist/chunks/latex-4tqdYtbu.js +1 -0
  228. package/webview-dist/chunks/lean-CewbzKMR.js +1 -0
  229. package/webview-dist/chunks/less-DVTAwKKz.js +1 -0
  230. package/webview-dist/chunks/light-plus-DVQuIRkW.js +1 -0
  231. package/webview-dist/chunks/liquid-BiiWRCLG.js +1 -0
  232. package/webview-dist/chunks/llvm-DqHOMS-s.js +1 -0
  233. package/webview-dist/chunks/log-BNLmms1o.js +1 -0
  234. package/webview-dist/chunks/logo-Cluzi2Zq.js +1 -0
  235. package/webview-dist/chunks/lua-BPFdS2Mc.js +1 -0
  236. package/webview-dist/chunks/luau-C2pBCSgt.js +1 -0
  237. package/webview-dist/chunks/make-Dixweg8N.js +1 -0
  238. package/webview-dist/chunks/markdown-BYOwaDjH.js +1 -0
  239. package/webview-dist/chunks/marko-BLi1Yy1V.js +1 -0
  240. package/webview-dist/chunks/material-theme-Bm3Qr25_.js +1 -0
  241. package/webview-dist/chunks/material-theme-darker-2IIEA8gg.js +1 -0
  242. package/webview-dist/chunks/material-theme-lighter-uhdI0v04.js +1 -0
  243. package/webview-dist/chunks/material-theme-ocean-CHQ94UKr.js +1 -0
  244. package/webview-dist/chunks/material-theme-palenight-B5W6OYN7.js +1 -0
  245. package/webview-dist/chunks/matlab-D7qyCx1q.js +1 -0
  246. package/webview-dist/chunks/mdc-Dx-qyM1x.js +1 -0
  247. package/webview-dist/chunks/mdx-DQZ5AkYe.js +1 -0
  248. package/webview-dist/chunks/mermaid-BxpfTIzt.js +1 -0
  249. package/webview-dist/chunks/min-dark-BSWPekZh.js +1 -0
  250. package/webview-dist/chunks/min-light-DDpmG2fV.js +1 -0
  251. package/webview-dist/chunks/mipsasm-BMqwQI7S.js +1 -0
  252. package/webview-dist/chunks/mojo-fg40_ntQ.js +1 -0
  253. package/webview-dist/chunks/monokai-B_bV9PQ9.js +1 -0
  254. package/webview-dist/chunks/moonbit-DgjMoLWr.js +1 -0
  255. package/webview-dist/chunks/move-BYnGhZoM.js +1 -0
  256. package/webview-dist/chunks/narrat-_X_XdTYD.js +1 -0
  257. package/webview-dist/chunks/nextflow-BJtWHP5T.js +1 -0
  258. package/webview-dist/chunks/nextflow-groovy-DJMQeKeT.js +1 -0
  259. package/webview-dist/chunks/nginx-rnpjAIVq.js +1 -0
  260. package/webview-dist/chunks/night-owl-DhmEMT88.js +1 -0
  261. package/webview-dist/chunks/night-owl-light-eJ-hLW7d.js +1 -0
  262. package/webview-dist/chunks/nim-kKTJ2fIs.js +1 -0
  263. package/webview-dist/chunks/nix-IvuFDN5E.js +1 -0
  264. package/webview-dist/chunks/nord-Cb4Vim4T.js +1 -0
  265. package/webview-dist/chunks/nsis-CjNLYCLg.js +1 -0
  266. package/webview-dist/chunks/nushell-DHYfO66s.js +1 -0
  267. package/webview-dist/chunks/objective-c-D1A_Heim.js +1 -0
  268. package/webview-dist/chunks/objective-cpp-BsSzOQcm.js +1 -0
  269. package/webview-dist/chunks/ocaml-O90oeIOV.js +1 -0
  270. package/webview-dist/chunks/odin-B1RWQWA5.js +1 -0
  271. package/webview-dist/chunks/one-dark-pro-CLwyXe_n.js +1 -0
  272. package/webview-dist/chunks/one-light-D7Lr4KcI.js +1 -0
  273. package/webview-dist/chunks/openscad-BUDT5pXO.js +1 -0
  274. package/webview-dist/chunks/org-BGWCjkJX.js +1 -0
  275. package/webview-dist/chunks/pascal-4ZHwLPI5.js +1 -0
  276. package/webview-dist/chunks/perl-DEimDILQ.js +1 -0
  277. package/webview-dist/chunks/php-QnaNN--1.js +1 -0
  278. package/webview-dist/chunks/pierre-dark-CpLgRqie.js +1 -0
  279. package/webview-dist/chunks/pierre-dark-protanopia-deuteranopia-B35FxJx-.js +1 -0
  280. package/webview-dist/chunks/pierre-dark-soft-kZQmAZld.js +1 -0
  281. package/webview-dist/chunks/pierre-dark-tritanopia-CpjhbsIL.js +1 -0
  282. package/webview-dist/chunks/pierre-dark-vibrant-CpQYzh95.js +1 -0
  283. package/webview-dist/chunks/pierre-light-CoaEpmwp.js +1 -0
  284. package/webview-dist/chunks/pierre-light-protanopia-deuteranopia-0fSaH845.js +1 -0
  285. package/webview-dist/chunks/pierre-light-soft-lWLdNTOI.js +1 -0
  286. package/webview-dist/chunks/pierre-light-tritanopia-CEbqgOJL.js +1 -0
  287. package/webview-dist/chunks/pierre-light-vibrant-D80Fkn33.js +1 -0
  288. package/webview-dist/chunks/pkl-ot-7Btpt.js +1 -0
  289. package/webview-dist/chunks/plastic-DQwYfKfQ.js +1 -0
  290. package/webview-dist/chunks/plsql-DGHpHOYJ.js +1 -0
  291. package/webview-dist/chunks/po-BiJDBrnU.js +1 -0
  292. package/webview-dist/chunks/poimandres-DRFjx7u4.js +1 -0
  293. package/webview-dist/chunks/polar-C7UOKdEL.js +1 -0
  294. package/webview-dist/chunks/postcss-BXeXVLqQ.js +1 -0
  295. package/webview-dist/chunks/powerquery-DNMTfnFr.js +1 -0
  296. package/webview-dist/chunks/powershell-CCSX75yM.js +1 -0
  297. package/webview-dist/chunks/prisma-DMgNhnYS.js +1 -0
  298. package/webview-dist/chunks/prolog-iXnhIJG7.js +1 -0
  299. package/webview-dist/chunks/proto-DB4EqR-F.js +1 -0
  300. package/webview-dist/chunks/pug-D5rsKmMX.js +1 -0
  301. package/webview-dist/chunks/puppet-CDv2pdJW.js +1 -0
  302. package/webview-dist/chunks/purescript-9MfHhQsQ.js +1 -0
  303. package/webview-dist/chunks/python-gzcpVVnB.js +1 -0
  304. package/webview-dist/chunks/qml-wvbZb8UE.js +1 -0
  305. package/webview-dist/chunks/qmldir-DCQb3MpD.js +1 -0
  306. package/webview-dist/chunks/qss-Fe1Jh2GI.js +1 -0
  307. package/webview-dist/chunks/r-BNyBFaU1.js +1 -0
  308. package/webview-dist/chunks/racket-DcIDlBhZ.js +1 -0
  309. package/webview-dist/chunks/raku-B3gFvitq.js +1 -0
  310. package/webview-dist/chunks/razor-bKaHS6Kz.js +1 -0
  311. package/webview-dist/chunks/rbs-C0MpOrj4.js +1 -0
  312. package/webview-dist/chunks/red-DX1BQOs8.js +1 -0
  313. package/webview-dist/chunks/reg-CRGYupPL.js +1 -0
  314. package/webview-dist/chunks/regexp-B-mZuWUh.js +1 -0
  315. package/webview-dist/chunks/rel-BtDbiS_P.js +1 -0
  316. package/webview-dist/chunks/riscv-Ckw8ddFX.js +1 -0
  317. package/webview-dist/chunks/ron-VUp2lXgN.js +1 -0
  318. package/webview-dist/chunks/rose-pine-aMsaMD1D.js +1 -0
  319. package/webview-dist/chunks/rose-pine-dawn-8PwUyIlP.js +1 -0
  320. package/webview-dist/chunks/rose-pine-moon-DO-qXg-I.js +1 -0
  321. package/webview-dist/chunks/rosmsg-CAekHB0j.js +1 -0
  322. package/webview-dist/chunks/rst-Qq8ybXHe.js +1 -0
  323. package/webview-dist/chunks/ruby-U659LEwU.js +1 -0
  324. package/webview-dist/chunks/rust-Cfkwpbl8.js +1 -0
  325. package/webview-dist/chunks/sas-C4NtLApe.js +1 -0
  326. package/webview-dist/chunks/sass-DXrisJhu.js +1 -0
  327. package/webview-dist/chunks/scala-BiFt_7mu.js +1 -0
  328. package/webview-dist/chunks/scheme-DQCgrYNe.js +1 -0
  329. package/webview-dist/chunks/scss-KAaA4sHk.js +1 -0
  330. package/webview-dist/chunks/sdbl-bTVj8UrX.js +1 -0
  331. package/webview-dist/chunks/shaderlab-TOUzSsQk.js +1 -0
  332. package/webview-dist/chunks/shellscript-_7bOVsRC.js +1 -0
  333. package/webview-dist/chunks/shellsession-Bs_5k0qk.js +1 -0
  334. package/webview-dist/chunks/slack-dark-DnToyrRv.js +1 -0
  335. package/webview-dist/chunks/slack-ochin-B2OO5cIa.js +1 -0
  336. package/webview-dist/chunks/smalltalk-BHpQb5nM.js +1 -0
  337. package/webview-dist/chunks/smithy-Dgaz7aur.js +1 -0
  338. package/webview-dist/chunks/snazzy-light-4G7pJPwS.js +1 -0
  339. package/webview-dist/chunks/solarized-dark-UdsmMDCL.js +1 -0
  340. package/webview-dist/chunks/solarized-light-C1IUL_tW.js +1 -0
  341. package/webview-dist/chunks/solidity-Bj7E1mRn.js +1 -0
  342. package/webview-dist/chunks/soy-C5iuoFCh.js +1 -0
  343. package/webview-dist/chunks/sparql-D_iOobhT.js +1 -0
  344. package/webview-dist/chunks/splunk-BC2Px7Mm.js +1 -0
  345. package/webview-dist/chunks/sql-JX305rZh.js +1 -0
  346. package/webview-dist/chunks/ssh-config-BgfXC-Er.js +1 -0
  347. package/webview-dist/chunks/stata-2Rtik3TV.js +1 -0
  348. package/webview-dist/chunks/stylus-B6D30XZt.js +1 -0
  349. package/webview-dist/chunks/surrealql-IvpiLAIH.js +1 -0
  350. package/webview-dist/chunks/svelte-DeZcV_1u.js +1 -0
  351. package/webview-dist/chunks/swift-CyEgAFGc.js +1 -0
  352. package/webview-dist/chunks/synthwave-84-nFMaYfgc.js +1 -0
  353. package/webview-dist/chunks/system-verilog-Dh5ihWbf.js +1 -0
  354. package/webview-dist/chunks/systemd-BxMlprV5.js +1 -0
  355. package/webview-dist/chunks/talonscript-CohzipZa.js +1 -0
  356. package/webview-dist/chunks/tasl-DMoTqEGO.js +1 -0
  357. package/webview-dist/chunks/tcl-CZd0xW_V.js +1 -0
  358. package/webview-dist/chunks/templ-CcwjPXJr.js +1 -0
  359. package/webview-dist/chunks/terraform-DswuEJGm.js +1 -0
  360. package/webview-dist/chunks/tex-CZYHgHl8.js +1 -0
  361. package/webview-dist/chunks/tokyo-night-oM2G3aXe.js +1 -0
  362. package/webview-dist/chunks/toml-CcmNWLt0.js +1 -0
  363. package/webview-dist/chunks/ts-tags-DPINfEO_.js +1 -0
  364. package/webview-dist/chunks/tsv-sltzmVWM.js +1 -0
  365. package/webview-dist/chunks/tsx-Dq7pSIyE.js +1 -0
  366. package/webview-dist/chunks/turtle-ByJddavk.js +1 -0
  367. package/webview-dist/chunks/twig-DFpC8yDL.js +1 -0
  368. package/webview-dist/chunks/typescript-CN-guYmK.js +1 -0
  369. package/webview-dist/chunks/typespec-BRdr0IET.js +1 -0
  370. package/webview-dist/chunks/typst-hgW4q6mN.js +1 -0
  371. package/webview-dist/chunks/v-DBj4K9d_.js +1 -0
  372. package/webview-dist/chunks/vala-zf12oZj6.js +1 -0
  373. package/webview-dist/chunks/vb-DOwzaHZ0.js +1 -0
  374. package/webview-dist/chunks/verilog-B2gwz-sJ.js +1 -0
  375. package/webview-dist/chunks/vesper-DdrHHSXu.js +1 -0
  376. package/webview-dist/chunks/vhdl-BroJfC0k.js +1 -0
  377. package/webview-dist/chunks/viml-DvXPmvsu.js +1 -0
  378. package/webview-dist/chunks/vitesse-black-fwtXNY1n.js +1 -0
  379. package/webview-dist/chunks/vitesse-dark-BZCL-v6S.js +1 -0
  380. package/webview-dist/chunks/vitesse-light-VbXTXTou.js +1 -0
  381. package/webview-dist/chunks/vue-Dkz9ntel.js +1 -0
  382. package/webview-dist/chunks/vue-html-Dg8LQ5v3.js +1 -0
  383. package/webview-dist/chunks/vue-vine-CIEXICEN.js +1 -0
  384. package/webview-dist/chunks/vyper-CgoNMtux.js +1 -0
  385. package/webview-dist/chunks/wasm-BnjxR4X6.js +1 -0
  386. package/webview-dist/chunks/wasm-ByWQv1Qj.js +1 -0
  387. package/webview-dist/chunks/wenyan-C8pVoKbM.js +1 -0
  388. package/webview-dist/chunks/wgsl-BsKzXJz4.js +1 -0
  389. package/webview-dist/chunks/wikitext-ClFFjSW2.js +1 -0
  390. package/webview-dist/chunks/wit-DdvCle-K.js +1 -0
  391. package/webview-dist/chunks/wolfram-DLL8P-h_.js +1 -0
  392. package/webview-dist/chunks/worker-D52zl71O.js +1 -0
  393. package/webview-dist/chunks/worker-pool-lOjh8Q2A.js +1543 -0
  394. package/webview-dist/chunks/xml-X7YOen_c.js +1 -0
  395. package/webview-dist/chunks/xsl-h4d_Px-X.js +1 -0
  396. package/webview-dist/chunks/yaml-BRDpsfaj.js +1 -0
  397. package/webview-dist/chunks/zenscript-BnlCZFoB.js +1 -0
  398. package/webview-dist/chunks/zig-CMLA9XwU.js +1 -0
  399. package/webview-dist/index.html +18 -0
  400. package/webview-dist/pierre-worker-portable.js +13633 -0
  401. package/webview-dist/repo-timeline-app.js +7 -0
  402. package/webview-dist/repo-timeline.html +14 -0
  403. package/webview-dist/timeline-app.css +2 -0
  404. package/webview-dist/timeline-app.js +85 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timeline-service.cjs","names":["buildGitLineHistoryArgs","parseGitLineHistoryRevisions","path","readFile","filterEntriesTouchingLineRange","resolveHistoryWorkspacePath","resolveHistoryAdapter","normalizeLineHistoryRange","buildGitBlameArgs","findBlameForLine","parseGitBlamePorcelain","buildJjAnnotateArgs","parseJjFileAnnotate","buildGitBlameFileArgs","JJ_OP_LOG_TEMPLATE","filterFileOpLogPeek","parseJjOpLogOutput","searchHistoryDiffContents","searchHistoryContents","readdir","computeDiffStats","buildNonTextualDetails"],"sources":["../../src/extension/timeline-service.ts"],"sourcesContent":["import { readdir, readFile } from 'node:fs/promises';\nimport path from 'node:path';\nimport { buildNonTextualDetails } from '../shared/non-textual-details.ts';\nimport { computeDiffStats } from '../shared/diff-stats.ts';\nimport {\n\tbuildGitBlameArgs,\n\tbuildGitBlameFileArgs,\n\tbuildJjAnnotateArgs,\n\tfindBlameForLine,\n\tparseGitBlamePorcelain,\n\tparseJjFileAnnotate,\n} from '../shared/blame.ts';\nimport type { BlameLine } from '../shared/blame.ts';\nimport {\n\tbuildGitLineHistoryArgs,\n\tfilterEntriesTouchingLineRange,\n\tnormalizeLineHistoryRange,\n\tparseGitLineHistoryRevisions,\n\ttype LineHistoryRange,\n} from '../shared/line-history.ts';\nimport { searchHistoryContents, searchHistoryDiffContents } from '../shared/history-search.ts';\nimport { filterFileOpLogPeek, JJ_OP_LOG_TEMPLATE, parseJjOpLogOutput } from '../shared/file-oplog.ts';\nimport type {\n\tComparisonSource,\n\tDiffPreview,\n\tFileRevisionEntry,\n\tRangeOverviewItem,\n\tTimelineData,\n\tTimelinePreferences,\n} from '../shared/timeline-types.ts';\nimport { MAX_SNAPSHOT_HYDRATION_CHANGES, INITIAL_TIMELINE_ENTRIES, MAX_TIMELINE_ENTRIES } from './constants.ts';\nimport { resolveHistoryAdapter, resolveHistoryWorkspacePath } from './history-adapters.ts';\nimport type {\n\tCommandRunner,\n\tExtensionTimelineSession,\n\tHistoryAdapter,\n\tSessionAction,\n\tTimelinePayloadArgs,\n} from './types.ts';\n\nconst DEFAULT_TIMELINE_PREFERENCES: Required<TimelinePreferences> = {\n\tsidebarWidth: 276,\n\tsidebarCollapsed: false,\n\ttimelinePaneHeight: 220,\n\ttimelinePaneCollapsed: false,\n\tlayoutMode: 'split',\n\tcontentMode: 'diffs',\n\tcomparisonMode: 'range',\n\tcomparisonSource: 'revision',\n\tshowIntermediateRevisions: false,\n\tpreset: 'year',\n\tcustomRevset: '',\n\tthemePreference: 'auto',\n\theatmapOpen: false,\n\tlineDiffType: 'word-alt',\n};\n\nconst IGNORED_WORKSPACE_DIRECTORIES = new Set(['.git', '.jj', 'node_modules', 'dist', 'build', 'out', 'coverage']);\n\nfunction getComparisonEntries(request: {\n\tentries: FileRevisionEntry[];\n\tfromIndex: number;\n\ttoIndex: number;\n}): { fromEntry: FileRevisionEntry; toEntry: FileRevisionEntry } | undefined {\n\tconst normalizedFromIndex = Math.max(0, Math.min(request.fromIndex, request.toIndex));\n\tconst normalizedToIndex = Math.max(normalizedFromIndex, Math.max(request.fromIndex, request.toIndex));\n\tconst fromEntry = request.entries[normalizedFromIndex];\n\tconst toEntry = request.entries[normalizedToIndex];\n\tif (!fromEntry || !toEntry) {\n\t\treturn undefined;\n\t}\n\n\treturn { fromEntry, toEntry };\n}\n\nfunction syncSession(request: { target: ExtensionTimelineSession; source: ExtensionTimelineSession }): void {\n\trequest.target.adapter = request.source.adapter;\n\trequest.target.backend = request.source.backend;\n\trequest.target.workspacePath = request.source.workspacePath;\n\trequest.target.relativePath = request.source.relativePath;\n\trequest.target.absolutePath = request.source.absolutePath;\n\trequest.target.fileName = request.source.fileName;\n\trequest.target.entries = request.source.entries;\n\trequest.target.snapshotEntries = request.source.snapshotEntries;\n\trequest.target.snapshotLoadedChangeIds = request.source.snapshotLoadedChangeIds;\n\trequest.target.snapshotPendingChangeIds = request.source.snapshotPendingChangeIds;\n\trequest.target.workspaceFiles = request.source.workspaceFiles;\n\trequest.target.workspaceFilesLoaded = request.source.workspaceFilesLoaded;\n\trequest.target.historyLimit = request.source.historyLimit;\n\trequest.target.intermediateRevisionsLoaded = request.source.intermediateRevisionsLoaded;\n\trequest.target.contentCache = request.source.contentCache;\n\trequest.target.previewCache = request.source.previewCache;\n\trequest.target.rangeOverviewCache = request.source.rangeOverviewCache;\n\trequest.target.entryDiffCountCache = request.source.entryDiffCountCache;\n\trequest.target.pathCache = request.source.pathCache;\n\trequest.target.activeActionAbortController = request.source.activeActionAbortController;\n\trequest.target.lineHistory = request.source.lineHistory;\n\trequest.target.customRevset = request.source.customRevset;\n}\n\nasync function getContentForRevset(request: {\n\tsession: ExtensionTimelineSession;\n\trevset: string;\n\tfilePath: string;\n}): Promise<string> {\n\tconst cacheKey = `revset:${request.revset}:${request.filePath}`;\n\tconst cached = request.session.contentCache.get(cacheKey);\n\tif (cached !== undefined) {\n\t\treturn cached;\n\t}\n\n\tconst content = await request.session.adapter.showFileAtRevision({\n\t\tworkspacePath: request.session.workspacePath,\n\t\trevset: request.revset,\n\t\tfilePath: request.filePath,\n\t});\n\trequest.session.contentCache.set(cacheKey, content);\n\treturn content;\n}\n\nasync function filterSessionEntriesForLineHistory(args: {\n\tadapter: HistoryAdapter;\n\trunner: CommandRunner;\n\tworkspacePath: string;\n\trelativePath: string;\n\tentries: FileRevisionEntry[];\n\trange: LineHistoryRange;\n\tlimit: number;\n}): Promise<FileRevisionEntry[]> {\n\tif (args.adapter.backend === 'git') {\n\t\ttry {\n\t\t\tconst { stdout } = await args.runner.runGit({\n\t\t\t\tworkspacePath: args.workspacePath,\n\t\t\t\targs: buildGitLineHistoryArgs({\n\t\t\t\t\trelativePath: args.relativePath,\n\t\t\t\t\trange: args.range,\n\t\t\t\t\tlimit: args.limit,\n\t\t\t\t}),\n\t\t\t});\n\t\t\tconst revisions = new Set(parseGitLineHistoryRevisions(stdout));\n\t\t\tconst filtered = args.entries.filter((entry) => entry.isWorkingTree || revisions.has(entry.revision));\n\t\t\tif (filtered.length) {\n\t\t\t\treturn filtered;\n\t\t\t}\n\t\t} catch {\n\t\t\t// Fall through to content-based filtering (e.g. empty -L result / binary).\n\t\t}\n\t}\n\n\tconst contentByRevision = new Map<string, string>();\n\tfor (const entry of args.entries) {\n\t\tconst filePath = entry.filePath || args.relativePath;\n\t\tconst revset = entry.isWorkingTree ? '@' : entry.revision;\n\t\ttry {\n\t\t\tconst content = await args.adapter.showFileAtRevision({\n\t\t\t\tworkspacePath: args.workspacePath,\n\t\t\t\trevset: entry.isWorkingTree && args.adapter.backend === 'git' ? 'HEAD' : revset,\n\t\t\t\tfilePath,\n\t\t\t});\n\t\t\t// Working tree: prefer reading isn't available here for git HEAD vs WT — use entry content via show.\n\t\t\tcontentByRevision.set(entry.revision, content);\n\t\t} catch {\n\t\t\tcontentByRevision.set(entry.revision, '');\n\t\t}\n\t}\n\n\t// For git working tree tip, showFileAtRevision('HEAD') is last commit; still OK as baseline for tip keep.\n\tif (args.adapter.backend === 'git') {\n\t\tconst tip = args.entries.find((entry) => entry.isWorkingTree);\n\t\tif (tip) {\n\t\t\ttry {\n\t\t\t\tconst diskPath = path.join(args.workspacePath, tip.filePath || args.relativePath);\n\t\t\t\tcontentByRevision.set(tip.revision, await readFile(diskPath, 'utf8'));\n\t\t\t} catch {\n\t\t\t\t// keep prior content\n\t\t\t}\n\t\t}\n\t}\n\n\treturn filterEntriesTouchingLineRange({\n\t\tentries: args.entries,\n\t\trange: args.range,\n\t\tgetContent: (entry) => contentByRevision.get(entry.revision) || '',\n\t});\n}\n\nasync function hydrateEntryFilePaths(args: {\n\tadapter: HistoryAdapter;\n\tworkspacePath: string;\n\trelativePath: string;\n\tentries: FileRevisionEntry[];\n}): Promise<void> {\n\tif (!args.entries.length) {\n\t\treturn;\n\t}\n\n\targs.entries[args.entries.length - 1].filePath = args.relativePath;\n\tlet currentPath = args.relativePath;\n\tfor (let index = args.entries.length - 1; index > 0; index -= 1) {\n\t\tconst currentEntry = args.entries[index];\n\t\tconst previousEntry = args.entries[index - 1];\n\t\tif (previousEntry.filePath) {\n\t\t\tcurrentPath = previousEntry.filePath;\n\t\t\tcontinue;\n\t\t}\n\n\t\tlet previousPath = currentPath;\n\t\tif (currentEntry.touchesFile && !currentEntry.isWorkingTree) {\n\t\t\tpreviousPath = await args.adapter.resolvePreviousPath({\n\t\t\t\tworkspacePath: args.workspacePath,\n\t\t\t\trevision: currentEntry.revision,\n\t\t\t\tcurrentPath,\n\t\t\t});\n\t\t}\n\t\tpreviousEntry.filePath = previousPath;\n\t\tcurrentPath = previousPath;\n\t}\n}\n\nasync function resolvePreviousPathAcrossRevision(request: {\n\tsession: ExtensionTimelineSession;\n\tentry: FileRevisionEntry;\n\tcurrentPath: string;\n}): Promise<string> {\n\tconst cacheKey = `${request.entry.revision}:${request.currentPath}`;\n\tconst cached = request.session.pathCache.get(cacheKey);\n\tif (cached) {\n\t\treturn cached;\n\t}\n\n\tconst previousPath = await request.session.adapter.resolvePreviousPath({\n\t\tworkspacePath: request.session.workspacePath,\n\t\trevision: request.entry.revision,\n\t\tcurrentPath: request.currentPath,\n\t});\n\trequest.session.pathCache.set(cacheKey, previousPath);\n\treturn previousPath;\n}\n\nasync function loadRevisionTreeFiles(request: {\n\tsession: ExtensionTimelineSession;\n\trevision: string;\n}): Promise<string[]> {\n\tconst revision = request.revision.trim() || '@';\n\ttry {\n\t\treturn await request.session.adapter.listRevisionTreeFiles({\n\t\t\tworkspacePath: request.session.workspacePath,\n\t\t\trevision,\n\t\t});\n\t} catch {\n\t\treturn [];\n\t}\n}\n\nexport function createTimelineService(args: { runner: CommandRunner }) {\n\tconst { runner } = args;\n\n\treturn {\n\t\tbuildSession,\n\t\tbuildPayload,\n\t\tmapEntriesForPayload,\n\t\tensureWorkspaceFiles,\n\t\tloadRevisionTreeFiles,\n\t\tensureIntermediateRevisions,\n\t\texpandFileHistory,\n\t\tfindNearestNonEmptyVisibleRange,\n\t\tgetComparisonEntries,\n\t\tgetDiffPreview,\n\t\tgetDiffBlame,\n\t\tgetFileOpLog,\n\t\tsearchFileHistory,\n\t\tgetEntryDiffCounts,\n\t\tgetEntriesForSource,\n\t\tgetRangeOverview,\n\t\tgetRangeStackPreviews,\n\t\thydrateSnapshotEntries,\n\t\tresolveBlameRevisionForLine,\n\t\trunSessionAction,\n\t\tresolveEntryFilePath,\n\t\tsyncSession,\n\t};\n\n\tasync function buildSession(request: {\n\t\tworkspacePath: string;\n\t\tabsolutePath: string;\n\t\toptions?: {\n\t\t\tincludeWorkspaceFiles?: boolean;\n\t\t\tincludeIntermediateRevisions?: boolean;\n\t\t\tentryLimit?: number;\n\t\t\tlineHistory?: LineHistoryRange;\n\t\t\tcustomRevset?: string;\n\t\t};\n\t}): Promise<ExtensionTimelineSession> {\n\t\tconst historyWorkspacePath = await resolveHistoryWorkspacePath({ workspacePath: request.workspacePath, runner });\n\t\tconst relativePath = path.relative(historyWorkspacePath, request.absolutePath).replace(/\\\\/g, '/');\n\t\tconst adapter = await resolveHistoryAdapter({ workspacePath: historyWorkspacePath, runner });\n\t\tconst entryLimit = request.options?.entryLimit ?? INITIAL_TIMELINE_ENTRIES;\n\t\tconst includeWorkspaceFiles = request.options?.includeWorkspaceFiles === true;\n\t\tconst includeIntermediateRevisions = request.options?.includeIntermediateRevisions === true;\n\t\tconst lineHistory = request.options?.lineHistory\n\t\t\t? normalizeLineHistoryRange(request.options.lineHistory.startLine, request.options.lineHistory.endLine)\n\t\t\t: null;\n\t\tconst customRevset = (request.options?.customRevset || '').trim() || undefined;\n\n\t\tconst workspaceFiles = includeWorkspaceFiles\n\t\t\t? await listWorkspaceFiles({ adapter, workspacePath: historyWorkspacePath })\n\t\t\t: [relativePath];\n\t\tconst fileEntries = await adapter.getFileRevisionHistory({\n\t\t\tworkspacePath: historyWorkspacePath,\n\t\t\trelativePath,\n\t\t\tlimit: entryLimit,\n\t\t\tcustomRevset,\n\t\t});\n\t\tlet entries = await buildTimelineEntries({\n\t\t\tadapter,\n\t\t\tworkspacePath: historyWorkspacePath,\n\t\t\tabsolutePath: request.absolutePath,\n\t\t\trelativePath,\n\t\t\tfileEntries,\n\t\t\tincludeIntermediateRevisions,\n\t\t\tentryLimit,\n\t\t});\n\t\tif (lineHistory) {\n\t\t\tentries = await filterSessionEntriesForLineHistory({\n\t\t\t\tadapter,\n\t\t\t\trunner,\n\t\t\t\tworkspacePath: historyWorkspacePath,\n\t\t\t\trelativePath,\n\t\t\t\tentries,\n\t\t\t\trange: lineHistory,\n\t\t\t\tlimit: entryLimit,\n\t\t\t});\n\t\t}\n\t\tconst snapshotEntries = adapter.backend === 'jj' ? [] : [...entries];\n\t\tconst remoteBaseUrl = await adapter.getRemoteBaseUrl({ workspacePath: historyWorkspacePath });\n\n\t\tif (remoteBaseUrl) {\n\t\t\tfor (const entry of entries) {\n\t\t\t\tif (!entry.isWorkingTree) {\n\t\t\t\t\tentry.remoteUrl = `${remoteBaseUrl}/commit/${entry.revision}`;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tawait hydrateEntryFilePaths({\n\t\t\tadapter,\n\t\t\tworkspacePath: historyWorkspacePath,\n\t\t\trelativePath,\n\t\t\tentries,\n\t\t});\n\n\t\treturn {\n\t\t\tadapter,\n\t\t\tbackend: adapter.backend,\n\t\t\tworkspacePath: historyWorkspacePath,\n\t\t\tabsolutePath: request.absolutePath,\n\t\t\trelativePath,\n\t\t\tfileName: path.basename(request.absolutePath),\n\t\t\tentries,\n\t\t\tsnapshotEntries,\n\t\t\tsnapshotLoadedChangeIds: new Set(),\n\t\t\tsnapshotPendingChangeIds: new Set(),\n\t\t\tworkspaceFiles,\n\t\t\tworkspaceFilesLoaded: includeWorkspaceFiles,\n\t\t\thistoryLimit: entryLimit,\n\t\t\tintermediateRevisionsLoaded: includeIntermediateRevisions,\n\t\t\tlineHistory: lineHistory ?? undefined,\n\t\t\tcustomRevset,\n\t\t\tcontentCache: new Map(),\n\t\t\tpreviewCache: new Map(),\n\t\t\trangeOverviewCache: new Map(),\n\t\t\tentryDiffCountCache: new Map(),\n\t\t\tpathCache: new Map(),\n\t\t\tactiveActionAbortController: undefined,\n\t\t};\n\t}\n\n\tfunction mapEntriesForPayload(entries: FileRevisionEntry[]): TimelineData['entries'] {\n\t\treturn entries.map((entry, index) => ({\n\t\t\t...entry,\n\t\t\tindex,\n\t\t\thasPreviousEntry: index > 0,\n\t\t\tmonthLabel: formatEntryMonthLabel(entry.authorDate),\n\t\t\tshortDate: formatEntryShortDate(entry.authorDate),\n\t\t\trelativeDate: formatRelativeTime(entry.timestamp),\n\t\t}));\n\t}\n\n\tfunction buildPayload(request: TimelinePayloadArgs): TimelineData {\n\t\treturn {\n\t\t\tbackend: request.session.backend,\n\t\t\tworkspacePath: request.session.workspacePath,\n\t\t\trelativePath: request.session.relativePath,\n\t\t\tfileName: request.session.fileName,\n\t\t\tversion: request.version,\n\t\t\tpresets: request.presets,\n\t\t\tdefaultIndex: Math.max(0, request.session.entries.length - 1),\n\t\t\tlatestIndex: Math.max(0, request.session.entries.length - 1),\n\t\t\tpreferences: normalizeTimelinePreferences(request.preferences),\n\t\t\tworkspaceFiles: request.session.workspaceFiles,\n\t\t\tworkspaceFilesLoaded: request.session.workspaceFilesLoaded,\n\t\t\thasIntermediateRevisions: request.session.entries.some((entry) => !entry.touchesFile),\n\t\t\tentries: mapEntriesForPayload(request.session.entries),\n\t\t\tsnapshotEntries: mapEntriesForPayload(request.session.snapshotEntries),\n\t\t\tsnapshotState: {\n\t\t\t\tloadedChangeIds: [...request.session.snapshotLoadedChangeIds],\n\t\t\t},\n\t\t\t...(request.session.lineHistory ? { lineHistory: request.session.lineHistory } : {}),\n\t\t\t...(request.session.customRevset ? { customRevset: request.session.customRevset } : {}),\n\t\t};\n\t}\n\n\tasync function ensureWorkspaceFiles(request: { session: ExtensionTimelineSession }): Promise<boolean> {\n\t\tif (request.session.workspaceFilesLoaded) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst workspaceFiles = await listWorkspaceFiles({\n\t\t\tadapter: request.session.adapter,\n\t\t\tworkspacePath: request.session.workspacePath,\n\t\t});\n\t\trequest.session.workspaceFiles = workspaceFiles;\n\t\trequest.session.workspaceFilesLoaded = true;\n\t\trequest.session.rangeOverviewCache.clear();\n\t\treturn true;\n\t}\n\n\tasync function ensureIntermediateRevisions(request: { session: ExtensionTimelineSession }): Promise<boolean> {\n\t\tif (request.session.intermediateRevisionsLoaded) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst touchingEntries = request.session.entries.filter((entry) => entry.touchesFile && !entry.isWorkingTree);\n\t\tif (touchingEntries.length < 2) {\n\t\t\trequest.session.intermediateRevisionsLoaded = true;\n\t\t\treturn false;\n\t\t}\n\n\t\ttry {\n\t\t\tconst repositoryEntries = await request.session.adapter.getRepositoryRevisionHistory({\n\t\t\t\tworkspacePath: request.session.workspacePath,\n\t\t\t\tlimit: MAX_TIMELINE_ENTRIES,\n\t\t\t});\n\t\t\tconst workingTreeEntry = request.session.entries.find((entry) => entry.isWorkingTree);\n\t\t\tlet entries = mergeTimelineEntries({ repositoryEntries, fileEntries: touchingEntries });\n\t\t\tif (request.session.backend === 'jj') {\n\t\t\t\tentries = dedupeAdjacentTimelineEntries(entries);\n\t\t\t}\n\t\t\tif (workingTreeEntry) {\n\t\t\t\tentries = [...entries, workingTreeEntry];\n\t\t\t}\n\t\t\trequest.session.entries = entries;\n\t\t\trequest.session.intermediateRevisionsLoaded = true;\n\t\t\trequest.session.previewCache.clear();\n\t\t\trequest.session.rangeOverviewCache.clear();\n\t\t\trequest.session.entryDiffCountCache.clear();\n\t\t\treturn true;\n\t\t} catch {\n\t\t\trequest.session.intermediateRevisionsLoaded = true;\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tasync function expandFileHistory(request: { session: ExtensionTimelineSession }): Promise<boolean> {\n\t\tif (request.session.historyLimit >= MAX_TIMELINE_ENTRIES) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst previousTouchingCount = request.session.entries.filter(\n\t\t\t(entry) => entry.touchesFile && !entry.isWorkingTree,\n\t\t).length;\n\t\tif (previousTouchingCount < request.session.historyLimit) {\n\t\t\trequest.session.historyLimit = MAX_TIMELINE_ENTRIES;\n\t\t\treturn false;\n\t\t}\n\n\t\tconst fileEntries = await request.session.adapter.getFileRevisionHistory({\n\t\t\tworkspacePath: request.session.workspacePath,\n\t\t\trelativePath: request.session.relativePath,\n\t\t\tlimit: MAX_TIMELINE_ENTRIES,\n\t\t});\n\t\tconst entries = await buildTimelineEntries({\n\t\t\tadapter: request.session.adapter,\n\t\t\tworkspacePath: request.session.workspacePath,\n\t\t\tabsolutePath: request.session.absolutePath,\n\t\t\trelativePath: request.session.relativePath,\n\t\t\tfileEntries,\n\t\t\tincludeIntermediateRevisions: request.session.intermediateRevisionsLoaded,\n\t\t\tentryLimit: MAX_TIMELINE_ENTRIES,\n\t\t});\n\t\tconst nextTouchingCount = entries.filter((entry) => entry.touchesFile && !entry.isWorkingTree).length;\n\t\trequest.session.entries = entries;\n\t\trequest.session.historyLimit = MAX_TIMELINE_ENTRIES;\n\t\trequest.session.previewCache.clear();\n\t\trequest.session.rangeOverviewCache.clear();\n\t\trequest.session.entryDiffCountCache.clear();\n\t\treturn nextTouchingCount > previousTouchingCount;\n\t}\n\n\tfunction getEntriesForSource(request: {\n\t\tsession: ExtensionTimelineSession;\n\t\tcomparisonSource: ComparisonSource;\n\t}): FileRevisionEntry[] {\n\t\tif (request.session.backend !== 'jj' || request.comparisonSource !== 'snapshot') {\n\t\t\treturn request.session.entries;\n\t\t}\n\n\t\treturn composeSnapshotEntries({\n\t\t\trevisionEntries: request.session.entries,\n\t\t\tsnapshotEntries: request.session.snapshotEntries,\n\t\t\tloadedChangeIds: request.session.snapshotLoadedChangeIds,\n\t\t});\n\t}\n\n\tasync function getDiffPreview(request: {\n\t\tsession: ExtensionTimelineSession;\n\t\tfromIndex: number;\n\t\ttoIndex: number;\n\t\tcomparisonSource?: ComparisonSource;\n\t}): Promise<DiffPreview> {\n\t\tconst comparisonSource = request.comparisonSource || 'revision';\n\t\tconst sourceEntries = getEntriesForSource({\n\t\t\tsession: request.session,\n\t\t\tcomparisonSource,\n\t\t});\n\t\tconst normalizedFromIndex = Math.max(0, Math.min(request.fromIndex, request.toIndex));\n\t\tconst normalizedToIndex = Math.max(normalizedFromIndex, Math.max(request.fromIndex, request.toIndex));\n\t\tconst cacheKey = `${comparisonSource}:${normalizedFromIndex}:${normalizedToIndex}`;\n\t\tconst cached = request.session.previewCache.get(cacheKey);\n\t\tif (cached) {\n\t\t\treturn cached;\n\t\t}\n\n\t\tif (request.session.backend === 'jj' && comparisonSource === 'snapshot') {\n\t\t\tconst preview = await getJjSnapshotPreview({\n\t\t\t\tsession: request.session,\n\t\t\t\tfromIndex: normalizedFromIndex,\n\t\t\t\ttoIndex: normalizedToIndex,\n\t\t\t});\n\t\t\trequest.session.previewCache.set(cacheKey, preview);\n\t\t\treturn preview;\n\t\t}\n\n\t\tconst comparison = getComparisonEntries({\n\t\t\tentries: sourceEntries,\n\t\t\tfromIndex: normalizedFromIndex,\n\t\t\ttoIndex: normalizedToIndex,\n\t\t});\n\t\tif (!comparison) {\n\t\t\treturn createEmptyPreview({\n\t\t\t\tindex: normalizedToIndex,\n\t\t\t\tfromIndex: normalizedFromIndex,\n\t\t\t\ttoIndex: normalizedToIndex,\n\t\t\t\tcomparisonSource,\n\t\t\t\ttitle: 'No revision selected',\n\t\t\t});\n\t\t}\n\n\t\tconst beforePath = comparison.fromEntry\n\t\t\t? await resolveEntryFilePath({\n\t\t\t\t\tsession: request.session,\n\t\t\t\t\tentry: comparison.fromEntry,\n\t\t\t\t\tentryIndex: normalizedFromIndex,\n\t\t\t\t})\n\t\t\t: '';\n\t\tconst afterPath = await resolveEntryFilePath({\n\t\t\tsession: request.session,\n\t\t\tentry: comparison.toEntry,\n\t\t\tentryIndex: normalizedToIndex,\n\t\t});\n\t\tconst beforeText = comparison.fromEntry\n\t\t\t? await getRevisionContent({\n\t\t\t\t\tsession: request.session,\n\t\t\t\t\tentry: comparison.fromEntry,\n\t\t\t\t\tentryIndex: normalizedFromIndex,\n\t\t\t\t})\n\t\t\t: '';\n\t\tconst afterText = await getRevisionContent({\n\t\t\tsession: request.session,\n\t\t\tentry: comparison.toEntry,\n\t\t\tentryIndex: normalizedToIndex,\n\t\t});\n\t\tconst preview = buildDiffPreview({\n\t\t\tindex: normalizedToIndex,\n\t\t\tpreviousEntry: comparison.fromEntry,\n\t\t\tcurrentEntry: comparison.toEntry,\n\t\t\tbeforeText,\n\t\t\tafterText,\n\t\t\tfromIndex: normalizedFromIndex,\n\t\t\ttoIndex: normalizedToIndex,\n\t\t\tbeforePath,\n\t\t\tafterPath,\n\t\t\tcomparisonSource,\n\t\t});\n\t\trequest.session.previewCache.set(cacheKey, preview);\n\t\treturn preview;\n\t}\n\n\tasync function hydrateSnapshotEntries(request: {\n\t\tsession: ExtensionTimelineSession;\n\t\trevisionIndexes: number[];\n\t}): Promise<boolean> {\n\t\tif (request.session.backend !== 'jj') {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst uniqueTargets = request.revisionIndexes\n\t\t\t.map((index) => request.session.entries[index])\n\t\t\t.filter((entry): entry is FileRevisionEntry =>\n\t\t\t\tBoolean(\n\t\t\t\t\tentry &&\n\t\t\t\t\t!entry.isWorkingTree &&\n\t\t\t\t\tentry.touchesFile &&\n\t\t\t\t\tentry.changeId &&\n\t\t\t\t\t!request.session.snapshotLoadedChangeIds.has(entry.changeId) &&\n\t\t\t\t\t!request.session.snapshotPendingChangeIds.has(entry.changeId),\n\t\t\t\t),\n\t\t\t)\n\t\t\t.reduce<FileRevisionEntry[]>((entries, entry) => {\n\t\t\t\tif (!entry.changeId || entries.some((candidate) => candidate.changeId === entry.changeId)) {\n\t\t\t\t\treturn entries;\n\t\t\t\t}\n\n\t\t\t\tentries.push(entry);\n\t\t\t\treturn entries;\n\t\t\t}, [])\n\t\t\t.slice(-MAX_SNAPSHOT_HYDRATION_CHANGES);\n\n\t\tif (!uniqueTargets.length) {\n\t\t\treturn false;\n\t\t}\n\n\t\tlet didUpdate = false;\n\t\tfor (const entry of uniqueTargets) {\n\t\t\tconst changeId = entry.changeId;\n\t\t\tif (!changeId) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\trequest.session.snapshotPendingChangeIds.add(changeId);\n\t\t\tconst expandedEntries = await request.session.adapter.getSnapshotEntriesForFile({\n\t\t\t\tworkspacePath: request.session.workspacePath,\n\t\t\t\trelativePath: request.session.relativePath,\n\t\t\t\tentry,\n\t\t\t});\n\t\t\trequest.session.snapshotPendingChangeIds.delete(changeId);\n\t\t\trequest.session.snapshotLoadedChangeIds.add(changeId);\n\n\t\t\tif (expandedEntries.length) {\n\t\t\t\trequest.session.snapshotEntries.push(...expandedEntries);\n\t\t\t\tdidUpdate = true;\n\t\t\t}\n\t\t}\n\n\t\tif (!didUpdate) {\n\t\t\treturn true;\n\t\t}\n\n\t\trequest.session.snapshotEntries = request.session.snapshotEntries.toSorted(\n\t\t\t(left, right) => left.timestamp - right.timestamp || left.revision.localeCompare(right.revision),\n\t\t);\n\t\tfor (const cacheKey of request.session.previewCache.keys()) {\n\t\t\tif (cacheKey.startsWith('snapshot:')) {\n\t\t\t\trequest.session.previewCache.delete(cacheKey);\n\t\t\t}\n\t\t}\n\t\tfor (const cacheKey of request.session.rangeOverviewCache.keys()) {\n\t\t\tif (cacheKey.startsWith('snapshot:')) {\n\t\t\t\trequest.session.rangeOverviewCache.delete(cacheKey);\n\t\t\t}\n\t\t}\n\t\tfor (const cacheKey of request.session.entryDiffCountCache.keys()) {\n\t\t\tif (cacheKey.startsWith('snapshot:')) {\n\t\t\t\trequest.session.entryDiffCountCache.delete(cacheKey);\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tasync function findNearestNonEmptyVisibleRange(request: {\n\t\tsession: ExtensionTimelineSession;\n\t\tcandidateIndexes: number[];\n\t}): Promise<{ fromIndex: number; toIndex: number } | null> {\n\t\tif (request.candidateIndexes.length < 2) {\n\t\t\treturn null;\n\t\t}\n\n\t\tfor (let index = request.candidateIndexes.length - 1; index > 0; index -= 1) {\n\t\t\tconst fromIndex = request.candidateIndexes[index - 1];\n\t\t\tconst toIndex = request.candidateIndexes[index];\n\t\t\tconst preview = await getDiffPreview({\n\t\t\t\tsession: request.session,\n\t\t\t\tfromIndex,\n\t\t\t\ttoIndex,\n\t\t\t});\n\t\t\tif (preview.hasChanges) {\n\t\t\t\treturn { fromIndex, toIndex };\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tasync function getRangeOverview(request: {\n\t\tsession: ExtensionTimelineSession;\n\t\tfromIndex: number;\n\t\ttoIndex: number;\n\t\tcomparisonSource?: ComparisonSource;\n\t\tselectedEntryIndexes?: number[];\n\t}): Promise<RangeOverviewItem[]> {\n\t\tconst comparisonSource = request.comparisonSource || 'revision';\n\t\tconst normalizedFromIndex = Math.max(0, Math.min(request.fromIndex, request.toIndex));\n\t\tconst normalizedToIndex = Math.max(normalizedFromIndex, Math.max(request.fromIndex, request.toIndex));\n\t\tconst selectedEntryIndexes = (request.selectedEntryIndexes || []).filter((value) => Number.isInteger(value));\n\t\tconst selectedKey = selectedEntryIndexes.length ? selectedEntryIndexes.join(',') : 'all';\n\t\tconst cacheKey = `${comparisonSource}:${normalizedFromIndex}:${normalizedToIndex}:${selectedKey}`;\n\t\tconst cached = request.session.rangeOverviewCache.get(cacheKey);\n\t\tif (cached) {\n\t\t\treturn cached;\n\t\t}\n\n\t\tconst sourceEntries = getEntriesForSource({\n\t\t\tsession: request.session,\n\t\t\tcomparisonSource,\n\t\t});\n\t\tconst countedPaths = new Map<string, number>();\n\t\tif (!request.session.workspaceFilesLoaded) {\n\t\t\tawait ensureWorkspaceFiles({ session: request.session });\n\t\t}\n\t\tconst workspaceFileSet = new Set(request.session.workspaceFiles);\n\t\tconst entryIndexesToScan = selectedEntryIndexes.length\n\t\t\t? selectedEntryIndexes\n\t\t\t: Array.from({ length: normalizedToIndex - normalizedFromIndex }, (_, index) => normalizedFromIndex + index + 1);\n\n\t\tfor (const index of entryIndexesToScan) {\n\t\t\tconst entry = sourceEntries[index];\n\t\t\tif (!entry) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst changedFiles = entry.isWorkingTree\n\t\t\t\t? await request.session.adapter.listWorkingTreeFiles({ workspacePath: request.session.workspacePath })\n\t\t\t\t: await request.session.adapter.listRevisionFiles({\n\t\t\t\t\t\tworkspacePath: request.session.workspacePath,\n\t\t\t\t\t\trevision: entry.revision,\n\t\t\t\t\t});\n\n\t\t\tfor (const relativePath of changedFiles) {\n\t\t\t\tif (!relativePath || (!workspaceFileSet.has(relativePath) && relativePath !== request.session.relativePath)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tcountedPaths.set(relativePath, (countedPaths.get(relativePath) || 0) + 1);\n\t\t\t}\n\t\t}\n\n\t\tconst items = [...countedPaths.entries()]\n\t\t\t.map(([relativePath, changeCount]) => ({\n\t\t\t\trelativePath,\n\t\t\t\tchangeCount,\n\t\t\t\tisCurrentFile: relativePath === request.session.relativePath,\n\t\t\t}))\n\t\t\t.toSorted((left, right) => {\n\t\t\t\tif (left.changeCount !== right.changeCount) {\n\t\t\t\t\treturn right.changeCount - left.changeCount;\n\t\t\t\t}\n\n\t\t\t\tif (left.isCurrentFile !== right.isCurrentFile) {\n\t\t\t\t\treturn Number(right.isCurrentFile) - Number(left.isCurrentFile);\n\t\t\t\t}\n\n\t\t\t\treturn left.relativePath.localeCompare(right.relativePath);\n\t\t\t})\n\t\t\t.slice(0, 150);\n\n\t\trequest.session.rangeOverviewCache.set(cacheKey, items);\n\t\treturn items;\n\t}\n\n\tasync function getRangeStackPreviews(request: {\n\t\tsession: ExtensionTimelineSession;\n\t\tfromIndex: number;\n\t\ttoIndex: number;\n\t\tcomparisonSource?: ComparisonSource;\n\t\trelativePaths: string[];\n\t}): Promise<Array<{ relativePath: string; preview: DiffPreview }>> {\n\t\tconst comparisonSource = request.comparisonSource || 'revision';\n\t\tconst normalizedFromIndex = Math.max(0, Math.min(request.fromIndex, request.toIndex));\n\t\tconst normalizedToIndex = Math.max(normalizedFromIndex, Math.max(request.fromIndex, request.toIndex));\n\t\tconst sourceEntries = getEntriesForSource({\n\t\t\tsession: request.session,\n\t\t\tcomparisonSource,\n\t\t});\n\t\tconst comparison = getComparisonEntries({\n\t\t\tentries: sourceEntries,\n\t\t\tfromIndex: normalizedFromIndex,\n\t\t\ttoIndex: normalizedToIndex,\n\t\t});\n\t\tif (!comparison) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst items: Array<{ relativePath: string; preview: DiffPreview }> = [];\n\t\tfor (const relativePath of request.relativePaths) {\n\t\t\tconst trimmed = relativePath.trim();\n\t\t\tif (!trimmed) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (trimmed === request.session.relativePath) {\n\t\t\t\titems.push({\n\t\t\t\t\trelativePath: trimmed,\n\t\t\t\t\tpreview: await getDiffPreview({\n\t\t\t\t\t\tsession: request.session,\n\t\t\t\t\t\tfromIndex: normalizedFromIndex,\n\t\t\t\t\t\ttoIndex: normalizedToIndex,\n\t\t\t\t\t\tcomparisonSource,\n\t\t\t\t\t}),\n\t\t\t\t});\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst beforeText = comparison.fromEntry\n\t\t\t\t? await readPathAtEntry({\n\t\t\t\t\t\tsession: request.session,\n\t\t\t\t\t\tentry: comparison.fromEntry,\n\t\t\t\t\t\trelativePath: trimmed,\n\t\t\t\t\t})\n\t\t\t\t: '';\n\t\t\tconst afterText = await readPathAtEntry({\n\t\t\t\tsession: request.session,\n\t\t\t\tentry: comparison.toEntry,\n\t\t\t\trelativePath: trimmed,\n\t\t\t});\n\t\t\titems.push({\n\t\t\t\trelativePath: trimmed,\n\t\t\t\tpreview: buildDiffPreview({\n\t\t\t\t\tindex: normalizedToIndex,\n\t\t\t\t\tpreviousEntry: comparison.fromEntry,\n\t\t\t\t\tcurrentEntry: comparison.toEntry,\n\t\t\t\t\tbeforeText,\n\t\t\t\t\tafterText,\n\t\t\t\t\tfromIndex: normalizedFromIndex,\n\t\t\t\t\ttoIndex: normalizedToIndex,\n\t\t\t\t\tbeforePath: trimmed,\n\t\t\t\t\tafterPath: trimmed,\n\t\t\t\t\tcomparisonSource,\n\t\t\t\t}),\n\t\t\t});\n\t\t}\n\t\treturn items;\n\t}\n\n\tasync function readPathAtEntry(request: {\n\t\tsession: ExtensionTimelineSession;\n\t\tentry: FileRevisionEntry;\n\t\trelativePath: string;\n\t}): Promise<string> {\n\t\tconst cacheKey = `${request.entry.id}:stack:${request.relativePath}`;\n\t\tconst cached = request.session.contentCache.get(cacheKey);\n\t\tif (cached !== undefined) {\n\t\t\treturn cached;\n\t\t}\n\t\ttry {\n\t\t\tconst content = request.entry.isWorkingTree\n\t\t\t\t? await readFile(path.join(request.session.workspacePath, request.relativePath), 'utf8')\n\t\t\t\t: await request.session.adapter.showFileAtRevision({\n\t\t\t\t\t\tworkspacePath: request.session.workspacePath,\n\t\t\t\t\t\trevset: request.entry.revision,\n\t\t\t\t\t\tfilePath: request.relativePath,\n\t\t\t\t\t});\n\t\t\trequest.session.contentCache.set(cacheKey, content);\n\t\t\treturn content;\n\t\t} catch {\n\t\t\trequest.session.contentCache.set(cacheKey, '');\n\t\t\treturn '';\n\t\t}\n\t}\n\n\tasync function getEntryDiffCounts(request: {\n\t\tsession: ExtensionTimelineSession;\n\t\tentryIndexes: number[];\n\t\tcomparisonSource?: ComparisonSource;\n\t}): Promise<Array<{ entryIndex: number; diffCount: number }>> {\n\t\tconst comparisonSource = request.comparisonSource || 'revision';\n\t\tconst sourceEntries = getEntriesForSource({\n\t\t\tsession: request.session,\n\t\t\tcomparisonSource,\n\t\t});\n\n\t\treturn Promise.all(\n\t\t\trequest.entryIndexes.map(async (entryIndex) => {\n\t\t\t\tconst cacheKey = `${comparisonSource}:${entryIndex}`;\n\t\t\t\tconst cached = request.session.entryDiffCountCache.get(cacheKey);\n\t\t\t\tif (cached !== undefined) {\n\t\t\t\t\treturn { entryIndex, diffCount: cached };\n\t\t\t\t}\n\n\t\t\t\tconst entry = sourceEntries[entryIndex];\n\t\t\t\tif (!entry || entryIndex <= 0) {\n\t\t\t\t\trequest.session.entryDiffCountCache.set(cacheKey, 0);\n\t\t\t\t\treturn { entryIndex, diffCount: 0 };\n\t\t\t\t}\n\n\t\t\t\tlet diffCount = 0;\n\t\t\t\tif (entry.isWorkingTree) {\n\t\t\t\t\tconst previousEntry = sourceEntries[entryIndex - 1];\n\t\t\t\t\tif (previousEntry) {\n\t\t\t\t\t\tconst plan = await request.session.adapter.buildRangeMultiDiffPlan({\n\t\t\t\t\t\t\tworkspacePath: request.session.workspacePath,\n\t\t\t\t\t\t\tfromEntry: previousEntry,\n\t\t\t\t\t\t\ttoEntry: entry,\n\t\t\t\t\t\t\tcomparisonSource,\n\t\t\t\t\t\t\tsourceEntries,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tdiffCount = plan.files.length;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tconst plan = await request.session.adapter.buildRevisionMultiDiffPlan({\n\t\t\t\t\t\tworkspacePath: request.session.workspacePath,\n\t\t\t\t\t\tentry,\n\t\t\t\t\t\tentryIndex,\n\t\t\t\t\t\tcomparisonSource,\n\t\t\t\t\t\tsourceEntries,\n\t\t\t\t\t});\n\t\t\t\t\tdiffCount = plan.files.length;\n\t\t\t\t}\n\n\t\t\t\trequest.session.entryDiffCountCache.set(cacheKey, diffCount);\n\t\t\t\treturn { entryIndex, diffCount };\n\t\t\t}),\n\t\t);\n\t}\n\n\tasync function resolveEntryFilePath(request: {\n\t\tsession: ExtensionTimelineSession;\n\t\tentry: FileRevisionEntry;\n\t\tentryIndex: number;\n\t}): Promise<string> {\n\t\tif (request.entry.isWorkingTree) {\n\t\t\treturn request.session.relativePath;\n\t\t}\n\n\t\tif (request.entry.filePath) {\n\t\t\treturn request.entry.filePath;\n\t\t}\n\n\t\tawait ensureEntryFilePath(request);\n\t\treturn request.entry.filePath || request.session.relativePath;\n\t}\n\n\tasync function runSessionAction(request: {\n\t\tsession: ExtensionTimelineSession;\n\t\taction: SessionAction;\n\t}): Promise<void> {\n\t\trequest.session.activeActionAbortController?.abort();\n\t\tconst controller = new AbortController();\n\t\trequest.session.activeActionAbortController = controller;\n\n\t\ttry {\n\t\t\tawait request.action(controller.signal);\n\t\t} catch (error) {\n\t\t\tif (isAbortError(error) || controller.signal.aborted) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthrow error;\n\t\t} finally {\n\t\t\tif (request.session.activeActionAbortController === controller) {\n\t\t\t\trequest.session.activeActionAbortController = undefined;\n\t\t\t}\n\t\t}\n\t}\n\n\tasync function resolveBlameRevisionForLine(request: {\n\t\tworkspacePath: string;\n\t\trelativePath: string;\n\t\tline: number;\n\t\tbackend: 'git' | 'jj';\n\t}): Promise<string | undefined> {\n\t\ttry {\n\t\t\tif (request.backend === 'git') {\n\t\t\t\tconst { stdout } = await runner.runGit({\n\t\t\t\t\tworkspacePath: request.workspacePath,\n\t\t\t\t\targs: buildGitBlameArgs({ relativePath: request.relativePath, line: request.line }),\n\t\t\t\t});\n\t\t\t\treturn findBlameForLine(parseGitBlamePorcelain(stdout), request.line)?.revision;\n\t\t\t}\n\n\t\t\tconst { stdout } = await runner.runJj({\n\t\t\t\tworkspacePath: request.workspacePath,\n\t\t\t\targs: buildJjAnnotateArgs({ relativePath: request.relativePath }),\n\t\t\t});\n\t\t\treturn findBlameForLine(parseJjFileAnnotate(stdout), request.line)?.revision;\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\tasync function getDiffBlame(request: {\n\t\tsession: ExtensionTimelineSession;\n\t\tfromIndex: number;\n\t\ttoIndex: number;\n\t\tcomparisonSource?: ComparisonSource;\n\t}): Promise<{ relativePath: string; lines: BlameLine[] }> {\n\t\tconst comparisonSource = request.comparisonSource || 'revision';\n\t\tconst normalizedFromIndex = Math.max(0, Math.min(request.fromIndex, request.toIndex));\n\t\tconst normalizedToIndex = Math.max(normalizedFromIndex, Math.max(request.fromIndex, request.toIndex));\n\t\tconst sourceEntries = getEntriesForSource({\n\t\t\tsession: request.session,\n\t\t\tcomparisonSource,\n\t\t});\n\t\tconst toEntry = sourceEntries[normalizedToIndex];\n\t\tconst relativePath = toEntry?.filePath || request.session.relativePath;\n\t\tif (!toEntry) {\n\t\t\treturn { relativePath, lines: [] };\n\t\t}\n\n\t\ttry {\n\t\t\tif (request.session.backend === 'git') {\n\t\t\t\tconst { stdout } = await runner.runGit({\n\t\t\t\t\tworkspacePath: request.session.workspacePath,\n\t\t\t\t\targs: buildGitBlameFileArgs({\n\t\t\t\t\t\trelativePath,\n\t\t\t\t\t\trevision: toEntry.isWorkingTree ? undefined : toEntry.revision,\n\t\t\t\t\t}),\n\t\t\t\t});\n\t\t\t\treturn { relativePath, lines: parseGitBlamePorcelain(stdout) };\n\t\t\t}\n\n\t\t\tconst { stdout } = await runner.runJj({\n\t\t\t\tworkspacePath: request.session.workspacePath,\n\t\t\t\targs: buildJjAnnotateArgs({\n\t\t\t\t\trelativePath,\n\t\t\t\t\trevision: toEntry.isWorkingTree ? undefined : toEntry.revision,\n\t\t\t\t}),\n\t\t\t});\n\t\t\treturn { relativePath, lines: parseJjFileAnnotate(stdout) };\n\t\t} catch {\n\t\t\treturn { relativePath, lines: [] };\n\t\t}\n\t}\n\n\tasync function getFileOpLog(request: {\n\t\tsession: ExtensionTimelineSession;\n\t}): Promise<{ relativePath: string; entries: ReturnType<typeof filterFileOpLogPeek> }> {\n\t\tconst relativePath = request.session.relativePath;\n\t\tif (request.session.backend !== 'jj') {\n\t\t\treturn { relativePath, entries: [] };\n\t\t}\n\t\ttry {\n\t\t\tconst { stdout } = await runner.runJj({\n\t\t\t\tworkspacePath: request.session.workspacePath,\n\t\t\t\targs: ['op', 'log', '--limit', '80', '-T', JJ_OP_LOG_TEMPLATE],\n\t\t\t});\n\t\t\tconst fileEntries = [\n\t\t\t\t...request.session.snapshotEntries,\n\t\t\t\t...request.session.entries.filter((entry) => Boolean(entry.operationId)),\n\t\t\t];\n\t\t\treturn {\n\t\t\t\trelativePath,\n\t\t\t\tentries: filterFileOpLogPeek({\n\t\t\t\t\topLog: parseJjOpLogOutput(stdout),\n\t\t\t\t\tfileEntries,\n\t\t\t\t\trelativePath,\n\t\t\t\t\tlimit: 12,\n\t\t\t\t}),\n\t\t\t};\n\t\t} catch {\n\t\t\treturn { relativePath, entries: [] };\n\t\t}\n\t}\n\n\tasync function searchFileHistory(request: {\n\t\tsession: ExtensionTimelineSession;\n\t\tquery: string;\n\t\tmaxEntries?: number;\n\t\tpurpose?: 'history' | 'sidebar';\n\t}): Promise<ReturnType<typeof searchHistoryContents>> {\n\t\tconst maxEntries = request.maxEntries ?? 40;\n\t\tconst touching = request.session.entries\n\t\t\t.map((entry, index) => ({ entry, index }))\n\t\t\t.filter(({ entry }) => entry.touchesFile && !entry.isWorkingTree)\n\t\t\t.slice(-maxEntries);\n\t\tconst contentsByIndex = new Map<number, string>();\n\t\tfor (const { entry, index } of touching) {\n\t\t\ttry {\n\t\t\t\tconst content = await getRevisionContent({\n\t\t\t\t\tsession: request.session,\n\t\t\t\t\tentry,\n\t\t\t\t\tentryIndex: index,\n\t\t\t\t});\n\t\t\t\tcontentsByIndex.set(index, content);\n\t\t\t} catch {\n\t\t\t\tcontentsByIndex.set(index, '');\n\t\t\t}\n\t\t}\n\t\tconst orderedEntryIndexes = touching.map(({ index }) => index);\n\t\tif (request.purpose === 'sidebar') {\n\t\t\treturn searchHistoryDiffContents({\n\t\t\t\tquery: request.query,\n\t\t\t\torderedEntryIndexes,\n\t\t\t\tcontentsByIndex,\n\t\t\t});\n\t\t}\n\t\treturn searchHistoryContents({\n\t\t\tquery: request.query,\n\t\t\torderedEntryIndexes,\n\t\t\tcontentsByIndex,\n\t\t});\n\t}\n\n\tasync function buildTimelineEntries(request: {\n\t\tadapter: HistoryAdapter;\n\t\tworkspacePath: string;\n\t\tabsolutePath: string;\n\t\trelativePath: string;\n\t\tfileEntries: FileRevisionEntry[];\n\t\tincludeIntermediateRevisions: boolean;\n\t\tentryLimit: number;\n\t}): Promise<FileRevisionEntry[]> {\n\t\tconst touchingEntries = request.fileEntries.map((entry) => ({\n\t\t\t...entry,\n\t\t\ttouchesFile: true,\n\t\t}));\n\n\t\tif (touchingEntries.length) {\n\t\t\ttouchingEntries[touchingEntries.length - 1].filePath = request.relativePath;\n\t\t}\n\n\t\tlet entries = touchingEntries;\n\t\tif (request.includeIntermediateRevisions && touchingEntries.length >= 2) {\n\t\t\ttry {\n\t\t\t\tconst repositoryEntries = await request.adapter.getRepositoryRevisionHistory({\n\t\t\t\t\tworkspacePath: request.workspacePath,\n\t\t\t\t\tlimit: Math.max(request.entryLimit, MAX_TIMELINE_ENTRIES),\n\t\t\t\t});\n\t\t\t\tentries = mergeTimelineEntries({ repositoryEntries, fileEntries: touchingEntries });\n\t\t\t} catch {\n\t\t\t\tentries = touchingEntries;\n\t\t\t}\n\t\t}\n\n\t\tif (request.adapter.backend === 'jj') {\n\t\t\tentries = dedupeAdjacentTimelineEntries(entries);\n\t\t}\n\n\t\treturn appendWorkingTreeEntry({\n\t\t\tadapter: request.adapter,\n\t\t\tworkspacePath: request.workspacePath,\n\t\t\tabsolutePath: request.absolutePath,\n\t\t\trelativePath: request.relativePath,\n\t\t\tentries,\n\t\t});\n\t}\n\n\tasync function listWorkspaceFiles(request: { adapter: HistoryAdapter; workspacePath: string }): Promise<string[]> {\n\t\tif (request.adapter.backend === 'git') {\n\t\t\ttry {\n\t\t\t\tconst { stdout } = await runner.runGit({\n\t\t\t\t\tworkspacePath: request.workspacePath,\n\t\t\t\t\targs: ['ls-files', '--cached', '-z'],\n\t\t\t\t});\n\t\t\t\tconst files = stdout\n\t\t\t\t\t.split('\\u0000')\n\t\t\t\t\t.map((value) => value.trim())\n\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t.toSorted((left, right) => left.localeCompare(right));\n\t\t\t\tif (files.length) {\n\t\t\t\t\treturn files;\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Fall back to filesystem traversal.\n\t\t\t}\n\t\t}\n\n\t\tif (request.adapter.backend === 'jj') {\n\t\t\ttry {\n\t\t\t\tconst { stdout } = await runner.runJj({\n\t\t\t\t\tworkspacePath: request.workspacePath,\n\t\t\t\t\targs: ['file', 'list'],\n\t\t\t\t});\n\t\t\t\tconst files = stdout\n\t\t\t\t\t.split(/\\r?\\n/u)\n\t\t\t\t\t.map((value) => value.trim())\n\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t.toSorted((left, right) => left.localeCompare(right));\n\t\t\t\tif (files.length) {\n\t\t\t\t\treturn files;\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Fall back to filesystem traversal.\n\t\t\t}\n\t\t}\n\n\t\tconst files: string[] = [];\n\t\tawait collectWorkspaceFiles({\n\t\t\tworkspacePath: request.workspacePath,\n\t\t\tcurrentDirectory: request.workspacePath,\n\t\t\tfiles,\n\t\t});\n\t\treturn files.toSorted((left, right) => left.localeCompare(right));\n\t}\n\n\tasync function collectWorkspaceFiles(request: {\n\t\tworkspacePath: string;\n\t\tcurrentDirectory: string;\n\t\tfiles: string[];\n\t}): Promise<void> {\n\t\tconst directoryEntries = await readdir(request.currentDirectory, { withFileTypes: true });\n\t\tfor (const directoryEntry of directoryEntries) {\n\t\t\tif (directoryEntry.isDirectory() && IGNORED_WORKSPACE_DIRECTORIES.has(directoryEntry.name)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst absolutePath = path.join(request.currentDirectory, directoryEntry.name);\n\t\t\tif (directoryEntry.isDirectory()) {\n\t\t\t\tawait collectWorkspaceFiles({\n\t\t\t\t\tworkspacePath: request.workspacePath,\n\t\t\t\t\tcurrentDirectory: absolutePath,\n\t\t\t\t\tfiles: request.files,\n\t\t\t\t});\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (!directoryEntry.isFile()) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\trequest.files.push(path.relative(request.workspacePath, absolutePath).replace(/\\\\/g, '/'));\n\t\t}\n\t}\n\n\tasync function appendWorkingTreeEntry(request: {\n\t\tadapter: HistoryAdapter;\n\t\tworkspacePath: string;\n\t\tabsolutePath: string;\n\t\trelativePath: string;\n\t\tentries: FileRevisionEntry[];\n\t}): Promise<FileRevisionEntry[]> {\n\t\tif (!(await runner.fileExists({ filePath: request.absolutePath }))) {\n\t\t\treturn request.entries;\n\t\t}\n\n\t\tconst lastEntry = request.entries.at(-1);\n\t\tconst lastTouchingEntry = request.entries.filter((entry) => entry.touchesFile && !entry.isWorkingTree).at(-1);\n\t\tif (lastEntry?.isWorkingTree) {\n\t\t\treturn request.entries;\n\t\t}\n\n\t\tif (lastTouchingEntry) {\n\t\t\tconst currentContent = await readFile(request.absolutePath, 'utf8');\n\t\t\tconst previousContent = await request.adapter.showFileAtRevision({\n\t\t\t\tworkspacePath: request.workspacePath,\n\t\t\t\trevset: lastTouchingEntry.revision,\n\t\t\t\tfilePath: lastTouchingEntry.filePath || request.relativePath,\n\t\t\t});\n\t\t\tif (\n\t\t\t\tcurrentContent === previousContent &&\n\t\t\t\t(lastTouchingEntry.filePath || request.relativePath) === request.relativePath\n\t\t\t) {\n\t\t\t\treturn request.entries;\n\t\t\t}\n\t\t}\n\n\t\tconst now = new Date();\n\t\treturn [\n\t\t\t...request.entries,\n\t\t\t{\n\t\t\t\tid: 'working-tree',\n\t\t\t\trevision: 'WORKTREE',\n\t\t\t\tshortRevision: 'Current',\n\t\t\t\tchangeId: undefined,\n\t\t\t\tauthorDate: now.toISOString(),\n\t\t\t\tauthorName: '',\n\t\t\t\tdescription: 'Working tree',\n\t\t\t\tisWorkingTree: true,\n\t\t\t\ttouchesFile: true,\n\t\t\t\ttimestamp: now.getTime(),\n\t\t\t\tfilePath: request.relativePath,\n\t\t\t},\n\t\t];\n\t}\n\n\tfunction composeSnapshotEntries(request: {\n\t\trevisionEntries: FileRevisionEntry[];\n\t\tsnapshotEntries: FileRevisionEntry[];\n\t\tloadedChangeIds: Set<string>;\n\t}): FileRevisionEntry[] {\n\t\tif (!request.loadedChangeIds.size) {\n\t\t\treturn request.revisionEntries;\n\t\t}\n\n\t\tconst snapshotEntriesByChangeId = request.snapshotEntries.reduce((groups, entry) => {\n\t\t\tif (!entry.changeId) {\n\t\t\t\treturn groups;\n\t\t\t}\n\t\t\tconst existing = groups.get(entry.changeId) || [];\n\t\t\texisting.push(entry);\n\t\t\tgroups.set(entry.changeId, existing);\n\t\t\treturn groups;\n\t\t}, new Map<string, FileRevisionEntry[]>());\n\n\t\treturn request.revisionEntries.flatMap((entry) => {\n\t\t\tif (\n\t\t\t\tentry.isWorkingTree ||\n\t\t\t\t!entry.touchesFile ||\n\t\t\t\t!entry.changeId ||\n\t\t\t\t!request.loadedChangeIds.has(entry.changeId)\n\t\t\t) {\n\t\t\t\treturn [entry];\n\t\t\t}\n\n\t\t\treturn snapshotEntriesByChangeId.get(entry.changeId) || [entry];\n\t\t});\n\t}\n\n\tasync function getJjSnapshotPreview(request: {\n\t\tsession: ExtensionTimelineSession;\n\t\tfromIndex: number;\n\t\ttoIndex: number;\n\t}): Promise<DiffPreview> {\n\t\tconst sourceEntries = getEntriesForSource({ session: request.session, comparisonSource: 'snapshot' });\n\t\tconst normalizedFromIndex = Math.max(0, Math.min(request.fromIndex, request.toIndex));\n\t\tconst normalizedToIndex = Math.max(normalizedFromIndex, Math.max(request.fromIndex, request.toIndex));\n\t\tconst entry = sourceEntries[normalizedToIndex];\n\t\tif (!entry) {\n\t\t\treturn createEmptyPreview({\n\t\t\t\tindex: normalizedToIndex,\n\t\t\t\tfromIndex: normalizedFromIndex,\n\t\t\t\ttoIndex: normalizedToIndex,\n\t\t\t\tcomparisonSource: 'snapshot',\n\t\t\t\ttitle: 'No revision selected',\n\t\t\t});\n\t\t}\n\n\t\tconst afterPath = await resolveEntryFilePath({\n\t\t\tsession: request.session,\n\t\t\tentry,\n\t\t\tentryIndex: normalizedToIndex,\n\t\t});\n\t\tconst previousEntryIndex = normalizedFromIndex === normalizedToIndex ? normalizedToIndex - 1 : normalizedFromIndex;\n\t\tconst previousEntry = previousEntryIndex >= 0 ? sourceEntries[previousEntryIndex] : undefined;\n\t\tconst previousPath = previousEntry\n\t\t\t? await resolveEntryFilePath({\n\t\t\t\t\tsession: request.session,\n\t\t\t\t\tentry: previousEntry,\n\t\t\t\t\tentryIndex: previousEntryIndex,\n\t\t\t\t})\n\t\t\t: entry.isWorkingTree\n\t\t\t\t? request.session.relativePath\n\t\t\t\t: await resolvePreviousPathAcrossRevision({\n\t\t\t\t\t\tsession: request.session,\n\t\t\t\t\t\tentry,\n\t\t\t\t\t\tcurrentPath: afterPath,\n\t\t\t\t\t});\n\t\tconst beforeText = previousEntry\n\t\t\t? await getRevisionContent({\n\t\t\t\t\tsession: request.session,\n\t\t\t\t\tentry: previousEntry,\n\t\t\t\t\tentryIndex: previousEntryIndex,\n\t\t\t\t})\n\t\t\t: entry.isWorkingTree\n\t\t\t\t? ''\n\t\t\t\t: await getContentForRevset({\n\t\t\t\t\t\tsession: request.session,\n\t\t\t\t\t\trevset: `${entry.revision}-`,\n\t\t\t\t\t\tfilePath: previousPath,\n\t\t\t\t\t});\n\t\tconst afterText = await getRevisionContent({\n\t\t\tsession: request.session,\n\t\t\tentry,\n\t\t\tentryIndex: normalizedToIndex,\n\t\t});\n\n\t\treturn {\n\t\t\t...buildDiffPreview({\n\t\t\t\tindex: normalizedToIndex,\n\t\t\t\tpreviousEntry,\n\t\t\t\tcurrentEntry: entry,\n\t\t\t\tbeforeText,\n\t\t\t\tafterText,\n\t\t\t\tfromIndex: normalizedFromIndex,\n\t\t\t\ttoIndex: normalizedToIndex,\n\t\t\t\tbeforePath: previousPath,\n\t\t\t\tafterPath,\n\t\t\t\tcomparisonSource: 'snapshot',\n\t\t\t}),\n\t\t\ttitle: entry.isWorkingTree ? `Snapshot @ ${entry.shortRevision}` : `Snapshot ${entry.shortRevision}`,\n\t\t};\n\t}\n\n\tasync function getRevisionContent(request: {\n\t\tsession: ExtensionTimelineSession;\n\t\tentry: FileRevisionEntry;\n\t\tentryIndex: number;\n\t}): Promise<string> {\n\t\tconst resolvedPath = request.entry.isWorkingTree\n\t\t\t? request.session.relativePath\n\t\t\t: await resolveEntryFilePath(request);\n\t\tconst cacheKey = `${request.entry.id}:${resolvedPath}`;\n\t\tconst cached = request.session.contentCache.get(cacheKey);\n\t\tif (cached !== undefined) {\n\t\t\treturn cached;\n\t\t}\n\n\t\tconst content = request.entry.isWorkingTree\n\t\t\t? await readFile(request.session.absolutePath, 'utf8')\n\t\t\t: await request.session.adapter.showFileAtRevision({\n\t\t\t\t\tworkspacePath: request.session.workspacePath,\n\t\t\t\t\trevset: request.entry.revision,\n\t\t\t\t\tfilePath: resolvedPath,\n\t\t\t\t});\n\t\trequest.session.contentCache.set(cacheKey, content);\n\t\treturn content;\n\t}\n\n\tasync function ensureEntryFilePath(request: {\n\t\tsession: ExtensionTimelineSession;\n\t\tentry: FileRevisionEntry;\n\t\tentryIndex: number;\n\t}): Promise<void> {\n\t\tconst targetEntry = request.session.entries[request.entryIndex];\n\t\tif (!targetEntry || targetEntry.filePath || targetEntry.isWorkingTree) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet knownIndex = -1;\n\t\tfor (let index = request.entryIndex + 1; index < request.session.entries.length; index += 1) {\n\t\t\tif (request.session.entries[index]?.filePath) {\n\t\t\t\tknownIndex = index;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (knownIndex < 0) {\n\t\t\ttargetEntry.filePath = request.session.relativePath;\n\t\t\treturn;\n\t\t}\n\n\t\tlet currentPath = request.session.entries[knownIndex].filePath || request.session.relativePath;\n\t\tfor (let index = knownIndex; index > request.entryIndex; index -= 1) {\n\t\t\tconst currentEntry = request.session.entries[index];\n\t\t\tconst previousEntry = request.session.entries[index - 1];\n\t\t\tif (!previousEntry) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (!previousEntry.filePath) {\n\t\t\t\tlet previousPath = currentPath;\n\t\t\t\tif (currentEntry.touchesFile && !currentEntry.isWorkingTree) {\n\t\t\t\t\tpreviousPath = await resolvePreviousPathAcrossRevision({\n\t\t\t\t\t\tsession: request.session,\n\t\t\t\t\t\tentry: currentEntry,\n\t\t\t\t\t\tcurrentPath,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tpreviousEntry.filePath = previousPath;\n\t\t\t}\n\n\t\t\tcurrentPath = previousEntry.filePath || currentPath;\n\t\t}\n\t}\n}\n\nexport function normalizeTimelinePreferences(\n\tpreferences: TimelinePreferences | null | undefined,\n): Required<TimelinePreferences> {\n\tif (!preferences) {\n\t\treturn { ...DEFAULT_TIMELINE_PREFERENCES };\n\t}\n\n\treturn {\n\t\tsidebarWidth:\n\t\t\ttypeof preferences.sidebarWidth === 'number'\n\t\t\t\t? preferences.sidebarWidth\n\t\t\t\t: DEFAULT_TIMELINE_PREFERENCES.sidebarWidth,\n\t\tsidebarCollapsed: preferences.sidebarCollapsed === true,\n\t\ttimelinePaneHeight:\n\t\t\ttypeof preferences.timelinePaneHeight === 'number'\n\t\t\t\t? preferences.timelinePaneHeight\n\t\t\t\t: DEFAULT_TIMELINE_PREFERENCES.timelinePaneHeight,\n\t\ttimelinePaneCollapsed: preferences.timelinePaneCollapsed === true,\n\t\tlayoutMode: preferences.layoutMode === 'unified' ? 'unified' : DEFAULT_TIMELINE_PREFERENCES.layoutMode,\n\t\tcontentMode: preferences.contentMode === 'full' ? 'full' : DEFAULT_TIMELINE_PREFERENCES.contentMode,\n\t\tcomparisonMode: preferences.comparisonMode === 'step' ? 'step' : DEFAULT_TIMELINE_PREFERENCES.comparisonMode,\n\t\tcomparisonSource:\n\t\t\tpreferences.comparisonSource === 'snapshot' ? 'snapshot' : DEFAULT_TIMELINE_PREFERENCES.comparisonSource,\n\t\tshowIntermediateRevisions: preferences.showIntermediateRevisions === true,\n\t\tpreset:\n\t\t\tpreferences.preset === '7d' ||\n\t\t\tpreferences.preset === '30d' ||\n\t\t\tpreferences.preset === '90d' ||\n\t\t\tpreferences.preset === 'all' ||\n\t\t\tpreferences.preset === 'year'\n\t\t\t\t? preferences.preset\n\t\t\t\t: DEFAULT_TIMELINE_PREFERENCES.preset,\n\t\tcustomRevset: typeof preferences.customRevset === 'string' ? preferences.customRevset.trim() : '',\n\t\tthemePreference:\n\t\t\tpreferences.themePreference === 'light' || preferences.themePreference === 'dark'\n\t\t\t\t? preferences.themePreference\n\t\t\t\t: DEFAULT_TIMELINE_PREFERENCES.themePreference,\n\t\theatmapOpen: preferences.heatmapOpen === true,\n\t\tlineDiffType:\n\t\t\tpreferences.lineDiffType === 'word' ||\n\t\t\tpreferences.lineDiffType === 'char' ||\n\t\t\tpreferences.lineDiffType === 'none' ||\n\t\t\tpreferences.lineDiffType === 'word-alt'\n\t\t\t\t? preferences.lineDiffType\n\t\t\t\t: DEFAULT_TIMELINE_PREFERENCES.lineDiffType,\n\t};\n}\n\nfunction createEmptyPreview(args: {\n\tindex: number;\n\tfromIndex: number;\n\ttoIndex: number;\n\tcomparisonSource: ComparisonSource;\n\ttitle: string;\n}): DiffPreview {\n\treturn {\n\t\tindex: args.index,\n\t\ttitle: args.title,\n\t\tsubtitle: '',\n\t\tdiffCount: 0,\n\t\tadditions: 0,\n\t\tdeletions: 0,\n\t\thunkCount: 0,\n\t\thasChanges: false,\n\t\tfromIndex: args.fromIndex,\n\t\ttoIndex: args.toIndex,\n\t\tcomparisonSource: args.comparisonSource,\n\t\tbeforePath: '',\n\t\tafterPath: '',\n\t\tbeforeText: '',\n\t\tafterText: '',\n\t\tnonTextualDetails: [],\n\t};\n}\n\nfunction buildDiffPreview(args: {\n\tindex: number;\n\tpreviousEntry?: FileRevisionEntry;\n\tcurrentEntry: FileRevisionEntry;\n\tbeforeText: string;\n\tafterText: string;\n\tfromIndex: number;\n\ttoIndex: number;\n\tbeforePath: string;\n\tafterPath: string;\n\tcomparisonSource: ComparisonSource;\n}): DiffPreview {\n\tconst stats = computeDiffStats(args.beforeText, args.afterText);\n\tconst title = args.previousEntry\n\t\t? `${args.previousEntry.shortRevision} -> ${args.currentEntry.shortRevision}`\n\t\t: `Initial revision -> ${args.currentEntry.shortRevision}`;\n\tconst subtitle = args.currentEntry.isWorkingTree\n\t\t? 'Working tree'\n\t\t: `${formatEntryDateTime(args.currentEntry.authorDate)} · ${args.currentEntry.description}`;\n\n\treturn {\n\t\tindex: args.index,\n\t\ttitle,\n\t\tsubtitle,\n\t\tdiffCount: 0,\n\t\tadditions: stats.additions,\n\t\tdeletions: stats.deletions,\n\t\thunkCount: stats.hunkCount,\n\t\thasChanges: stats.hasChanges,\n\t\tfromIndex: args.fromIndex,\n\t\ttoIndex: args.toIndex,\n\t\tcomparisonSource: args.comparisonSource,\n\t\tbeforePath: args.beforePath,\n\t\tafterPath: args.afterPath,\n\t\tbeforeText: args.beforeText,\n\t\tafterText: args.afterText,\n\t\tnonTextualDetails: stats.hasChanges\n\t\t\t? []\n\t\t\t: buildNonTextualDetails({\n\t\t\t\t\tbeforeText: args.beforeText,\n\t\t\t\t\tafterText: args.afterText,\n\t\t\t\t\tbeforePath: args.beforePath,\n\t\t\t\t\tafterPath: args.afterPath,\n\t\t\t\t\tisWorkingTree: args.currentEntry.isWorkingTree,\n\t\t\t\t}),\n\t};\n}\n\nfunction mergeTimelineEntries(args: {\n\trepositoryEntries: FileRevisionEntry[];\n\tfileEntries: FileRevisionEntry[];\n}): FileRevisionEntry[] {\n\tconst touchingByRevision = new Map(args.fileEntries.map((entry) => [entry.revision, entry]));\n\tconst repoIndexes = args.fileEntries\n\t\t.map((entry) => args.repositoryEntries.findIndex((candidate) => candidate.revision === entry.revision))\n\t\t.filter((index) => index >= 0);\n\n\tif (!repoIndexes.length) {\n\t\treturn args.fileEntries;\n\t}\n\n\tconst startIndex = Math.min(...repoIndexes);\n\tconst endIndex = Math.max(...repoIndexes);\n\tconst merged = args.repositoryEntries\n\t\t.slice(startIndex, endIndex + 1)\n\t\t.map((entry) => touchingByRevision.get(entry.revision) || entry);\n\n\tfor (const entry of args.fileEntries) {\n\t\tif (!merged.some((candidate) => candidate.revision === entry.revision)) {\n\t\t\tmerged.push(entry);\n\t\t}\n\t}\n\n\treturn merged.toSorted(\n\t\t(left, right) => left.timestamp - right.timestamp || left.revision.localeCompare(right.revision),\n\t);\n}\n\nfunction dedupeAdjacentTimelineEntries(entries: FileRevisionEntry[]): FileRevisionEntry[] {\n\treturn entries.reduce<FileRevisionEntry[]>((deduped, entry) => {\n\t\tconst previousEntry = deduped.at(-1);\n\t\tif (!previousEntry?.changeId || previousEntry.changeId !== entry.changeId) {\n\t\t\tdeduped.push(entry);\n\t\t\treturn deduped;\n\t\t}\n\n\t\tif (previousEntry.touchesFile && entry.touchesFile) {\n\t\t\tdeduped.push(entry);\n\t\t\treturn deduped;\n\t\t}\n\n\t\tif (!previousEntry.touchesFile && entry.touchesFile) {\n\t\t\tdeduped[deduped.length - 1] = entry;\n\t\t}\n\n\t\treturn deduped;\n\t}, []);\n}\n\nfunction formatEntryMonthLabel(authorDate: string): string {\n\tconst date = new Date(authorDate);\n\tif (Number.isNaN(date.getTime())) {\n\t\treturn 'Unknown month';\n\t}\n\n\treturn new Intl.DateTimeFormat('en', { month: 'long' }).format(date);\n}\n\nfunction formatEntryShortDate(authorDate: string): string {\n\tconst date = new Date(authorDate);\n\tif (Number.isNaN(date.getTime())) {\n\t\treturn 'Unknown date';\n\t}\n\n\treturn new Intl.DateTimeFormat('en', { month: 'short', day: 'numeric', year: 'numeric' }).format(date);\n}\n\nfunction formatRelativeTime(timestamp: number): string {\n\tconst deltaSeconds = Math.round((timestamp - Date.now()) / 1000);\n\tconst formatter = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });\n\tconst divisions: Array<[Intl.RelativeTimeFormatUnit, number]> = [\n\t\t['day', 60 * 60 * 24],\n\t\t['hour', 60 * 60],\n\t\t['minute', 60],\n\t];\n\n\tfor (const [unit, amount] of divisions) {\n\t\tif (Math.abs(deltaSeconds) >= amount || unit === 'minute') {\n\t\t\treturn formatter.format(Math.round(deltaSeconds / amount), unit);\n\t\t}\n\t}\n\n\treturn formatter.format(deltaSeconds, 'second');\n}\n\nfunction formatEntryDateTime(authorDate: string): string {\n\tconst date = new Date(authorDate);\n\tif (Number.isNaN(date.getTime())) {\n\t\treturn 'Unknown time';\n\t}\n\n\treturn date.toLocaleString();\n}\n\nfunction isAbortError(error: unknown): boolean {\n\treturn error instanceof Error && (error.name === 'AbortError' || /aborted/i.test(error.message));\n}\n"],"mappings":";;;;;;;;;;;;;AAwCA,MAAM,+BAA8D;CACnE,cAAc;CACd,kBAAkB;CAClB,oBAAoB;CACpB,uBAAuB;CACvB,YAAY;CACZ,aAAa;CACb,gBAAgB;CAChB,kBAAkB;CAClB,2BAA2B;CAC3B,QAAQ;CACR,cAAc;CACd,iBAAiB;CACjB,aAAa;CACb,cAAc;AACf;AAEA,MAAM,gDAAgC,IAAI,IAAI;CAAC;CAAQ;CAAO;CAAgB;CAAQ;CAAS;CAAO;AAAU,CAAC;AAEjH,SAAS,qBAAqB,SAI+C;CAC5E,MAAM,sBAAsB,KAAK,IAAI,GAAG,KAAK,IAAI,QAAQ,WAAW,QAAQ,OAAO,CAAC;CACpF,MAAM,oBAAoB,KAAK,IAAI,qBAAqB,KAAK,IAAI,QAAQ,WAAW,QAAQ,OAAO,CAAC;CACpG,MAAM,YAAY,QAAQ,QAAQ;CAClC,MAAM,UAAU,QAAQ,QAAQ;CAChC,IAAI,CAAC,aAAa,CAAC,SAClB;CAGD,OAAO;EAAE;EAAW;CAAQ;AAC7B;AAEA,SAAS,YAAY,SAAuF;CAC3G,QAAQ,OAAO,UAAU,QAAQ,OAAO;CACxC,QAAQ,OAAO,UAAU,QAAQ,OAAO;CACxC,QAAQ,OAAO,gBAAgB,QAAQ,OAAO;CAC9C,QAAQ,OAAO,eAAe,QAAQ,OAAO;CAC7C,QAAQ,OAAO,eAAe,QAAQ,OAAO;CAC7C,QAAQ,OAAO,WAAW,QAAQ,OAAO;CACzC,QAAQ,OAAO,UAAU,QAAQ,OAAO;CACxC,QAAQ,OAAO,kBAAkB,QAAQ,OAAO;CAChD,QAAQ,OAAO,0BAA0B,QAAQ,OAAO;CACxD,QAAQ,OAAO,2BAA2B,QAAQ,OAAO;CACzD,QAAQ,OAAO,iBAAiB,QAAQ,OAAO;CAC/C,QAAQ,OAAO,uBAAuB,QAAQ,OAAO;CACrD,QAAQ,OAAO,eAAe,QAAQ,OAAO;CAC7C,QAAQ,OAAO,8BAA8B,QAAQ,OAAO;CAC5D,QAAQ,OAAO,eAAe,QAAQ,OAAO;CAC7C,QAAQ,OAAO,eAAe,QAAQ,OAAO;CAC7C,QAAQ,OAAO,qBAAqB,QAAQ,OAAO;CACnD,QAAQ,OAAO,sBAAsB,QAAQ,OAAO;CACpD,QAAQ,OAAO,YAAY,QAAQ,OAAO;CAC1C,QAAQ,OAAO,8BAA8B,QAAQ,OAAO;CAC5D,QAAQ,OAAO,cAAc,QAAQ,OAAO;CAC5C,QAAQ,OAAO,eAAe,QAAQ,OAAO;AAC9C;AAEA,eAAe,oBAAoB,SAIf;CACnB,MAAM,WAAW,UAAU,QAAQ,OAAO,GAAG,QAAQ;CACrD,MAAM,SAAS,QAAQ,QAAQ,aAAa,IAAI,QAAQ;CACxD,IAAI,WAAW,KAAA,GACd,OAAO;CAGR,MAAM,UAAU,MAAM,QAAQ,QAAQ,QAAQ,mBAAmB;EAChE,eAAe,QAAQ,QAAQ;EAC/B,QAAQ,QAAQ;EAChB,UAAU,QAAQ;CACnB,CAAC;CACD,QAAQ,QAAQ,aAAa,IAAI,UAAU,OAAO;CAClD,OAAO;AACR;AAEA,eAAe,mCAAmC,MAQjB;CAChC,IAAI,KAAK,QAAQ,YAAY,OAC5B,IAAI;EACH,MAAM,EAAE,WAAW,MAAM,KAAK,OAAO,OAAO;GAC3C,eAAe,KAAK;GACpB,MAAMA,qBAAAA,wBAAwB;IAC7B,cAAc,KAAK;IACnB,OAAO,KAAK;IACZ,OAAO,KAAK;GACb,CAAC;EACF,CAAC;EACD,MAAM,YAAY,IAAI,IAAIC,qBAAAA,6BAA6B,MAAM,CAAC;EAC9D,MAAM,WAAW,KAAK,QAAQ,QAAQ,UAAU,MAAM,iBAAiB,UAAU,IAAI,MAAM,QAAQ,CAAC;EACpG,IAAI,SAAS,QACZ,OAAO;CAET,QAAQ,CAER;CAGD,MAAM,oCAAoB,IAAI,IAAoB;CAClD,KAAK,MAAM,SAAS,KAAK,SAAS;EACjC,MAAM,WAAW,MAAM,YAAY,KAAK;EACxC,MAAM,SAAS,MAAM,gBAAgB,MAAM,MAAM;EACjD,IAAI;GACH,MAAM,UAAU,MAAM,KAAK,QAAQ,mBAAmB;IACrD,eAAe,KAAK;IACpB,QAAQ,MAAM,iBAAiB,KAAK,QAAQ,YAAY,QAAQ,SAAS;IACzE;GACD,CAAC;GAED,kBAAkB,IAAI,MAAM,UAAU,OAAO;EAC9C,QAAQ;GACP,kBAAkB,IAAI,MAAM,UAAU,EAAE;EACzC;CACD;CAGA,IAAI,KAAK,QAAQ,YAAY,OAAO;EACnC,MAAM,MAAM,KAAK,QAAQ,MAAM,UAAU,MAAM,aAAa;EAC5D,IAAI,KACH,IAAI;GACH,MAAM,WAAWC,UAAAA,QAAK,KAAK,KAAK,eAAe,IAAI,YAAY,KAAK,YAAY;GAChF,kBAAkB,IAAI,IAAI,UAAU,OAAA,GAAMC,iBAAAA,SAAAA,CAAS,UAAU,MAAM,CAAC;EACrE,QAAQ,CAER;CAEF;CAEA,OAAOC,qBAAAA,+BAA+B;EACrC,SAAS,KAAK;EACd,OAAO,KAAK;EACZ,aAAa,UAAU,kBAAkB,IAAI,MAAM,QAAQ,KAAK;CACjE,CAAC;AACF;AAEA,eAAe,sBAAsB,MAKnB;CACjB,IAAI,CAAC,KAAK,QAAQ,QACjB;CAGD,KAAK,QAAQ,KAAK,QAAQ,SAAS,EAAE,CAAC,WAAW,KAAK;CACtD,IAAI,cAAc,KAAK;CACvB,KAAK,IAAI,QAAQ,KAAK,QAAQ,SAAS,GAAG,QAAQ,GAAG,SAAS,GAAG;EAChE,MAAM,eAAe,KAAK,QAAQ;EAClC,MAAM,gBAAgB,KAAK,QAAQ,QAAQ;EAC3C,IAAI,cAAc,UAAU;GAC3B,cAAc,cAAc;GAC5B;EACD;EAEA,IAAI,eAAe;EACnB,IAAI,aAAa,eAAe,CAAC,aAAa,eAC7C,eAAe,MAAM,KAAK,QAAQ,oBAAoB;GACrD,eAAe,KAAK;GACpB,UAAU,aAAa;GACvB;EACD,CAAC;EAEF,cAAc,WAAW;EACzB,cAAc;CACf;AACD;AAEA,eAAe,kCAAkC,SAI7B;CACnB,MAAM,WAAW,GAAG,QAAQ,MAAM,SAAS,GAAG,QAAQ;CACtD,MAAM,SAAS,QAAQ,QAAQ,UAAU,IAAI,QAAQ;CACrD,IAAI,QACH,OAAO;CAGR,MAAM,eAAe,MAAM,QAAQ,QAAQ,QAAQ,oBAAoB;EACtE,eAAe,QAAQ,QAAQ;EAC/B,UAAU,QAAQ,MAAM;EACxB,aAAa,QAAQ;CACtB,CAAC;CACD,QAAQ,QAAQ,UAAU,IAAI,UAAU,YAAY;CACpD,OAAO;AACR;AAEA,eAAe,sBAAsB,SAGf;CACrB,MAAM,WAAW,QAAQ,SAAS,KAAK,KAAK;CAC5C,IAAI;EACH,OAAO,MAAM,QAAQ,QAAQ,QAAQ,sBAAsB;GAC1D,eAAe,QAAQ,QAAQ;GAC/B;EACD,CAAC;CACF,QAAQ;EACP,OAAO,CAAC;CACT;AACD;AAEA,SAAgB,sBAAsB,MAAiC;CACtE,MAAM,EAAE,WAAW;CAEnB,OAAO;EACN;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACD;CAEA,eAAe,aAAa,SAUU;EACrC,MAAM,uBAAuB,MAAMC,yBAAAA,4BAA4B;GAAE,eAAe,QAAQ;GAAe;EAAO,CAAC;EAC/G,MAAM,eAAeH,UAAAA,QAAK,SAAS,sBAAsB,QAAQ,YAAY,CAAC,CAAC,QAAQ,OAAO,GAAG;EACjG,MAAM,UAAU,MAAMI,yBAAAA,sBAAsB;GAAE,eAAe;GAAsB;EAAO,CAAC;EAC3F,MAAM,aAAa,QAAQ,SAAS,cAAA;EACpC,MAAM,wBAAwB,QAAQ,SAAS,0BAA0B;EACzE,MAAM,+BAA+B,QAAQ,SAAS,iCAAiC;EACvF,MAAM,cAAc,QAAQ,SAAS,cAClCC,qBAAAA,0BAA0B,QAAQ,QAAQ,YAAY,WAAW,QAAQ,QAAQ,YAAY,OAAO,IACpG;EACH,MAAM,gBAAgB,QAAQ,SAAS,gBAAgB,GAAA,CAAI,KAAK,KAAK,KAAA;EAErE,MAAM,iBAAiB,wBACpB,MAAM,mBAAmB;GAAE;GAAS,eAAe;EAAqB,CAAC,IACzE,CAAC,YAAY;EAChB,MAAM,cAAc,MAAM,QAAQ,uBAAuB;GACxD,eAAe;GACf;GACA,OAAO;GACP;EACD,CAAC;EACD,IAAI,UAAU,MAAM,qBAAqB;GACxC;GACA,eAAe;GACf,cAAc,QAAQ;GACtB;GACA;GACA;GACA;EACD,CAAC;EACD,IAAI,aACH,UAAU,MAAM,mCAAmC;GAClD;GACA;GACA,eAAe;GACf;GACA;GACA,OAAO;GACP,OAAO;EACR,CAAC;EAEF,MAAM,kBAAkB,QAAQ,YAAY,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO;EACnE,MAAM,gBAAgB,MAAM,QAAQ,iBAAiB,EAAE,eAAe,qBAAqB,CAAC;EAE5F,IAAI,eACE;QAAA,MAAM,SAAS,SACnB,IAAI,CAAC,MAAM,eACV,MAAM,YAAY,GAAG,cAAc,UAAU,MAAM;EAAA;EAKtD,MAAM,sBAAsB;GAC3B;GACA,eAAe;GACf;GACA;EACD,CAAC;EAED,OAAO;GACN;GACA,SAAS,QAAQ;GACjB,eAAe;GACf,cAAc,QAAQ;GACtB;GACA,UAAUL,UAAAA,QAAK,SAAS,QAAQ,YAAY;GAC5C;GACA;GACA,yCAAyB,IAAI,IAAI;GACjC,0CAA0B,IAAI,IAAI;GAClC;GACA,sBAAsB;GACtB,cAAc;GACd,6BAA6B;GAC7B,aAAa,eAAe,KAAA;GAC5B;GACA,8BAAc,IAAI,IAAI;GACtB,8BAAc,IAAI,IAAI;GACtB,oCAAoB,IAAI,IAAI;GAC5B,qCAAqB,IAAI,IAAI;GAC7B,2BAAW,IAAI,IAAI;GACnB,6BAA6B,KAAA;EAC9B;CACD;CAEA,SAAS,qBAAqB,SAAuD;EACpF,OAAO,QAAQ,KAAK,OAAO,WAAW;GACrC,GAAG;GACH;GACA,kBAAkB,QAAQ;GAC1B,YAAY,sBAAsB,MAAM,UAAU;GAClD,WAAW,qBAAqB,MAAM,UAAU;GAChD,cAAc,mBAAmB,MAAM,SAAS;EACjD,EAAE;CACH;CAEA,SAAS,aAAa,SAA4C;EACjE,OAAO;GACN,SAAS,QAAQ,QAAQ;GACzB,eAAe,QAAQ,QAAQ;GAC/B,cAAc,QAAQ,QAAQ;GAC9B,UAAU,QAAQ,QAAQ;GAC1B,SAAS,QAAQ;GACjB,SAAS,QAAQ;GACjB,cAAc,KAAK,IAAI,GAAG,QAAQ,QAAQ,QAAQ,SAAS,CAAC;GAC5D,aAAa,KAAK,IAAI,GAAG,QAAQ,QAAQ,QAAQ,SAAS,CAAC;GAC3D,aAAa,6BAA6B,QAAQ,WAAW;GAC7D,gBAAgB,QAAQ,QAAQ;GAChC,sBAAsB,QAAQ,QAAQ;GACtC,0BAA0B,QAAQ,QAAQ,QAAQ,MAAM,UAAU,CAAC,MAAM,WAAW;GACpF,SAAS,qBAAqB,QAAQ,QAAQ,OAAO;GACrD,iBAAiB,qBAAqB,QAAQ,QAAQ,eAAe;GACrE,eAAe,EACd,iBAAiB,CAAC,GAAG,QAAQ,QAAQ,uBAAuB,EAC7D;GACA,GAAI,QAAQ,QAAQ,cAAc,EAAE,aAAa,QAAQ,QAAQ,YAAY,IAAI,CAAC;GAClF,GAAI,QAAQ,QAAQ,eAAe,EAAE,cAAc,QAAQ,QAAQ,aAAa,IAAI,CAAC;EACtF;CACD;CAEA,eAAe,qBAAqB,SAAkE;EACrG,IAAI,QAAQ,QAAQ,sBACnB,OAAO;EAGR,MAAM,iBAAiB,MAAM,mBAAmB;GAC/C,SAAS,QAAQ,QAAQ;GACzB,eAAe,QAAQ,QAAQ;EAChC,CAAC;EACD,QAAQ,QAAQ,iBAAiB;EACjC,QAAQ,QAAQ,uBAAuB;EACvC,QAAQ,QAAQ,mBAAmB,MAAM;EACzC,OAAO;CACR;CAEA,eAAe,4BAA4B,SAAkE;EAC5G,IAAI,QAAQ,QAAQ,6BACnB,OAAO;EAGR,MAAM,kBAAkB,QAAQ,QAAQ,QAAQ,QAAQ,UAAU,MAAM,eAAe,CAAC,MAAM,aAAa;EAC3G,IAAI,gBAAgB,SAAS,GAAG;GAC/B,QAAQ,QAAQ,8BAA8B;GAC9C,OAAO;EACR;EAEA,IAAI;GACH,MAAM,oBAAoB,MAAM,QAAQ,QAAQ,QAAQ,6BAA6B;IACpF,eAAe,QAAQ,QAAQ;IAC/B,OAAA;GACD,CAAC;GACD,MAAM,mBAAmB,QAAQ,QAAQ,QAAQ,MAAM,UAAU,MAAM,aAAa;GACpF,IAAI,UAAU,qBAAqB;IAAE;IAAmB,aAAa;GAAgB,CAAC;GACtF,IAAI,QAAQ,QAAQ,YAAY,MAC/B,UAAU,8BAA8B,OAAO;GAEhD,IAAI,kBACH,UAAU,CAAC,GAAG,SAAS,gBAAgB;GAExC,QAAQ,QAAQ,UAAU;GAC1B,QAAQ,QAAQ,8BAA8B;GAC9C,QAAQ,QAAQ,aAAa,MAAM;GACnC,QAAQ,QAAQ,mBAAmB,MAAM;GACzC,QAAQ,QAAQ,oBAAoB,MAAM;GAC1C,OAAO;EACR,QAAQ;GACP,QAAQ,QAAQ,8BAA8B;GAC9C,OAAO;EACR;CACD;CAEA,eAAe,kBAAkB,SAAkE;EAClG,IAAI,QAAQ,QAAQ,gBAAA,KACnB,OAAO;EAGR,MAAM,wBAAwB,QAAQ,QAAQ,QAAQ,QACpD,UAAU,MAAM,eAAe,CAAC,MAAM,aACxC,CAAC,CAAC;EACF,IAAI,wBAAwB,QAAQ,QAAQ,cAAc;GACzD,QAAQ,QAAQ,eAAA;GAChB,OAAO;EACR;EAEA,MAAM,cAAc,MAAM,QAAQ,QAAQ,QAAQ,uBAAuB;GACxE,eAAe,QAAQ,QAAQ;GAC/B,cAAc,QAAQ,QAAQ;GAC9B,OAAA;EACD,CAAC;EACD,MAAM,UAAU,MAAM,qBAAqB;GAC1C,SAAS,QAAQ,QAAQ;GACzB,eAAe,QAAQ,QAAQ;GAC/B,cAAc,QAAQ,QAAQ;GAC9B,cAAc,QAAQ,QAAQ;GAC9B;GACA,8BAA8B,QAAQ,QAAQ;GAC9C,YAAA;EACD,CAAC;EACD,MAAM,oBAAoB,QAAQ,QAAQ,UAAU,MAAM,eAAe,CAAC,MAAM,aAAa,CAAC,CAAC;EAC/F,QAAQ,QAAQ,UAAU;EAC1B,QAAQ,QAAQ,eAAA;EAChB,QAAQ,QAAQ,aAAa,MAAM;EACnC,QAAQ,QAAQ,mBAAmB,MAAM;EACzC,QAAQ,QAAQ,oBAAoB,MAAM;EAC1C,OAAO,oBAAoB;CAC5B;CAEA,SAAS,oBAAoB,SAGL;EACvB,IAAI,QAAQ,QAAQ,YAAY,QAAQ,QAAQ,qBAAqB,YACpE,OAAO,QAAQ,QAAQ;EAGxB,OAAO,uBAAuB;GAC7B,iBAAiB,QAAQ,QAAQ;GACjC,iBAAiB,QAAQ,QAAQ;GACjC,iBAAiB,QAAQ,QAAQ;EAClC,CAAC;CACF;CAEA,eAAe,eAAe,SAKL;EACxB,MAAM,mBAAmB,QAAQ,oBAAoB;EACrD,MAAM,gBAAgB,oBAAoB;GACzC,SAAS,QAAQ;GACjB;EACD,CAAC;EACD,MAAM,sBAAsB,KAAK,IAAI,GAAG,KAAK,IAAI,QAAQ,WAAW,QAAQ,OAAO,CAAC;EACpF,MAAM,oBAAoB,KAAK,IAAI,qBAAqB,KAAK,IAAI,QAAQ,WAAW,QAAQ,OAAO,CAAC;EACpG,MAAM,WAAW,GAAG,iBAAiB,GAAG,oBAAoB,GAAG;EAC/D,MAAM,SAAS,QAAQ,QAAQ,aAAa,IAAI,QAAQ;EACxD,IAAI,QACH,OAAO;EAGR,IAAI,QAAQ,QAAQ,YAAY,QAAQ,qBAAqB,YAAY;GACxE,MAAM,UAAU,MAAM,qBAAqB;IAC1C,SAAS,QAAQ;IACjB,WAAW;IACX,SAAS;GACV,CAAC;GACD,QAAQ,QAAQ,aAAa,IAAI,UAAU,OAAO;GAClD,OAAO;EACR;EAEA,MAAM,aAAa,qBAAqB;GACvC,SAAS;GACT,WAAW;GACX,SAAS;EACV,CAAC;EACD,IAAI,CAAC,YACJ,OAAO,mBAAmB;GACzB,OAAO;GACP,WAAW;GACX,SAAS;GACT;GACA,OAAO;EACR,CAAC;EAGF,MAAM,aAAa,WAAW,YAC3B,MAAM,qBAAqB;GAC3B,SAAS,QAAQ;GACjB,OAAO,WAAW;GAClB,YAAY;EACb,CAAC,IACA;EACH,MAAM,YAAY,MAAM,qBAAqB;GAC5C,SAAS,QAAQ;GACjB,OAAO,WAAW;GAClB,YAAY;EACb,CAAC;EACD,MAAM,aAAa,WAAW,YAC3B,MAAM,mBAAmB;GACzB,SAAS,QAAQ;GACjB,OAAO,WAAW;GAClB,YAAY;EACb,CAAC,IACA;EACH,MAAM,YAAY,MAAM,mBAAmB;GAC1C,SAAS,QAAQ;GACjB,OAAO,WAAW;GAClB,YAAY;EACb,CAAC;EACD,MAAM,UAAU,iBAAiB;GAChC,OAAO;GACP,eAAe,WAAW;GAC1B,cAAc,WAAW;GACzB;GACA;GACA,WAAW;GACX,SAAS;GACT;GACA;GACA;EACD,CAAC;EACD,QAAQ,QAAQ,aAAa,IAAI,UAAU,OAAO;EAClD,OAAO;CACR;CAEA,eAAe,uBAAuB,SAGjB;EACpB,IAAI,QAAQ,QAAQ,YAAY,MAC/B,OAAO;EAGR,MAAM,gBAAgB,QAAQ,gBAC5B,KAAK,UAAU,QAAQ,QAAQ,QAAQ,MAAM,CAAC,CAC9C,QAAQ,UACR,QACC,SACA,CAAC,MAAM,iBACP,MAAM,eACN,MAAM,YACN,CAAC,QAAQ,QAAQ,wBAAwB,IAAI,MAAM,QAAQ,KAC3D,CAAC,QAAQ,QAAQ,yBAAyB,IAAI,MAAM,QAAQ,CAC7D,CACD,CAAC,CACA,QAA6B,SAAS,UAAU;GAChD,IAAI,CAAC,MAAM,YAAY,QAAQ,MAAM,cAAc,UAAU,aAAa,MAAM,QAAQ,GACvF,OAAO;GAGR,QAAQ,KAAK,KAAK;GAClB,OAAO;EACR,GAAG,CAAC,CAAC,CAAC,CACL,MAAM,EAA+B;EAEvC,IAAI,CAAC,cAAc,QAClB,OAAO;EAGR,IAAI,YAAY;EAChB,KAAK,MAAM,SAAS,eAAe;GAClC,MAAM,WAAW,MAAM;GACvB,IAAI,CAAC,UACJ;GAGD,QAAQ,QAAQ,yBAAyB,IAAI,QAAQ;GACrD,MAAM,kBAAkB,MAAM,QAAQ,QAAQ,QAAQ,0BAA0B;IAC/E,eAAe,QAAQ,QAAQ;IAC/B,cAAc,QAAQ,QAAQ;IAC9B;GACD,CAAC;GACD,QAAQ,QAAQ,yBAAyB,OAAO,QAAQ;GACxD,QAAQ,QAAQ,wBAAwB,IAAI,QAAQ;GAEpD,IAAI,gBAAgB,QAAQ;IAC3B,QAAQ,QAAQ,gBAAgB,KAAK,GAAG,eAAe;IACvD,YAAY;GACb;EACD;EAEA,IAAI,CAAC,WACJ,OAAO;EAGR,QAAQ,QAAQ,kBAAkB,QAAQ,QAAQ,gBAAgB,UAChE,MAAM,UAAU,KAAK,YAAY,MAAM,aAAa,KAAK,SAAS,cAAc,MAAM,QAAQ,CAChG;EACA,KAAK,MAAM,YAAY,QAAQ,QAAQ,aAAa,KAAK,GACxD,IAAI,SAAS,WAAW,WAAW,GAClC,QAAQ,QAAQ,aAAa,OAAO,QAAQ;EAG9C,KAAK,MAAM,YAAY,QAAQ,QAAQ,mBAAmB,KAAK,GAC9D,IAAI,SAAS,WAAW,WAAW,GAClC,QAAQ,QAAQ,mBAAmB,OAAO,QAAQ;EAGpD,KAAK,MAAM,YAAY,QAAQ,QAAQ,oBAAoB,KAAK,GAC/D,IAAI,SAAS,WAAW,WAAW,GAClC,QAAQ,QAAQ,oBAAoB,OAAO,QAAQ;EAIrD,OAAO;CACR;CAEA,eAAe,gCAAgC,SAGY;EAC1D,IAAI,QAAQ,iBAAiB,SAAS,GACrC,OAAO;EAGR,KAAK,IAAI,QAAQ,QAAQ,iBAAiB,SAAS,GAAG,QAAQ,GAAG,SAAS,GAAG;GAC5E,MAAM,YAAY,QAAQ,iBAAiB,QAAQ;GACnD,MAAM,UAAU,QAAQ,iBAAiB;GAMzC,KAAI,MALkB,eAAe;IACpC,SAAS,QAAQ;IACjB;IACA;GACD,CAAC,EAAA,CACW,YACX,OAAO;IAAE;IAAW;GAAQ;EAE9B;EAEA,OAAO;CACR;CAEA,eAAe,iBAAiB,SAMC;EAChC,MAAM,mBAAmB,QAAQ,oBAAoB;EACrD,MAAM,sBAAsB,KAAK,IAAI,GAAG,KAAK,IAAI,QAAQ,WAAW,QAAQ,OAAO,CAAC;EACpF,MAAM,oBAAoB,KAAK,IAAI,qBAAqB,KAAK,IAAI,QAAQ,WAAW,QAAQ,OAAO,CAAC;EACpG,MAAM,wBAAwB,QAAQ,wBAAwB,CAAC,EAAA,CAAG,QAAQ,UAAU,OAAO,UAAU,KAAK,CAAC;EAE3G,MAAM,WAAW,GAAG,iBAAiB,GAAG,oBAAoB,GAAG,kBAAkB,GAD7D,qBAAqB,SAAS,qBAAqB,KAAK,GAAG,IAAI;EAEnF,MAAM,SAAS,QAAQ,QAAQ,mBAAmB,IAAI,QAAQ;EAC9D,IAAI,QACH,OAAO;EAGR,MAAM,gBAAgB,oBAAoB;GACzC,SAAS,QAAQ;GACjB;EACD,CAAC;EACD,MAAM,+BAAe,IAAI,IAAoB;EAC7C,IAAI,CAAC,QAAQ,QAAQ,sBACpB,MAAM,qBAAqB,EAAE,SAAS,QAAQ,QAAQ,CAAC;EAExD,MAAM,mBAAmB,IAAI,IAAI,QAAQ,QAAQ,cAAc;EAC/D,MAAM,qBAAqB,qBAAqB,SAC7C,uBACA,MAAM,KAAK,EAAE,QAAQ,oBAAoB,oBAAoB,IAAI,GAAG,UAAU,sBAAsB,QAAQ,CAAC;EAEhH,KAAK,MAAM,SAAS,oBAAoB;GACvC,MAAM,QAAQ,cAAc;GAC5B,IAAI,CAAC,OACJ;GAGD,MAAM,eAAe,MAAM,gBACxB,MAAM,QAAQ,QAAQ,QAAQ,qBAAqB,EAAE,eAAe,QAAQ,QAAQ,cAAc,CAAC,IACnG,MAAM,QAAQ,QAAQ,QAAQ,kBAAkB;IAChD,eAAe,QAAQ,QAAQ;IAC/B,UAAU,MAAM;GACjB,CAAC;GAEH,KAAK,MAAM,gBAAgB,cAAc;IACxC,IAAI,CAAC,gBAAiB,CAAC,iBAAiB,IAAI,YAAY,KAAK,iBAAiB,QAAQ,QAAQ,cAC7F;IAGD,aAAa,IAAI,eAAe,aAAa,IAAI,YAAY,KAAK,KAAK,CAAC;GACzE;EACD;EAEA,MAAM,QAAQ,CAAC,GAAG,aAAa,QAAQ,CAAC,CAAC,CACvC,KAAK,CAAC,cAAc,kBAAkB;GACtC;GACA;GACA,eAAe,iBAAiB,QAAQ,QAAQ;EACjD,EAAE,CAAC,CACF,UAAU,MAAM,UAAU;GAC1B,IAAI,KAAK,gBAAgB,MAAM,aAC9B,OAAO,MAAM,cAAc,KAAK;GAGjC,IAAI,KAAK,kBAAkB,MAAM,eAChC,OAAO,OAAO,MAAM,aAAa,IAAI,OAAO,KAAK,aAAa;GAG/D,OAAO,KAAK,aAAa,cAAc,MAAM,YAAY;EAC1D,CAAC,CAAC,CACD,MAAM,GAAG,GAAG;EAEd,QAAQ,QAAQ,mBAAmB,IAAI,UAAU,KAAK;EACtD,OAAO;CACR;CAEA,eAAe,sBAAsB,SAM8B;EAClE,MAAM,mBAAmB,QAAQ,oBAAoB;EACrD,MAAM,sBAAsB,KAAK,IAAI,GAAG,KAAK,IAAI,QAAQ,WAAW,QAAQ,OAAO,CAAC;EACpF,MAAM,oBAAoB,KAAK,IAAI,qBAAqB,KAAK,IAAI,QAAQ,WAAW,QAAQ,OAAO,CAAC;EAKpG,MAAM,aAAa,qBAAqB;GACvC,SALqB,oBAAoB;IACzC,SAAS,QAAQ;IACjB;GACD,CAEsB;GACrB,WAAW;GACX,SAAS;EACV,CAAC;EACD,IAAI,CAAC,YACJ,OAAO,CAAC;EAGT,MAAM,QAA+D,CAAC;EACtE,KAAK,MAAM,gBAAgB,QAAQ,eAAe;GACjD,MAAM,UAAU,aAAa,KAAK;GAClC,IAAI,CAAC,SACJ;GAED,IAAI,YAAY,QAAQ,QAAQ,cAAc;IAC7C,MAAM,KAAK;KACV,cAAc;KACd,SAAS,MAAM,eAAe;MAC7B,SAAS,QAAQ;MACjB,WAAW;MACX,SAAS;MACT;KACD,CAAC;IACF,CAAC;IACD;GACD;GAEA,MAAM,aAAa,WAAW,YAC3B,MAAM,gBAAgB;IACtB,SAAS,QAAQ;IACjB,OAAO,WAAW;IAClB,cAAc;GACf,CAAC,IACA;GACH,MAAM,YAAY,MAAM,gBAAgB;IACvC,SAAS,QAAQ;IACjB,OAAO,WAAW;IAClB,cAAc;GACf,CAAC;GACD,MAAM,KAAK;IACV,cAAc;IACd,SAAS,iBAAiB;KACzB,OAAO;KACP,eAAe,WAAW;KAC1B,cAAc,WAAW;KACzB;KACA;KACA,WAAW;KACX,SAAS;KACT,YAAY;KACZ,WAAW;KACX;IACD,CAAC;GACF,CAAC;EACF;EACA,OAAO;CACR;CAEA,eAAe,gBAAgB,SAIX;EACnB,MAAM,WAAW,GAAG,QAAQ,MAAM,GAAG,SAAS,QAAQ;EACtD,MAAM,SAAS,QAAQ,QAAQ,aAAa,IAAI,QAAQ;EACxD,IAAI,WAAW,KAAA,GACd,OAAO;EAER,IAAI;GACH,MAAM,UAAU,QAAQ,MAAM,gBAC3B,OAAA,GAAMC,iBAAAA,SAAAA,CAASD,UAAAA,QAAK,KAAK,QAAQ,QAAQ,eAAe,QAAQ,YAAY,GAAG,MAAM,IACrF,MAAM,QAAQ,QAAQ,QAAQ,mBAAmB;IACjD,eAAe,QAAQ,QAAQ;IAC/B,QAAQ,QAAQ,MAAM;IACtB,UAAU,QAAQ;GACnB,CAAC;GACH,QAAQ,QAAQ,aAAa,IAAI,UAAU,OAAO;GAClD,OAAO;EACR,QAAQ;GACP,QAAQ,QAAQ,aAAa,IAAI,UAAU,EAAE;GAC7C,OAAO;EACR;CACD;CAEA,eAAe,mBAAmB,SAI4B;EAC7D,MAAM,mBAAmB,QAAQ,oBAAoB;EACrD,MAAM,gBAAgB,oBAAoB;GACzC,SAAS,QAAQ;GACjB;EACD,CAAC;EAED,OAAO,QAAQ,IACd,QAAQ,aAAa,IAAI,OAAO,eAAe;GAC9C,MAAM,WAAW,GAAG,iBAAiB,GAAG;GACxC,MAAM,SAAS,QAAQ,QAAQ,oBAAoB,IAAI,QAAQ;GAC/D,IAAI,WAAW,KAAA,GACd,OAAO;IAAE;IAAY,WAAW;GAAO;GAGxC,MAAM,QAAQ,cAAc;GAC5B,IAAI,CAAC,SAAS,cAAc,GAAG;IAC9B,QAAQ,QAAQ,oBAAoB,IAAI,UAAU,CAAC;IACnD,OAAO;KAAE;KAAY,WAAW;IAAE;GACnC;GAEA,IAAI,YAAY;GAChB,IAAI,MAAM,eAAe;IACxB,MAAM,gBAAgB,cAAc,aAAa;IACjD,IAAI,eAQH,aAAY,MAPO,QAAQ,QAAQ,QAAQ,wBAAwB;KAClE,eAAe,QAAQ,QAAQ;KAC/B,WAAW;KACX,SAAS;KACT;KACA;IACD,CAAC,EAAA,CACgB,MAAM;GAEzB,OAQC,aAAY,MAPO,QAAQ,QAAQ,QAAQ,2BAA2B;IACrE,eAAe,QAAQ,QAAQ;IAC/B;IACA;IACA;IACA;GACD,CAAC,EAAA,CACgB,MAAM;GAGxB,QAAQ,QAAQ,oBAAoB,IAAI,UAAU,SAAS;GAC3D,OAAO;IAAE;IAAY;GAAU;EAChC,CAAC,CACF;CACD;CAEA,eAAe,qBAAqB,SAIhB;EACnB,IAAI,QAAQ,MAAM,eACjB,OAAO,QAAQ,QAAQ;EAGxB,IAAI,QAAQ,MAAM,UACjB,OAAO,QAAQ,MAAM;EAGtB,MAAM,oBAAoB,OAAO;EACjC,OAAO,QAAQ,MAAM,YAAY,QAAQ,QAAQ;CAClD;CAEA,eAAe,iBAAiB,SAGd;EACjB,QAAQ,QAAQ,6BAA6B,MAAM;EACnD,MAAM,aAAa,IAAI,gBAAgB;EACvC,QAAQ,QAAQ,8BAA8B;EAE9C,IAAI;GACH,MAAM,QAAQ,OAAO,WAAW,MAAM;EACvC,SAAS,OAAO;GACf,IAAI,aAAa,KAAK,KAAK,WAAW,OAAO,SAC5C;GAED,MAAM;EACP,UAAU;GACT,IAAI,QAAQ,QAAQ,gCAAgC,YACnD,QAAQ,QAAQ,8BAA8B,KAAA;EAEhD;CACD;CAEA,eAAe,4BAA4B,SAKX;EAC/B,IAAI;GACH,IAAI,QAAQ,YAAY,OAAO;IAC9B,MAAM,EAAE,WAAW,MAAM,OAAO,OAAO;KACtC,eAAe,QAAQ;KACvB,MAAMM,cAAAA,kBAAkB;MAAE,cAAc,QAAQ;MAAc,MAAM,QAAQ;KAAK,CAAC;IACnF,CAAC;IACD,OAAOC,cAAAA,iBAAiBC,cAAAA,uBAAuB,MAAM,GAAG,QAAQ,IAAI,CAAC,EAAE;GACxE;GAEA,MAAM,EAAE,WAAW,MAAM,OAAO,MAAM;IACrC,eAAe,QAAQ;IACvB,MAAMC,cAAAA,oBAAoB,EAAE,cAAc,QAAQ,aAAa,CAAC;GACjE,CAAC;GACD,OAAOF,cAAAA,iBAAiBG,cAAAA,oBAAoB,MAAM,GAAG,QAAQ,IAAI,CAAC,EAAE;EACrE,QAAQ;GACP;EACD;CACD;CAEA,eAAe,aAAa,SAK8B;EACzD,MAAM,mBAAmB,QAAQ,oBAAoB;EACrD,MAAM,sBAAsB,KAAK,IAAI,GAAG,KAAK,IAAI,QAAQ,WAAW,QAAQ,OAAO,CAAC;EACpF,MAAM,oBAAoB,KAAK,IAAI,qBAAqB,KAAK,IAAI,QAAQ,WAAW,QAAQ,OAAO,CAAC;EAKpG,MAAM,UAJgB,oBAAoB;GACzC,SAAS,QAAQ;GACjB;EACD,CAC4B,CAAC,CAAC;EAC9B,MAAM,eAAe,SAAS,YAAY,QAAQ,QAAQ;EAC1D,IAAI,CAAC,SACJ,OAAO;GAAE;GAAc,OAAO,CAAC;EAAE;EAGlC,IAAI;GACH,IAAI,QAAQ,QAAQ,YAAY,OAAO;IACtC,MAAM,EAAE,WAAW,MAAM,OAAO,OAAO;KACtC,eAAe,QAAQ,QAAQ;KAC/B,MAAMC,cAAAA,sBAAsB;MAC3B;MACA,UAAU,QAAQ,gBAAgB,KAAA,IAAY,QAAQ;KACvD,CAAC;IACF,CAAC;IACD,OAAO;KAAE;KAAc,OAAOH,cAAAA,uBAAuB,MAAM;IAAE;GAC9D;GAEA,MAAM,EAAE,WAAW,MAAM,OAAO,MAAM;IACrC,eAAe,QAAQ,QAAQ;IAC/B,MAAMC,cAAAA,oBAAoB;KACzB;KACA,UAAU,QAAQ,gBAAgB,KAAA,IAAY,QAAQ;IACvD,CAAC;GACF,CAAC;GACD,OAAO;IAAE;IAAc,OAAOC,cAAAA,oBAAoB,MAAM;GAAE;EAC3D,QAAQ;GACP,OAAO;IAAE;IAAc,OAAO,CAAC;GAAE;EAClC;CACD;CAEA,eAAe,aAAa,SAE2D;EACtF,MAAM,eAAe,QAAQ,QAAQ;EACrC,IAAI,QAAQ,QAAQ,YAAY,MAC/B,OAAO;GAAE;GAAc,SAAS,CAAC;EAAE;EAEpC,IAAI;GACH,MAAM,EAAE,WAAW,MAAM,OAAO,MAAM;IACrC,eAAe,QAAQ,QAAQ;IAC/B,MAAM;KAAC;KAAM;KAAO;KAAW;KAAM;KAAME,mBAAAA;IAAkB;GAC9D,CAAC;GACD,MAAM,cAAc,CACnB,GAAG,QAAQ,QAAQ,iBACnB,GAAG,QAAQ,QAAQ,QAAQ,QAAQ,UAAU,QAAQ,MAAM,WAAW,CAAC,CACxE;GACA,OAAO;IACN;IACA,SAASC,mBAAAA,oBAAoB;KAC5B,OAAOC,mBAAAA,mBAAmB,MAAM;KAChC;KACA;KACA,OAAO;IACR,CAAC;GACF;EACD,QAAQ;GACP,OAAO;IAAE;IAAc,SAAS,CAAC;GAAE;EACpC;CACD;CAEA,eAAe,kBAAkB,SAKqB;EACrD,MAAM,aAAa,QAAQ,cAAc;EACzC,MAAM,WAAW,QAAQ,QAAQ,QAC/B,KAAK,OAAO,WAAW;GAAE;GAAO;EAAM,EAAE,CAAC,CACzC,QAAQ,EAAE,YAAY,MAAM,eAAe,CAAC,MAAM,aAAa,CAAC,CAChE,MAAM,CAAC,UAAU;EACnB,MAAM,kCAAkB,IAAI,IAAoB;EAChD,KAAK,MAAM,EAAE,OAAO,WAAW,UAC9B,IAAI;GACH,MAAM,UAAU,MAAM,mBAAmB;IACxC,SAAS,QAAQ;IACjB;IACA,YAAY;GACb,CAAC;GACD,gBAAgB,IAAI,OAAO,OAAO;EACnC,QAAQ;GACP,gBAAgB,IAAI,OAAO,EAAE;EAC9B;EAED,MAAM,sBAAsB,SAAS,KAAK,EAAE,YAAY,KAAK;EAC7D,IAAI,QAAQ,YAAY,WACvB,OAAOC,uBAAAA,0BAA0B;GAChC,OAAO,QAAQ;GACf;GACA;EACD,CAAC;EAEF,OAAOC,uBAAAA,sBAAsB;GAC5B,OAAO,QAAQ;GACf;GACA;EACD,CAAC;CACF;CAEA,eAAe,qBAAqB,SAQH;EAChC,MAAM,kBAAkB,QAAQ,YAAY,KAAK,WAAW;GAC3D,GAAG;GACH,aAAa;EACd,EAAE;EAEF,IAAI,gBAAgB,QACnB,gBAAgB,gBAAgB,SAAS,EAAE,CAAC,WAAW,QAAQ;EAGhE,IAAI,UAAU;EACd,IAAI,QAAQ,gCAAgC,gBAAgB,UAAU,GACrE,IAAI;GAKH,UAAU,qBAAqB;IAAE,mBAAA,MAJD,QAAQ,QAAQ,6BAA6B;KAC5E,eAAe,QAAQ;KACvB,OAAO,KAAK,IAAI,QAAQ,YAAA,GAAgC;IACzD,CAAC;IACmD,aAAa;GAAgB,CAAC;EACnF,QAAQ;GACP,UAAU;EACX;EAGD,IAAI,QAAQ,QAAQ,YAAY,MAC/B,UAAU,8BAA8B,OAAO;EAGhD,OAAO,uBAAuB;GAC7B,SAAS,QAAQ;GACjB,eAAe,QAAQ;GACvB,cAAc,QAAQ;GACtB,cAAc,QAAQ;GACtB;EACD,CAAC;CACF;CAEA,eAAe,mBAAmB,SAAgF;EACjH,IAAI,QAAQ,QAAQ,YAAY,OAC/B,IAAI;GACH,MAAM,EAAE,WAAW,MAAM,OAAO,OAAO;IACtC,eAAe,QAAQ;IACvB,MAAM;KAAC;KAAY;KAAY;IAAI;GACpC,CAAC;GACD,MAAM,QAAQ,OACZ,MAAM,IAAQ,CAAC,CACf,KAAK,UAAU,MAAM,KAAK,CAAC,CAAC,CAC5B,OAAO,OAAO,CAAC,CACf,UAAU,MAAM,UAAU,KAAK,cAAc,KAAK,CAAC;GACrD,IAAI,MAAM,QACT,OAAO;EAET,QAAQ,CAER;EAGD,IAAI,QAAQ,QAAQ,YAAY,MAC/B,IAAI;GACH,MAAM,EAAE,WAAW,MAAM,OAAO,MAAM;IACrC,eAAe,QAAQ;IACvB,MAAM,CAAC,QAAQ,MAAM;GACtB,CAAC;GACD,MAAM,QAAQ,OACZ,MAAM,QAAQ,CAAC,CACf,KAAK,UAAU,MAAM,KAAK,CAAC,CAAC,CAC5B,OAAO,OAAO,CAAC,CACf,UAAU,MAAM,UAAU,KAAK,cAAc,KAAK,CAAC;GACrD,IAAI,MAAM,QACT,OAAO;EAET,QAAQ,CAER;EAGD,MAAM,QAAkB,CAAC;EACzB,MAAM,sBAAsB;GAC3B,eAAe,QAAQ;GACvB,kBAAkB,QAAQ;GAC1B;EACD,CAAC;EACD,OAAO,MAAM,UAAU,MAAM,UAAU,KAAK,cAAc,KAAK,CAAC;CACjE;CAEA,eAAe,sBAAsB,SAInB;EACjB,MAAM,mBAAmB,OAAA,GAAMC,iBAAAA,QAAAA,CAAQ,QAAQ,kBAAkB,EAAE,eAAe,KAAK,CAAC;EACxF,KAAK,MAAM,kBAAkB,kBAAkB;GAC9C,IAAI,eAAe,YAAY,KAAK,8BAA8B,IAAI,eAAe,IAAI,GACxF;GAGD,MAAM,eAAejB,UAAAA,QAAK,KAAK,QAAQ,kBAAkB,eAAe,IAAI;GAC5E,IAAI,eAAe,YAAY,GAAG;IACjC,MAAM,sBAAsB;KAC3B,eAAe,QAAQ;KACvB,kBAAkB;KAClB,OAAO,QAAQ;IAChB,CAAC;IACD;GACD;GAEA,IAAI,CAAC,eAAe,OAAO,GAC1B;GAGD,QAAQ,MAAM,KAAKA,UAAAA,QAAK,SAAS,QAAQ,eAAe,YAAY,CAAC,CAAC,QAAQ,OAAO,GAAG,CAAC;EAC1F;CACD;CAEA,eAAe,uBAAuB,SAML;EAChC,IAAI,CAAE,MAAM,OAAO,WAAW,EAAE,UAAU,QAAQ,aAAa,CAAC,GAC/D,OAAO,QAAQ;EAGhB,MAAM,YAAY,QAAQ,QAAQ,GAAG,EAAE;EACvC,MAAM,oBAAoB,QAAQ,QAAQ,QAAQ,UAAU,MAAM,eAAe,CAAC,MAAM,aAAa,CAAC,CAAC,GAAG,EAAE;EAC5G,IAAI,WAAW,eACd,OAAO,QAAQ;EAGhB,IAAI,mBAQF;OAAA,OAAA,GAP4BC,iBAAAA,SAAAA,CAAS,QAAQ,cAAc,MAAM,MAO9C,MANU,QAAQ,QAAQ,mBAAmB;IAChE,eAAe,QAAQ;IACvB,QAAQ,kBAAkB;IAC1B,UAAU,kBAAkB,YAAY,QAAQ;GACjD,CAAC,MAGC,kBAAkB,YAAY,QAAQ,kBAAkB,QAAQ,cAEjE,OAAO,QAAQ;EAAA;EAIjB,MAAM,sBAAM,IAAI,KAAK;EACrB,OAAO,CACN,GAAG,QAAQ,SACX;GACC,IAAI;GACJ,UAAU;GACV,eAAe;GACf,UAAU,KAAA;GACV,YAAY,IAAI,YAAY;GAC5B,YAAY;GACZ,aAAa;GACb,eAAe;GACf,aAAa;GACb,WAAW,IAAI,QAAQ;GACvB,UAAU,QAAQ;EACnB,CACD;CACD;CAEA,SAAS,uBAAuB,SAIR;EACvB,IAAI,CAAC,QAAQ,gBAAgB,MAC5B,OAAO,QAAQ;EAGhB,MAAM,4BAA4B,QAAQ,gBAAgB,QAAQ,QAAQ,UAAU;GACnF,IAAI,CAAC,MAAM,UACV,OAAO;GAER,MAAM,WAAW,OAAO,IAAI,MAAM,QAAQ,KAAK,CAAC;GAChD,SAAS,KAAK,KAAK;GACnB,OAAO,IAAI,MAAM,UAAU,QAAQ;GACnC,OAAO;EACR,mBAAG,IAAI,IAAiC,CAAC;EAEzC,OAAO,QAAQ,gBAAgB,SAAS,UAAU;GACjD,IACC,MAAM,iBACN,CAAC,MAAM,eACP,CAAC,MAAM,YACP,CAAC,QAAQ,gBAAgB,IAAI,MAAM,QAAQ,GAE3C,OAAO,CAAC,KAAK;GAGd,OAAO,0BAA0B,IAAI,MAAM,QAAQ,KAAK,CAAC,KAAK;EAC/D,CAAC;CACF;CAEA,eAAe,qBAAqB,SAIX;EACxB,MAAM,gBAAgB,oBAAoB;GAAE,SAAS,QAAQ;GAAS,kBAAkB;EAAW,CAAC;EACpG,MAAM,sBAAsB,KAAK,IAAI,GAAG,KAAK,IAAI,QAAQ,WAAW,QAAQ,OAAO,CAAC;EACpF,MAAM,oBAAoB,KAAK,IAAI,qBAAqB,KAAK,IAAI,QAAQ,WAAW,QAAQ,OAAO,CAAC;EACpG,MAAM,QAAQ,cAAc;EAC5B,IAAI,CAAC,OACJ,OAAO,mBAAmB;GACzB,OAAO;GACP,WAAW;GACX,SAAS;GACT,kBAAkB;GAClB,OAAO;EACR,CAAC;EAGF,MAAM,YAAY,MAAM,qBAAqB;GAC5C,SAAS,QAAQ;GACjB;GACA,YAAY;EACb,CAAC;EACD,MAAM,qBAAqB,wBAAwB,oBAAoB,oBAAoB,IAAI;EAC/F,MAAM,gBAAgB,sBAAsB,IAAI,cAAc,sBAAsB,KAAA;EACpF,MAAM,eAAe,gBAClB,MAAM,qBAAqB;GAC3B,SAAS,QAAQ;GACjB,OAAO;GACP,YAAY;EACb,CAAC,IACA,MAAM,gBACL,QAAQ,QAAQ,eAChB,MAAM,kCAAkC;GACxC,SAAS,QAAQ;GACjB;GACA,aAAa;EACd,CAAC;EAoBJ,OAAO;GACN,GAAG,iBAAiB;IACnB,OAAO;IACP;IACA,cAAc;IACd,YAxBiB,gBAChB,MAAM,mBAAmB;KACzB,SAAS,QAAQ;KACjB,OAAO;KACP,YAAY;IACb,CAAC,IACA,MAAM,gBACL,KACA,MAAM,oBAAoB;KAC1B,SAAS,QAAQ;KACjB,QAAQ,GAAG,MAAM,SAAS;KAC1B,UAAU;IACX,CAAC;IAaF,WAAA,MAZsB,mBAAmB;KAC1C,SAAS,QAAQ;KACjB;KACA,YAAY;IACb,CAAC;IASC,WAAW;IACX,SAAS;IACT,YAAY;IACZ;IACA,kBAAkB;GACnB,CAAC;GACD,OAAO,MAAM,gBAAgB,cAAc,MAAM,kBAAkB,YAAY,MAAM;EACtF;CACD;CAEA,eAAe,mBAAmB,SAId;EACnB,MAAM,eAAe,QAAQ,MAAM,gBAChC,QAAQ,QAAQ,eAChB,MAAM,qBAAqB,OAAO;EACrC,MAAM,WAAW,GAAG,QAAQ,MAAM,GAAG,GAAG;EACxC,MAAM,SAAS,QAAQ,QAAQ,aAAa,IAAI,QAAQ;EACxD,IAAI,WAAW,KAAA,GACd,OAAO;EAGR,MAAM,UAAU,QAAQ,MAAM,gBAC3B,OAAA,GAAMA,iBAAAA,SAAAA,CAAS,QAAQ,QAAQ,cAAc,MAAM,IACnD,MAAM,QAAQ,QAAQ,QAAQ,mBAAmB;GACjD,eAAe,QAAQ,QAAQ;GAC/B,QAAQ,QAAQ,MAAM;GACtB,UAAU;EACX,CAAC;EACH,QAAQ,QAAQ,aAAa,IAAI,UAAU,OAAO;EAClD,OAAO;CACR;CAEA,eAAe,oBAAoB,SAIjB;EACjB,MAAM,cAAc,QAAQ,QAAQ,QAAQ,QAAQ;EACpD,IAAI,CAAC,eAAe,YAAY,YAAY,YAAY,eACvD;EAGD,IAAI,aAAa;EACjB,KAAK,IAAI,QAAQ,QAAQ,aAAa,GAAG,QAAQ,QAAQ,QAAQ,QAAQ,QAAQ,SAAS,GACzF,IAAI,QAAQ,QAAQ,QAAQ,MAAM,EAAE,UAAU;GAC7C,aAAa;GACb;EACD;EAGD,IAAI,aAAa,GAAG;GACnB,YAAY,WAAW,QAAQ,QAAQ;GACvC;EACD;EAEA,IAAI,cAAc,QAAQ,QAAQ,QAAQ,WAAW,CAAC,YAAY,QAAQ,QAAQ;EAClF,KAAK,IAAI,QAAQ,YAAY,QAAQ,QAAQ,YAAY,SAAS,GAAG;GACpE,MAAM,eAAe,QAAQ,QAAQ,QAAQ;GAC7C,MAAM,gBAAgB,QAAQ,QAAQ,QAAQ,QAAQ;GACtD,IAAI,CAAC,eACJ;GAGD,IAAI,CAAC,cAAc,UAAU;IAC5B,IAAI,eAAe;IACnB,IAAI,aAAa,eAAe,CAAC,aAAa,eAC7C,eAAe,MAAM,kCAAkC;KACtD,SAAS,QAAQ;KACjB,OAAO;KACP;IACD,CAAC;IAEF,cAAc,WAAW;GAC1B;GAEA,cAAc,cAAc,YAAY;EACzC;CACD;AACD;AAEA,SAAgB,6BACf,aACgC;CAChC,IAAI,CAAC,aACJ,OAAO,EAAE,GAAG,6BAA6B;CAG1C,OAAO;EACN,cACC,OAAO,YAAY,iBAAiB,WACjC,YAAY,eACZ,6BAA6B;EACjC,kBAAkB,YAAY,qBAAqB;EACnD,oBACC,OAAO,YAAY,uBAAuB,WACvC,YAAY,qBACZ,6BAA6B;EACjC,uBAAuB,YAAY,0BAA0B;EAC7D,YAAY,YAAY,eAAe,YAAY,YAAY,6BAA6B;EAC5F,aAAa,YAAY,gBAAgB,SAAS,SAAS,6BAA6B;EACxF,gBAAgB,YAAY,mBAAmB,SAAS,SAAS,6BAA6B;EAC9F,kBACC,YAAY,qBAAqB,aAAa,aAAa,6BAA6B;EACzF,2BAA2B,YAAY,8BAA8B;EACrE,QACC,YAAY,WAAW,QACvB,YAAY,WAAW,SACvB,YAAY,WAAW,SACvB,YAAY,WAAW,SACvB,YAAY,WAAW,SACpB,YAAY,SACZ,6BAA6B;EACjC,cAAc,OAAO,YAAY,iBAAiB,WAAW,YAAY,aAAa,KAAK,IAAI;EAC/F,iBACC,YAAY,oBAAoB,WAAW,YAAY,oBAAoB,SACxE,YAAY,kBACZ,6BAA6B;EACjC,aAAa,YAAY,gBAAgB;EACzC,cACC,YAAY,iBAAiB,UAC7B,YAAY,iBAAiB,UAC7B,YAAY,iBAAiB,UAC7B,YAAY,iBAAiB,aAC1B,YAAY,eACZ,6BAA6B;CAClC;AACD;AAEA,SAAS,mBAAmB,MAMZ;CACf,OAAO;EACN,OAAO,KAAK;EACZ,OAAO,KAAK;EACZ,UAAU;EACV,WAAW;EACX,WAAW;EACX,WAAW;EACX,WAAW;EACX,YAAY;EACZ,WAAW,KAAK;EAChB,SAAS,KAAK;EACd,kBAAkB,KAAK;EACvB,YAAY;EACZ,WAAW;EACX,YAAY;EACZ,WAAW;EACX,mBAAmB,CAAC;CACrB;AACD;AAEA,SAAS,iBAAiB,MAWV;CACf,MAAM,QAAQiB,mBAAAA,iBAAiB,KAAK,YAAY,KAAK,SAAS;CAC9D,MAAM,QAAQ,KAAK,gBAChB,GAAG,KAAK,cAAc,cAAc,MAAM,KAAK,aAAa,kBAC5D,uBAAuB,KAAK,aAAa;CAC5C,MAAM,WAAW,KAAK,aAAa,gBAChC,iBACA,GAAG,oBAAoB,KAAK,aAAa,UAAU,EAAE,KAAK,KAAK,aAAa;CAE/E,OAAO;EACN,OAAO,KAAK;EACZ;EACA;EACA,WAAW;EACX,WAAW,MAAM;EACjB,WAAW,MAAM;EACjB,WAAW,MAAM;EACjB,YAAY,MAAM;EAClB,WAAW,KAAK;EAChB,SAAS,KAAK;EACd,kBAAkB,KAAK;EACvB,YAAY,KAAK;EACjB,WAAW,KAAK;EAChB,YAAY,KAAK;EACjB,WAAW,KAAK;EAChB,mBAAmB,MAAM,aACtB,CAAC,IACDC,4BAAAA,uBAAuB;GACvB,YAAY,KAAK;GACjB,WAAW,KAAK;GAChB,YAAY,KAAK;GACjB,WAAW,KAAK;GAChB,eAAe,KAAK,aAAa;EAClC,CAAC;CACJ;AACD;AAEA,SAAS,qBAAqB,MAGN;CACvB,MAAM,qBAAqB,IAAI,IAAI,KAAK,YAAY,KAAK,UAAU,CAAC,MAAM,UAAU,KAAK,CAAC,CAAC;CAC3F,MAAM,cAAc,KAAK,YACvB,KAAK,UAAU,KAAK,kBAAkB,WAAW,cAAc,UAAU,aAAa,MAAM,QAAQ,CAAC,CAAC,CACtG,QAAQ,UAAU,SAAS,CAAC;CAE9B,IAAI,CAAC,YAAY,QAChB,OAAO,KAAK;CAGb,MAAM,aAAa,KAAK,IAAI,GAAG,WAAW;CAC1C,MAAM,WAAW,KAAK,IAAI,GAAG,WAAW;CACxC,MAAM,SAAS,KAAK,kBAClB,MAAM,YAAY,WAAW,CAAC,CAAC,CAC/B,KAAK,UAAU,mBAAmB,IAAI,MAAM,QAAQ,KAAK,KAAK;CAEhE,KAAK,MAAM,SAAS,KAAK,aACxB,IAAI,CAAC,OAAO,MAAM,cAAc,UAAU,aAAa,MAAM,QAAQ,GACpE,OAAO,KAAK,KAAK;CAInB,OAAO,OAAO,UACZ,MAAM,UAAU,KAAK,YAAY,MAAM,aAAa,KAAK,SAAS,cAAc,MAAM,QAAQ,CAChG;AACD;AAEA,SAAS,8BAA8B,SAAmD;CACzF,OAAO,QAAQ,QAA6B,SAAS,UAAU;EAC9D,MAAM,gBAAgB,QAAQ,GAAG,EAAE;EACnC,IAAI,CAAC,eAAe,YAAY,cAAc,aAAa,MAAM,UAAU;GAC1E,QAAQ,KAAK,KAAK;GAClB,OAAO;EACR;EAEA,IAAI,cAAc,eAAe,MAAM,aAAa;GACnD,QAAQ,KAAK,KAAK;GAClB,OAAO;EACR;EAEA,IAAI,CAAC,cAAc,eAAe,MAAM,aACvC,QAAQ,QAAQ,SAAS,KAAK;EAG/B,OAAO;CACR,GAAG,CAAC,CAAC;AACN;AAEA,SAAS,sBAAsB,YAA4B;CAC1D,MAAM,OAAO,IAAI,KAAK,UAAU;CAChC,IAAI,OAAO,MAAM,KAAK,QAAQ,CAAC,GAC9B,OAAO;CAGR,OAAO,IAAI,KAAK,eAAe,MAAM,EAAE,OAAO,OAAO,CAAC,CAAC,CAAC,OAAO,IAAI;AACpE;AAEA,SAAS,qBAAqB,YAA4B;CACzD,MAAM,OAAO,IAAI,KAAK,UAAU;CAChC,IAAI,OAAO,MAAM,KAAK,QAAQ,CAAC,GAC9B,OAAO;CAGR,OAAO,IAAI,KAAK,eAAe,MAAM;EAAE,OAAO;EAAS,KAAK;EAAW,MAAM;CAAU,CAAC,CAAC,CAAC,OAAO,IAAI;AACtG;AAEA,SAAS,mBAAmB,WAA2B;CACtD,MAAM,eAAe,KAAK,OAAO,YAAY,KAAK,IAAI,KAAK,GAAI;CAC/D,MAAM,YAAY,IAAI,KAAK,mBAAmB,MAAM,EAAE,SAAS,OAAO,CAAC;CAOvE,KAAK,MAAM,CAAC,MAAM,WAAW;EAL5B,CAAC,OAAO,KAAY;EACpB,CAAC,QAAQ,IAAO;EAChB,CAAC,UAAU,EAAE;CAGuB,GACpC,IAAI,KAAK,IAAI,YAAY,KAAK,UAAU,SAAS,UAChD,OAAO,UAAU,OAAO,KAAK,MAAM,eAAe,MAAM,GAAG,IAAI;CAIjE,OAAO,UAAU,OAAO,cAAc,QAAQ;AAC/C;AAEA,SAAS,oBAAoB,YAA4B;CACxD,MAAM,OAAO,IAAI,KAAK,UAAU;CAChC,IAAI,OAAO,MAAM,KAAK,QAAQ,CAAC,GAC9B,OAAO;CAGR,OAAO,KAAK,eAAe;AAC5B;AAEA,SAAS,aAAa,OAAyB;CAC9C,OAAO,iBAAiB,UAAU,MAAM,SAAS,gBAAgB,WAAW,KAAK,MAAM,OAAO;AAC/F"}
@@ -0,0 +1,75 @@
1
+ const require_runtime = require("../_virtual/_rolldown/runtime.cjs");
2
+ const require_constants = require("./constants.cjs");
3
+ let vscode = require("vscode");
4
+ vscode = require_runtime.__toESM(vscode, 1);
5
+ //#region src/extension/uri-utils.ts
6
+ function createSnapshotUri(args) {
7
+ return vscode.Uri.from({
8
+ scheme: require_constants.SNAPSHOT_SCHEME,
9
+ path: `/${args.relativePath}`,
10
+ query: JSON.stringify({
11
+ workspacePath: args.workspacePath,
12
+ filePath: args.relativePath,
13
+ revset: args.revset,
14
+ backend: args.backend
15
+ })
16
+ });
17
+ }
18
+ function parseRangeDiffUri(uri) {
19
+ const params = new URLSearchParams(uri.query);
20
+ return {
21
+ from: getQueryParam(params, "from") || getQueryParam(params, "base"),
22
+ to: getQueryParam(params, "to") || getQueryParam(params, "target"),
23
+ base: getQueryParam(params, "base"),
24
+ target: getQueryParam(params, "target"),
25
+ title: getQueryParam(params, "title"),
26
+ workspacePath: getQueryParam(params, "workspacePath"),
27
+ confirm: getBooleanQueryParam(params, "confirm"),
28
+ verbose: getBooleanQueryParam(params, "verbose"),
29
+ source: getQueryParam(params, "source")
30
+ };
31
+ }
32
+ function parseSnapshotUri(uri) {
33
+ return JSON.parse(uri.query);
34
+ }
35
+ function sanitizeRangeDiffArgs(args) {
36
+ if (!args) return;
37
+ return {
38
+ from: args.from,
39
+ to: args.to,
40
+ base: args.base,
41
+ target: args.target,
42
+ title: args.title,
43
+ workspacePath: args.workspacePath,
44
+ confirm: args.confirm,
45
+ verbose: args.verbose,
46
+ source: args.source
47
+ };
48
+ }
49
+ function areSamePath(args) {
50
+ return normalizePath(args.left) === normalizePath(args.right);
51
+ }
52
+ function normalizePath(value) {
53
+ return value.replace(/\\/g, "/").replace(/\/+$/, "") || "/";
54
+ }
55
+ function isRangeDiffUriTarget(args) {
56
+ return args.uri.authority === args.extensionId && args.uri.path === "/open-range-multi-diff";
57
+ }
58
+ function getQueryParam(params, name) {
59
+ return params.get(name)?.trim() || void 0;
60
+ }
61
+ function getBooleanQueryParam(params, name) {
62
+ const value = params.get(name)?.trim().toLowerCase();
63
+ if (!value) return;
64
+ if (value === "1" || value === "true" || value === "yes") return true;
65
+ if (value === "0" || value === "false" || value === "no") return false;
66
+ }
67
+ //#endregion
68
+ exports.areSamePath = areSamePath;
69
+ exports.createSnapshotUri = createSnapshotUri;
70
+ exports.isRangeDiffUriTarget = isRangeDiffUriTarget;
71
+ exports.parseRangeDiffUri = parseRangeDiffUri;
72
+ exports.parseSnapshotUri = parseSnapshotUri;
73
+ exports.sanitizeRangeDiffArgs = sanitizeRangeDiffArgs;
74
+
75
+ //# sourceMappingURL=uri-utils.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uri-utils.cjs","names":["SNAPSHOT_SCHEME"],"sources":["../../src/extension/uri-utils.ts"],"sourcesContent":["import * as vscode from 'vscode';\nimport type { HistoryBackend } from '../shared/timeline-types.ts';\nimport { OPEN_RANGE_DIFF_URI_PATH, SNAPSHOT_SCHEME } from './constants.ts';\nimport type { RangeDiffArgs, SnapshotQuery } from './types.ts';\n\nexport function createSnapshotUri(args: {\n\tworkspacePath: string;\n\trevset: string;\n\trelativePath: string;\n\tbackend?: HistoryBackend;\n}): vscode.Uri {\n\treturn vscode.Uri.from({\n\t\tscheme: SNAPSHOT_SCHEME,\n\t\tpath: `/${args.relativePath}`,\n\t\tquery: JSON.stringify({\n\t\t\tworkspacePath: args.workspacePath,\n\t\t\tfilePath: args.relativePath,\n\t\t\trevset: args.revset,\n\t\t\tbackend: args.backend,\n\t\t}),\n\t});\n}\n\nexport function parseRangeDiffUri(uri: vscode.Uri): RangeDiffArgs {\n\tconst params = new URLSearchParams(uri.query);\n\n\treturn {\n\t\tfrom: getQueryParam(params, 'from') || getQueryParam(params, 'base'),\n\t\tto: getQueryParam(params, 'to') || getQueryParam(params, 'target'),\n\t\tbase: getQueryParam(params, 'base'),\n\t\ttarget: getQueryParam(params, 'target'),\n\t\ttitle: getQueryParam(params, 'title'),\n\t\tworkspacePath: getQueryParam(params, 'workspacePath'),\n\t\tconfirm: getBooleanQueryParam(params, 'confirm'),\n\t\tverbose: getBooleanQueryParam(params, 'verbose'),\n\t\tsource: getQueryParam(params, 'source'),\n\t};\n}\n\nexport function parseSnapshotUri(uri: vscode.Uri): SnapshotQuery {\n\treturn JSON.parse(uri.query) as SnapshotQuery;\n}\n\nexport function sanitizeRangeDiffArgs(args: RangeDiffArgs | undefined): RangeDiffArgs | undefined {\n\tif (!args) {\n\t\treturn undefined;\n\t}\n\n\treturn {\n\t\tfrom: args.from,\n\t\tto: args.to,\n\t\tbase: args.base,\n\t\ttarget: args.target,\n\t\ttitle: args.title,\n\t\tworkspacePath: args.workspacePath,\n\t\tconfirm: args.confirm,\n\t\tverbose: args.verbose,\n\t\tsource: args.source,\n\t};\n}\n\nexport function areSamePath(args: { left: string; right: string }): boolean {\n\treturn normalizePath(args.left) === normalizePath(args.right);\n}\n\nfunction normalizePath(value: string): string {\n\treturn value.replace(/\\\\/g, '/').replace(/\\/+$/, '') || '/';\n}\n\nexport function isRangeDiffUriTarget(args: { uri: vscode.Uri; extensionId: string }): boolean {\n\treturn args.uri.authority === args.extensionId && args.uri.path === OPEN_RANGE_DIFF_URI_PATH;\n}\n\nfunction getQueryParam(params: URLSearchParams, name: string): string | undefined {\n\tconst value = params.get(name)?.trim();\n\treturn value || undefined;\n}\n\nfunction getBooleanQueryParam(params: URLSearchParams, name: string): boolean | undefined {\n\tconst value = params.get(name)?.trim().toLowerCase();\n\tif (!value) {\n\t\treturn undefined;\n\t}\n\n\tif (value === '1' || value === 'true' || value === 'yes') {\n\t\treturn true;\n\t}\n\n\tif (value === '0' || value === 'false' || value === 'no') {\n\t\treturn false;\n\t}\n\n\treturn undefined;\n}\n"],"mappings":";;;;;AAKA,SAAgB,kBAAkB,MAKnB;CACd,OAAO,OAAO,IAAI,KAAK;EACtB,QAAQA,kBAAAA;EACR,MAAM,IAAI,KAAK;EACf,OAAO,KAAK,UAAU;GACrB,eAAe,KAAK;GACpB,UAAU,KAAK;GACf,QAAQ,KAAK;GACb,SAAS,KAAK;EACf,CAAC;CACF,CAAC;AACF;AAEA,SAAgB,kBAAkB,KAAgC;CACjE,MAAM,SAAS,IAAI,gBAAgB,IAAI,KAAK;CAE5C,OAAO;EACN,MAAM,cAAc,QAAQ,MAAM,KAAK,cAAc,QAAQ,MAAM;EACnE,IAAI,cAAc,QAAQ,IAAI,KAAK,cAAc,QAAQ,QAAQ;EACjE,MAAM,cAAc,QAAQ,MAAM;EAClC,QAAQ,cAAc,QAAQ,QAAQ;EACtC,OAAO,cAAc,QAAQ,OAAO;EACpC,eAAe,cAAc,QAAQ,eAAe;EACpD,SAAS,qBAAqB,QAAQ,SAAS;EAC/C,SAAS,qBAAqB,QAAQ,SAAS;EAC/C,QAAQ,cAAc,QAAQ,QAAQ;CACvC;AACD;AAEA,SAAgB,iBAAiB,KAAgC;CAChE,OAAO,KAAK,MAAM,IAAI,KAAK;AAC5B;AAEA,SAAgB,sBAAsB,MAA4D;CACjG,IAAI,CAAC,MACJ;CAGD,OAAO;EACN,MAAM,KAAK;EACX,IAAI,KAAK;EACT,MAAM,KAAK;EACX,QAAQ,KAAK;EACb,OAAO,KAAK;EACZ,eAAe,KAAK;EACpB,SAAS,KAAK;EACd,SAAS,KAAK;EACd,QAAQ,KAAK;CACd;AACD;AAEA,SAAgB,YAAY,MAAgD;CAC3E,OAAO,cAAc,KAAK,IAAI,MAAM,cAAc,KAAK,KAAK;AAC7D;AAEA,SAAS,cAAc,OAAuB;CAC7C,OAAO,MAAM,QAAQ,OAAO,GAAG,CAAC,CAAC,QAAQ,QAAQ,EAAE,KAAK;AACzD;AAEA,SAAgB,qBAAqB,MAAyD;CAC7F,OAAO,KAAK,IAAI,cAAc,KAAK,eAAe,KAAK,IAAI,SAAA;AAC5D;AAEA,SAAS,cAAc,QAAyB,MAAkC;CAEjF,OADc,OAAO,IAAI,IAAI,CAAC,EAAE,KAAK,KACrB,KAAA;AACjB;AAEA,SAAS,qBAAqB,QAAyB,MAAmC;CACzF,MAAM,QAAQ,OAAO,IAAI,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC,YAAY;CACnD,IAAI,CAAC,OACJ;CAGD,IAAI,UAAU,OAAO,UAAU,UAAU,UAAU,OAClD,OAAO;CAGR,IAAI,UAAU,OAAO,UAAU,WAAW,UAAU,MACnD,OAAO;AAIT"}
@@ -0,0 +1,11 @@
1
+ //#region package.json
2
+ var version = "0.10.10";
3
+ //#endregion
4
+ Object.defineProperty(exports, "version", {
5
+ enumerable: true,
6
+ get: function() {
7
+ return version;
8
+ }
9
+ });
10
+
11
+ //# sourceMappingURL=package.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package.cjs","names":[],"sources":["../package.json"],"sourcesContent":[""],"mappings":""}
@@ -0,0 +1,211 @@
1
+ //#region src/shared/blame.ts
2
+ function parseGitBlamePorcelain(stdout) {
3
+ const lines = [];
4
+ let pending = {};
5
+ for (const raw of stdout.split(/\r?\n/u)) {
6
+ if (!raw) continue;
7
+ if (/^[0-9a-f]{7,40}\s+\d+\s+\d+/i.test(raw)) {
8
+ const [revision, , finalLine] = raw.split(/\s+/u);
9
+ if (pending.revision && pending.line) lines.push(finalizeBlamePending(pending));
10
+ pending = {
11
+ revision,
12
+ line: Number(finalLine)
13
+ };
14
+ continue;
15
+ }
16
+ if (raw.startsWith("author ")) {
17
+ pending.author = raw.slice(7);
18
+ continue;
19
+ }
20
+ if (raw.startsWith("author-time ")) {
21
+ const timestamp = Number(raw.slice(12));
22
+ if (Number.isFinite(timestamp)) {
23
+ pending.authorTimestamp = timestamp;
24
+ pending.authorDate = formatBlameAuthorDate(timestamp);
25
+ }
26
+ continue;
27
+ }
28
+ if (raw.startsWith("summary ")) pending.summary = raw.slice(8);
29
+ }
30
+ if (pending.revision && pending.line) lines.push(finalizeBlamePending(pending));
31
+ return lines;
32
+ }
33
+ function finalizeBlamePending(pending) {
34
+ return {
35
+ line: pending.line,
36
+ revision: pending.revision,
37
+ author: pending.author,
38
+ authorTimestamp: pending.authorTimestamp,
39
+ authorDate: pending.authorDate,
40
+ summary: pending.summary
41
+ };
42
+ }
43
+ /**
44
+ * Default / templated jj annotate lines.
45
+ * Preferred template (see buildJjAnnotateArgs):
46
+ * `REV\tAUTHOR\tEPOCH_SECONDS\tSUMMARY`
47
+ * Also accepts legacy `REV PATH:LINE: content` / `REV content`, and ISO timestamps.
48
+ */
49
+ function parseJjFileAnnotate(stdout) {
50
+ const lines = [];
51
+ let line = 1;
52
+ for (const raw of stdout.split(/\r?\n/u)) {
53
+ if (!raw) continue;
54
+ const tabulated = /^([0-9a-f]{7,40}|[a-z0-9]+)\t([^\t]*)\t([^\t]*)\t?(.*)$/iu.exec(raw);
55
+ if (tabulated) {
56
+ const parsedTime = parseBlameTimestamp(tabulated[3] ?? "");
57
+ lines.push({
58
+ line,
59
+ revision: tabulated[1],
60
+ author: tabulated[2]?.trim() || void 0,
61
+ authorTimestamp: parsedTime?.timestamp,
62
+ authorDate: parsedTime?.authorDate || tabulated[3]?.trim() || void 0,
63
+ summary: tabulated[4]?.trim() || void 0
64
+ });
65
+ line += 1;
66
+ continue;
67
+ }
68
+ const match = /^([0-9a-f]{7,40}|[a-z0-9]+)\s+(?:\S+\s+)?(.*)$/i.exec(raw);
69
+ if (!match) {
70
+ line += 1;
71
+ continue;
72
+ }
73
+ lines.push({
74
+ line,
75
+ revision: match[1],
76
+ summary: match[2]?.trim() || void 0
77
+ });
78
+ line += 1;
79
+ }
80
+ return lines;
81
+ }
82
+ /** Parse unix seconds or jj timestamp strings like `2026-04-08 15:39:22.000 +02:00`. */
83
+ function parseBlameTimestamp(raw, nowMs = Date.now()) {
84
+ const trimmed = raw.trim();
85
+ if (!trimmed) return;
86
+ if (/^\d{9,12}$/u.test(trimmed)) {
87
+ const timestamp = Number(trimmed);
88
+ if (!Number.isFinite(timestamp)) return;
89
+ return {
90
+ timestamp,
91
+ authorDate: formatBlameAuthorDate(timestamp, nowMs)
92
+ };
93
+ }
94
+ const isoish = trimmed.replace(/^(\d{4}-\d{2}-\d{2}) /u, "$1T").replace(/ ([+-]\d{2}:\d{2})$/u, "$1");
95
+ const ms = Date.parse(isoish);
96
+ if (!Number.isFinite(ms)) return;
97
+ const timestamp = Math.floor(ms / 1e3);
98
+ return {
99
+ timestamp,
100
+ authorDate: formatBlameAuthorDate(timestamp, nowMs)
101
+ };
102
+ }
103
+ function formatBlameAuthorDate(timestampSeconds, nowMs = Date.now()) {
104
+ const date = /* @__PURE__ */ new Date(timestampSeconds * 1e3);
105
+ if (Number.isNaN(date.getTime())) return "";
106
+ const deltaSec = Math.max(0, Math.round((nowMs - date.getTime()) / 1e3));
107
+ if (deltaSec < 60) return "just now";
108
+ if (deltaSec < 3600) return `${Math.floor(deltaSec / 60)}m ago`;
109
+ if (deltaSec < 86400) return `${Math.floor(deltaSec / 3600)}h ago`;
110
+ if (deltaSec < 2592e3) return `${Math.floor(deltaSec / 86400)}d ago`;
111
+ return date.toISOString().slice(0, 10);
112
+ }
113
+ function formatBlameGutterLabel(entry) {
114
+ const author = entry.author?.trim().split(/\s+/u)[0] || "";
115
+ const date = entry.authorDate || "";
116
+ const summary = truncateBlameSummaryForDecoration(entry.summary || "", 42);
117
+ if (author && date && summary) return `${author}, ${date} • ${summary}`;
118
+ if (author && date) return `${author}, ${date}`;
119
+ if (author && summary) return `${author} • ${summary}`;
120
+ if (date && summary) return `${date} • ${summary}`;
121
+ return author || date || summary || shortBlameRevision(entry.revision);
122
+ }
123
+ function truncateBlameSummaryForDecoration(value, maxLength) {
124
+ const cleaned = value.trim().replace(/\s+/gu, " ").replace(/[0-9a-f]{7,40}/giu, " ").replace(/\b\d{9,12}\b/gu, " ").replace(/\s+/gu, " ").trim();
125
+ if (cleaned.length <= maxLength) return cleaned;
126
+ return `${cleaned.slice(0, Math.max(1, maxLength - 1))}…`;
127
+ }
128
+ function findBlameForLine(blame, line) {
129
+ return blame.find((entry) => entry.line === line);
130
+ }
131
+ function buildGitBlameArgs(args) {
132
+ return [
133
+ "blame",
134
+ "-L",
135
+ `${args.line},${args.line}`,
136
+ "--porcelain",
137
+ "--",
138
+ args.relativePath
139
+ ];
140
+ }
141
+ function buildGitBlameFileArgs(args) {
142
+ if (args.revision) return [
143
+ "blame",
144
+ "--porcelain",
145
+ args.revision,
146
+ "--",
147
+ args.relativePath
148
+ ];
149
+ return [
150
+ "blame",
151
+ "--porcelain",
152
+ "--",
153
+ args.relativePath
154
+ ];
155
+ }
156
+ /** Tab-separated: commit id, author name, author unix seconds, first-line description.
157
+ * Trailing newline is required — without it jj concatenates adjacent annotate rows. */
158
+ const JJ_FILE_ANNOTATE_TEMPLATE = "commit.commit_id().short() ++ \"\\t\" ++ commit.author().name() ++ \"\\t\" ++ commit.author().timestamp().format(\"%s\") ++ \"\\t\" ++ commit.description().first_line() ++ \"\\n\"";
159
+ function buildJjAnnotateArgs(args) {
160
+ const templateArgs = ["-T", JJ_FILE_ANNOTATE_TEMPLATE];
161
+ if (args.revision) return [
162
+ "file",
163
+ "annotate",
164
+ "-r",
165
+ args.revision,
166
+ ...templateArgs,
167
+ args.relativePath
168
+ ];
169
+ return [
170
+ "file",
171
+ "annotate",
172
+ ...templateArgs,
173
+ args.relativePath
174
+ ];
175
+ }
176
+ function revisionMatchesBlame(entryRevision, blameRevision) {
177
+ const left = entryRevision.toLowerCase();
178
+ const right = blameRevision.toLowerCase();
179
+ return left === right || left.startsWith(right) || right.startsWith(left);
180
+ }
181
+ /** Keep first line of each contiguous same-revision run — sparse Pierre annotations. */
182
+ function collapseBlameToHunkStarts(blame) {
183
+ const starts = [];
184
+ let previousRevision = "";
185
+ for (const entry of blame) {
186
+ if (entry.revision === previousRevision) continue;
187
+ starts.push(entry);
188
+ previousRevision = entry.revision;
189
+ }
190
+ return starts;
191
+ }
192
+ function shortBlameRevision(revision, maxLength = 7) {
193
+ return revision.length <= maxLength ? revision : revision.slice(0, maxLength);
194
+ }
195
+ //#endregion
196
+ exports.JJ_FILE_ANNOTATE_TEMPLATE = JJ_FILE_ANNOTATE_TEMPLATE;
197
+ exports.buildGitBlameArgs = buildGitBlameArgs;
198
+ exports.buildGitBlameFileArgs = buildGitBlameFileArgs;
199
+ exports.buildJjAnnotateArgs = buildJjAnnotateArgs;
200
+ exports.collapseBlameToHunkStarts = collapseBlameToHunkStarts;
201
+ exports.findBlameForLine = findBlameForLine;
202
+ exports.formatBlameAuthorDate = formatBlameAuthorDate;
203
+ exports.formatBlameGutterLabel = formatBlameGutterLabel;
204
+ exports.parseBlameTimestamp = parseBlameTimestamp;
205
+ exports.parseGitBlamePorcelain = parseGitBlamePorcelain;
206
+ exports.parseJjFileAnnotate = parseJjFileAnnotate;
207
+ exports.revisionMatchesBlame = revisionMatchesBlame;
208
+ exports.shortBlameRevision = shortBlameRevision;
209
+ exports.truncateBlameSummaryForDecoration = truncateBlameSummaryForDecoration;
210
+
211
+ //# sourceMappingURL=blame.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blame.cjs","names":[],"sources":["../../src/shared/blame.ts"],"sourcesContent":["export type BlameLine = {\n\t/** 1-based line number in the blamed file. */\n\tline: number;\n\trevision: string;\n\tauthor?: string;\n\t/** Unix epoch seconds when available (git porcelain author-time). */\n\tauthorTimestamp?: number;\n\t/** Display-ready author date string when available. */\n\tauthorDate?: string;\n\tsummary?: string;\n};\n\nexport function parseGitBlamePorcelain(stdout: string): BlameLine[] {\n\tconst lines: BlameLine[] = [];\n\tlet pending: Partial<BlameLine> & { revision?: string } = {};\n\tfor (const raw of stdout.split(/\\r?\\n/u)) {\n\t\tif (!raw) {\n\t\t\tcontinue;\n\t\t}\n\t\tif (/^[0-9a-f]{7,40}\\s+\\d+\\s+\\d+/i.test(raw)) {\n\t\t\tconst [revision, , finalLine] = raw.split(/\\s+/u);\n\t\t\tif (pending.revision && pending.line) {\n\t\t\t\tlines.push(finalizeBlamePending(pending));\n\t\t\t}\n\t\t\tpending = { revision, line: Number(finalLine) };\n\t\t\tcontinue;\n\t\t}\n\t\tif (raw.startsWith('author ')) {\n\t\t\tpending.author = raw.slice('author '.length);\n\t\t\tcontinue;\n\t\t}\n\t\tif (raw.startsWith('author-time ')) {\n\t\t\tconst timestamp = Number(raw.slice('author-time '.length));\n\t\t\tif (Number.isFinite(timestamp)) {\n\t\t\t\tpending.authorTimestamp = timestamp;\n\t\t\t\tpending.authorDate = formatBlameAuthorDate(timestamp);\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tif (raw.startsWith('summary ')) {\n\t\t\tpending.summary = raw.slice('summary '.length);\n\t\t}\n\t}\n\tif (pending.revision && pending.line) {\n\t\tlines.push(finalizeBlamePending(pending));\n\t}\n\treturn lines;\n}\n\nfunction finalizeBlamePending(pending: Partial<BlameLine> & { revision?: string }): BlameLine {\n\treturn {\n\t\tline: pending.line!,\n\t\trevision: pending.revision!,\n\t\tauthor: pending.author,\n\t\tauthorTimestamp: pending.authorTimestamp,\n\t\tauthorDate: pending.authorDate,\n\t\tsummary: pending.summary,\n\t};\n}\n\n/**\n * Default / templated jj annotate lines.\n * Preferred template (see buildJjAnnotateArgs):\n * `REV\\tAUTHOR\\tEPOCH_SECONDS\\tSUMMARY`\n * Also accepts legacy `REV PATH:LINE: content` / `REV content`, and ISO timestamps.\n */\nexport function parseJjFileAnnotate(stdout: string): BlameLine[] {\n\tconst lines: BlameLine[] = [];\n\tlet line = 1;\n\tfor (const raw of stdout.split(/\\r?\\n/u)) {\n\t\tif (!raw) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst tabulated = /^([0-9a-f]{7,40}|[a-z0-9]+)\\t([^\\t]*)\\t([^\\t]*)\\t?(.*)$/iu.exec(raw);\n\t\tif (tabulated) {\n\t\t\tconst parsedTime = parseBlameTimestamp(tabulated[3] ?? '');\n\t\t\tlines.push({\n\t\t\t\tline,\n\t\t\t\trevision: tabulated[1]!,\n\t\t\t\tauthor: tabulated[2]?.trim() || undefined,\n\t\t\t\tauthorTimestamp: parsedTime?.timestamp,\n\t\t\t\tauthorDate: parsedTime?.authorDate || tabulated[3]?.trim() || undefined,\n\t\t\t\tsummary: tabulated[4]?.trim() || undefined,\n\t\t\t});\n\t\t\tline += 1;\n\t\t\tcontinue;\n\t\t}\n\t\tconst match = /^([0-9a-f]{7,40}|[a-z0-9]+)\\s+(?:\\S+\\s+)?(.*)$/i.exec(raw);\n\t\tif (!match) {\n\t\t\tline += 1;\n\t\t\tcontinue;\n\t\t}\n\t\tlines.push({\n\t\t\tline,\n\t\t\trevision: match[1]!,\n\t\t\tsummary: match[2]?.trim() || undefined,\n\t\t});\n\t\tline += 1;\n\t}\n\treturn lines;\n}\n\n/** Parse unix seconds or jj timestamp strings like `2026-04-08 15:39:22.000 +02:00`. */\nexport function parseBlameTimestamp(\n\traw: string,\n\tnowMs = Date.now(),\n): { timestamp: number; authorDate: string } | undefined {\n\tconst trimmed = raw.trim();\n\tif (!trimmed) {\n\t\treturn undefined;\n\t}\n\tif (/^\\d{9,12}$/u.test(trimmed)) {\n\t\tconst timestamp = Number(trimmed);\n\t\tif (!Number.isFinite(timestamp)) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn { timestamp, authorDate: formatBlameAuthorDate(timestamp, nowMs) };\n\t}\n\tconst isoish = trimmed.replace(/^(\\d{4}-\\d{2}-\\d{2}) /u, '$1T').replace(/ ([+-]\\d{2}:\\d{2})$/u, '$1');\n\tconst ms = Date.parse(isoish);\n\tif (!Number.isFinite(ms)) {\n\t\treturn undefined;\n\t}\n\tconst timestamp = Math.floor(ms / 1000);\n\treturn { timestamp, authorDate: formatBlameAuthorDate(timestamp, nowMs) };\n}\n\nexport function formatBlameAuthorDate(timestampSeconds: number, nowMs = Date.now()): string {\n\tconst date = new Date(timestampSeconds * 1000);\n\tif (Number.isNaN(date.getTime())) {\n\t\treturn '';\n\t}\n\tconst deltaSec = Math.max(0, Math.round((nowMs - date.getTime()) / 1000));\n\tif (deltaSec < 60) {\n\t\treturn 'just now';\n\t}\n\tif (deltaSec < 3600) {\n\t\tconst mins = Math.floor(deltaSec / 60);\n\t\treturn `${mins}m ago`;\n\t}\n\tif (deltaSec < 86400) {\n\t\tconst hours = Math.floor(deltaSec / 3600);\n\t\treturn `${hours}h ago`;\n\t}\n\tif (deltaSec < 86400 * 30) {\n\t\tconst days = Math.floor(deltaSec / 86400);\n\t\treturn `${days}d ago`;\n\t}\n\treturn date.toISOString().slice(0, 10);\n}\n\nexport function formatBlameGutterLabel(entry: BlameLine): string {\n\tconst author = entry.author?.trim().split(/\\s+/u)[0] || '';\n\tconst date = entry.authorDate || '';\n\tconst summary = truncateBlameSummaryForDecoration(entry.summary || '', 42);\n\tif (author && date && summary) {\n\t\treturn `${author}, ${date} • ${summary}`;\n\t}\n\tif (author && date) {\n\t\treturn `${author}, ${date}`;\n\t}\n\tif (author && summary) {\n\t\treturn `${author} • ${summary}`;\n\t}\n\tif (date && summary) {\n\t\treturn `${date} • ${summary}`;\n\t}\n\treturn author || date || summary || shortBlameRevision(entry.revision);\n}\n\nexport function truncateBlameSummaryForDecoration(value: string, maxLength: number): string {\n\tconst trimmed = value.trim().replace(/\\s+/gu, ' ');\n\t// Guard against corrupt annotate glue (hash/author fragments leaking into summary).\n\tconst cleaned = trimmed\n\t\t.replace(/[0-9a-f]{7,40}/giu, ' ')\n\t\t.replace(/\\b\\d{9,12}\\b/gu, ' ')\n\t\t.replace(/\\s+/gu, ' ')\n\t\t.trim();\n\tif (cleaned.length <= maxLength) {\n\t\treturn cleaned;\n\t}\n\treturn `${cleaned.slice(0, Math.max(1, maxLength - 1))}…`;\n}\n\nexport function formatBlameHoverTooltip(entry: BlameLine): string {\n\treturn [\n\t\tentry.author ? `Author: ${entry.author}` : '',\n\t\tentry.authorDate ? `Date: ${entry.authorDate}` : '',\n\t\tentry.revision ? `Revision: ${entry.revision}` : '',\n\t\tentry.summary ? `Summary: ${entry.summary}` : '',\n\t]\n\t\t.filter(Boolean)\n\t\t.join('\\n');\n}\n\nexport function findBlameForLine(blame: BlameLine[], line: number): BlameLine | undefined {\n\treturn blame.find((entry) => entry.line === line);\n}\n\nexport function buildGitBlameArgs(args: { relativePath: string; line: number }): string[] {\n\treturn ['blame', '-L', `${args.line},${args.line}`, '--porcelain', '--', args.relativePath];\n}\n\nexport function buildGitBlameFileArgs(args: { relativePath: string; revision?: string }): string[] {\n\tif (args.revision) {\n\t\treturn ['blame', '--porcelain', args.revision, '--', args.relativePath];\n\t}\n\treturn ['blame', '--porcelain', '--', args.relativePath];\n}\n\n/** Tab-separated: commit id, author name, author unix seconds, first-line description.\n * Trailing newline is required — without it jj concatenates adjacent annotate rows. */\nexport const JJ_FILE_ANNOTATE_TEMPLATE =\n\t'commit.commit_id().short() ++ \"\\\\t\" ++ commit.author().name() ++ \"\\\\t\" ++ commit.author().timestamp().format(\"%s\") ++ \"\\\\t\" ++ commit.description().first_line() ++ \"\\\\n\"';\n\nexport function buildJjAnnotateArgs(args: { relativePath: string; revision?: string }): string[] {\n\tconst templateArgs = ['-T', JJ_FILE_ANNOTATE_TEMPLATE];\n\tif (args.revision) {\n\t\treturn ['file', 'annotate', '-r', args.revision, ...templateArgs, args.relativePath];\n\t}\n\treturn ['file', 'annotate', ...templateArgs, args.relativePath];\n}\n\nexport function revisionMatchesBlame(entryRevision: string, blameRevision: string): boolean {\n\tconst left = entryRevision.toLowerCase();\n\tconst right = blameRevision.toLowerCase();\n\treturn left === right || left.startsWith(right) || right.startsWith(left);\n}\n\n/** Keep first line of each contiguous same-revision run — sparse Pierre annotations. */\nexport function collapseBlameToHunkStarts(blame: BlameLine[]): BlameLine[] {\n\tconst starts: BlameLine[] = [];\n\tlet previousRevision = '';\n\tfor (const entry of blame) {\n\t\tif (entry.revision === previousRevision) {\n\t\t\tcontinue;\n\t\t}\n\t\tstarts.push(entry);\n\t\tpreviousRevision = entry.revision;\n\t}\n\treturn starts;\n}\n\nexport function shortBlameRevision(revision: string, maxLength = 7): string {\n\treturn revision.length <= maxLength ? revision : revision.slice(0, maxLength);\n}\n\nexport function findEntryIndexForBlameRevision(\n\tentries: Array<{ revision: string; isWorkingTree?: boolean }>,\n\tblameRevision: string,\n): number {\n\treturn entries.findIndex((entry) => !entry.isWorkingTree && revisionMatchesBlame(entry.revision, blameRevision));\n}\n"],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ //#region src/shared/diff-content-search.ts
2
+ /**
3
+ * True when `needle` appears on a line that was added or removed between before→after.
4
+ * Full-file presence alone does not match (avoids content: hits on unchanged context).
5
+ */
6
+ function diffHunkContainsNeedle(args) {
7
+ const needle = args.needle.trim();
8
+ if (!needle) return false;
9
+ const beforeCounts = countLines(args.before);
10
+ const afterCounts = countLines(args.after);
11
+ for (const [line, afterCount] of afterCounts) if (afterCount > (beforeCounts.get(line) ?? 0) && line.includes(needle)) return true;
12
+ for (const [line, beforeCount] of beforeCounts) if (beforeCount > (afterCounts.get(line) ?? 0) && line.includes(needle)) return true;
13
+ return false;
14
+ }
15
+ function countLines(text) {
16
+ const counts = /* @__PURE__ */ new Map();
17
+ for (const line of text.split(/\r?\n/u)) counts.set(line, (counts.get(line) ?? 0) + 1);
18
+ return counts;
19
+ }
20
+ //#endregion
21
+ exports.diffHunkContainsNeedle = diffHunkContainsNeedle;
22
+
23
+ //# sourceMappingURL=diff-content-search.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-content-search.cjs","names":[],"sources":["../../src/shared/diff-content-search.ts"],"sourcesContent":["/**\n * True when `needle` appears on a line that was added or removed between before→after.\n * Full-file presence alone does not match (avoids content: hits on unchanged context).\n */\nexport function diffHunkContainsNeedle(args: { before: string; after: string; needle: string }): boolean {\n\tconst needle = args.needle.trim();\n\tif (!needle) {\n\t\treturn false;\n\t}\n\tconst beforeCounts = countLines(args.before);\n\tconst afterCounts = countLines(args.after);\n\tfor (const [line, afterCount] of afterCounts) {\n\t\tconst beforeCount = beforeCounts.get(line) ?? 0;\n\t\tif (afterCount > beforeCount && line.includes(needle)) {\n\t\t\treturn true;\n\t\t}\n\t}\n\tfor (const [line, beforeCount] of beforeCounts) {\n\t\tconst afterCount = afterCounts.get(line) ?? 0;\n\t\tif (beforeCount > afterCount && line.includes(needle)) {\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\nfunction countLines(text: string): Map<string, number> {\n\tconst counts = new Map<string, number>();\n\tfor (const line of text.split(/\\r?\\n/u)) {\n\t\tcounts.set(line, (counts.get(line) ?? 0) + 1);\n\t}\n\treturn counts;\n}\n"],"mappings":";;;;;AAIA,SAAgB,uBAAuB,MAAkE;CACxG,MAAM,SAAS,KAAK,OAAO,KAAK;CAChC,IAAI,CAAC,QACJ,OAAO;CAER,MAAM,eAAe,WAAW,KAAK,MAAM;CAC3C,MAAM,cAAc,WAAW,KAAK,KAAK;CACzC,KAAK,MAAM,CAAC,MAAM,eAAe,aAEhC,IAAI,cADgB,aAAa,IAAI,IAAI,KAAK,MACd,KAAK,SAAS,MAAM,GACnD,OAAO;CAGT,KAAK,MAAM,CAAC,MAAM,gBAAgB,cAEjC,IAAI,eADe,YAAY,IAAI,IAAI,KAAK,MACZ,KAAK,SAAS,MAAM,GACnD,OAAO;CAGT,OAAO;AACR;AAEA,SAAS,WAAW,MAAmC;CACtD,MAAM,yBAAS,IAAI,IAAoB;CACvC,KAAK,MAAM,QAAQ,KAAK,MAAM,QAAQ,GACrC,OAAO,IAAI,OAAO,OAAO,IAAI,IAAI,KAAK,KAAK,CAAC;CAE7C,OAAO;AACR"}
@@ -0,0 +1,12 @@
1
+ //#region src/shared/diff-helpers.ts
2
+ function normalizeTextForComparison(value) {
3
+ return value.replace(/\r\n/g, "\n");
4
+ }
5
+ function textsMatchIgnoringLineEndings(beforeText, afterText) {
6
+ return beforeText === afterText || normalizeTextForComparison(beforeText) === normalizeTextForComparison(afterText);
7
+ }
8
+ //#endregion
9
+ exports.normalizeTextForComparison = normalizeTextForComparison;
10
+ exports.textsMatchIgnoringLineEndings = textsMatchIgnoringLineEndings;
11
+
12
+ //# sourceMappingURL=diff-helpers.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-helpers.cjs","names":[],"sources":["../../src/shared/diff-helpers.ts"],"sourcesContent":["export function normalizeTextForComparison(value: string): string {\n\treturn value.replace(/\\r\\n/g, '\\n');\n}\n\nexport function textsMatchIgnoringLineEndings(beforeText: string, afterText: string): boolean {\n\treturn beforeText === afterText || normalizeTextForComparison(beforeText) === normalizeTextForComparison(afterText);\n}\n"],"mappings":";AAAA,SAAgB,2BAA2B,OAAuB;CACjE,OAAO,MAAM,QAAQ,SAAS,IAAI;AACnC;AAEA,SAAgB,8BAA8B,YAAoB,WAA4B;CAC7F,OAAO,eAAe,aAAa,2BAA2B,UAAU,MAAM,2BAA2B,SAAS;AACnH"}