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.
- package/CHANGELOG.md +30 -0
- package/README.md +102 -0
- package/assets/jj-plus-icon.png +0 -0
- package/dist/_virtual/_rolldown/runtime.cjs +23 -0
- package/dist/bin.cjs +112 -0
- package/dist/bin.cjs.map +1 -0
- package/dist/cli/options.cjs +376 -0
- package/dist/cli/options.cjs.map +1 -0
- package/dist/cli/timeline-json.cjs +29 -0
- package/dist/cli/timeline-json.cjs.map +1 -0
- package/dist/extension/blame-codelens.cjs +228 -0
- package/dist/extension/blame-codelens.cjs.map +1 -0
- package/dist/extension/command-runner.cjs +99 -0
- package/dist/extension/command-runner.cjs.map +1 -0
- package/dist/extension/constants.cjs +56 -0
- package/dist/extension/constants.cjs.map +1 -0
- package/dist/extension/editor-extra-features.cjs +464 -0
- package/dist/extension/editor-extra-features.cjs.map +1 -0
- package/dist/extension/history-adapters.cjs +702 -0
- package/dist/extension/history-adapters.cjs.map +1 -0
- package/dist/extension/index.cjs +657 -0
- package/dist/extension/index.cjs.map +1 -0
- package/dist/extension/repo-timeline-panel.cjs +402 -0
- package/dist/extension/repo-timeline-panel.cjs.map +1 -0
- package/dist/extension/resolve-file-path.cjs +16 -0
- package/dist/extension/resolve-file-path.cjs.map +1 -0
- package/dist/extension/revision-diff-nav.cjs +169 -0
- package/dist/extension/revision-diff-nav.cjs.map +1 -0
- package/dist/extension/settings.cjs +41 -0
- package/dist/extension/settings.cjs.map +1 -0
- package/dist/extension/timeline-at-line.cjs +72 -0
- package/dist/extension/timeline-at-line.cjs.map +1 -0
- package/dist/extension/timeline-panel.cjs +1113 -0
- package/dist/extension/timeline-panel.cjs.map +1 -0
- package/dist/extension/timeline-service.cjs +1154 -0
- package/dist/extension/timeline-service.cjs.map +1 -0
- package/dist/extension/uri-utils.cjs +75 -0
- package/dist/extension/uri-utils.cjs.map +1 -0
- package/dist/package.cjs +11 -0
- package/dist/package.cjs.map +1 -0
- package/dist/shared/blame.cjs +211 -0
- package/dist/shared/blame.cjs.map +1 -0
- package/dist/shared/diff-content-search.cjs +23 -0
- package/dist/shared/diff-content-search.cjs.map +1 -0
- package/dist/shared/diff-helpers.cjs +12 -0
- package/dist/shared/diff-helpers.cjs.map +1 -0
- package/dist/shared/diff-stats.cjs +129 -0
- package/dist/shared/diff-stats.cjs.map +1 -0
- package/dist/shared/file-oplog.cjs +82 -0
- package/dist/shared/file-oplog.cjs.map +1 -0
- package/dist/shared/history-helpers.cjs +257 -0
- package/dist/shared/history-helpers.cjs.map +1 -0
- package/dist/shared/history-search.cjs +85 -0
- package/dist/shared/history-search.cjs.map +1 -0
- package/dist/shared/jj-revset-suggestions.cjs +41 -0
- package/dist/shared/jj-revset-suggestions.cjs.map +1 -0
- package/dist/shared/line-history.cjs +181 -0
- package/dist/shared/line-history.cjs.map +1 -0
- package/dist/shared/list-file-revisions.cjs +36 -0
- package/dist/shared/list-file-revisions.cjs.map +1 -0
- package/dist/shared/non-textual-details.cjs +43 -0
- package/dist/shared/non-textual-details.cjs.map +1 -0
- package/dist/shared/resolve-file-path.cjs +14 -0
- package/dist/shared/resolve-file-path.cjs.map +1 -0
- package/dist/shared/revision-diff-availability.cjs +18 -0
- package/dist/shared/revision-diff-availability.cjs.map +1 -0
- package/dist/shared/revision-diff-pair.cjs +42 -0
- package/dist/shared/revision-diff-pair.cjs.map +1 -0
- package/dist/shared/revset.cjs +16 -0
- package/dist/shared/revset.cjs.map +1 -0
- package/dist/shared/timeline-model.cjs +29 -0
- package/dist/shared/timeline-model.cjs.map +1 -0
- package/dist/standalone/server.cjs +1733 -0
- package/dist/standalone/server.cjs.map +1 -0
- package/dist/webview/timeline-template.cjs +214 -0
- package/dist/webview/timeline-template.cjs.map +1 -0
- package/package.json +320 -0
- package/webview-dist/assets/worker-DuV13XDT.js +161 -0
- package/webview-dist/chunks/abap-CLvhMVsD.js +1 -0
- package/webview-dist/chunks/actionscript-3-Cs6JJXT5.js +1 -0
- package/webview-dist/chunks/ada-C5qYipkI.js +1 -0
- package/webview-dist/chunks/ahk-CA9gdOdF.js +1 -0
- package/webview-dist/chunks/ahk2-_6rzW9BS.js +1 -0
- package/webview-dist/chunks/andromeeda-vGVdxbeo.js +1 -0
- package/webview-dist/chunks/angular-html-DTpR04n4.js +1 -0
- package/webview-dist/chunks/angular-ts-BCtbMvbl.js +1 -0
- package/webview-dist/chunks/apache-U0d_L8uA.js +1 -0
- package/webview-dist/chunks/apex-KFGFyKwG.js +1 -0
- package/webview-dist/chunks/apl-BMZuN1Ql.js +1 -0
- package/webview-dist/chunks/applescript-CCn79oCD.js +1 -0
- package/webview-dist/chunks/ara-4CJ0cIlV.js +1 -0
- package/webview-dist/chunks/asciidoc-SCjQUq34.js +1 -0
- package/webview-dist/chunks/asm-Cmm7eHzH.js +1 -0
- package/webview-dist/chunks/astro-DrbV4Z7r.js +1 -0
- package/webview-dist/chunks/aurora-x-CDeNXAV0.js +1 -0
- package/webview-dist/chunks/awk-BWXHIvNe.js +1 -0
- package/webview-dist/chunks/ayu-dark-DluEY0Gj.js +1 -0
- package/webview-dist/chunks/ayu-light-C3h-C4tm.js +1 -0
- package/webview-dist/chunks/ayu-mirage-Bqwy1Gya.js +1 -0
- package/webview-dist/chunks/ballerina-B7ZEbQpA.js +1 -0
- package/webview-dist/chunks/bat-qdxAdBWQ.js +1 -0
- package/webview-dist/chunks/beancount-D-usSTwE.js +1 -0
- package/webview-dist/chunks/berry-DKpUyyne.js +1 -0
- package/webview-dist/chunks/bibtex-Ci_nEsc7.js +1 -0
- package/webview-dist/chunks/bicep-CUHmPFLl.js +1 -0
- package/webview-dist/chunks/bird2-CYIUgYqB.js +1 -0
- package/webview-dist/chunks/blade-oPV8S6rR.js +1 -0
- package/webview-dist/chunks/bsl-_VjlB9mv.js +1 -0
- package/webview-dist/chunks/c-DYf-3tob.js +1 -0
- package/webview-dist/chunks/c3-D0apG41V.js +1 -0
- package/webview-dist/chunks/cadence-CQ2zXKGN.js +1 -0
- package/webview-dist/chunks/cairo-DLTphjLi.js +1 -0
- package/webview-dist/chunks/catppuccin-frappe-C9Q5zVZY.js +1 -0
- package/webview-dist/chunks/catppuccin-latte-CtsyrtPq.js +1 -0
- package/webview-dist/chunks/catppuccin-macchiato-R8nAf1vR.js +1 -0
- package/webview-dist/chunks/catppuccin-mocha-DjuaAJKi.js +1 -0
- package/webview-dist/chunks/chapel-DY-WYB1D.js +1 -0
- package/webview-dist/chunks/clarity-CtfBBspg.js +1 -0
- package/webview-dist/chunks/clojure-DqKBuwfJ.js +1 -0
- package/webview-dist/chunks/cmake-Bj61d0ZC.js +1 -0
- package/webview-dist/chunks/cobol-DvdX_6CO.js +1 -0
- package/webview-dist/chunks/codeowners-C8r90Shi.js +1 -0
- package/webview-dist/chunks/codeql-oeQT6MSM.js +1 -0
- package/webview-dist/chunks/coffee-C1kO7jr_.js +1 -0
- package/webview-dist/chunks/common-lisp-Cv5bFMCO.js +1 -0
- package/webview-dist/chunks/coq-DuBRPxYg.js +1 -0
- package/webview-dist/chunks/cpp-CoSarUrI.js +1 -0
- package/webview-dist/chunks/crystal-SLJeZ5EP.js +1 -0
- package/webview-dist/chunks/csharp-oqKa8noW.js +1 -0
- package/webview-dist/chunks/css-cfScyrSP.js +1 -0
- package/webview-dist/chunks/csv-Dx-8-gkx.js +1 -0
- package/webview-dist/chunks/cue-CE9AQfxI.js +1 -0
- package/webview-dist/chunks/cypher-ClKdZ_lG.js +1 -0
- package/webview-dist/chunks/d-qD-0Kul2.js +1 -0
- package/webview-dist/chunks/dark-plus-Cs2F2srj.js +1 -0
- package/webview-dist/chunks/dart-CnvKMtbv.js +1 -0
- package/webview-dist/chunks/dax-BkyTk9wS.js +1 -0
- package/webview-dist/chunks/desktop-Dlh5hvp9.js +1 -0
- package/webview-dist/chunks/diff-woXpYk--.js +1 -0
- package/webview-dist/chunks/docker-IyjqRm3v.js +1 -0
- package/webview-dist/chunks/dotenv-_5a1GRtc.js +1 -0
- package/webview-dist/chunks/dracula-BHWKrbxM.js +1 -0
- package/webview-dist/chunks/dracula-soft-5eyTD99u.js +1 -0
- package/webview-dist/chunks/dream-maker-DW3nJb8Q.js +1 -0
- package/webview-dist/chunks/edge-lvBr3t3s.js +1 -0
- package/webview-dist/chunks/elixir-BLoPe0KG.js +1 -0
- package/webview-dist/chunks/elm-BveBINBn.js +1 -0
- package/webview-dist/chunks/emacs-lisp-c_oH4hRZ.js +1 -0
- package/webview-dist/chunks/erb-Bmf8z4ph.js +1 -0
- package/webview-dist/chunks/erlang-Cphh6RMH.js +1 -0
- package/webview-dist/chunks/everforest-dark-sB-x3p7T.js +1 -0
- package/webview-dist/chunks/everforest-light-Df2xbC6M.js +1 -0
- package/webview-dist/chunks/fennel-DQxkIbk2.js +1 -0
- package/webview-dist/chunks/fish-BJitypiv.js +1 -0
- package/webview-dist/chunks/fluent-C03EYrpw.js +1 -0
- package/webview-dist/chunks/fortran-fixed-form-DEKoE2YW.js +1 -0
- package/webview-dist/chunks/fortran-free-form-CYNrtFtB.js +1 -0
- package/webview-dist/chunks/fsharp-D13ZGOAj.js +1 -0
- package/webview-dist/chunks/gdresource-xMC7jr7x.js +1 -0
- package/webview-dist/chunks/gdscript-DYvRD3hg.js +1 -0
- package/webview-dist/chunks/gdshader-CBce3t8t.js +1 -0
- package/webview-dist/chunks/genie-CV2tkWYe.js +1 -0
- package/webview-dist/chunks/gherkin-DExj1W_8.js +1 -0
- package/webview-dist/chunks/git-commit-BSykSTBG.js +1 -0
- package/webview-dist/chunks/git-rebase-BBii7GBM.js +1 -0
- package/webview-dist/chunks/github-dark-C-LZuMrd.js +1 -0
- package/webview-dist/chunks/github-dark-default-DXG-b-1a.js +1 -0
- package/webview-dist/chunks/github-dark-dimmed-Bx1FflLF.js +1 -0
- package/webview-dist/chunks/github-dark-high-contrast-B_tTalzw.js +1 -0
- package/webview-dist/chunks/github-light-EUqPIrTm.js +1 -0
- package/webview-dist/chunks/github-light-default-BXViO-2h.js +1 -0
- package/webview-dist/chunks/github-light-high-contrast-B68TUdTA.js +1 -0
- package/webview-dist/chunks/gleam-CSRkHgEL.js +1 -0
- package/webview-dist/chunks/glimmer-js-CuCPna-X.js +1 -0
- package/webview-dist/chunks/glimmer-ts-DNAjZNDK.js +1 -0
- package/webview-dist/chunks/glsl-COQvRxdz.js +1 -0
- package/webview-dist/chunks/gn-ilITqXS6.js +1 -0
- package/webview-dist/chunks/gnuplot-7GGW24-e.js +1 -0
- package/webview-dist/chunks/go-rLFTqkRN.js +1 -0
- package/webview-dist/chunks/graphql-1cKCVreZ.js +1 -0
- package/webview-dist/chunks/groovy-CacY0gHj.js +1 -0
- package/webview-dist/chunks/gruvbox-dark-hard-C820rvS2.js +1 -0
- package/webview-dist/chunks/gruvbox-dark-medium-BPjhmG05.js +1 -0
- package/webview-dist/chunks/gruvbox-dark-soft-MrdJrrXF.js +1 -0
- package/webview-dist/chunks/gruvbox-light-hard-BC_s9l72.js +1 -0
- package/webview-dist/chunks/gruvbox-light-medium-BAWPOn9u.js +1 -0
- package/webview-dist/chunks/gruvbox-light-soft-BSMLrYjP.js +1 -0
- package/webview-dist/chunks/hack-7CXYxWGO.js +1 -0
- package/webview-dist/chunks/haml-CeE16iG9.js +1 -0
- package/webview-dist/chunks/handlebars-CLm7Miue.js +1 -0
- package/webview-dist/chunks/haskell-D8IpX4py.js +1 -0
- package/webview-dist/chunks/haxe-C8oCnwJJ.js +1 -0
- package/webview-dist/chunks/hcl-Dh228itO.js +1 -0
- package/webview-dist/chunks/hjson-CxZEssPk.js +1 -0
- package/webview-dist/chunks/hlsl-Cvrh5tZx.js +1 -0
- package/webview-dist/chunks/horizon-CE9ld1lL.js +1 -0
- package/webview-dist/chunks/horizon-bright-DSNQnXHK.js +1 -0
- package/webview-dist/chunks/houston-CsvMBhTu.js +1 -0
- package/webview-dist/chunks/html-EbCri-_j.js +1 -0
- package/webview-dist/chunks/html-derivative-DGcE2kQi.js +1 -0
- package/webview-dist/chunks/http-DpnqgCg2.js +1 -0
- package/webview-dist/chunks/hurl-B6NGpamo.js +1 -0
- package/webview-dist/chunks/hxml-Dcm88srW.js +1 -0
- package/webview-dist/chunks/hy-CZbG8q4J.js +1 -0
- package/webview-dist/chunks/imba-DsUTQ-LC.js +1 -0
- package/webview-dist/chunks/ini-B5eOa1yu.js +1 -0
- package/webview-dist/chunks/java-ZkUoUSJy.js +1 -0
- package/webview-dist/chunks/javascript-DLd0EIw7.js +1 -0
- package/webview-dist/chunks/jinja-WhIqNp3q.js +1 -0
- package/webview-dist/chunks/jison-CIn1t7S8.js +1 -0
- package/webview-dist/chunks/json-AHG_JuKN.js +1 -0
- package/webview-dist/chunks/json5-BR5RXkoi.js +1 -0
- package/webview-dist/chunks/jsonc-CYpm1nAK.js +1 -0
- package/webview-dist/chunks/jsonl-CmCQp5Yx.js +1 -0
- package/webview-dist/chunks/jsonnet-CJTPZ8u_.js +1 -0
- package/webview-dist/chunks/jssm-DXw9l8Rf.js +1 -0
- package/webview-dist/chunks/jsx-BLy2KGb2.js +1 -0
- package/webview-dist/chunks/julia-XrhdGMY0.js +1 -0
- package/webview-dist/chunks/just-CiO9rOBq.js +1 -0
- package/webview-dist/chunks/kanagawa-dragon-Bozd7klA.js +1 -0
- package/webview-dist/chunks/kanagawa-lotus-BmuOG9ZW.js +1 -0
- package/webview-dist/chunks/kanagawa-wave-BML5mF2J.js +1 -0
- package/webview-dist/chunks/kdl-CsD5j6eV.js +1 -0
- package/webview-dist/chunks/kotlin-DhhofPvG.js +1 -0
- package/webview-dist/chunks/kusto-C7mF5XQf.js +1 -0
- package/webview-dist/chunks/laserwave-C_8bwKvT.js +1 -0
- package/webview-dist/chunks/latex-4tqdYtbu.js +1 -0
- package/webview-dist/chunks/lean-CewbzKMR.js +1 -0
- package/webview-dist/chunks/less-DVTAwKKz.js +1 -0
- package/webview-dist/chunks/light-plus-DVQuIRkW.js +1 -0
- package/webview-dist/chunks/liquid-BiiWRCLG.js +1 -0
- package/webview-dist/chunks/llvm-DqHOMS-s.js +1 -0
- package/webview-dist/chunks/log-BNLmms1o.js +1 -0
- package/webview-dist/chunks/logo-Cluzi2Zq.js +1 -0
- package/webview-dist/chunks/lua-BPFdS2Mc.js +1 -0
- package/webview-dist/chunks/luau-C2pBCSgt.js +1 -0
- package/webview-dist/chunks/make-Dixweg8N.js +1 -0
- package/webview-dist/chunks/markdown-BYOwaDjH.js +1 -0
- package/webview-dist/chunks/marko-BLi1Yy1V.js +1 -0
- package/webview-dist/chunks/material-theme-Bm3Qr25_.js +1 -0
- package/webview-dist/chunks/material-theme-darker-2IIEA8gg.js +1 -0
- package/webview-dist/chunks/material-theme-lighter-uhdI0v04.js +1 -0
- package/webview-dist/chunks/material-theme-ocean-CHQ94UKr.js +1 -0
- package/webview-dist/chunks/material-theme-palenight-B5W6OYN7.js +1 -0
- package/webview-dist/chunks/matlab-D7qyCx1q.js +1 -0
- package/webview-dist/chunks/mdc-Dx-qyM1x.js +1 -0
- package/webview-dist/chunks/mdx-DQZ5AkYe.js +1 -0
- package/webview-dist/chunks/mermaid-BxpfTIzt.js +1 -0
- package/webview-dist/chunks/min-dark-BSWPekZh.js +1 -0
- package/webview-dist/chunks/min-light-DDpmG2fV.js +1 -0
- package/webview-dist/chunks/mipsasm-BMqwQI7S.js +1 -0
- package/webview-dist/chunks/mojo-fg40_ntQ.js +1 -0
- package/webview-dist/chunks/monokai-B_bV9PQ9.js +1 -0
- package/webview-dist/chunks/moonbit-DgjMoLWr.js +1 -0
- package/webview-dist/chunks/move-BYnGhZoM.js +1 -0
- package/webview-dist/chunks/narrat-_X_XdTYD.js +1 -0
- package/webview-dist/chunks/nextflow-BJtWHP5T.js +1 -0
- package/webview-dist/chunks/nextflow-groovy-DJMQeKeT.js +1 -0
- package/webview-dist/chunks/nginx-rnpjAIVq.js +1 -0
- package/webview-dist/chunks/night-owl-DhmEMT88.js +1 -0
- package/webview-dist/chunks/night-owl-light-eJ-hLW7d.js +1 -0
- package/webview-dist/chunks/nim-kKTJ2fIs.js +1 -0
- package/webview-dist/chunks/nix-IvuFDN5E.js +1 -0
- package/webview-dist/chunks/nord-Cb4Vim4T.js +1 -0
- package/webview-dist/chunks/nsis-CjNLYCLg.js +1 -0
- package/webview-dist/chunks/nushell-DHYfO66s.js +1 -0
- package/webview-dist/chunks/objective-c-D1A_Heim.js +1 -0
- package/webview-dist/chunks/objective-cpp-BsSzOQcm.js +1 -0
- package/webview-dist/chunks/ocaml-O90oeIOV.js +1 -0
- package/webview-dist/chunks/odin-B1RWQWA5.js +1 -0
- package/webview-dist/chunks/one-dark-pro-CLwyXe_n.js +1 -0
- package/webview-dist/chunks/one-light-D7Lr4KcI.js +1 -0
- package/webview-dist/chunks/openscad-BUDT5pXO.js +1 -0
- package/webview-dist/chunks/org-BGWCjkJX.js +1 -0
- package/webview-dist/chunks/pascal-4ZHwLPI5.js +1 -0
- package/webview-dist/chunks/perl-DEimDILQ.js +1 -0
- package/webview-dist/chunks/php-QnaNN--1.js +1 -0
- package/webview-dist/chunks/pierre-dark-CpLgRqie.js +1 -0
- package/webview-dist/chunks/pierre-dark-protanopia-deuteranopia-B35FxJx-.js +1 -0
- package/webview-dist/chunks/pierre-dark-soft-kZQmAZld.js +1 -0
- package/webview-dist/chunks/pierre-dark-tritanopia-CpjhbsIL.js +1 -0
- package/webview-dist/chunks/pierre-dark-vibrant-CpQYzh95.js +1 -0
- package/webview-dist/chunks/pierre-light-CoaEpmwp.js +1 -0
- package/webview-dist/chunks/pierre-light-protanopia-deuteranopia-0fSaH845.js +1 -0
- package/webview-dist/chunks/pierre-light-soft-lWLdNTOI.js +1 -0
- package/webview-dist/chunks/pierre-light-tritanopia-CEbqgOJL.js +1 -0
- package/webview-dist/chunks/pierre-light-vibrant-D80Fkn33.js +1 -0
- package/webview-dist/chunks/pkl-ot-7Btpt.js +1 -0
- package/webview-dist/chunks/plastic-DQwYfKfQ.js +1 -0
- package/webview-dist/chunks/plsql-DGHpHOYJ.js +1 -0
- package/webview-dist/chunks/po-BiJDBrnU.js +1 -0
- package/webview-dist/chunks/poimandres-DRFjx7u4.js +1 -0
- package/webview-dist/chunks/polar-C7UOKdEL.js +1 -0
- package/webview-dist/chunks/postcss-BXeXVLqQ.js +1 -0
- package/webview-dist/chunks/powerquery-DNMTfnFr.js +1 -0
- package/webview-dist/chunks/powershell-CCSX75yM.js +1 -0
- package/webview-dist/chunks/prisma-DMgNhnYS.js +1 -0
- package/webview-dist/chunks/prolog-iXnhIJG7.js +1 -0
- package/webview-dist/chunks/proto-DB4EqR-F.js +1 -0
- package/webview-dist/chunks/pug-D5rsKmMX.js +1 -0
- package/webview-dist/chunks/puppet-CDv2pdJW.js +1 -0
- package/webview-dist/chunks/purescript-9MfHhQsQ.js +1 -0
- package/webview-dist/chunks/python-gzcpVVnB.js +1 -0
- package/webview-dist/chunks/qml-wvbZb8UE.js +1 -0
- package/webview-dist/chunks/qmldir-DCQb3MpD.js +1 -0
- package/webview-dist/chunks/qss-Fe1Jh2GI.js +1 -0
- package/webview-dist/chunks/r-BNyBFaU1.js +1 -0
- package/webview-dist/chunks/racket-DcIDlBhZ.js +1 -0
- package/webview-dist/chunks/raku-B3gFvitq.js +1 -0
- package/webview-dist/chunks/razor-bKaHS6Kz.js +1 -0
- package/webview-dist/chunks/rbs-C0MpOrj4.js +1 -0
- package/webview-dist/chunks/red-DX1BQOs8.js +1 -0
- package/webview-dist/chunks/reg-CRGYupPL.js +1 -0
- package/webview-dist/chunks/regexp-B-mZuWUh.js +1 -0
- package/webview-dist/chunks/rel-BtDbiS_P.js +1 -0
- package/webview-dist/chunks/riscv-Ckw8ddFX.js +1 -0
- package/webview-dist/chunks/ron-VUp2lXgN.js +1 -0
- package/webview-dist/chunks/rose-pine-aMsaMD1D.js +1 -0
- package/webview-dist/chunks/rose-pine-dawn-8PwUyIlP.js +1 -0
- package/webview-dist/chunks/rose-pine-moon-DO-qXg-I.js +1 -0
- package/webview-dist/chunks/rosmsg-CAekHB0j.js +1 -0
- package/webview-dist/chunks/rst-Qq8ybXHe.js +1 -0
- package/webview-dist/chunks/ruby-U659LEwU.js +1 -0
- package/webview-dist/chunks/rust-Cfkwpbl8.js +1 -0
- package/webview-dist/chunks/sas-C4NtLApe.js +1 -0
- package/webview-dist/chunks/sass-DXrisJhu.js +1 -0
- package/webview-dist/chunks/scala-BiFt_7mu.js +1 -0
- package/webview-dist/chunks/scheme-DQCgrYNe.js +1 -0
- package/webview-dist/chunks/scss-KAaA4sHk.js +1 -0
- package/webview-dist/chunks/sdbl-bTVj8UrX.js +1 -0
- package/webview-dist/chunks/shaderlab-TOUzSsQk.js +1 -0
- package/webview-dist/chunks/shellscript-_7bOVsRC.js +1 -0
- package/webview-dist/chunks/shellsession-Bs_5k0qk.js +1 -0
- package/webview-dist/chunks/slack-dark-DnToyrRv.js +1 -0
- package/webview-dist/chunks/slack-ochin-B2OO5cIa.js +1 -0
- package/webview-dist/chunks/smalltalk-BHpQb5nM.js +1 -0
- package/webview-dist/chunks/smithy-Dgaz7aur.js +1 -0
- package/webview-dist/chunks/snazzy-light-4G7pJPwS.js +1 -0
- package/webview-dist/chunks/solarized-dark-UdsmMDCL.js +1 -0
- package/webview-dist/chunks/solarized-light-C1IUL_tW.js +1 -0
- package/webview-dist/chunks/solidity-Bj7E1mRn.js +1 -0
- package/webview-dist/chunks/soy-C5iuoFCh.js +1 -0
- package/webview-dist/chunks/sparql-D_iOobhT.js +1 -0
- package/webview-dist/chunks/splunk-BC2Px7Mm.js +1 -0
- package/webview-dist/chunks/sql-JX305rZh.js +1 -0
- package/webview-dist/chunks/ssh-config-BgfXC-Er.js +1 -0
- package/webview-dist/chunks/stata-2Rtik3TV.js +1 -0
- package/webview-dist/chunks/stylus-B6D30XZt.js +1 -0
- package/webview-dist/chunks/surrealql-IvpiLAIH.js +1 -0
- package/webview-dist/chunks/svelte-DeZcV_1u.js +1 -0
- package/webview-dist/chunks/swift-CyEgAFGc.js +1 -0
- package/webview-dist/chunks/synthwave-84-nFMaYfgc.js +1 -0
- package/webview-dist/chunks/system-verilog-Dh5ihWbf.js +1 -0
- package/webview-dist/chunks/systemd-BxMlprV5.js +1 -0
- package/webview-dist/chunks/talonscript-CohzipZa.js +1 -0
- package/webview-dist/chunks/tasl-DMoTqEGO.js +1 -0
- package/webview-dist/chunks/tcl-CZd0xW_V.js +1 -0
- package/webview-dist/chunks/templ-CcwjPXJr.js +1 -0
- package/webview-dist/chunks/terraform-DswuEJGm.js +1 -0
- package/webview-dist/chunks/tex-CZYHgHl8.js +1 -0
- package/webview-dist/chunks/tokyo-night-oM2G3aXe.js +1 -0
- package/webview-dist/chunks/toml-CcmNWLt0.js +1 -0
- package/webview-dist/chunks/ts-tags-DPINfEO_.js +1 -0
- package/webview-dist/chunks/tsv-sltzmVWM.js +1 -0
- package/webview-dist/chunks/tsx-Dq7pSIyE.js +1 -0
- package/webview-dist/chunks/turtle-ByJddavk.js +1 -0
- package/webview-dist/chunks/twig-DFpC8yDL.js +1 -0
- package/webview-dist/chunks/typescript-CN-guYmK.js +1 -0
- package/webview-dist/chunks/typespec-BRdr0IET.js +1 -0
- package/webview-dist/chunks/typst-hgW4q6mN.js +1 -0
- package/webview-dist/chunks/v-DBj4K9d_.js +1 -0
- package/webview-dist/chunks/vala-zf12oZj6.js +1 -0
- package/webview-dist/chunks/vb-DOwzaHZ0.js +1 -0
- package/webview-dist/chunks/verilog-B2gwz-sJ.js +1 -0
- package/webview-dist/chunks/vesper-DdrHHSXu.js +1 -0
- package/webview-dist/chunks/vhdl-BroJfC0k.js +1 -0
- package/webview-dist/chunks/viml-DvXPmvsu.js +1 -0
- package/webview-dist/chunks/vitesse-black-fwtXNY1n.js +1 -0
- package/webview-dist/chunks/vitesse-dark-BZCL-v6S.js +1 -0
- package/webview-dist/chunks/vitesse-light-VbXTXTou.js +1 -0
- package/webview-dist/chunks/vue-Dkz9ntel.js +1 -0
- package/webview-dist/chunks/vue-html-Dg8LQ5v3.js +1 -0
- package/webview-dist/chunks/vue-vine-CIEXICEN.js +1 -0
- package/webview-dist/chunks/vyper-CgoNMtux.js +1 -0
- package/webview-dist/chunks/wasm-BnjxR4X6.js +1 -0
- package/webview-dist/chunks/wasm-ByWQv1Qj.js +1 -0
- package/webview-dist/chunks/wenyan-C8pVoKbM.js +1 -0
- package/webview-dist/chunks/wgsl-BsKzXJz4.js +1 -0
- package/webview-dist/chunks/wikitext-ClFFjSW2.js +1 -0
- package/webview-dist/chunks/wit-DdvCle-K.js +1 -0
- package/webview-dist/chunks/wolfram-DLL8P-h_.js +1 -0
- package/webview-dist/chunks/worker-D52zl71O.js +1 -0
- package/webview-dist/chunks/worker-pool-lOjh8Q2A.js +1543 -0
- package/webview-dist/chunks/xml-X7YOen_c.js +1 -0
- package/webview-dist/chunks/xsl-h4d_Px-X.js +1 -0
- package/webview-dist/chunks/yaml-BRDpsfaj.js +1 -0
- package/webview-dist/chunks/zenscript-BnlCZFoB.js +1 -0
- package/webview-dist/chunks/zig-CMLA9XwU.js +1 -0
- package/webview-dist/index.html +18 -0
- package/webview-dist/pierre-worker-portable.js +13633 -0
- package/webview-dist/repo-timeline-app.js +7 -0
- package/webview-dist/repo-timeline.html +14 -0
- package/webview-dist/timeline-app.css +2 -0
- package/webview-dist/timeline-app.js +85 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
//#region src/shared/jj-revset-suggestions.ts
|
|
2
|
+
/** Single-revision targets for “compare file with …” quick picks. */
|
|
3
|
+
const JJ_COMPARE_TARGET_SUGGESTIONS = [
|
|
4
|
+
{
|
|
5
|
+
label: "Parent",
|
|
6
|
+
revset: "@-"
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
label: "Trunk",
|
|
10
|
+
revset: "trunk()"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
label: "Closest bookmark",
|
|
14
|
+
revset: "closest_bookmark(@)"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
label: "Closest pushable",
|
|
18
|
+
revset: "closest_pushable(@)"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
label: "Tip",
|
|
22
|
+
revset: "tip"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
label: "Latest",
|
|
26
|
+
revset: "latest"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
label: "main@origin",
|
|
30
|
+
revset: "main@origin"
|
|
31
|
+
}
|
|
32
|
+
];
|
|
33
|
+
function mergeCompareQuickPickValues(bookmarkNames) {
|
|
34
|
+
const seeded = JJ_COMPARE_TARGET_SUGGESTIONS.map((entry) => entry.revset);
|
|
35
|
+
return [.../* @__PURE__ */ new Set([...seeded, ...bookmarkNames.map((name) => name.trim()).filter(Boolean)])];
|
|
36
|
+
}
|
|
37
|
+
//#endregion
|
|
38
|
+
exports.JJ_COMPARE_TARGET_SUGGESTIONS = JJ_COMPARE_TARGET_SUGGESTIONS;
|
|
39
|
+
exports.mergeCompareQuickPickValues = mergeCompareQuickPickValues;
|
|
40
|
+
|
|
41
|
+
//# sourceMappingURL=jj-revset-suggestions.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jj-revset-suggestions.cjs","names":[],"sources":["../../src/shared/jj-revset-suggestions.ts"],"sourcesContent":["/**\n * Common jj revset chips / compare targets.\n * Prefer built-ins + widely useful aliases (closest_bookmark, slice, tip, …).\n * Avoid fileset-confused / version-fragile helpers like tags() / heads(all()).\n */\n\nexport type RevsetSuggestion = { label: string; revset: string };\n\n/** Single-revision targets for “compare file with …” quick picks. */\nexport const JJ_COMPARE_TARGET_SUGGESTIONS: ReadonlyArray<RevsetSuggestion> = [\n\t{ label: 'Parent', revset: '@-' },\n\t{ label: 'Trunk', revset: 'trunk()' },\n\t{ label: 'Closest bookmark', revset: 'closest_bookmark(@)' },\n\t{ label: 'Closest pushable', revset: 'closest_pushable(@)' },\n\t{ label: 'Tip', revset: 'tip' },\n\t{ label: 'Latest', revset: 'latest' },\n\t{ label: 'main@origin', revset: 'main@origin' },\n];\n\n/** Timeline View-menu revset filter chips (ranges + filters OK). */\nexport const JJ_TIMELINE_REVSET_SUGGESTIONS: ReadonlyArray<RevsetSuggestion> = [\n\t{ label: 'vs bookmark', revset: 'trunk()..closest_bookmark(@)' },\n\t{ label: 'vs pushable', revset: 'trunk()..closest_pushable(@)' },\n\t{ label: 'Slice', revset: 'slice()' },\n\t{ label: 'Tip', revset: 'tip' },\n\t{ label: 'Latest', revset: 'latest' },\n\t{ label: 'Mine', revset: 'mine()' },\n\t{ label: 'Bookmarks', revset: 'bookmarks()' },\n\t{ label: 'Remote bookmarks', revset: 'remote_bookmarks()' },\n\t{ label: 'Branch start', revset: 'branch_start(@)' },\n\t{ label: 'Trunk…@', revset: 'trunk()..@' },\n\t{ label: 'Mutable', revset: 'mutable()' },\n\t{ label: 'Immutable', revset: 'immutable()' },\n\t{ label: 'Conflicts', revset: 'conflicts()' },\n\t{ label: 'Empty', revset: 'empty()' },\n\t{ label: 'Ancestors', revset: 'ancestors(@)' },\n];\n\nexport function mergeCompareQuickPickValues(bookmarkNames: ReadonlyArray<string>): string[] {\n\tconst seeded = JJ_COMPARE_TARGET_SUGGESTIONS.map((entry) => entry.revset);\n\treturn [...new Set([...seeded, ...bookmarkNames.map((name) => name.trim()).filter(Boolean)])];\n}\n"],"mappings":";;AASA,MAAa,gCAAiE;CAC7E;EAAE,OAAO;EAAU,QAAQ;CAAK;CAChC;EAAE,OAAO;EAAS,QAAQ;CAAU;CACpC;EAAE,OAAO;EAAoB,QAAQ;CAAsB;CAC3D;EAAE,OAAO;EAAoB,QAAQ;CAAsB;CAC3D;EAAE,OAAO;EAAO,QAAQ;CAAM;CAC9B;EAAE,OAAO;EAAU,QAAQ;CAAS;CACpC;EAAE,OAAO;EAAe,QAAQ;CAAc;AAC/C;AAqBA,SAAgB,4BAA4B,eAAgD;CAC3F,MAAM,SAAS,8BAA8B,KAAK,UAAU,MAAM,MAAM;CACxE,OAAO,CAAC,mBAAG,IAAI,IAAI,CAAC,GAAG,QAAQ,GAAG,cAAc,KAAK,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,CAAC;AAC7F"}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
const require_diff_helpers = require("./diff-helpers.cjs");
|
|
2
|
+
//#region src/shared/line-history.ts
|
|
3
|
+
function normalizeLineHistoryRange(startLine, endLine) {
|
|
4
|
+
if (!Number.isFinite(startLine) || !Number.isFinite(endLine)) return null;
|
|
5
|
+
return {
|
|
6
|
+
startLine: Math.max(1, Math.floor(Math.min(startLine, endLine))),
|
|
7
|
+
endLine: Math.max(1, Math.floor(Math.max(startLine, endLine)))
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
function formatStatusBarLineHistoryChip(range) {
|
|
11
|
+
if (range.startLine === range.endLine) return `JJ Timeline L${range.startLine}`;
|
|
12
|
+
return `JJ Timeline L${range.startLine}–${range.endLine}`;
|
|
13
|
+
}
|
|
14
|
+
function splitTextIntoLines(value) {
|
|
15
|
+
if (!value) return [];
|
|
16
|
+
const lines = value.replace(/\r\n/g, "\n").split("\n");
|
|
17
|
+
if (lines.at(-1) === "") lines.pop();
|
|
18
|
+
return lines;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* True when the diff between before/after changes any line whose
|
|
22
|
+
* before-file or after-file line number falls in the inclusive 1-based range.
|
|
23
|
+
*/
|
|
24
|
+
function diffTouchesLineRange(args) {
|
|
25
|
+
if (require_diff_helpers.textsMatchIgnoringLineEndings(args.beforeText, args.afterText)) return false;
|
|
26
|
+
const beforeLines = splitTextIntoLines(args.beforeText);
|
|
27
|
+
const afterLines = splitTextIntoLines(args.afterText);
|
|
28
|
+
if (!beforeLines.length && afterLines.length) return lineRangeOverlaps(1, afterLines.length, args.range);
|
|
29
|
+
if (beforeLines.length && !afterLines.length) return lineRangeOverlaps(1, beforeLines.length, args.range);
|
|
30
|
+
let beforeLine = 1;
|
|
31
|
+
let afterLine = 1;
|
|
32
|
+
const operations = buildLineOperations(beforeLines, afterLines);
|
|
33
|
+
for (const operation of operations) {
|
|
34
|
+
if (operation.type === "context") {
|
|
35
|
+
beforeLine += 1;
|
|
36
|
+
afterLine += 1;
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
if (operation.type === "remove") {
|
|
40
|
+
if (lineInRange(beforeLine, args.range)) return true;
|
|
41
|
+
beforeLine += 1;
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
if (lineInRange(afterLine, args.range)) return true;
|
|
45
|
+
afterLine += 1;
|
|
46
|
+
}
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
function filterEntriesTouchingLineRange(args) {
|
|
50
|
+
if (args.entries.length <= 1) return [...args.entries];
|
|
51
|
+
const kept = [];
|
|
52
|
+
for (let index = 1; index < args.entries.length; index += 1) {
|
|
53
|
+
const previous = args.entries[index - 1];
|
|
54
|
+
const entry = args.entries[index];
|
|
55
|
+
if (diffTouchesLineRange({
|
|
56
|
+
beforeText: args.getContent(previous),
|
|
57
|
+
afterText: args.getContent(entry),
|
|
58
|
+
range: args.range
|
|
59
|
+
})) kept.push(entry);
|
|
60
|
+
}
|
|
61
|
+
if (!kept.length) {
|
|
62
|
+
const tip = args.entries.at(-1);
|
|
63
|
+
return tip ? [tip] : [];
|
|
64
|
+
}
|
|
65
|
+
const tip = args.entries.at(-1);
|
|
66
|
+
if (tip && kept.at(-1) !== tip) kept.push(tip);
|
|
67
|
+
return kept;
|
|
68
|
+
}
|
|
69
|
+
/** Parse `git log -L` / `--format=%H` style stdout into ordered oldest→newest hashes. */
|
|
70
|
+
function parseGitLineHistoryRevisions(stdout) {
|
|
71
|
+
return stdout.split(/\r?\n/u).map((line) => line.trim()).filter((line) => /^[0-9a-f]{7,40}$/i.test(line)).toReversed();
|
|
72
|
+
}
|
|
73
|
+
function buildGitLineHistoryArgs(args) {
|
|
74
|
+
return [
|
|
75
|
+
"log",
|
|
76
|
+
"--follow",
|
|
77
|
+
`-L${args.range.startLine},${args.range.endLine}:${args.relativePath}`,
|
|
78
|
+
"--date=iso-strict",
|
|
79
|
+
"--format=%H",
|
|
80
|
+
`--max-count=${args.limit ?? 200}`
|
|
81
|
+
];
|
|
82
|
+
}
|
|
83
|
+
function lineInRange(line, range) {
|
|
84
|
+
return line >= range.startLine && line <= range.endLine;
|
|
85
|
+
}
|
|
86
|
+
function lineRangeOverlaps(start, end, range) {
|
|
87
|
+
return start <= range.endLine && end >= range.startLine;
|
|
88
|
+
}
|
|
89
|
+
function buildLineOperations(beforeLines, afterLines) {
|
|
90
|
+
if (!beforeLines.length) return afterLines.map((text) => ({
|
|
91
|
+
type: "add",
|
|
92
|
+
text
|
|
93
|
+
}));
|
|
94
|
+
if (!afterLines.length) return beforeLines.map((text) => ({
|
|
95
|
+
type: "remove",
|
|
96
|
+
text
|
|
97
|
+
}));
|
|
98
|
+
if (beforeLines.length * afterLines.length > 12e5) return buildFallbackLineOperations(beforeLines, afterLines);
|
|
99
|
+
const matrix = Array.from({ length: beforeLines.length + 1 }, () => new Uint32Array(afterLines.length + 1));
|
|
100
|
+
for (let leftIndex = beforeLines.length - 1; leftIndex >= 0; leftIndex -= 1) for (let rightIndex = afterLines.length - 1; rightIndex >= 0; rightIndex -= 1) matrix[leftIndex][rightIndex] = beforeLines[leftIndex] === afterLines[rightIndex] ? matrix[leftIndex + 1][rightIndex + 1] + 1 : Math.max(matrix[leftIndex + 1][rightIndex], matrix[leftIndex][rightIndex + 1]);
|
|
101
|
+
const operations = [];
|
|
102
|
+
let leftIndex = 0;
|
|
103
|
+
let rightIndex = 0;
|
|
104
|
+
while (leftIndex < beforeLines.length && rightIndex < afterLines.length) {
|
|
105
|
+
if (beforeLines[leftIndex] === afterLines[rightIndex]) {
|
|
106
|
+
operations.push({
|
|
107
|
+
type: "context",
|
|
108
|
+
text: beforeLines[leftIndex]
|
|
109
|
+
});
|
|
110
|
+
leftIndex += 1;
|
|
111
|
+
rightIndex += 1;
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
if (matrix[leftIndex + 1][rightIndex] >= matrix[leftIndex][rightIndex + 1]) {
|
|
115
|
+
operations.push({
|
|
116
|
+
type: "remove",
|
|
117
|
+
text: beforeLines[leftIndex]
|
|
118
|
+
});
|
|
119
|
+
leftIndex += 1;
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
operations.push({
|
|
123
|
+
type: "add",
|
|
124
|
+
text: afterLines[rightIndex]
|
|
125
|
+
});
|
|
126
|
+
rightIndex += 1;
|
|
127
|
+
}
|
|
128
|
+
while (leftIndex < beforeLines.length) {
|
|
129
|
+
operations.push({
|
|
130
|
+
type: "remove",
|
|
131
|
+
text: beforeLines[leftIndex]
|
|
132
|
+
});
|
|
133
|
+
leftIndex += 1;
|
|
134
|
+
}
|
|
135
|
+
while (rightIndex < afterLines.length) {
|
|
136
|
+
operations.push({
|
|
137
|
+
type: "add",
|
|
138
|
+
text: afterLines[rightIndex]
|
|
139
|
+
});
|
|
140
|
+
rightIndex += 1;
|
|
141
|
+
}
|
|
142
|
+
return operations;
|
|
143
|
+
}
|
|
144
|
+
function buildFallbackLineOperations(beforeLines, afterLines) {
|
|
145
|
+
const operations = [];
|
|
146
|
+
let prefix = 0;
|
|
147
|
+
while (prefix < beforeLines.length && prefix < afterLines.length && beforeLines[prefix] === afterLines[prefix]) prefix += 1;
|
|
148
|
+
let beforeSuffix = beforeLines.length - 1;
|
|
149
|
+
let afterSuffix = afterLines.length - 1;
|
|
150
|
+
while (beforeSuffix >= prefix && afterSuffix >= prefix && beforeLines[beforeSuffix] === afterLines[afterSuffix]) {
|
|
151
|
+
beforeSuffix -= 1;
|
|
152
|
+
afterSuffix -= 1;
|
|
153
|
+
}
|
|
154
|
+
for (const text of beforeLines.slice(0, prefix)) operations.push({
|
|
155
|
+
type: "context",
|
|
156
|
+
text
|
|
157
|
+
});
|
|
158
|
+
for (const text of beforeLines.slice(prefix, beforeSuffix + 1)) operations.push({
|
|
159
|
+
type: "remove",
|
|
160
|
+
text
|
|
161
|
+
});
|
|
162
|
+
for (const text of afterLines.slice(prefix, afterSuffix + 1)) operations.push({
|
|
163
|
+
type: "add",
|
|
164
|
+
text
|
|
165
|
+
});
|
|
166
|
+
for (const text of beforeLines.slice(beforeSuffix + 1)) operations.push({
|
|
167
|
+
type: "context",
|
|
168
|
+
text
|
|
169
|
+
});
|
|
170
|
+
return operations;
|
|
171
|
+
}
|
|
172
|
+
//#endregion
|
|
173
|
+
exports.buildGitLineHistoryArgs = buildGitLineHistoryArgs;
|
|
174
|
+
exports.diffTouchesLineRange = diffTouchesLineRange;
|
|
175
|
+
exports.filterEntriesTouchingLineRange = filterEntriesTouchingLineRange;
|
|
176
|
+
exports.formatStatusBarLineHistoryChip = formatStatusBarLineHistoryChip;
|
|
177
|
+
exports.normalizeLineHistoryRange = normalizeLineHistoryRange;
|
|
178
|
+
exports.parseGitLineHistoryRevisions = parseGitLineHistoryRevisions;
|
|
179
|
+
exports.splitTextIntoLines = splitTextIntoLines;
|
|
180
|
+
|
|
181
|
+
//# sourceMappingURL=line-history.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"line-history.cjs","names":["textsMatchIgnoringLineEndings"],"sources":["../../src/shared/line-history.ts"],"sourcesContent":["import { textsMatchIgnoringLineEndings } from './diff-helpers.ts';\n\nexport type LineHistoryRange = {\n\tstartLine: number;\n\tendLine: number;\n};\n\nexport function normalizeLineHistoryRange(startLine: number, endLine: number): LineHistoryRange | null {\n\tif (!Number.isFinite(startLine) || !Number.isFinite(endLine)) {\n\t\treturn null;\n\t}\n\tconst start = Math.max(1, Math.floor(Math.min(startLine, endLine)));\n\tconst end = Math.max(1, Math.floor(Math.max(startLine, endLine)));\n\treturn { startLine: start, endLine: end };\n}\n\nexport function formatLineHistoryLabel(range: LineHistoryRange): string {\n\tif (range.startLine === range.endLine) {\n\t\treturn `Line ${range.startLine}`;\n\t}\n\treturn `Lines ${range.startLine}–${range.endLine}`;\n}\n\nexport function formatStatusBarLineHistoryChip(range: LineHistoryRange): string {\n\tif (range.startLine === range.endLine) {\n\t\treturn `JJ Timeline L${range.startLine}`;\n\t}\n\treturn `JJ Timeline L${range.startLine}–${range.endLine}`;\n}\n\nexport function splitTextIntoLines(value: string): string[] {\n\tif (!value) {\n\t\treturn [];\n\t}\n\tconst normalized = value.replace(/\\r\\n/g, '\\n');\n\tconst lines = normalized.split('\\n');\n\tif (lines.at(-1) === '') {\n\t\tlines.pop();\n\t}\n\treturn lines;\n}\n\n/**\n * True when the diff between before/after changes any line whose\n * before-file or after-file line number falls in the inclusive 1-based range.\n */\nexport function diffTouchesLineRange(args: {\n\tbeforeText: string;\n\tafterText: string;\n\trange: LineHistoryRange;\n}): boolean {\n\tif (textsMatchIgnoringLineEndings(args.beforeText, args.afterText)) {\n\t\treturn false;\n\t}\n\n\tconst beforeLines = splitTextIntoLines(args.beforeText);\n\tconst afterLines = splitTextIntoLines(args.afterText);\n\n\tif (!beforeLines.length && afterLines.length) {\n\t\treturn lineRangeOverlaps(1, afterLines.length, args.range);\n\t}\n\tif (beforeLines.length && !afterLines.length) {\n\t\treturn lineRangeOverlaps(1, beforeLines.length, args.range);\n\t}\n\n\tlet beforeLine = 1;\n\tlet afterLine = 1;\n\tconst operations = buildLineOperations(beforeLines, afterLines);\n\n\tfor (const operation of operations) {\n\t\tif (operation.type === 'context') {\n\t\t\tbeforeLine += 1;\n\t\t\tafterLine += 1;\n\t\t\tcontinue;\n\t\t}\n\t\tif (operation.type === 'remove') {\n\t\t\tif (lineInRange(beforeLine, args.range)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tbeforeLine += 1;\n\t\t\tcontinue;\n\t\t}\n\t\tif (lineInRange(afterLine, args.range)) {\n\t\t\treturn true;\n\t\t}\n\t\tafterLine += 1;\n\t}\n\n\treturn false;\n}\n\nexport function filterEntriesTouchingLineRange<T extends { revision: string; isWorkingTree?: boolean }>(args: {\n\tentries: T[];\n\trange: LineHistoryRange;\n\tgetContent: (entry: T) => string;\n}): T[] {\n\tif (args.entries.length <= 1) {\n\t\treturn [...args.entries];\n\t}\n\n\tconst kept: T[] = [];\n\tfor (let index = 1; index < args.entries.length; index += 1) {\n\t\tconst previous = args.entries[index - 1];\n\t\tconst entry = args.entries[index];\n\t\tif (\n\t\t\tdiffTouchesLineRange({\n\t\t\t\tbeforeText: args.getContent(previous),\n\t\t\t\tafterText: args.getContent(entry),\n\t\t\t\trange: args.range,\n\t\t\t})\n\t\t) {\n\t\t\tkept.push(entry);\n\t\t}\n\t}\n\n\tif (!kept.length) {\n\t\tconst tip = args.entries.at(-1);\n\t\treturn tip ? [tip] : [];\n\t}\n\n\tconst tip = args.entries.at(-1);\n\tif (tip && kept.at(-1) !== tip) {\n\t\tkept.push(tip);\n\t}\n\n\treturn kept;\n}\n\n/** Parse `git log -L` / `--format=%H` style stdout into ordered oldest→newest hashes. */\nexport function parseGitLineHistoryRevisions(stdout: string): string[] {\n\treturn stdout\n\t\t.split(/\\r?\\n/u)\n\t\t.map((line) => line.trim())\n\t\t.filter((line) => /^[0-9a-f]{7,40}$/i.test(line))\n\t\t.toReversed();\n}\n\nexport function buildGitLineHistoryArgs(args: {\n\trelativePath: string;\n\trange: LineHistoryRange;\n\tlimit?: number;\n}): string[] {\n\treturn [\n\t\t'log',\n\t\t'--follow',\n\t\t`-L${args.range.startLine},${args.range.endLine}:${args.relativePath}`,\n\t\t'--date=iso-strict',\n\t\t'--format=%H',\n\t\t`--max-count=${args.limit ?? 200}`,\n\t];\n}\n\nfunction lineInRange(line: number, range: LineHistoryRange): boolean {\n\treturn line >= range.startLine && line <= range.endLine;\n}\n\nfunction lineRangeOverlaps(start: number, end: number, range: LineHistoryRange): boolean {\n\treturn start <= range.endLine && end >= range.startLine;\n}\n\ntype LineOp = { type: 'context' | 'add' | 'remove'; text: string };\n\nfunction buildLineOperations(beforeLines: string[], afterLines: string[]): LineOp[] {\n\tif (!beforeLines.length) {\n\t\treturn afterLines.map((text) => ({ type: 'add' as const, text }));\n\t}\n\tif (!afterLines.length) {\n\t\treturn beforeLines.map((text) => ({ type: 'remove' as const, text }));\n\t}\n\tif (beforeLines.length * afterLines.length > 1_200_000) {\n\t\treturn buildFallbackLineOperations(beforeLines, afterLines);\n\t}\n\n\tconst matrix = Array.from({ length: beforeLines.length + 1 }, () => new Uint32Array(afterLines.length + 1));\n\tfor (let leftIndex = beforeLines.length - 1; leftIndex >= 0; leftIndex -= 1) {\n\t\tfor (let rightIndex = afterLines.length - 1; rightIndex >= 0; rightIndex -= 1) {\n\t\t\tmatrix[leftIndex][rightIndex] =\n\t\t\t\tbeforeLines[leftIndex] === afterLines[rightIndex]\n\t\t\t\t\t? matrix[leftIndex + 1][rightIndex + 1] + 1\n\t\t\t\t\t: Math.max(matrix[leftIndex + 1][rightIndex], matrix[leftIndex][rightIndex + 1]);\n\t\t}\n\t}\n\n\tconst operations: LineOp[] = [];\n\tlet leftIndex = 0;\n\tlet rightIndex = 0;\n\twhile (leftIndex < beforeLines.length && rightIndex < afterLines.length) {\n\t\tif (beforeLines[leftIndex] === afterLines[rightIndex]) {\n\t\t\toperations.push({ type: 'context', text: beforeLines[leftIndex] });\n\t\t\tleftIndex += 1;\n\t\t\trightIndex += 1;\n\t\t\tcontinue;\n\t\t}\n\t\tif (matrix[leftIndex + 1][rightIndex] >= matrix[leftIndex][rightIndex + 1]) {\n\t\t\toperations.push({ type: 'remove', text: beforeLines[leftIndex] });\n\t\t\tleftIndex += 1;\n\t\t\tcontinue;\n\t\t}\n\t\toperations.push({ type: 'add', text: afterLines[rightIndex] });\n\t\trightIndex += 1;\n\t}\n\twhile (leftIndex < beforeLines.length) {\n\t\toperations.push({ type: 'remove', text: beforeLines[leftIndex] });\n\t\tleftIndex += 1;\n\t}\n\twhile (rightIndex < afterLines.length) {\n\t\toperations.push({ type: 'add', text: afterLines[rightIndex] });\n\t\trightIndex += 1;\n\t}\n\treturn operations;\n}\n\nfunction buildFallbackLineOperations(beforeLines: string[], afterLines: string[]): LineOp[] {\n\tconst operations: LineOp[] = [];\n\tlet prefix = 0;\n\twhile (prefix < beforeLines.length && prefix < afterLines.length && beforeLines[prefix] === afterLines[prefix]) {\n\t\tprefix += 1;\n\t}\n\tlet beforeSuffix = beforeLines.length - 1;\n\tlet afterSuffix = afterLines.length - 1;\n\twhile (beforeSuffix >= prefix && afterSuffix >= prefix && beforeLines[beforeSuffix] === afterLines[afterSuffix]) {\n\t\tbeforeSuffix -= 1;\n\t\tafterSuffix -= 1;\n\t}\n\tfor (const text of beforeLines.slice(0, prefix)) {\n\t\toperations.push({ type: 'context', text });\n\t}\n\tfor (const text of beforeLines.slice(prefix, beforeSuffix + 1)) {\n\t\toperations.push({ type: 'remove', text });\n\t}\n\tfor (const text of afterLines.slice(prefix, afterSuffix + 1)) {\n\t\toperations.push({ type: 'add', text });\n\t}\n\tfor (const text of beforeLines.slice(beforeSuffix + 1)) {\n\t\toperations.push({ type: 'context', text });\n\t}\n\treturn operations;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
//#region src/shared/list-file-revisions.ts
|
|
2
|
+
async function listFileRevisionIds(args) {
|
|
3
|
+
if (args.backend === "git") {
|
|
4
|
+
const { stdout } = await args.runner.runGit({
|
|
5
|
+
workspacePath: args.workspacePath,
|
|
6
|
+
args: [
|
|
7
|
+
"log",
|
|
8
|
+
"--follow",
|
|
9
|
+
"--format=%H",
|
|
10
|
+
"--",
|
|
11
|
+
args.relativePath
|
|
12
|
+
]
|
|
13
|
+
});
|
|
14
|
+
return stdout.split(/\r?\n/u).map((line) => line.trim()).filter(Boolean).toReversed();
|
|
15
|
+
}
|
|
16
|
+
const { stdout } = await args.runner.runJj({
|
|
17
|
+
workspacePath: args.workspacePath,
|
|
18
|
+
args: [
|
|
19
|
+
"log",
|
|
20
|
+
"-r",
|
|
21
|
+
"::@",
|
|
22
|
+
"--no-graph",
|
|
23
|
+
"-T",
|
|
24
|
+
"commit_id ++ \"\\n\"",
|
|
25
|
+
"--",
|
|
26
|
+
args.relativePath
|
|
27
|
+
]
|
|
28
|
+
});
|
|
29
|
+
const ids = stdout.split(/\r?\n/u).map((line) => line.trim()).filter(Boolean).toReversed();
|
|
30
|
+
if (ids.at(-1) !== "@") ids.push("@");
|
|
31
|
+
return ids;
|
|
32
|
+
}
|
|
33
|
+
//#endregion
|
|
34
|
+
exports.listFileRevisionIds = listFileRevisionIds;
|
|
35
|
+
|
|
36
|
+
//# sourceMappingURL=list-file-revisions.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-file-revisions.cjs","names":[],"sources":["../../src/shared/list-file-revisions.ts"],"sourcesContent":["export async function listFileRevisionIds(args: {\n\trunner: {\n\t\trunGit: (args: { workspacePath: string; args: string[] }) => Promise<{ stdout: string }>;\n\t\trunJj: (args: { workspacePath: string; args: string[] }) => Promise<{ stdout: string }>;\n\t};\n\tworkspacePath: string;\n\trelativePath: string;\n\tbackend: 'git' | 'jj';\n}): Promise<string[]> {\n\tif (args.backend === 'git') {\n\t\tconst { stdout } = await args.runner.runGit({\n\t\t\tworkspacePath: args.workspacePath,\n\t\t\targs: ['log', '--follow', '--format=%H', '--', args.relativePath],\n\t\t});\n\t\treturn stdout\n\t\t\t.split(/\\r?\\n/u)\n\t\t\t.map((line) => line.trim())\n\t\t\t.filter(Boolean)\n\t\t\t.toReversed();\n\t}\n\tconst { stdout } = await args.runner.runJj({\n\t\tworkspacePath: args.workspacePath,\n\t\targs: ['log', '-r', '::@', '--no-graph', '-T', 'commit_id ++ \"\\\\n\"', '--', args.relativePath],\n\t});\n\tconst ids = stdout\n\t\t.split(/\\r?\\n/u)\n\t\t.map((line) => line.trim())\n\t\t.filter(Boolean)\n\t\t.toReversed();\n\tif (ids.at(-1) !== '@') {\n\t\tids.push('@');\n\t}\n\treturn ids;\n}\n"],"mappings":";AAAA,eAAsB,oBAAoB,MAQpB;CACrB,IAAI,KAAK,YAAY,OAAO;EAC3B,MAAM,EAAE,WAAW,MAAM,KAAK,OAAO,OAAO;GAC3C,eAAe,KAAK;GACpB,MAAM;IAAC;IAAO;IAAY;IAAe;IAAM,KAAK;GAAY;EACjE,CAAC;EACD,OAAO,OACL,MAAM,QAAQ,CAAC,CACf,KAAK,SAAS,KAAK,KAAK,CAAC,CAAC,CAC1B,OAAO,OAAO,CAAC,CACf,WAAW;CACd;CACA,MAAM,EAAE,WAAW,MAAM,KAAK,OAAO,MAAM;EAC1C,eAAe,KAAK;EACpB,MAAM;GAAC;GAAO;GAAM;GAAO;GAAc;GAAM;GAAsB;GAAM,KAAK;EAAY;CAC7F,CAAC;CACD,MAAM,MAAM,OACV,MAAM,QAAQ,CAAC,CACf,KAAK,SAAS,KAAK,KAAK,CAAC,CAAC,CAC1B,OAAO,OAAO,CAAC,CACf,WAAW;CACb,IAAI,IAAI,GAAG,EAAE,MAAM,KAClB,IAAI,KAAK,GAAG;CAEb,OAAO;AACR"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
const require_diff_helpers = require("./diff-helpers.cjs");
|
|
2
|
+
//#region src/shared/non-textual-details.ts
|
|
3
|
+
function stripAllWhitespace(value) {
|
|
4
|
+
return value.replace(/\s+/gu, "");
|
|
5
|
+
}
|
|
6
|
+
function textsMatchIgnoringWhitespace(beforeText, afterText) {
|
|
7
|
+
return stripAllWhitespace(beforeText) === stripAllWhitespace(afterText);
|
|
8
|
+
}
|
|
9
|
+
function looksBinary(text) {
|
|
10
|
+
return text.includes("\0");
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Explain why a selection has no textual line diff worth rendering in Pierre.
|
|
14
|
+
* Always returns at least one human-readable reason when called for an empty preview.
|
|
15
|
+
*/
|
|
16
|
+
function buildNonTextualDetails(args) {
|
|
17
|
+
const details = [];
|
|
18
|
+
const before = args.beforeText ?? "";
|
|
19
|
+
const after = args.afterText ?? "";
|
|
20
|
+
const beforePath = args.beforePath || "";
|
|
21
|
+
const afterPath = args.afterPath || "";
|
|
22
|
+
if (beforePath && afterPath && beforePath !== afterPath) details.push(`Path changed: ${beforePath} -> ${afterPath}`);
|
|
23
|
+
if (args.beforeMode && args.afterMode && args.beforeMode !== args.afterMode) details.push(`File mode changed: ${args.beforeMode} -> ${args.afterMode}`);
|
|
24
|
+
if (!before && !after) {
|
|
25
|
+
details.push("Both sides are empty for this path.");
|
|
26
|
+
return details;
|
|
27
|
+
}
|
|
28
|
+
if (looksBinary(before) || looksBinary(after)) {
|
|
29
|
+
details.push("Binary (or null-byte) content changed; inline text diff is skipped.");
|
|
30
|
+
return details;
|
|
31
|
+
}
|
|
32
|
+
if (before !== after && require_diff_helpers.textsMatchIgnoringLineEndings(before, after)) details.push("Line endings changed.");
|
|
33
|
+
if (before !== after && !require_diff_helpers.textsMatchIgnoringLineEndings(before, after) && textsMatchIgnoringWhitespace(before, after)) details.push("Whitespace-only changes.");
|
|
34
|
+
if (!before && after) details.push("File appeared (empty before, content after) but no line hunks were produced.");
|
|
35
|
+
else if (before && !after) details.push("File disappeared (content before, empty after) but no line hunks were produced.");
|
|
36
|
+
if (!details.length && args.isWorkingTree) details.push("The working tree differs in a way this preview does not render as a textual line diff.");
|
|
37
|
+
if (!details.length) details.push("This selection changed file metadata or another non-text detail that is not shown in the inline preview.");
|
|
38
|
+
return details;
|
|
39
|
+
}
|
|
40
|
+
//#endregion
|
|
41
|
+
exports.buildNonTextualDetails = buildNonTextualDetails;
|
|
42
|
+
|
|
43
|
+
//# sourceMappingURL=non-textual-details.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"non-textual-details.cjs","names":["textsMatchIgnoringLineEndings"],"sources":["../../src/shared/non-textual-details.ts"],"sourcesContent":["import { textsMatchIgnoringLineEndings } from './diff-helpers.ts';\n\nexport type NonTextualDetailArgs = {\n\tbeforeText: string;\n\tafterText: string;\n\tbeforePath: string;\n\tafterPath: string;\n\tisWorkingTree?: boolean;\n\t/** Optional file modes from git/jj (e.g. 100644 / 100755). */\n\tbeforeMode?: string;\n\tafterMode?: string;\n};\n\nfunction stripAllWhitespace(value: string): string {\n\treturn value.replace(/\\s+/gu, '');\n}\n\nfunction textsMatchIgnoringWhitespace(beforeText: string, afterText: string): boolean {\n\treturn stripAllWhitespace(beforeText) === stripAllWhitespace(afterText);\n}\n\nfunction looksBinary(text: string): boolean {\n\treturn text.includes('\\u0000');\n}\n\n/**\n * Explain why a selection has no textual line diff worth rendering in Pierre.\n * Always returns at least one human-readable reason when called for an empty preview.\n */\nexport function buildNonTextualDetails(args: NonTextualDetailArgs): string[] {\n\tconst details: string[] = [];\n\tconst before = args.beforeText ?? '';\n\tconst after = args.afterText ?? '';\n\tconst beforePath = args.beforePath || '';\n\tconst afterPath = args.afterPath || '';\n\n\tif (beforePath && afterPath && beforePath !== afterPath) {\n\t\tdetails.push(`Path changed: ${beforePath} -> ${afterPath}`);\n\t}\n\n\tif (args.beforeMode && args.afterMode && args.beforeMode !== args.afterMode) {\n\t\tdetails.push(`File mode changed: ${args.beforeMode} -> ${args.afterMode}`);\n\t}\n\n\tif (!before && !after) {\n\t\tdetails.push('Both sides are empty for this path.');\n\t\treturn details;\n\t}\n\n\tif (looksBinary(before) || looksBinary(after)) {\n\t\tdetails.push('Binary (or null-byte) content changed; inline text diff is skipped.');\n\t\treturn details;\n\t}\n\n\tif (before !== after && textsMatchIgnoringLineEndings(before, after)) {\n\t\tdetails.push('Line endings changed.');\n\t}\n\n\tif (\n\t\tbefore !== after &&\n\t\t!textsMatchIgnoringLineEndings(before, after) &&\n\t\ttextsMatchIgnoringWhitespace(before, after)\n\t) {\n\t\tdetails.push('Whitespace-only changes.');\n\t}\n\n\tif (!before && after) {\n\t\tdetails.push('File appeared (empty before, content after) but no line hunks were produced.');\n\t} else if (before && !after) {\n\t\tdetails.push('File disappeared (content before, empty after) but no line hunks were produced.');\n\t}\n\n\tif (!details.length && args.isWorkingTree) {\n\t\tdetails.push('The working tree differs in a way this preview does not render as a textual line diff.');\n\t}\n\n\tif (!details.length) {\n\t\tdetails.push(\n\t\t\t'This selection changed file metadata or another non-text detail that is not shown in the inline preview.',\n\t\t);\n\t}\n\n\treturn details;\n}\n"],"mappings":";;AAaA,SAAS,mBAAmB,OAAuB;CAClD,OAAO,MAAM,QAAQ,SAAS,EAAE;AACjC;AAEA,SAAS,6BAA6B,YAAoB,WAA4B;CACrF,OAAO,mBAAmB,UAAU,MAAM,mBAAmB,SAAS;AACvE;AAEA,SAAS,YAAY,MAAuB;CAC3C,OAAO,KAAK,SAAS,IAAQ;AAC9B;;;;;AAMA,SAAgB,uBAAuB,MAAsC;CAC5E,MAAM,UAAoB,CAAC;CAC3B,MAAM,SAAS,KAAK,cAAc;CAClC,MAAM,QAAQ,KAAK,aAAa;CAChC,MAAM,aAAa,KAAK,cAAc;CACtC,MAAM,YAAY,KAAK,aAAa;CAEpC,IAAI,cAAc,aAAa,eAAe,WAC7C,QAAQ,KAAK,iBAAiB,WAAW,MAAM,WAAW;CAG3D,IAAI,KAAK,cAAc,KAAK,aAAa,KAAK,eAAe,KAAK,WACjE,QAAQ,KAAK,sBAAsB,KAAK,WAAW,MAAM,KAAK,WAAW;CAG1E,IAAI,CAAC,UAAU,CAAC,OAAO;EACtB,QAAQ,KAAK,qCAAqC;EAClD,OAAO;CACR;CAEA,IAAI,YAAY,MAAM,KAAK,YAAY,KAAK,GAAG;EAC9C,QAAQ,KAAK,qEAAqE;EAClF,OAAO;CACR;CAEA,IAAI,WAAW,SAASA,qBAAAA,8BAA8B,QAAQ,KAAK,GAClE,QAAQ,KAAK,uBAAuB;CAGrC,IACC,WAAW,SACX,CAACA,qBAAAA,8BAA8B,QAAQ,KAAK,KAC5C,6BAA6B,QAAQ,KAAK,GAE1C,QAAQ,KAAK,0BAA0B;CAGxC,IAAI,CAAC,UAAU,OACd,QAAQ,KAAK,8EAA8E;MACrF,IAAI,UAAU,CAAC,OACrB,QAAQ,KAAK,iFAAiF;CAG/F,IAAI,CAAC,QAAQ,UAAU,KAAK,eAC3B,QAAQ,KAAK,wFAAwF;CAGtG,IAAI,CAAC,QAAQ,QACZ,QAAQ,KACP,0GACD;CAGD,OAAO;AACR"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
//#region src/shared/resolve-file-path.ts
|
|
2
|
+
/** Coerce editor/title / command args (Uri | string | { fsPath }) into a filesystem path. */
|
|
3
|
+
function coerceFsPath(value) {
|
|
4
|
+
if (typeof value === "string" && value.trim()) return value;
|
|
5
|
+
if (!value || typeof value !== "object") return;
|
|
6
|
+
const fsPath = Reflect.get(value, "fsPath");
|
|
7
|
+
if (typeof fsPath === "string" && fsPath.trim()) return fsPath;
|
|
8
|
+
const pathValue = Reflect.get(value, "path");
|
|
9
|
+
if (typeof pathValue === "string" && pathValue.trim() && !pathValue.includes("://")) return pathValue;
|
|
10
|
+
}
|
|
11
|
+
//#endregion
|
|
12
|
+
exports.coerceFsPath = coerceFsPath;
|
|
13
|
+
|
|
14
|
+
//# sourceMappingURL=resolve-file-path.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-file-path.cjs","names":[],"sources":["../../src/shared/resolve-file-path.ts"],"sourcesContent":["/** Coerce editor/title / command args (Uri | string | { fsPath }) into a filesystem path. */\nexport function coerceFsPath(value: unknown): string | undefined {\n\tif (typeof value === 'string' && value.trim()) {\n\t\treturn value;\n\t}\n\tif (!value || typeof value !== 'object') {\n\t\treturn undefined;\n\t}\n\tconst fsPath = Reflect.get(value, 'fsPath');\n\tif (typeof fsPath === 'string' && fsPath.trim()) {\n\t\treturn fsPath;\n\t}\n\tconst pathValue = Reflect.get(value, 'path');\n\tif (typeof pathValue === 'string' && pathValue.trim() && !pathValue.includes('://')) {\n\t\treturn pathValue;\n\t}\n\treturn undefined;\n}\n"],"mappings":";;AACA,SAAgB,aAAa,OAAoC;CAChE,IAAI,OAAO,UAAU,YAAY,MAAM,KAAK,GAC3C,OAAO;CAER,IAAI,CAAC,SAAS,OAAO,UAAU,UAC9B;CAED,MAAM,SAAS,QAAQ,IAAI,OAAO,QAAQ;CAC1C,IAAI,OAAO,WAAW,YAAY,OAAO,KAAK,GAC7C,OAAO;CAER,MAAM,YAAY,QAAQ,IAAI,OAAO,MAAM;CAC3C,IAAI,OAAO,cAAc,YAAY,UAAU,KAAK,KAAK,CAAC,UAAU,SAAS,KAAK,GACjF,OAAO;AAGT"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
//#region src/shared/revision-diff-availability.ts
|
|
2
|
+
/** tipIndex is the "after" side; a pair needs tipIndex >= 1. */
|
|
3
|
+
function getRevisionDiffNavAvailability(session) {
|
|
4
|
+
if (!session || session.revisions.length < 2) return {
|
|
5
|
+
active: false,
|
|
6
|
+
hasPrevious: false,
|
|
7
|
+
hasNext: false
|
|
8
|
+
};
|
|
9
|
+
return {
|
|
10
|
+
active: true,
|
|
11
|
+
hasPrevious: session.previousTipIndex === void 0 ? session.tipIndex > 1 : session.previousTipIndex !== null,
|
|
12
|
+
hasNext: session.nextTipIndex === void 0 ? session.tipIndex < session.revisions.length - 1 : session.nextTipIndex !== null
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
exports.getRevisionDiffNavAvailability = getRevisionDiffNavAvailability;
|
|
17
|
+
|
|
18
|
+
//# sourceMappingURL=revision-diff-availability.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"revision-diff-availability.cjs","names":[],"sources":["../../src/shared/revision-diff-availability.ts"],"sourcesContent":["export type RevisionDiffSessionLike = {\n\trevisions: string[];\n\t/** Index of the \"after\" / tip side currently shown. */\n\ttipIndex: number;\n\t/** Nearest non-empty pair before the current one; null means the edge is known. */\n\tpreviousTipIndex?: number | null;\n\t/** Nearest non-empty pair after the current one; null means the edge is known. */\n\tnextTipIndex?: number | null;\n};\n\nexport type RevisionDiffNavAvailability = {\n\tactive: boolean;\n\thasPrevious: boolean;\n\thasNext: boolean;\n};\n\n/** tipIndex is the \"after\" side; a pair needs tipIndex >= 1. */\nexport function getRevisionDiffNavAvailability(\n\tsession: RevisionDiffSessionLike | undefined,\n): RevisionDiffNavAvailability {\n\tif (!session || session.revisions.length < 2) {\n\t\treturn { active: false, hasPrevious: false, hasNext: false };\n\t}\n\tconst hasPrevious = session.previousTipIndex === undefined ? session.tipIndex > 1 : session.previousTipIndex !== null;\n\tconst hasNext =\n\t\tsession.nextTipIndex === undefined\n\t\t\t? session.tipIndex < session.revisions.length - 1\n\t\t\t: session.nextTipIndex !== null;\n\treturn {\n\t\tactive: true,\n\t\thasPrevious,\n\t\thasNext,\n\t};\n}\n"],"mappings":";;AAiBA,SAAgB,+BACf,SAC8B;CAC9B,IAAI,CAAC,WAAW,QAAQ,UAAU,SAAS,GAC1C,OAAO;EAAE,QAAQ;EAAO,aAAa;EAAO,SAAS;CAAM;CAO5D,OAAO;EACN,QAAQ;EACR,aAPmB,QAAQ,qBAAqB,KAAA,IAAY,QAAQ,WAAW,IAAI,QAAQ,qBAAqB;EAQhH,SANA,QAAQ,iBAAiB,KAAA,IACtB,QAAQ,WAAW,QAAQ,UAAU,SAAS,IAC9C,QAAQ,iBAAiB;CAK7B;AACD"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
//#region src/shared/revision-diff-pair.ts
|
|
2
|
+
/**
|
|
3
|
+
* Walk tipIndex downward until base→tip file contents differ.
|
|
4
|
+
* Avoids empty vscode.diff when tip is `@` (or any rev) with identical content to its parent side.
|
|
5
|
+
*/
|
|
6
|
+
async function resolveNonEmptyRevisionPair(args) {
|
|
7
|
+
return resolveNonEmptyRevisionPairInDirection({
|
|
8
|
+
...args,
|
|
9
|
+
direction: "backward"
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
/** Walk tipIndex upward to the next non-empty pair after the current diff. */
|
|
13
|
+
async function resolveNextNonEmptyRevisionPair(args) {
|
|
14
|
+
return resolveNonEmptyRevisionPairInDirection({
|
|
15
|
+
...args,
|
|
16
|
+
direction: "forward"
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
async function resolveNonEmptyRevisionPairInDirection(args) {
|
|
20
|
+
let tipIndex = args.direction === "backward" ? Math.min(args.tipIndex, args.revisions.length - 1) : Math.max(1, args.tipIndex);
|
|
21
|
+
const step = args.direction === "backward" ? -1 : 1;
|
|
22
|
+
while (tipIndex >= 1 && tipIndex < args.revisions.length) {
|
|
23
|
+
const tip = args.revisions[tipIndex];
|
|
24
|
+
const base = args.revisions[tipIndex - 1];
|
|
25
|
+
if (!tip || !base) break;
|
|
26
|
+
const [originalContent, modifiedContent] = await Promise.all([args.showFile(base), args.showFile(tip)]);
|
|
27
|
+
if (originalContent !== modifiedContent) return {
|
|
28
|
+
tipIndex,
|
|
29
|
+
base,
|
|
30
|
+
tip,
|
|
31
|
+
originalContent,
|
|
32
|
+
modifiedContent
|
|
33
|
+
};
|
|
34
|
+
tipIndex += step;
|
|
35
|
+
}
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
//#endregion
|
|
39
|
+
exports.resolveNextNonEmptyRevisionPair = resolveNextNonEmptyRevisionPair;
|
|
40
|
+
exports.resolveNonEmptyRevisionPair = resolveNonEmptyRevisionPair;
|
|
41
|
+
|
|
42
|
+
//# sourceMappingURL=revision-diff-pair.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"revision-diff-pair.cjs","names":[],"sources":["../../src/shared/revision-diff-pair.ts"],"sourcesContent":["type RevisionPairArgs = {\n\trevisions: string[];\n\ttipIndex: number;\n\tshowFile: (revset: string) => Promise<string>;\n};\n\nexport type NonEmptyRevisionPair = {\n\ttipIndex: number;\n\tbase: string;\n\ttip: string;\n\toriginalContent: string;\n\tmodifiedContent: string;\n};\n\n/**\n * Walk tipIndex downward until base→tip file contents differ.\n * Avoids empty vscode.diff when tip is `@` (or any rev) with identical content to its parent side.\n */\nexport async function resolveNonEmptyRevisionPair(args: RevisionPairArgs): Promise<NonEmptyRevisionPair | null> {\n\treturn resolveNonEmptyRevisionPairInDirection({ ...args, direction: 'backward' });\n}\n\n/** Walk tipIndex upward to the next non-empty pair after the current diff. */\nexport async function resolveNextNonEmptyRevisionPair(args: RevisionPairArgs): Promise<NonEmptyRevisionPair | null> {\n\treturn resolveNonEmptyRevisionPairInDirection({ ...args, direction: 'forward' });\n}\n\nasync function resolveNonEmptyRevisionPairInDirection(\n\targs: RevisionPairArgs & { direction: 'backward' | 'forward' },\n): Promise<NonEmptyRevisionPair | null> {\n\tlet tipIndex =\n\t\targs.direction === 'backward' ? Math.min(args.tipIndex, args.revisions.length - 1) : Math.max(1, args.tipIndex);\n\tconst step = args.direction === 'backward' ? -1 : 1;\n\n\twhile (tipIndex >= 1 && tipIndex < args.revisions.length) {\n\t\tconst tip = args.revisions[tipIndex];\n\t\tconst base = args.revisions[tipIndex - 1];\n\t\tif (!tip || !base) {\n\t\t\tbreak;\n\t\t}\n\t\tconst [originalContent, modifiedContent] = await Promise.all([args.showFile(base), args.showFile(tip)]);\n\t\tif (originalContent !== modifiedContent) {\n\t\t\treturn { tipIndex, base, tip, originalContent, modifiedContent };\n\t\t}\n\t\ttipIndex += step;\n\t}\n\treturn null;\n}\n"],"mappings":";;;;;AAkBA,eAAsB,4BAA4B,MAA8D;CAC/G,OAAO,uCAAuC;EAAE,GAAG;EAAM,WAAW;CAAW,CAAC;AACjF;;AAGA,eAAsB,gCAAgC,MAA8D;CACnH,OAAO,uCAAuC;EAAE,GAAG;EAAM,WAAW;CAAU,CAAC;AAChF;AAEA,eAAe,uCACd,MACuC;CACvC,IAAI,WACH,KAAK,cAAc,aAAa,KAAK,IAAI,KAAK,UAAU,KAAK,UAAU,SAAS,CAAC,IAAI,KAAK,IAAI,GAAG,KAAK,QAAQ;CAC/G,MAAM,OAAO,KAAK,cAAc,aAAa,KAAK;CAElD,OAAO,YAAY,KAAK,WAAW,KAAK,UAAU,QAAQ;EACzD,MAAM,MAAM,KAAK,UAAU;EAC3B,MAAM,OAAO,KAAK,UAAU,WAAW;EACvC,IAAI,CAAC,OAAO,CAAC,MACZ;EAED,MAAM,CAAC,iBAAiB,mBAAmB,MAAM,QAAQ,IAAI,CAAC,KAAK,SAAS,IAAI,GAAG,KAAK,SAAS,GAAG,CAAC,CAAC;EACtG,IAAI,oBAAoB,iBACvB,OAAO;GAAE;GAAU;GAAM;GAAK;GAAiB;EAAgB;EAEhE,YAAY;CACb;CACA,OAAO;AACR"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
//#region src/shared/revset.ts
|
|
2
|
+
/** Normalize a user-entered jj revset; empty means "use default history". */
|
|
3
|
+
function normalizeCustomRevset(value) {
|
|
4
|
+
return (value || "").trim();
|
|
5
|
+
}
|
|
6
|
+
/** Combine an optional power-user revset with the default ancestor window. */
|
|
7
|
+
function composeJjHistoryRevset(args) {
|
|
8
|
+
const custom = normalizeCustomRevset(args.customRevset);
|
|
9
|
+
if (!custom) return args.defaultRevset;
|
|
10
|
+
return `(${custom}) & (${args.defaultRevset})`;
|
|
11
|
+
}
|
|
12
|
+
//#endregion
|
|
13
|
+
exports.composeJjHistoryRevset = composeJjHistoryRevset;
|
|
14
|
+
exports.normalizeCustomRevset = normalizeCustomRevset;
|
|
15
|
+
|
|
16
|
+
//# sourceMappingURL=revset.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"revset.cjs","names":[],"sources":["../../src/shared/revset.ts"],"sourcesContent":["/** Normalize a user-entered jj revset; empty means \"use default history\". */\nexport function normalizeCustomRevset(value: string | null | undefined): string {\n\treturn (value || '').trim();\n}\n\nexport function isCustomRevsetActive(value: string | null | undefined): boolean {\n\treturn normalizeCustomRevset(value).length > 0;\n}\n\n/** Combine an optional power-user revset with the default ancestor window. */\nexport function composeJjHistoryRevset(args: { defaultRevset: string; customRevset?: string | null }): string {\n\tconst custom = normalizeCustomRevset(args.customRevset);\n\tif (!custom) {\n\t\treturn args.defaultRevset;\n\t}\n\treturn `(${custom}) & (${args.defaultRevset})`;\n}\n"],"mappings":";;AACA,SAAgB,sBAAsB,OAA0C;CAC/E,QAAQ,SAAS,GAAA,CAAI,KAAK;AAC3B;;AAOA,SAAgB,uBAAuB,MAAuE;CAC7G,MAAM,SAAS,sBAAsB,KAAK,YAAY;CACtD,IAAI,CAAC,QACJ,OAAO,KAAK;CAEb,OAAO,IAAI,OAAO,OAAO,KAAK,cAAc;AAC7C"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
//#region src/shared/timeline-model.ts
|
|
2
|
+
function getEntriesForSource(data, comparisonSource) {
|
|
3
|
+
if (!data) return [];
|
|
4
|
+
if (data.backend === "jj" && comparisonSource === "snapshot") {
|
|
5
|
+
const revisionEntries = Array.isArray(data.entries) ? data.entries : [];
|
|
6
|
+
const snapshotEntries = Array.isArray(data.snapshotEntries) ? data.snapshotEntries : [];
|
|
7
|
+
const loadedChangeIds = new Set(Array.isArray(data.snapshotState?.loadedChangeIds) ? data.snapshotState.loadedChangeIds : []);
|
|
8
|
+
if (!loadedChangeIds.size) return revisionEntries;
|
|
9
|
+
const snapshotEntriesByChangeId = snapshotEntries.reduce((groups, entry) => {
|
|
10
|
+
if (!entry.changeId) return groups;
|
|
11
|
+
const existing = groups.get(entry.changeId) || [];
|
|
12
|
+
existing.push(entry);
|
|
13
|
+
groups.set(entry.changeId, existing);
|
|
14
|
+
return groups;
|
|
15
|
+
}, /* @__PURE__ */ new Map());
|
|
16
|
+
return revisionEntries.flatMap((entry) => {
|
|
17
|
+
if (!entry.changeId || entry.isWorkingTree || !entry.touchesFile || !loadedChangeIds.has(entry.changeId)) return [entry];
|
|
18
|
+
return snapshotEntriesByChangeId.get(entry.changeId) || [entry];
|
|
19
|
+
}).map((entry, index) => ({
|
|
20
|
+
...entry,
|
|
21
|
+
index
|
|
22
|
+
}));
|
|
23
|
+
}
|
|
24
|
+
return Array.isArray(data.entries) ? data.entries : [];
|
|
25
|
+
}
|
|
26
|
+
//#endregion
|
|
27
|
+
exports.getEntriesForSource = getEntriesForSource;
|
|
28
|
+
|
|
29
|
+
//# sourceMappingURL=timeline-model.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timeline-model.cjs","names":[],"sources":["../../src/shared/timeline-model.ts"],"sourcesContent":["import type {\n\tComparisonMode,\n\tComparisonSource,\n\tDiffPreview,\n\tFileRevisionEntry,\n\tRangeOverviewItem,\n\tTimelineData,\n} from './timeline-types.ts';\n\nexport function getEntriesForSource(\n\tdata: TimelineData | null,\n\tcomparisonSource: ComparisonSource,\n): FileRevisionEntry[] {\n\tif (!data) {\n\t\treturn [];\n\t}\n\n\tif (data.backend === 'jj' && comparisonSource === 'snapshot') {\n\t\tconst revisionEntries = Array.isArray(data.entries) ? data.entries : [];\n\t\tconst snapshotEntries = Array.isArray(data.snapshotEntries) ? data.snapshotEntries : [];\n\t\tconst loadedChangeIds = new Set(\n\t\t\tArray.isArray(data.snapshotState?.loadedChangeIds) ? data.snapshotState.loadedChangeIds : [],\n\t\t);\n\n\t\tif (!loadedChangeIds.size) {\n\t\t\treturn revisionEntries;\n\t\t}\n\n\t\tconst snapshotEntriesByChangeId = 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 revisionEntries\n\t\t\t.flatMap((entry) => {\n\t\t\t\tif (!entry.changeId || entry.isWorkingTree || !entry.touchesFile || !loadedChangeIds.has(entry.changeId)) {\n\t\t\t\t\treturn [entry];\n\t\t\t\t}\n\t\t\t\treturn snapshotEntriesByChangeId.get(entry.changeId) || [entry];\n\t\t\t})\n\t\t\t.map((entry, index) => ({ ...entry, index }));\n\t}\n\n\treturn Array.isArray(data.entries) ? data.entries : [];\n}\n\nexport function getSelectedEntryCount(visibleEntries: FileRevisionEntry[], fromIndex: number, toIndex: number): number {\n\tconst minIndex = Math.min(fromIndex, toIndex);\n\tconst maxIndex = Math.max(fromIndex, toIndex);\n\treturn visibleEntries.filter(\n\t\t(entry) => entry.index !== undefined && entry.index >= minIndex && entry.index <= maxIndex,\n\t).length;\n}\n\nexport function findRevisionEntryMatch(entries: FileRevisionEntry[], value: string): FileRevisionEntry | undefined {\n\tconst query = value.trim().toLowerCase();\n\tif (!query) {\n\t\treturn undefined;\n\t}\n\n\treturn (\n\t\tentries.find((entry) => entry.shortRevision.toLowerCase() === query) ||\n\t\tentries.find((entry) => entry.revision.toLowerCase().startsWith(query))\n\t);\n}\n\nexport function getSelectedDiffEntryIndexes(\n\tvisibleEntries: FileRevisionEntry[],\n\tfromIndex: number,\n\ttoIndex: number,\n\tcomparisonMode: ComparisonMode,\n): number[] {\n\tif (!visibleEntries.length) {\n\t\treturn [];\n\t}\n\n\tif (comparisonMode === 'step') {\n\t\treturn visibleEntries.some((entry) => entry.index === toIndex) ? [toIndex] : [];\n\t}\n\n\tconst minIndex = Math.min(fromIndex, toIndex);\n\tconst maxIndex = Math.max(fromIndex, toIndex);\n\treturn visibleEntries\n\t\t.map((entry) => entry.index)\n\t\t.filter(\n\t\t\t(entryIndex): entryIndex is number =>\n\t\t\t\tentryIndex !== undefined && entryIndex >= minIndex && entryIndex <= maxIndex,\n\t\t)\n\t\t.slice(1);\n}\n\nexport function getRangeOverviewDiffCount(items: RangeOverviewItem[]): number {\n\treturn items.reduce((total, item) => total + item.changeCount, 0);\n}\n\nexport function getTimelineAnchorPercent(visibleEntries: FileRevisionEntry[], visibleIndex: number): number {\n\tif (!visibleEntries.length) {\n\t\treturn 0;\n\t}\n\n\tconst denominator = Math.max(1, visibleEntries.length - 1);\n\treturn (Math.min(Math.max(visibleIndex, 0), visibleEntries.length - 1) / denominator) * 100;\n}\n\nexport function getPendingSnapshotRevisionIndexes(\n\trevisionEntries: FileRevisionEntry[],\n\tloadedChangeIds: Set<string>,\n\tlimit: number,\n\tpreferredIndexes: number[] = [],\n): number[] {\n\tconst preferredIndexSet = new Set(preferredIndexes);\n\tconst seenChangeIds = new Set<string>();\n\tconst orderedEntries = [\n\t\t...revisionEntries.filter((entry) => preferredIndexSet.has(entry.index ?? -1)),\n\t\t...revisionEntries,\n\t];\n\n\treturn orderedEntries\n\t\t.reduce<number[]>((indexes, entry) => {\n\t\t\tif (\n\t\t\t\t!entry.touchesFile ||\n\t\t\t\tentry.isWorkingTree ||\n\t\t\t\t!entry.changeId ||\n\t\t\t\tloadedChangeIds.has(entry.changeId) ||\n\t\t\t\tseenChangeIds.has(entry.changeId) ||\n\t\t\t\tentry.index === undefined\n\t\t\t) {\n\t\t\t\treturn indexes;\n\t\t\t}\n\n\t\t\tseenChangeIds.add(entry.changeId);\n\t\t\tindexes.push(entry.index);\n\t\t\treturn indexes;\n\t\t}, [])\n\t\t.slice(0, limit);\n}\n\nexport function getUnitPreviewRange(\n\tvisibleEntries: FileRevisionEntry[],\n\ttoIndex: number,\n): { fromIndex: number; toIndex: number } | null {\n\tconst currentIndex = visibleEntries.findIndex((entry) => entry.index === toIndex);\n\tif (currentIndex <= 0) {\n\t\treturn null;\n\t}\n\n\treturn {\n\t\tfromIndex: visibleEntries[currentIndex - 1]?.index ?? toIndex,\n\t\ttoIndex: visibleEntries[currentIndex]?.index ?? toIndex,\n\t};\n}\n\nexport function getSidebarPreviewRequests(\n\tvisibleEntries: FileRevisionEntry[],\n\tcomparisonSource: ComparisonSource,\n\tpreviewByRange: Record<string, DiffPreview>,\n\tselectedPreviewKey: string,\n\tbuildPreviewKey: (fromIndex: number, toIndex: number, source: ComparisonSource) => string,\n): Array<{ key: string; fromIndex: number; toIndex: number; comparisonSource: ComparisonSource }> {\n\tconst requests: Array<{ key: string; fromIndex: number; toIndex: number; comparisonSource: ComparisonSource }> = [];\n\n\tfor (let index = 1; index < visibleEntries.length; index += 1) {\n\t\tconst fromIndex = visibleEntries[index - 1]?.index;\n\t\tconst toIndex = visibleEntries[index]?.index;\n\t\tif (fromIndex === undefined || toIndex === undefined) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst key = buildPreviewKey(fromIndex, toIndex, comparisonSource);\n\t\tif (key === selectedPreviewKey || previewByRange[key]) {\n\t\t\tcontinue;\n\t\t}\n\n\t\trequests.push({ key, fromIndex, toIndex, comparisonSource });\n\t}\n\n\treturn requests;\n}\n\nexport function getPendingSelectionRange(\n\tvisibleEntries: FileRevisionEntry[],\n\tpendingSelectionIndex: number | null,\n\thoveredSelectionIndex: number | null,\n): { fromEntry: FileRevisionEntry; toEntry: FileRevisionEntry; selectedCount: number } | null {\n\tif (\n\t\tpendingSelectionIndex === null ||\n\t\thoveredSelectionIndex === null ||\n\t\tpendingSelectionIndex === hoveredSelectionIndex\n\t) {\n\t\treturn null;\n\t}\n\n\tconst fromIndex = Math.min(pendingSelectionIndex, hoveredSelectionIndex);\n\tconst toIndex = Math.max(pendingSelectionIndex, hoveredSelectionIndex);\n\tconst fromEntry = visibleEntries.find((entry) => entry.index === fromIndex);\n\tconst toEntry = visibleEntries.find((entry) => entry.index === toIndex);\n\tif (!fromEntry || !toEntry) {\n\t\treturn null;\n\t}\n\n\treturn {\n\t\tfromEntry,\n\t\ttoEntry,\n\t\tselectedCount: getSelectedEntryCount(visibleEntries, fromIndex, toIndex),\n\t};\n}\n\nexport function getIntermediateToggleLabel(\n\tvisibleCount: number,\n\ttotalCount: number,\n\t_showIntermediateRevisions?: boolean,\n): string {\n\tconst safeTotal = Math.max(0, totalCount);\n\tif (!safeTotal) {\n\t\treturn 'In-Between';\n\t}\n\n\tconst safeVisibleCount = Math.min(Math.max(0, visibleCount), safeTotal);\n\treturn `In-Between ${safeVisibleCount}/${safeTotal}`;\n}\n"],"mappings":";AASA,SAAgB,oBACf,MACA,kBACsB;CACtB,IAAI,CAAC,MACJ,OAAO,CAAC;CAGT,IAAI,KAAK,YAAY,QAAQ,qBAAqB,YAAY;EAC7D,MAAM,kBAAkB,MAAM,QAAQ,KAAK,OAAO,IAAI,KAAK,UAAU,CAAC;EACtE,MAAM,kBAAkB,MAAM,QAAQ,KAAK,eAAe,IAAI,KAAK,kBAAkB,CAAC;EACtF,MAAM,kBAAkB,IAAI,IAC3B,MAAM,QAAQ,KAAK,eAAe,eAAe,IAAI,KAAK,cAAc,kBAAkB,CAAC,CAC5F;EAEA,IAAI,CAAC,gBAAgB,MACpB,OAAO;EAGR,MAAM,4BAA4B,gBAAgB,QAAQ,QAAQ,UAAU;GAC3E,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,gBACL,SAAS,UAAU;GACnB,IAAI,CAAC,MAAM,YAAY,MAAM,iBAAiB,CAAC,MAAM,eAAe,CAAC,gBAAgB,IAAI,MAAM,QAAQ,GACtG,OAAO,CAAC,KAAK;GAEd,OAAO,0BAA0B,IAAI,MAAM,QAAQ,KAAK,CAAC,KAAK;EAC/D,CAAC,CAAC,CACD,KAAK,OAAO,WAAW;GAAE,GAAG;GAAO;EAAM,EAAE;CAC9C;CAEA,OAAO,MAAM,QAAQ,KAAK,OAAO,IAAI,KAAK,UAAU,CAAC;AACtD"}
|