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,1113 @@
|
|
|
1
|
+
const require_runtime = require("../_virtual/_rolldown/runtime.cjs");
|
|
2
|
+
const require_constants = require("./constants.cjs");
|
|
3
|
+
const require_blame = require("../shared/blame.cjs");
|
|
4
|
+
const require_resolve_file_path = require("../shared/resolve-file-path.cjs");
|
|
5
|
+
require("./resolve-file-path.cjs");
|
|
6
|
+
const require_timeline_template = require("../webview/timeline-template.cjs");
|
|
7
|
+
const require_line_history = require("../shared/line-history.cjs");
|
|
8
|
+
const require_uri_utils = require("./uri-utils.cjs");
|
|
9
|
+
let node_fs = require("node:fs");
|
|
10
|
+
node_fs = require_runtime.__toESM(node_fs, 1);
|
|
11
|
+
let node_path = require("node:path");
|
|
12
|
+
node_path = require_runtime.__toESM(node_path, 1);
|
|
13
|
+
let vscode = require("vscode");
|
|
14
|
+
vscode = require_runtime.__toESM(vscode, 1);
|
|
15
|
+
//#region src/extension/timeline-panel.ts
|
|
16
|
+
const LARGE_MULTI_DIFF_CONFIRMATION_THRESHOLD = 200;
|
|
17
|
+
function collectPendingSnapshotHydrationIndexes(session) {
|
|
18
|
+
return session.entries.reduce((indexes, entry, index) => {
|
|
19
|
+
if (entry && !entry.isWorkingTree && entry.touchesFile && entry.changeId && !session.snapshotLoadedChangeIds.has(entry.changeId)) indexes.push(index);
|
|
20
|
+
return indexes;
|
|
21
|
+
}, []);
|
|
22
|
+
}
|
|
23
|
+
function postTimelineMessage(request) {
|
|
24
|
+
return Promise.resolve(request.panel.webview.postMessage(request.message));
|
|
25
|
+
}
|
|
26
|
+
async function buildSelectedEntryMultiDiffPlan(request) {
|
|
27
|
+
const files = [];
|
|
28
|
+
for (const entryIndex of request.entryIndexes) {
|
|
29
|
+
const entry = request.sourceEntries[entryIndex];
|
|
30
|
+
if (!entry) continue;
|
|
31
|
+
let plan = {
|
|
32
|
+
title: request.title,
|
|
33
|
+
files: []
|
|
34
|
+
};
|
|
35
|
+
if (entry.isWorkingTree) {
|
|
36
|
+
const previousEntry = request.sourceEntries[entryIndex - 1];
|
|
37
|
+
if (!previousEntry) continue;
|
|
38
|
+
plan = await request.adapter.buildRangeMultiDiffPlan({
|
|
39
|
+
workspacePath: request.workspacePath,
|
|
40
|
+
fromEntry: previousEntry,
|
|
41
|
+
toEntry: entry,
|
|
42
|
+
comparisonSource: request.comparisonSource,
|
|
43
|
+
sourceEntries: request.sourceEntries,
|
|
44
|
+
signal: request.signal
|
|
45
|
+
});
|
|
46
|
+
} else plan = await request.adapter.buildRevisionMultiDiffPlan({
|
|
47
|
+
workspacePath: request.workspacePath,
|
|
48
|
+
entry,
|
|
49
|
+
entryIndex,
|
|
50
|
+
comparisonSource: request.comparisonSource,
|
|
51
|
+
sourceEntries: request.sourceEntries,
|
|
52
|
+
signal: request.signal
|
|
53
|
+
});
|
|
54
|
+
files.push(...plan.files);
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
title: request.title,
|
|
58
|
+
files
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
async function resolveTimelineSourcePath(request) {
|
|
62
|
+
const coerced = require_resolve_file_path.coerceFsPath(request.absolutePath);
|
|
63
|
+
if (coerced) return coerced;
|
|
64
|
+
const activeEditor = vscode.window.activeTextEditor;
|
|
65
|
+
if (activeEditor && isWorkspaceFileUri(activeEditor.document.uri)) return activeEditor.document.uri.fsPath;
|
|
66
|
+
return pickOpenWorkspaceEditorPath();
|
|
67
|
+
}
|
|
68
|
+
async function pickOpenWorkspaceEditorPath() {
|
|
69
|
+
const candidates = getOpenWorkspaceEditorCandidates();
|
|
70
|
+
if (!candidates.length) return;
|
|
71
|
+
return (await vscode.window.showQuickPick(candidates.map((candidate) => ({
|
|
72
|
+
label: candidate.label,
|
|
73
|
+
description: candidate.description,
|
|
74
|
+
detail: candidate.detail,
|
|
75
|
+
path: candidate.absolutePath
|
|
76
|
+
})), { placeHolder: "Select a workspace file to open its revision timeline" }))?.path;
|
|
77
|
+
}
|
|
78
|
+
function getOpenWorkspaceEditorCandidates() {
|
|
79
|
+
const candidates = [];
|
|
80
|
+
const seenPaths = /* @__PURE__ */ new Set();
|
|
81
|
+
for (const group of vscode.window.tabGroups?.all || []) for (const tab of group.tabs) {
|
|
82
|
+
const uri = getTabUri(tab);
|
|
83
|
+
if (!uri || uri.scheme !== "file") continue;
|
|
84
|
+
const workspaceFolder = vscode.workspace.getWorkspaceFolder(uri);
|
|
85
|
+
if (!workspaceFolder) continue;
|
|
86
|
+
const absolutePath = uri.fsPath;
|
|
87
|
+
if (seenPaths.has(absolutePath)) continue;
|
|
88
|
+
const relativePath = node_path.default.relative(workspaceFolder.uri.fsPath, absolutePath).replace(/\\/g, "/");
|
|
89
|
+
if (!relativePath || relativePath.startsWith("..")) continue;
|
|
90
|
+
seenPaths.add(absolutePath);
|
|
91
|
+
candidates.push({
|
|
92
|
+
label: node_path.default.basename(absolutePath),
|
|
93
|
+
description: relativePath,
|
|
94
|
+
detail: workspaceFolder.name,
|
|
95
|
+
absolutePath
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
return candidates;
|
|
99
|
+
}
|
|
100
|
+
function isWorkspaceFileUri(uri) {
|
|
101
|
+
return uri.scheme === "file" && Boolean(vscode.workspace.getWorkspaceFolder(uri));
|
|
102
|
+
}
|
|
103
|
+
function getTabUri(tab) {
|
|
104
|
+
return tab.input?.uri;
|
|
105
|
+
}
|
|
106
|
+
function createTimelinePanelController(args) {
|
|
107
|
+
const timelineSessions = /* @__PURE__ */ new Map();
|
|
108
|
+
const panelViewReady = /* @__PURE__ */ new WeakMap();
|
|
109
|
+
const panelLoadGeneration = /* @__PURE__ */ new WeakMap();
|
|
110
|
+
let activeTimelinePanel;
|
|
111
|
+
let timelineDebugState = createEmptyTimelineDebugState();
|
|
112
|
+
let timelinePreviewGeneration = 0;
|
|
113
|
+
const lineHistoryStatusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 90);
|
|
114
|
+
lineHistoryStatusBar.command = require_constants.CLEAR_LINE_HISTORY_COMMAND;
|
|
115
|
+
lineHistoryStatusBar.tooltip = "Clear line-history filter (show full file timeline)";
|
|
116
|
+
args.context.subscriptions.push(lineHistoryStatusBar);
|
|
117
|
+
function syncLineHistoryStatusBar(lineHistory) {
|
|
118
|
+
if (!lineHistory) {
|
|
119
|
+
lineHistoryStatusBar.hide();
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
lineHistoryStatusBar.text = `$(git-commit) ${require_line_history.formatStatusBarLineHistoryChip(lineHistory)}`;
|
|
123
|
+
lineHistoryStatusBar.show();
|
|
124
|
+
}
|
|
125
|
+
return {
|
|
126
|
+
dispose() {
|
|
127
|
+
for (const panel of timelineSessions.keys()) panel.dispose();
|
|
128
|
+
timelineSessions.clear();
|
|
129
|
+
activeTimelinePanel = void 0;
|
|
130
|
+
timelineDebugState = createEmptyTimelineDebugState();
|
|
131
|
+
syncLineHistoryStatusBar(null);
|
|
132
|
+
},
|
|
133
|
+
async clearLineHistoryFilter() {
|
|
134
|
+
const panel = activeTimelinePanel;
|
|
135
|
+
const session = panel ? timelineSessions.get(panel) : void 0;
|
|
136
|
+
if (!panel || !session?.lineHistory) {
|
|
137
|
+
if (panel) panel.reveal(void 0, true);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
await loadSessionIntoPanel({
|
|
141
|
+
panel,
|
|
142
|
+
workspacePath: session.workspacePath,
|
|
143
|
+
absolutePath: session.absolutePath,
|
|
144
|
+
customRevset: session.customRevset
|
|
145
|
+
});
|
|
146
|
+
},
|
|
147
|
+
getDebugState() {
|
|
148
|
+
return { ...timelineDebugState };
|
|
149
|
+
},
|
|
150
|
+
async getDiffLayoutMetrics() {
|
|
151
|
+
const panel = activeTimelinePanel;
|
|
152
|
+
if (!panel) throw new Error("no active timeline panel");
|
|
153
|
+
return await new Promise((resolve, reject) => {
|
|
154
|
+
const timeout = setTimeout(() => {
|
|
155
|
+
subscription.dispose();
|
|
156
|
+
reject(/* @__PURE__ */ new Error("timed out waiting for webview layout metrics"));
|
|
157
|
+
}, 8e3);
|
|
158
|
+
const subscription = panel.webview.onDidReceiveMessage((message) => {
|
|
159
|
+
if (!message || typeof message !== "object") return;
|
|
160
|
+
if (Reflect.get(message, "command") !== "layout-metrics") return;
|
|
161
|
+
const metrics = Reflect.get(message, "metrics");
|
|
162
|
+
if (!metrics || typeof metrics !== "object") return;
|
|
163
|
+
clearTimeout(timeout);
|
|
164
|
+
subscription.dispose();
|
|
165
|
+
resolve(metrics);
|
|
166
|
+
});
|
|
167
|
+
panel.webview.postMessage({ type: "debug-measure-layout" });
|
|
168
|
+
});
|
|
169
|
+
},
|
|
170
|
+
async selectTimelineRange(request) {
|
|
171
|
+
const panel = activeTimelinePanel;
|
|
172
|
+
if (!panel) throw new Error("no active timeline panel");
|
|
173
|
+
const session = timelineSessions.get(panel);
|
|
174
|
+
if (!session) throw new Error("no active timeline session");
|
|
175
|
+
await handleTimelineMessage({
|
|
176
|
+
panel,
|
|
177
|
+
session,
|
|
178
|
+
message: {
|
|
179
|
+
command: "select-entry",
|
|
180
|
+
fromIndex: request.fromIndex,
|
|
181
|
+
toIndex: request.toIndex,
|
|
182
|
+
comparisonSource: request.comparisonSource || "revision"
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
},
|
|
186
|
+
async setLayoutMode(layoutMode) {
|
|
187
|
+
const panel = activeTimelinePanel;
|
|
188
|
+
if (!panel) throw new Error("no active timeline panel");
|
|
189
|
+
const nextPreferences = {
|
|
190
|
+
...args.getPreferences(),
|
|
191
|
+
layoutMode: layoutMode === "unified" ? "unified" : "split"
|
|
192
|
+
};
|
|
193
|
+
await args.savePreferences(nextPreferences);
|
|
194
|
+
await postTimelineMessage({
|
|
195
|
+
panel,
|
|
196
|
+
message: {
|
|
197
|
+
type: "debug-set-layout-mode",
|
|
198
|
+
layoutMode: nextPreferences.layoutMode
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
},
|
|
202
|
+
async openFileRevisionTimeline({ absolutePath, lineHistory, focusRevision }) {
|
|
203
|
+
const initialPath = await resolveTimelineSourcePath({ absolutePath });
|
|
204
|
+
if (!initialPath) {
|
|
205
|
+
vscode.window.showErrorMessage("Open a workspace file to browse its revision timeline");
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
const documentUri = vscode.Uri.file(initialPath);
|
|
209
|
+
const workspaceFolder = vscode.workspace.getWorkspaceFolder(documentUri);
|
|
210
|
+
if (!workspaceFolder) {
|
|
211
|
+
vscode.window.showErrorMessage("The active file must belong to a workspace folder");
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
if (documentUri.scheme !== "file") {
|
|
215
|
+
vscode.window.showErrorMessage("The revision timeline only supports files on disk");
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
const fileName = node_path.default.basename(documentUri.fsPath);
|
|
219
|
+
const hadExistingPanel = timelineSessions.size > 0;
|
|
220
|
+
const panel = createTimelinePanel({ fileName });
|
|
221
|
+
activeTimelinePanel = panel;
|
|
222
|
+
panel.webview.html = getTimelineWebviewHtml({
|
|
223
|
+
context: args.context,
|
|
224
|
+
webview: panel.webview
|
|
225
|
+
});
|
|
226
|
+
panel.title = lineHistory ? `Revision Timeline: ${fileName} (L${lineHistory.startLine}${lineHistory.endLine === lineHistory.startLine ? "" : `–${lineHistory.endLine}`})` : `Revision Timeline: ${fileName}`;
|
|
227
|
+
timelineDebugState = {
|
|
228
|
+
...createEmptyTimelineDebugState(),
|
|
229
|
+
panelOpen: true,
|
|
230
|
+
panelCount: timelineSessions.size + 1,
|
|
231
|
+
panelTitle: panel.title,
|
|
232
|
+
workspacePath: workspaceFolder.uri.fsPath,
|
|
233
|
+
relativePath: node_path.default.relative(workspaceFolder.uri.fsPath, documentUri.fsPath).replace(/\\/g, "/"),
|
|
234
|
+
fileName,
|
|
235
|
+
lineHistory: lineHistory ? {
|
|
236
|
+
startLine: lineHistory.startLine,
|
|
237
|
+
endLine: lineHistory.endLine
|
|
238
|
+
} : null,
|
|
239
|
+
usesBundledWebview: hasBundledTimelineWebviewAssets({ context: args.context })
|
|
240
|
+
};
|
|
241
|
+
if (!hadExistingPanel && shouldMaximizeTimelinePanel()) await maximizeTimelinePanel();
|
|
242
|
+
await loadSessionIntoPanel({
|
|
243
|
+
panel,
|
|
244
|
+
workspacePath: workspaceFolder.uri.fsPath,
|
|
245
|
+
absolutePath: documentUri.fsPath,
|
|
246
|
+
lineHistory,
|
|
247
|
+
customRevset: args.getPreferences().customRevset || void 0,
|
|
248
|
+
focusRevision
|
|
249
|
+
});
|
|
250
|
+
syncLineHistoryStatusBar(lineHistory);
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
async function loadSessionIntoPanel(request) {
|
|
254
|
+
const generation = (panelLoadGeneration.get(request.panel) || 0) + 1;
|
|
255
|
+
panelLoadGeneration.set(request.panel, generation);
|
|
256
|
+
const session = await args.service.buildSession({
|
|
257
|
+
workspacePath: request.workspacePath,
|
|
258
|
+
absolutePath: request.absolutePath,
|
|
259
|
+
options: {
|
|
260
|
+
...request.lineHistory ? { lineHistory: request.lineHistory } : {},
|
|
261
|
+
...request.customRevset ? { customRevset: request.customRevset } : {}
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
if (panelLoadGeneration.get(request.panel) !== generation || request.panel.webview.html === "") return;
|
|
265
|
+
if (!session.entries.length) {
|
|
266
|
+
vscode.window.showInformationMessage("No file revisions were found for the active file");
|
|
267
|
+
if (!timelineSessions.has(request.panel)) request.panel.dispose();
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
timelineSessions.set(request.panel, session);
|
|
271
|
+
activeTimelinePanel = request.panel;
|
|
272
|
+
request.panel.title = session.lineHistory ? `Revision Timeline: ${session.fileName} (L${session.lineHistory.startLine}${session.lineHistory.endLine === session.lineHistory.startLine ? "" : `–${session.lineHistory.endLine}`})` : `Revision Timeline: ${session.fileName}`;
|
|
273
|
+
syncLineHistoryStatusBar(session.lineHistory);
|
|
274
|
+
timelineDebugState = createDebugState({
|
|
275
|
+
panel: request.panel,
|
|
276
|
+
session,
|
|
277
|
+
lastMessageCommand: timelineDebugState.lastMessageCommand,
|
|
278
|
+
panelCount: timelineSessions.size
|
|
279
|
+
});
|
|
280
|
+
timelineDebugState = {
|
|
281
|
+
...timelineDebugState,
|
|
282
|
+
viewReady: panelViewReady.get(request.panel) === true
|
|
283
|
+
};
|
|
284
|
+
if (panelViewReady.get(request.panel)) await eagerlyBootstrapTimeline({
|
|
285
|
+
panel: request.panel,
|
|
286
|
+
session
|
|
287
|
+
});
|
|
288
|
+
if (request.focusRevision) {
|
|
289
|
+
const match = args.service.mapEntriesForPayload(session.entries).find((entry) => !entry.isWorkingTree && require_blame.revisionMatchesBlame(entry.revision, request.focusRevision));
|
|
290
|
+
if (match && typeof match.index === "number") {
|
|
291
|
+
const fromIndex = Math.max(0, match.index - 1);
|
|
292
|
+
await handleTimelineMessage({
|
|
293
|
+
panel: request.panel,
|
|
294
|
+
session,
|
|
295
|
+
message: {
|
|
296
|
+
command: "select-entry",
|
|
297
|
+
fromIndex,
|
|
298
|
+
toIndex: match.index,
|
|
299
|
+
comparisonSource: "revision"
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
function createTimelinePanel(request) {
|
|
306
|
+
const panel = vscode.window.createWebviewPanel("jjRangeDiffTimeline", `Revision Timeline: ${request.fileName}`, getTimelineViewColumn(), {
|
|
307
|
+
enableScripts: true,
|
|
308
|
+
retainContextWhenHidden: true,
|
|
309
|
+
enableFindWidget: true,
|
|
310
|
+
localResourceRoots: [vscode.Uri.joinPath(args.context.extensionUri, "webview"), vscode.Uri.joinPath(args.context.extensionUri, "webview-dist")]
|
|
311
|
+
});
|
|
312
|
+
panel.onDidDispose(() => {
|
|
313
|
+
timelineSessions.get(panel)?.activeActionAbortController?.abort();
|
|
314
|
+
timelineSessions.delete(panel);
|
|
315
|
+
if (activeTimelinePanel === panel) {
|
|
316
|
+
const fallback = [...timelineSessions.entries()].at(-1);
|
|
317
|
+
if (!fallback) {
|
|
318
|
+
activeTimelinePanel = void 0;
|
|
319
|
+
timelineDebugState = createEmptyTimelineDebugState();
|
|
320
|
+
syncLineHistoryStatusBar(null);
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
activeTimelinePanel = fallback[0];
|
|
324
|
+
timelineDebugState = createDebugState({
|
|
325
|
+
panel: fallback[0],
|
|
326
|
+
session: fallback[1],
|
|
327
|
+
lastMessageCommand: timelineDebugState.lastMessageCommand,
|
|
328
|
+
panelCount: timelineSessions.size
|
|
329
|
+
});
|
|
330
|
+
syncLineHistoryStatusBar(fallback[1].lineHistory);
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
timelineDebugState = {
|
|
334
|
+
...timelineDebugState,
|
|
335
|
+
panelCount: timelineSessions.size
|
|
336
|
+
};
|
|
337
|
+
}, void 0, args.context.subscriptions);
|
|
338
|
+
panel.webview.onDidReceiveMessage(async (message) => {
|
|
339
|
+
try {
|
|
340
|
+
activeTimelinePanel = panel;
|
|
341
|
+
if ((message && typeof message === "object" ? Reflect.get(message, "command") : void 0) === "ready") {
|
|
342
|
+
panelViewReady.set(panel, true);
|
|
343
|
+
const session = timelineSessions.get(panel);
|
|
344
|
+
timelineDebugState = {
|
|
345
|
+
...session ? createDebugState({
|
|
346
|
+
panel,
|
|
347
|
+
session,
|
|
348
|
+
lastMessageCommand: "ready",
|
|
349
|
+
panelCount: timelineSessions.size
|
|
350
|
+
}) : timelineDebugState,
|
|
351
|
+
viewReady: true,
|
|
352
|
+
readyCount: (timelineDebugState.readyCount || 0) + 1,
|
|
353
|
+
lastReadyAt: Date.now(),
|
|
354
|
+
lastMessageCommand: "ready",
|
|
355
|
+
panelOpen: true,
|
|
356
|
+
panelTitle: panel.title
|
|
357
|
+
};
|
|
358
|
+
if (session?.entries.length) await eagerlyBootstrapTimeline({
|
|
359
|
+
panel,
|
|
360
|
+
session
|
|
361
|
+
});
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
const session = timelineSessions.get(panel);
|
|
365
|
+
if (!session) return;
|
|
366
|
+
await handleTimelineMessage({
|
|
367
|
+
panel,
|
|
368
|
+
session,
|
|
369
|
+
message
|
|
370
|
+
});
|
|
371
|
+
} catch (error) {
|
|
372
|
+
const text = error instanceof Error ? error.message : String(error);
|
|
373
|
+
vscode.window.showErrorMessage(`Timeline action failed: ${text}`);
|
|
374
|
+
}
|
|
375
|
+
}, void 0, args.context.subscriptions);
|
|
376
|
+
return panel;
|
|
377
|
+
}
|
|
378
|
+
async function handleTimelineMessage(request) {
|
|
379
|
+
if (!request.message || typeof request.message !== "object") return;
|
|
380
|
+
const command = Reflect.get(request.message, "command");
|
|
381
|
+
if (typeof command !== "string") return;
|
|
382
|
+
if (command === "ready") return;
|
|
383
|
+
if (command === "layout-metrics") return;
|
|
384
|
+
if (command === "select-entry") {
|
|
385
|
+
const fromIndex = Number(Reflect.get(request.message, "fromIndex"));
|
|
386
|
+
const toIndex = Number(Reflect.get(request.message, "toIndex"));
|
|
387
|
+
const comparisonSource = normalizeComparisonSource(Reflect.get(request.message, "comparisonSource"));
|
|
388
|
+
if (!Number.isInteger(fromIndex) || !Number.isInteger(toIndex)) return;
|
|
389
|
+
await sendTimelinePreview({
|
|
390
|
+
panel: request.panel,
|
|
391
|
+
session: request.session,
|
|
392
|
+
fromIndex,
|
|
393
|
+
toIndex,
|
|
394
|
+
comparisonSource
|
|
395
|
+
});
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
if (command === "load-range-overview") {
|
|
399
|
+
const fromIndex = Number(Reflect.get(request.message, "fromIndex"));
|
|
400
|
+
const toIndex = Number(Reflect.get(request.message, "toIndex"));
|
|
401
|
+
const comparisonSource = normalizeComparisonSource(Reflect.get(request.message, "comparisonSource"));
|
|
402
|
+
const selectedEntryIndexes = Array.isArray(Reflect.get(request.message, "selectedEntryIndexes")) ? Reflect.get(request.message, "selectedEntryIndexes").map((value) => Number(value)).filter((value) => Number.isInteger(value)) : [];
|
|
403
|
+
if (!Number.isInteger(fromIndex) || !Number.isInteger(toIndex)) return;
|
|
404
|
+
await sendRangeOverview({
|
|
405
|
+
panel: request.panel,
|
|
406
|
+
session: request.session,
|
|
407
|
+
fromIndex,
|
|
408
|
+
toIndex,
|
|
409
|
+
comparisonSource,
|
|
410
|
+
selectedEntryIndexes
|
|
411
|
+
});
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
if (command === "load-range-stack") {
|
|
415
|
+
const fromIndex = Number(Reflect.get(request.message, "fromIndex"));
|
|
416
|
+
const toIndex = Number(Reflect.get(request.message, "toIndex"));
|
|
417
|
+
const comparisonSource = normalizeComparisonSource(Reflect.get(request.message, "comparisonSource"));
|
|
418
|
+
const relativePaths = Array.isArray(Reflect.get(request.message, "relativePaths")) ? Reflect.get(request.message, "relativePaths").map((value) => String(value || "").trim()).filter(Boolean) : [];
|
|
419
|
+
if (!Number.isInteger(fromIndex) || !Number.isInteger(toIndex) || !relativePaths.length) return;
|
|
420
|
+
const normalizedFromIndex = Math.max(0, Math.min(fromIndex, toIndex));
|
|
421
|
+
const normalizedToIndex = Math.max(normalizedFromIndex, Math.max(fromIndex, toIndex));
|
|
422
|
+
await postTimelineMessage({
|
|
423
|
+
panel: request.panel,
|
|
424
|
+
message: {
|
|
425
|
+
type: "range-stack-previews",
|
|
426
|
+
payload: {
|
|
427
|
+
fromIndex: normalizedFromIndex,
|
|
428
|
+
toIndex: normalizedToIndex,
|
|
429
|
+
comparisonSource,
|
|
430
|
+
items: await args.service.getRangeStackPreviews({
|
|
431
|
+
session: request.session,
|
|
432
|
+
fromIndex: normalizedFromIndex,
|
|
433
|
+
toIndex: normalizedToIndex,
|
|
434
|
+
comparisonSource,
|
|
435
|
+
relativePaths
|
|
436
|
+
})
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
});
|
|
440
|
+
return;
|
|
441
|
+
}
|
|
442
|
+
if (command === "load-diff-blame") {
|
|
443
|
+
const fromIndex = Number(Reflect.get(request.message, "fromIndex"));
|
|
444
|
+
const toIndex = Number(Reflect.get(request.message, "toIndex"));
|
|
445
|
+
const comparisonSource = normalizeComparisonSource(Reflect.get(request.message, "comparisonSource"));
|
|
446
|
+
if (!Number.isInteger(fromIndex) || !Number.isInteger(toIndex)) return;
|
|
447
|
+
const normalizedFromIndex = Math.max(0, Math.min(fromIndex, toIndex));
|
|
448
|
+
const normalizedToIndex = Math.max(normalizedFromIndex, Math.max(fromIndex, toIndex));
|
|
449
|
+
const blame = await args.service.getDiffBlame({
|
|
450
|
+
session: request.session,
|
|
451
|
+
fromIndex: normalizedFromIndex,
|
|
452
|
+
toIndex: normalizedToIndex,
|
|
453
|
+
comparisonSource
|
|
454
|
+
});
|
|
455
|
+
await postTimelineMessage({
|
|
456
|
+
panel: request.panel,
|
|
457
|
+
message: {
|
|
458
|
+
type: "diff-blame",
|
|
459
|
+
payload: {
|
|
460
|
+
fromIndex: normalizedFromIndex,
|
|
461
|
+
toIndex: normalizedToIndex,
|
|
462
|
+
comparisonSource,
|
|
463
|
+
relativePath: blame.relativePath,
|
|
464
|
+
lines: blame.lines
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
});
|
|
468
|
+
return;
|
|
469
|
+
}
|
|
470
|
+
if (command === "load-file-oplog") {
|
|
471
|
+
const oplog = await args.service.getFileOpLog({ session: request.session });
|
|
472
|
+
await postTimelineMessage({
|
|
473
|
+
panel: request.panel,
|
|
474
|
+
message: {
|
|
475
|
+
type: "file-oplog",
|
|
476
|
+
payload: {
|
|
477
|
+
relativePath: oplog.relativePath,
|
|
478
|
+
entries: oplog.entries
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
});
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
if (command === "load-revision-tree-files") {
|
|
485
|
+
const revision = String(Reflect.get(request.message, "revision") || "@");
|
|
486
|
+
const files = await args.service.loadRevisionTreeFiles({
|
|
487
|
+
session: request.session,
|
|
488
|
+
revision
|
|
489
|
+
});
|
|
490
|
+
await postTimelineMessage({
|
|
491
|
+
panel: request.panel,
|
|
492
|
+
message: {
|
|
493
|
+
type: "revision-tree-files",
|
|
494
|
+
payload: {
|
|
495
|
+
revision,
|
|
496
|
+
files
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
});
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
if (command === "search-history") {
|
|
503
|
+
const query = String(Reflect.get(request.message, "query") || "");
|
|
504
|
+
const purpose = Reflect.get(request.message, "purpose") === "sidebar" ? "sidebar" : "history";
|
|
505
|
+
const result = await args.service.searchFileHistory({
|
|
506
|
+
session: request.session,
|
|
507
|
+
query,
|
|
508
|
+
purpose
|
|
509
|
+
});
|
|
510
|
+
await postTimelineMessage({
|
|
511
|
+
panel: request.panel,
|
|
512
|
+
message: {
|
|
513
|
+
type: "history-search",
|
|
514
|
+
payload: {
|
|
515
|
+
...result,
|
|
516
|
+
purpose
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
});
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
522
|
+
if (command === "load-entry-diff-counts") {
|
|
523
|
+
const comparisonSource = normalizeComparisonSource(Reflect.get(request.message, "comparisonSource"));
|
|
524
|
+
const entryIndexes = Array.isArray(Reflect.get(request.message, "entryIndexes")) ? Reflect.get(request.message, "entryIndexes").map((value) => Number(value)).filter((value) => Number.isInteger(value)) : [];
|
|
525
|
+
if (!entryIndexes.length) return;
|
|
526
|
+
await postTimelineMessage({
|
|
527
|
+
panel: request.panel,
|
|
528
|
+
message: {
|
|
529
|
+
type: "entry-diff-counts",
|
|
530
|
+
payload: {
|
|
531
|
+
comparisonSource,
|
|
532
|
+
counts: await args.service.getEntryDiffCounts({
|
|
533
|
+
session: request.session,
|
|
534
|
+
entryIndexes,
|
|
535
|
+
comparisonSource
|
|
536
|
+
})
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
});
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
542
|
+
if (command === "hydrate-snapshot-entries") {
|
|
543
|
+
const revisionIndexes = Reflect.get(request.message, "revisionIndexes");
|
|
544
|
+
if (!Array.isArray(revisionIndexes)) return;
|
|
545
|
+
if (!await args.service.hydrateSnapshotEntries({
|
|
546
|
+
session: request.session,
|
|
547
|
+
revisionIndexes: revisionIndexes.map((value) => Number(value)).filter((value) => Number.isInteger(value))
|
|
548
|
+
})) return;
|
|
549
|
+
const payload = buildPayload(request.session);
|
|
550
|
+
await postTimelineMessage({
|
|
551
|
+
panel: request.panel,
|
|
552
|
+
message: {
|
|
553
|
+
type: "snapshot-entries",
|
|
554
|
+
payload: {
|
|
555
|
+
snapshotEntries: payload.snapshotEntries,
|
|
556
|
+
snapshotState: payload.snapshotState
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
});
|
|
560
|
+
return;
|
|
561
|
+
}
|
|
562
|
+
if (command === "resolve-nonempty-range") {
|
|
563
|
+
const candidateIndexes = Reflect.get(request.message, "candidateIndexes");
|
|
564
|
+
if (!Array.isArray(candidateIndexes)) return;
|
|
565
|
+
const resolvedRange = await args.service.findNearestNonEmptyVisibleRange({
|
|
566
|
+
session: request.session,
|
|
567
|
+
candidateIndexes: candidateIndexes.map((value) => Number(value)).filter((value) => Number.isInteger(value))
|
|
568
|
+
});
|
|
569
|
+
await postTimelineMessage({
|
|
570
|
+
panel: request.panel,
|
|
571
|
+
message: {
|
|
572
|
+
type: "resolved-range",
|
|
573
|
+
payload: resolvedRange
|
|
574
|
+
}
|
|
575
|
+
});
|
|
576
|
+
return;
|
|
577
|
+
}
|
|
578
|
+
if (command === "open-editor-diff") {
|
|
579
|
+
const fromIndex = Number(Reflect.get(request.message, "fromIndex"));
|
|
580
|
+
const toIndex = Number(Reflect.get(request.message, "toIndex"));
|
|
581
|
+
const comparisonSource = normalizeComparisonSource(Reflect.get(request.message, "comparisonSource"));
|
|
582
|
+
if (!Number.isInteger(fromIndex) || !Number.isInteger(toIndex)) return;
|
|
583
|
+
await openRangeDiffInEditor({
|
|
584
|
+
session: request.session,
|
|
585
|
+
fromIndex,
|
|
586
|
+
toIndex,
|
|
587
|
+
comparisonSource
|
|
588
|
+
});
|
|
589
|
+
return;
|
|
590
|
+
}
|
|
591
|
+
if (command === "open-current-file") {
|
|
592
|
+
await vscode.commands.executeCommand("vscode.open", vscode.Uri.file(request.session.absolutePath), { preview: true });
|
|
593
|
+
return;
|
|
594
|
+
}
|
|
595
|
+
if (command === "open-range-files-diff") {
|
|
596
|
+
const fromIndex = Number(Reflect.get(request.message, "fromIndex"));
|
|
597
|
+
const toIndex = Number(Reflect.get(request.message, "toIndex"));
|
|
598
|
+
const comparisonSource = normalizeComparisonSource(Reflect.get(request.message, "comparisonSource"));
|
|
599
|
+
const selectedEntryIndexes = Array.isArray(Reflect.get(request.message, "selectedEntryIndexes")) ? Reflect.get(request.message, "selectedEntryIndexes").map((value) => Number(value)).filter((value) => Number.isInteger(value)) : [];
|
|
600
|
+
if (!Number.isInteger(fromIndex) || !Number.isInteger(toIndex)) return;
|
|
601
|
+
await openRangeFilesDiff({
|
|
602
|
+
session: request.session,
|
|
603
|
+
fromIndex,
|
|
604
|
+
toIndex,
|
|
605
|
+
comparisonSource,
|
|
606
|
+
selectedEntryIndexes
|
|
607
|
+
});
|
|
608
|
+
return;
|
|
609
|
+
}
|
|
610
|
+
if (command === "open-revision-files-diff") {
|
|
611
|
+
const entryIndex = Number(Reflect.get(request.message, "entryIndex"));
|
|
612
|
+
const comparisonSource = normalizeComparisonSource(Reflect.get(request.message, "comparisonSource"));
|
|
613
|
+
if (!Number.isInteger(entryIndex)) return;
|
|
614
|
+
await openRevisionFilesDiff({
|
|
615
|
+
session: request.session,
|
|
616
|
+
entryIndex,
|
|
617
|
+
comparisonSource
|
|
618
|
+
});
|
|
619
|
+
return;
|
|
620
|
+
}
|
|
621
|
+
if (command === "open-revision-remote") {
|
|
622
|
+
const entryIndex = Number(Reflect.get(request.message, "entryIndex"));
|
|
623
|
+
const comparisonSource = normalizeComparisonSource(Reflect.get(request.message, "comparisonSource"));
|
|
624
|
+
if (!Number.isInteger(entryIndex)) return;
|
|
625
|
+
await openRevisionOnRemote({
|
|
626
|
+
session: request.session,
|
|
627
|
+
entryIndex,
|
|
628
|
+
comparisonSource
|
|
629
|
+
});
|
|
630
|
+
return;
|
|
631
|
+
}
|
|
632
|
+
if (command === "cancel-active-request") {
|
|
633
|
+
request.session.activeActionAbortController?.abort();
|
|
634
|
+
return;
|
|
635
|
+
}
|
|
636
|
+
if (command === "switch-file") {
|
|
637
|
+
const relativePath = String(Reflect.get(request.message, "relativePath") || "").trim();
|
|
638
|
+
if (!relativePath) return;
|
|
639
|
+
await loadSessionIntoPanel({
|
|
640
|
+
panel: request.panel,
|
|
641
|
+
workspacePath: request.session.workspacePath,
|
|
642
|
+
absolutePath: node_path.default.join(request.session.workspacePath, relativePath),
|
|
643
|
+
lineHistory: request.session.lineHistory,
|
|
644
|
+
customRevset: request.session.customRevset
|
|
645
|
+
});
|
|
646
|
+
return;
|
|
647
|
+
}
|
|
648
|
+
if (command === "clear-line-history") {
|
|
649
|
+
await loadSessionIntoPanel({
|
|
650
|
+
panel: request.panel,
|
|
651
|
+
workspacePath: request.session.workspacePath,
|
|
652
|
+
absolutePath: request.session.absolutePath,
|
|
653
|
+
customRevset: request.session.customRevset
|
|
654
|
+
});
|
|
655
|
+
syncLineHistoryStatusBar(null);
|
|
656
|
+
return;
|
|
657
|
+
}
|
|
658
|
+
if (command === "set-custom-revset") {
|
|
659
|
+
const customRevset = String(Reflect.get(request.message, "customRevset") || "").trim();
|
|
660
|
+
const nextPreferences = {
|
|
661
|
+
...args.getPreferences(),
|
|
662
|
+
customRevset
|
|
663
|
+
};
|
|
664
|
+
await args.savePreferences(nextPreferences);
|
|
665
|
+
await loadSessionIntoPanel({
|
|
666
|
+
panel: request.panel,
|
|
667
|
+
workspacePath: request.session.workspacePath,
|
|
668
|
+
absolutePath: request.session.absolutePath,
|
|
669
|
+
lineHistory: request.session.lineHistory,
|
|
670
|
+
customRevset: customRevset || void 0
|
|
671
|
+
});
|
|
672
|
+
return;
|
|
673
|
+
}
|
|
674
|
+
if (command === "persist-state") {
|
|
675
|
+
await args.savePreferences({
|
|
676
|
+
sidebarWidth: Number(Reflect.get(request.message, "sidebarWidth")),
|
|
677
|
+
sidebarCollapsed: Boolean(Reflect.get(request.message, "sidebarCollapsed")),
|
|
678
|
+
timelinePaneHeight: Number(Reflect.get(request.message, "timelinePaneHeight")),
|
|
679
|
+
timelinePaneCollapsed: Boolean(Reflect.get(request.message, "timelinePaneCollapsed")),
|
|
680
|
+
layoutMode: Reflect.get(request.message, "layoutMode") === "unified" ? "unified" : "split",
|
|
681
|
+
contentMode: Reflect.get(request.message, "contentMode") === "full" ? "full" : "diffs",
|
|
682
|
+
comparisonMode: Reflect.get(request.message, "comparisonMode") === "step" ? "step" : "range",
|
|
683
|
+
comparisonSource: normalizeComparisonSource(Reflect.get(request.message, "comparisonSource")),
|
|
684
|
+
showIntermediateRevisions: Boolean(Reflect.get(request.message, "showIntermediateRevisions")),
|
|
685
|
+
preset: normalizeTimelinePreset(Reflect.get(request.message, "preset")),
|
|
686
|
+
customRevset: String(Reflect.get(request.message, "customRevset") || args.getPreferences().customRevset || ""),
|
|
687
|
+
themePreference: normalizeThemePreference(Reflect.get(request.message, "themePreference")),
|
|
688
|
+
heatmapOpen: Boolean(Reflect.get(request.message, "heatmapOpen")),
|
|
689
|
+
lineDiffType: normalizeLineDiffType(Reflect.get(request.message, "lineDiffType"))
|
|
690
|
+
});
|
|
691
|
+
return;
|
|
692
|
+
}
|
|
693
|
+
if (command === "refresh") {
|
|
694
|
+
await loadSessionIntoPanel({
|
|
695
|
+
panel: request.panel,
|
|
696
|
+
workspacePath: request.session.workspacePath,
|
|
697
|
+
absolutePath: request.session.absolutePath,
|
|
698
|
+
lineHistory: request.session.lineHistory,
|
|
699
|
+
customRevset: request.session.customRevset
|
|
700
|
+
});
|
|
701
|
+
return;
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
async function eagerlyBootstrapTimeline(request) {
|
|
705
|
+
const comparisonSource = normalizeComparisonSource(args.getPreferences().comparisonSource);
|
|
706
|
+
if (comparisonSource === "snapshot" && request.session.backend === "jj" && request.session.snapshotLoadedChangeIds.size === 0) await args.service.hydrateSnapshotEntries({
|
|
707
|
+
session: request.session,
|
|
708
|
+
revisionIndexes: collectPendingSnapshotHydrationIndexes(request.session)
|
|
709
|
+
});
|
|
710
|
+
const payload = buildPayload(request.session);
|
|
711
|
+
await postTimelineMessage({
|
|
712
|
+
panel: request.panel,
|
|
713
|
+
message: {
|
|
714
|
+
type: "timeline-data",
|
|
715
|
+
payload
|
|
716
|
+
}
|
|
717
|
+
});
|
|
718
|
+
const defaultFromIndex = Math.max(0, payload.defaultIndex - 1);
|
|
719
|
+
await sendTimelinePreview({
|
|
720
|
+
panel: request.panel,
|
|
721
|
+
session: request.session,
|
|
722
|
+
fromIndex: defaultFromIndex,
|
|
723
|
+
toIndex: payload.defaultIndex,
|
|
724
|
+
comparisonSource
|
|
725
|
+
});
|
|
726
|
+
enrichSessionInBackground({
|
|
727
|
+
panel: request.panel,
|
|
728
|
+
session: request.session
|
|
729
|
+
});
|
|
730
|
+
}
|
|
731
|
+
async function enrichSessionInBackground(request) {
|
|
732
|
+
const generation = panelLoadGeneration.get(request.panel);
|
|
733
|
+
const isCurrent = () => panelLoadGeneration.get(request.panel) === generation && timelineSessions.get(request.panel) === request.session;
|
|
734
|
+
try {
|
|
735
|
+
if (await args.service.ensureWorkspaceFiles({ session: request.session })) {
|
|
736
|
+
if (!isCurrent()) return;
|
|
737
|
+
await postTimelineMessage({
|
|
738
|
+
panel: request.panel,
|
|
739
|
+
message: {
|
|
740
|
+
type: "workspace-files",
|
|
741
|
+
payload: { workspaceFiles: request.session.workspaceFiles }
|
|
742
|
+
}
|
|
743
|
+
});
|
|
744
|
+
}
|
|
745
|
+
const expanded = await args.service.expandFileHistory({ session: request.session });
|
|
746
|
+
const intermediates = await args.service.ensureIntermediateRevisions({ session: request.session });
|
|
747
|
+
if (!isCurrent() || !expanded && !intermediates) return;
|
|
748
|
+
await postTimelineMessage({
|
|
749
|
+
panel: request.panel,
|
|
750
|
+
message: {
|
|
751
|
+
type: "entries-updated",
|
|
752
|
+
payload: {
|
|
753
|
+
entries: args.service.mapEntriesForPayload(request.session.entries),
|
|
754
|
+
hasIntermediateRevisions: request.session.entries.some((entry) => !entry.touchesFile)
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
});
|
|
758
|
+
} catch {}
|
|
759
|
+
}
|
|
760
|
+
function buildPayload(session) {
|
|
761
|
+
return args.service.buildPayload({
|
|
762
|
+
session,
|
|
763
|
+
preferences: args.getPreferences(),
|
|
764
|
+
version: args.version,
|
|
765
|
+
presets: require_constants.TIMELINE_PRESET_DAYS
|
|
766
|
+
});
|
|
767
|
+
}
|
|
768
|
+
async function sendTimelinePreview(request) {
|
|
769
|
+
const generation = ++timelinePreviewGeneration;
|
|
770
|
+
const preview = await args.service.getDiffPreview(request);
|
|
771
|
+
if (generation !== timelinePreviewGeneration) return;
|
|
772
|
+
await postTimelineMessage({
|
|
773
|
+
panel: request.panel,
|
|
774
|
+
message: {
|
|
775
|
+
type: "diff-preview",
|
|
776
|
+
payload: preview
|
|
777
|
+
}
|
|
778
|
+
});
|
|
779
|
+
}
|
|
780
|
+
async function sendRangeOverview(request) {
|
|
781
|
+
const normalizedFromIndex = Math.max(0, Math.min(request.fromIndex, request.toIndex));
|
|
782
|
+
const normalizedToIndex = Math.max(normalizedFromIndex, Math.max(request.fromIndex, request.toIndex));
|
|
783
|
+
const selectedEntryIndexes = request.selectedEntryIndexes || [];
|
|
784
|
+
await postTimelineMessage({
|
|
785
|
+
panel: request.panel,
|
|
786
|
+
message: {
|
|
787
|
+
type: "range-overview",
|
|
788
|
+
payload: {
|
|
789
|
+
fromIndex: normalizedFromIndex,
|
|
790
|
+
toIndex: normalizedToIndex,
|
|
791
|
+
comparisonSource: request.comparisonSource,
|
|
792
|
+
selectedEntryIndexes,
|
|
793
|
+
items: await args.service.getRangeOverview({
|
|
794
|
+
session: request.session,
|
|
795
|
+
fromIndex: normalizedFromIndex,
|
|
796
|
+
toIndex: normalizedToIndex,
|
|
797
|
+
comparisonSource: request.comparisonSource,
|
|
798
|
+
selectedEntryIndexes
|
|
799
|
+
})
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
});
|
|
803
|
+
}
|
|
804
|
+
async function openRangeDiffInEditor(request) {
|
|
805
|
+
const sourceEntries = args.service.getEntriesForSource({
|
|
806
|
+
session: request.session,
|
|
807
|
+
comparisonSource: request.comparisonSource
|
|
808
|
+
});
|
|
809
|
+
const comparison = args.service.getComparisonEntries({
|
|
810
|
+
entries: sourceEntries,
|
|
811
|
+
fromIndex: request.fromIndex,
|
|
812
|
+
toIndex: request.toIndex
|
|
813
|
+
});
|
|
814
|
+
if (!comparison) return;
|
|
815
|
+
if (!comparison.fromEntry) {
|
|
816
|
+
const uri = await createRevisionUri({
|
|
817
|
+
session: request.session,
|
|
818
|
+
entry: comparison.toEntry
|
|
819
|
+
});
|
|
820
|
+
await vscode.commands.executeCommand("vscode.open", uri, { preview: true });
|
|
821
|
+
return;
|
|
822
|
+
}
|
|
823
|
+
const originalUri = require_uri_utils.createSnapshotUri({
|
|
824
|
+
workspacePath: request.session.workspacePath,
|
|
825
|
+
revset: comparison.fromEntry.revision,
|
|
826
|
+
relativePath: await args.service.resolveEntryFilePath({
|
|
827
|
+
session: request.session,
|
|
828
|
+
entry: comparison.fromEntry,
|
|
829
|
+
entryIndex: Math.max(0, Math.min(request.fromIndex, request.toIndex))
|
|
830
|
+
}),
|
|
831
|
+
backend: request.session.backend
|
|
832
|
+
});
|
|
833
|
+
const modifiedUri = require_uri_utils.createSnapshotUri({
|
|
834
|
+
workspacePath: request.session.workspacePath,
|
|
835
|
+
revset: comparison.toEntry.revision,
|
|
836
|
+
relativePath: await args.service.resolveEntryFilePath({
|
|
837
|
+
session: request.session,
|
|
838
|
+
entry: comparison.toEntry,
|
|
839
|
+
entryIndex: Math.max(request.fromIndex, request.toIndex)
|
|
840
|
+
}),
|
|
841
|
+
backend: request.session.backend
|
|
842
|
+
});
|
|
843
|
+
const title = `${request.session.fileName}: ${comparison.fromEntry.shortRevision} -> ${comparison.toEntry.shortRevision}`;
|
|
844
|
+
await vscode.commands.executeCommand("vscode.diff", originalUri, modifiedUri, title, { preview: true });
|
|
845
|
+
}
|
|
846
|
+
async function openRangeFilesDiff(request) {
|
|
847
|
+
await args.service.runSessionAction({
|
|
848
|
+
session: request.session,
|
|
849
|
+
action: async (signal) => {
|
|
850
|
+
const sourceEntries = args.service.getEntriesForSource({
|
|
851
|
+
session: request.session,
|
|
852
|
+
comparisonSource: request.comparisonSource
|
|
853
|
+
});
|
|
854
|
+
const comparison = args.service.getComparisonEntries({
|
|
855
|
+
entries: sourceEntries,
|
|
856
|
+
fromIndex: request.fromIndex,
|
|
857
|
+
toIndex: request.toIndex
|
|
858
|
+
});
|
|
859
|
+
if (!comparison) return;
|
|
860
|
+
const plan = request.selectedEntryIndexes?.length ? await buildSelectedEntryMultiDiffPlan({
|
|
861
|
+
adapter: request.session.adapter,
|
|
862
|
+
workspacePath: request.session.workspacePath,
|
|
863
|
+
sourceEntries,
|
|
864
|
+
comparisonSource: request.comparisonSource,
|
|
865
|
+
entryIndexes: request.selectedEntryIndexes,
|
|
866
|
+
title: `${comparison.fromEntry.shortRevision}..${comparison.toEntry.shortRevision}`,
|
|
867
|
+
signal
|
|
868
|
+
}) : await request.session.adapter.buildRangeMultiDiffPlan({
|
|
869
|
+
workspacePath: request.session.workspacePath,
|
|
870
|
+
fromEntry: comparison.fromEntry,
|
|
871
|
+
toEntry: comparison.toEntry,
|
|
872
|
+
comparisonSource: request.comparisonSource,
|
|
873
|
+
sourceEntries,
|
|
874
|
+
signal
|
|
875
|
+
});
|
|
876
|
+
if (!plan.files.length) {
|
|
877
|
+
vscode.window.showInformationMessage(`No changes found for ${plan.title}`);
|
|
878
|
+
return;
|
|
879
|
+
}
|
|
880
|
+
if (!await confirmMultiDiffOpen({
|
|
881
|
+
title: plan.title,
|
|
882
|
+
fileCount: plan.files.length
|
|
883
|
+
})) return;
|
|
884
|
+
if (signal.aborted) return;
|
|
885
|
+
await vscode.commands.executeCommand(require_constants.OPEN_MULTI_DIFF_COMMAND, {
|
|
886
|
+
title: plan.title,
|
|
887
|
+
resources: await buildMultiDiffResources({
|
|
888
|
+
workspacePath: request.session.workspacePath,
|
|
889
|
+
files: plan.files
|
|
890
|
+
})
|
|
891
|
+
});
|
|
892
|
+
}
|
|
893
|
+
});
|
|
894
|
+
}
|
|
895
|
+
async function openRevisionFilesDiff(request) {
|
|
896
|
+
await args.service.runSessionAction({
|
|
897
|
+
session: request.session,
|
|
898
|
+
action: async (signal) => {
|
|
899
|
+
const sourceEntries = args.service.getEntriesForSource({
|
|
900
|
+
session: request.session,
|
|
901
|
+
comparisonSource: request.comparisonSource
|
|
902
|
+
});
|
|
903
|
+
const entry = sourceEntries[request.entryIndex];
|
|
904
|
+
if (!entry) return;
|
|
905
|
+
if (entry.isWorkingTree) {
|
|
906
|
+
await openRangeFilesDiff({
|
|
907
|
+
session: request.session,
|
|
908
|
+
fromIndex: Math.max(0, request.entryIndex - 1),
|
|
909
|
+
toIndex: request.entryIndex,
|
|
910
|
+
comparisonSource: request.comparisonSource
|
|
911
|
+
});
|
|
912
|
+
return;
|
|
913
|
+
}
|
|
914
|
+
const plan = await request.session.adapter.buildRevisionMultiDiffPlan({
|
|
915
|
+
workspacePath: request.session.workspacePath,
|
|
916
|
+
entry,
|
|
917
|
+
entryIndex: request.entryIndex,
|
|
918
|
+
comparisonSource: request.comparisonSource,
|
|
919
|
+
sourceEntries,
|
|
920
|
+
signal
|
|
921
|
+
});
|
|
922
|
+
if (!plan.files.length) {
|
|
923
|
+
vscode.window.showInformationMessage(`No files changed in ${entry.shortRevision}`);
|
|
924
|
+
return;
|
|
925
|
+
}
|
|
926
|
+
if (!await confirmMultiDiffOpen({
|
|
927
|
+
title: plan.title,
|
|
928
|
+
fileCount: plan.files.length
|
|
929
|
+
})) return;
|
|
930
|
+
if (signal.aborted) return;
|
|
931
|
+
await vscode.commands.executeCommand(require_constants.OPEN_MULTI_DIFF_COMMAND, {
|
|
932
|
+
title: plan.title,
|
|
933
|
+
resources: await buildMultiDiffResources({
|
|
934
|
+
workspacePath: request.session.workspacePath,
|
|
935
|
+
files: plan.files
|
|
936
|
+
})
|
|
937
|
+
});
|
|
938
|
+
}
|
|
939
|
+
});
|
|
940
|
+
}
|
|
941
|
+
async function openRevisionOnRemote(request) {
|
|
942
|
+
const entry = args.service.getEntriesForSource({
|
|
943
|
+
session: request.session,
|
|
944
|
+
comparisonSource: request.comparisonSource
|
|
945
|
+
})[request.entryIndex];
|
|
946
|
+
if (!entry?.remoteUrl) {
|
|
947
|
+
vscode.window.showInformationMessage("No GitHub remote URL is available for this revision.");
|
|
948
|
+
return;
|
|
949
|
+
}
|
|
950
|
+
await vscode.env.openExternal(vscode.Uri.parse(entry.remoteUrl));
|
|
951
|
+
}
|
|
952
|
+
async function buildMultiDiffResources(request) {
|
|
953
|
+
return Promise.all(request.files.map(async (file) => ({
|
|
954
|
+
originalUri: require_uri_utils.createSnapshotUri({
|
|
955
|
+
workspacePath: request.workspacePath,
|
|
956
|
+
revset: file.originalRevset,
|
|
957
|
+
relativePath: file.relativePath,
|
|
958
|
+
backend: file.backend
|
|
959
|
+
}),
|
|
960
|
+
modifiedUri: await createTargetUri({
|
|
961
|
+
workspacePath: request.workspacePath,
|
|
962
|
+
revset: file.modifiedRevset,
|
|
963
|
+
relativePath: file.relativePath,
|
|
964
|
+
backend: file.backend
|
|
965
|
+
})
|
|
966
|
+
})));
|
|
967
|
+
}
|
|
968
|
+
async function confirmMultiDiffOpen(request) {
|
|
969
|
+
if (request.fileCount <= LARGE_MULTI_DIFF_CONFIRMATION_THRESHOLD) return true;
|
|
970
|
+
const confirmLabel = `Open ${request.fileCount} diffs`;
|
|
971
|
+
return await vscode.window.showWarningMessage(`Open ${request.fileCount} file diffs?`, {
|
|
972
|
+
modal: true,
|
|
973
|
+
detail: `${request.title} touches a large number of files. Opening every diff at once may be slow and create a lot of editors.`
|
|
974
|
+
}, confirmLabel) === confirmLabel;
|
|
975
|
+
}
|
|
976
|
+
async function createTargetUri(request) {
|
|
977
|
+
if (request.revset === "@") {
|
|
978
|
+
const fileUri = vscode.Uri.file(node_path.default.join(request.workspacePath, request.relativePath));
|
|
979
|
+
if (await vscode.workspace.fs.stat(fileUri).then(() => true, () => false)) return fileUri;
|
|
980
|
+
}
|
|
981
|
+
return require_uri_utils.createSnapshotUri({
|
|
982
|
+
workspacePath: request.workspacePath,
|
|
983
|
+
revset: request.revset,
|
|
984
|
+
relativePath: request.relativePath,
|
|
985
|
+
backend: request.backend
|
|
986
|
+
});
|
|
987
|
+
}
|
|
988
|
+
async function createRevisionUri(request) {
|
|
989
|
+
if (request.entry.isWorkingTree) {
|
|
990
|
+
const fileUri = vscode.Uri.file(request.session.absolutePath);
|
|
991
|
+
if (await vscode.workspace.fs.stat(fileUri).then(() => true, () => false)) return fileUri;
|
|
992
|
+
}
|
|
993
|
+
const entryIndex = request.session.entries.findIndex((candidate) => candidate.id === request.entry.id);
|
|
994
|
+
const resolvedPath = await args.service.resolveEntryFilePath({
|
|
995
|
+
session: request.session,
|
|
996
|
+
entry: request.entry,
|
|
997
|
+
entryIndex
|
|
998
|
+
});
|
|
999
|
+
return require_uri_utils.createSnapshotUri({
|
|
1000
|
+
workspacePath: request.session.workspacePath,
|
|
1001
|
+
revset: request.entry.revision,
|
|
1002
|
+
relativePath: resolvedPath,
|
|
1003
|
+
backend: request.session.backend
|
|
1004
|
+
});
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
function getTimelineWebviewHtml(args) {
|
|
1008
|
+
if (!hasBundledTimelineWebviewAssets({ context: args.context })) return `<!DOCTYPE html>
|
|
1009
|
+
<html lang="en">
|
|
1010
|
+
<head>
|
|
1011
|
+
<meta charset="UTF-8" />
|
|
1012
|
+
<meta http-equiv="Content-Security-Policy" content="default-src 'none';" />
|
|
1013
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
1014
|
+
<title>Revision Timeline</title>
|
|
1015
|
+
</head>
|
|
1016
|
+
<body>
|
|
1017
|
+
<p>Webview bundle is missing. Run pnpm build:webview and reopen the timeline.</p>
|
|
1018
|
+
</body>
|
|
1019
|
+
</html>`;
|
|
1020
|
+
const appStylePath = vscode.Uri.joinPath(args.context.extensionUri, "webview-dist", "timeline-app.css");
|
|
1021
|
+
const appScriptPath = vscode.Uri.joinPath(args.context.extensionUri, "webview-dist", "timeline-app.js");
|
|
1022
|
+
const workerPath = vscode.Uri.joinPath(args.context.extensionUri, "webview-dist", "pierre-worker-portable.js");
|
|
1023
|
+
return require_timeline_template.renderTimelineDocumentHtml({
|
|
1024
|
+
title: "Revision Timeline",
|
|
1025
|
+
cspSource: args.webview.cspSource,
|
|
1026
|
+
styleHref: String(args.webview.asWebviewUri(appStylePath)),
|
|
1027
|
+
appSrc: String(args.webview.asWebviewUri(appScriptPath)),
|
|
1028
|
+
workerSrc: String(args.webview.asWebviewUri(workerPath))
|
|
1029
|
+
});
|
|
1030
|
+
}
|
|
1031
|
+
function hasBundledTimelineWebviewAssets(args) {
|
|
1032
|
+
const appStylePath = vscode.Uri.joinPath(args.context.extensionUri, "webview-dist", "timeline-app.css");
|
|
1033
|
+
const appScriptPath = vscode.Uri.joinPath(args.context.extensionUri, "webview-dist", "timeline-app.js");
|
|
1034
|
+
return node_fs.default.existsSync(appStylePath.fsPath) && node_fs.default.existsSync(appScriptPath.fsPath);
|
|
1035
|
+
}
|
|
1036
|
+
function createEmptyTimelineDebugState() {
|
|
1037
|
+
return {
|
|
1038
|
+
panelOpen: false,
|
|
1039
|
+
panelCount: 0,
|
|
1040
|
+
panelTitle: "",
|
|
1041
|
+
backend: "",
|
|
1042
|
+
workspacePath: "",
|
|
1043
|
+
relativePath: "",
|
|
1044
|
+
fileName: "",
|
|
1045
|
+
entryCount: 0,
|
|
1046
|
+
snapshotEntryCount: 0,
|
|
1047
|
+
lineHistory: null,
|
|
1048
|
+
usesBundledWebview: false,
|
|
1049
|
+
viewReady: false,
|
|
1050
|
+
readyCount: 0,
|
|
1051
|
+
lastMessageCommand: "",
|
|
1052
|
+
lastReadyAt: 0,
|
|
1053
|
+
entries: []
|
|
1054
|
+
};
|
|
1055
|
+
}
|
|
1056
|
+
function createDebugState(args) {
|
|
1057
|
+
return {
|
|
1058
|
+
panelOpen: true,
|
|
1059
|
+
panelCount: args.panelCount,
|
|
1060
|
+
panelTitle: args.panel.title,
|
|
1061
|
+
backend: args.session.backend,
|
|
1062
|
+
workspacePath: args.session.workspacePath,
|
|
1063
|
+
relativePath: args.session.relativePath,
|
|
1064
|
+
fileName: args.session.fileName,
|
|
1065
|
+
entryCount: args.session.entries.length,
|
|
1066
|
+
snapshotEntryCount: args.session.snapshotEntries.length,
|
|
1067
|
+
lineHistory: args.session.lineHistory ? {
|
|
1068
|
+
startLine: args.session.lineHistory.startLine,
|
|
1069
|
+
endLine: args.session.lineHistory.endLine
|
|
1070
|
+
} : null,
|
|
1071
|
+
usesBundledWebview: true,
|
|
1072
|
+
viewReady: false,
|
|
1073
|
+
readyCount: 0,
|
|
1074
|
+
lastMessageCommand: args.lastMessageCommand,
|
|
1075
|
+
lastReadyAt: 0,
|
|
1076
|
+
entries: args.session.entries.map((entry) => ({
|
|
1077
|
+
index: entry.index ?? 0,
|
|
1078
|
+
description: entry.description,
|
|
1079
|
+
shortRevision: entry.shortRevision
|
|
1080
|
+
}))
|
|
1081
|
+
};
|
|
1082
|
+
}
|
|
1083
|
+
function normalizeComparisonSource(value) {
|
|
1084
|
+
return value === "snapshot" ? "snapshot" : "revision";
|
|
1085
|
+
}
|
|
1086
|
+
function normalizeThemePreference(value) {
|
|
1087
|
+
return value === "light" || value === "dark" ? value : "auto";
|
|
1088
|
+
}
|
|
1089
|
+
function normalizeLineDiffType(value) {
|
|
1090
|
+
return value === "word" || value === "char" || value === "none" || value === "word-alt" ? value : "word-alt";
|
|
1091
|
+
}
|
|
1092
|
+
function normalizeTimelinePreset(value) {
|
|
1093
|
+
return typeof value === "string" && value in require_constants.TIMELINE_PRESET_DAYS ? value : "year";
|
|
1094
|
+
}
|
|
1095
|
+
async function maximizeTimelinePanel() {
|
|
1096
|
+
try {
|
|
1097
|
+
await vscode.commands.executeCommand("workbench.action.toggleMaximizeEditorGroup");
|
|
1098
|
+
} catch {}
|
|
1099
|
+
}
|
|
1100
|
+
function shouldMaximizeTimelinePanel() {
|
|
1101
|
+
return getEditorGroupCount() > 1;
|
|
1102
|
+
}
|
|
1103
|
+
function getTimelineViewColumn() {
|
|
1104
|
+
return shouldMaximizeTimelinePanel() ? vscode.ViewColumn.Beside : vscode.ViewColumn.Active;
|
|
1105
|
+
}
|
|
1106
|
+
function getEditorGroupCount() {
|
|
1107
|
+
const groups = vscode.window.tabGroups?.all;
|
|
1108
|
+
return Array.isArray(groups) && groups.length ? groups.length : 1;
|
|
1109
|
+
}
|
|
1110
|
+
//#endregion
|
|
1111
|
+
exports.createTimelinePanelController = createTimelinePanelController;
|
|
1112
|
+
|
|
1113
|
+
//# sourceMappingURL=timeline-panel.cjs.map
|