@young1lin/dsh-ui-gitworkbench 0.1.15 → 0.1.17
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 +26 -0
- package/CHANGELOG_EN.md +26 -0
- package/README.md +30 -5
- package/README_EN.md +1 -1
- package/lib/client.js +1600 -519
- package/lib/dir-listing.js +34 -0
- package/lib/fs-remove.js +5 -36
- package/lib/index.js +233 -52
- package/lib/path-lock.js +54 -0
- package/lib/worktree.js +133 -0
- package/lib/write-checked.js +1 -1
- package/package.json +1 -1
- package/src/client/ChromeGlyph.tsx +5 -0
- package/src/client/CodeEditor.tsx +19 -1
- package/src/client/DiffViews.tsx +122 -123
- package/src/client/FileBrowser.tsx +196 -23
- package/src/client/GitWorkbenchPanel.module.css +1 -0
- package/src/client/GitWorkbenchPanel.tsx +114 -12
- package/src/client/SideRails.tsx +106 -0
- package/src/client/diff-cells.tsx +147 -0
- package/src/client/diff-model.ts +20 -0
- package/src/client/diff-nav.ts +4 -1
- package/src/client/dir-tree.ts +31 -1
- package/src/client/file-rows.ts +40 -0
- package/src/client/h-rail.ts +70 -0
- package/src/client/ignored-cache.ts +193 -0
- package/src/client/index.ts +22 -3
- package/src/client/locales.ts +18 -4
- package/src/client/row-heights.ts +225 -0
- package/src/client/styles/changes.css +33 -2
- package/src/client/styles/controls.css +5 -0
- package/src/client/styles/files.css +5 -0
- package/src/client/styles/rails.css +72 -0
- package/src/client/use-row-window.ts +7 -3
- package/src/client/use-variable-row-window.ts +210 -0
- package/src/dir-listing.ts +47 -0
- package/src/fs-remove.ts +5 -36
- package/src/index.ts +257 -55
- package/src/path-lock.ts +56 -0
- package/src/types/dsh-shim.d.ts +12 -2
- package/src/worktree.ts +153 -0
- package/src/write-checked.ts +1 -1
package/lib/client.js
CHANGED
|
@@ -459,7 +459,7 @@ window.__ModuleLoader__.load({
|
|
|
459
459
|
}
|
|
460
460
|
//#endregion
|
|
461
461
|
//#region \0dsh-css:src/client/GitWorkbenchPanel.module.css.mjs
|
|
462
|
-
const css = ".SD8qLW_card{border:1px solid var(--dsw-alias-border-l2);min-height:28px;color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;cursor:pointer;background:0 0;border-radius:8px;align-items:center;gap:7px;padding:3px 10px;font-size:12px;line-height:18px;transition:background .12s,border-color .12s;display:inline-flex}.SD8qLW_card:hover,.SD8qLW_card:focus-visible{background:var(--dsw-alias-interactive-bg-hover);border-color:var(--dsw-alias-border-l3)}.SD8qLW_cardBranch{max-width:220px;color:var(--dsw-alias-label-primary);align-items:center;gap:4px;font-weight:550;display:inline-flex;overflow:hidden}.SD8qLW_cardBranchName{min-width:0;overflow:hidden}.SD8qLW_cardGlyph{opacity:.7;flex:none}.SD8qLW_cardDetached{background:var(--dsw-alias-state-warning-bg,#bb800926);color:var(--dsw-alias-state-warning-primary,#d29922);letter-spacing:.02em;border-radius:999px;padding:0 6px;font-size:10px;line-height:16px}.SD8qLW_cardWt{background:var(--dsw-alias-state-business-bg,#388bfd29);max-width:150px;color:var(--dsw-alias-state-business-primary,#58a6ff);letter-spacing:.02em;white-space:nowrap;text-overflow:ellipsis;border-radius:999px;align-items:center;gap:3px;padding:0 6px;font-size:10px;line-height:16px;display:inline-flex;overflow:hidden}.SD8qLW_cardAhead,.SD8qLW_cardBehind{color:var(--dsw-alias-label-tertiary);font-size:11px}.SD8qLW_cardAhead{color:var(--dsw-alias-state-success-primary)}.SD8qLW_cardBehind{color:var(--dsw-alias-state-attention-primary,#d29922)}.SD8qLW_cardSep{background:var(--dsw-alias-border-l2);width:1px;height:14px}.SD8qLW_cardAdded{color:var(--dsw-alias-state-success-primary)}.SD8qLW_cardDeleted{color:var(--dsw-alias-state-error-primary)}.SD8qLW_cardFiles{color:var(--dsw-alias-label-tertiary)}.SD8qLW_overlay[data-gs-theme=github-dark]{--gs-bg:#0d1117;--gs-panel:#161b22;--gs-raise:#21262d;--gs-border:#30363d;--gs-border-soft:#21262d;--gs-fg:#e6edf3;--gs-fg-muted:#c9d1d9;--gs-fg-dim:#8b949e;--gs-fg-faint:#6e7681;--gs-fg-fainter:#484f58;--gs-accent:#58a6ff;--gs-accent-bg:#388bfd24;--gs-accent-border:#388bfd8c;--gs-add:#3fb950;--gs-del:#f85149;--gs-warn:#d29922;--gs-info:#79c0ff;--gs-add-bg:#2ea04329;--gs-del-bg:#f8514929;--gs-warn-bg:#bb800929;--gs-info-bg:#388bfd29;--gs-add-line:#12261e;--gs-del-line:#25181c;--gs-add-word:#1a4a29;--gs-del-word:#6b2b2b;--gs-add-num:#1c4428;--gs-del-num:#542426;--gs-hunk:#111d2e;--gs-hunk-num:#0c2d6b;--gs-neutral-bg:#6e76812e;--gs-backdrop:#01040999;--gs-shadow:#0104098c}.SD8qLW_overlay[data-gs-theme=github-light]{--gs-bg:#fff;--gs-panel:#f6f8fa;--gs-raise:#eaeef2;--gs-border:#d0d7de;--gs-border-soft:#eaeef2;--gs-fg:#1f2328;--gs-fg-muted:#32383f;--gs-fg-dim:#656d76;--gs-fg-faint:#8c959f;--gs-fg-fainter:#afb8c1;--gs-accent:#0969da;--gs-accent-bg:#0969da1a;--gs-accent-border:#0969da73;--gs-add:#1a7f37;--gs-del:#cf222e;--gs-warn:#9a6700;--gs-info:#0550ae;--gs-add-bg:#1a7f371f;--gs-del-bg:#cf222e1f;--gs-warn-bg:#9a67001f;--gs-info-bg:#0969da1f;--gs-add-line:#dafbe1;--gs-del-line:#ffebe9;--gs-add-word:#aceebb;--gs-del-word:#ffcecb;--gs-add-num:#aceebb;--gs-del-num:#ffcecb;--gs-hunk:#ddf4ff;--gs-hunk-num:#b6e3ff;--gs-neutral-bg:#6e76811f;--gs-backdrop:#1f232847;--gs-shadow:#1f232838}.SD8qLW_overlay[data-gs-theme=idea-dark]{--gs-bg:#1e1f22;--gs-panel:#2b2d30;--gs-raise:#393b40;--gs-border:#393b40;--gs-border-soft:#2b2d30;--gs-fg:#dfe1e5;--gs-fg-muted:#ced0d6;--gs-fg-dim:#9da0a8;--gs-fg-faint:#6f737a;--gs-fg-fainter:#4e5157;--gs-accent:#548af7;--gs-accent-bg:#548af729;--gs-accent-border:#548af78c;--gs-add:#5fad65;--gs-del:#e26e6e;--gs-warn:#f0a732;--gs-info:#3592c4;--gs-add-bg:#5fad6529;--gs-del-bg:#e26e6e29;--gs-warn-bg:#f0a73229;--gs-info-bg:#3592c429;--gs-add-line:#293c2e;--gs-del-line:#3d2b2b;--gs-add-word:#3d6640;--gs-del-word:#6b3838;--gs-hunk:#548af71a;--gs-neutral-bg:#9da0a82e;--gs-backdrop:#10111399;--gs-shadow:#00000080}.SD8qLW_overlay[data-gs-theme=idea-light]{--gs-bg:#fff;--gs-panel:#f7f8fa;--gs-raise:#ebecf0;--gs-border:#d3d5db;--gs-border-soft:#ebecf0;--gs-fg:#1e1f22;--gs-fg-muted:#3c3f44;--gs-fg-dim:#6c707e;--gs-fg-faint:#818594;--gs-fg-fainter:#a8adbd;--gs-accent:#3574f0;--gs-accent-bg:#3574f01a;--gs-accent-border:#3574f073;--gs-add:#398a4a;--gs-del:#cc4a4a;--gs-warn:#a8760b;--gs-info:#2b7fb8;--gs-add-bg:#398a4a1f;--gs-del-bg:#cc4a4a1f;--gs-warn-bg:#a8760b1f;--gs-info-bg:#2b7fb81f;--gs-add-line:#e6f5e9;--gs-del-line:#fbe9ea;--gs-add-word:#c2e5c9;--gs-del-word:#f5c9cc;--gs-hunk:#3574f012;--gs-neutral-bg:#6c707e1f;--gs-backdrop:#1e1f2242;--gs-shadow:#1e1f222e}.SD8qLW_overlay[data-gs-theme=vscode-dark]{--gs-bg:#1e1e1e;--gs-panel:#252526;--gs-raise:#2d2d30;--gs-border:#3e3e42;--gs-border-soft:#2d2d30;--gs-fg:#d4d4d4;--gs-fg-muted:#ccc;--gs-fg-dim:#9d9d9d;--gs-fg-faint:gray;--gs-fg-fainter:#5a5a5a;--gs-accent:#0098ff;--gs-accent-bg:#007acc3d;--gs-accent-border:#0098ff99;--gs-add:#89d185;--gs-del:#f14c4c;--gs-warn:#cca700;--gs-info:#75beff;--gs-add-bg:#89d1852e;--gs-del-bg:#f14c4c2e;--gs-warn-bg:#cca7002e;--gs-info-bg:#75beff2e;--gs-add-line:#9bb9552e;--gs-del-line:#ff000029;--gs-add-word:#9bb95566;--gs-del-word:#ff00005c;--gs-hunk:#007acc24;--gs-neutral-bg:#bebebe24;--gs-backdrop:#0000008c;--gs-shadow:#0009}.SD8qLW_overlay[data-gs-theme=vscode-light]{--gs-bg:#fff;--gs-panel:#f3f3f3;--gs-raise:#e8e8e8;--gs-border:#cecece;--gs-border-soft:#e8e8e8;--gs-fg:#1e1e1e;--gs-fg-muted:#333;--gs-fg-dim:#616161;--gs-fg-faint:#767676;--gs-fg-fainter:#a0a0a0;--gs-accent:#005fb8;--gs-accent-bg:#005fb81a;--gs-accent-border:#005fb873;--gs-add:#10793f;--gs-del:#b5200d;--gs-warn:#855b00;--gs-info:#005fb8;--gs-add-bg:#10793f1f;--gs-del-bg:#b5200d1f;--gs-warn-bg:#855b001f;--gs-info-bg:#005fb81f;--gs-add-line:#9bb95538;--gs-del-line:#ff000021;--gs-add-word:#9bb95573;--gs-del-word:#ff00004d;--gs-hunk:#005fb812;--gs-neutral-bg:#6161611f;--gs-backdrop:#00000040;--gs-shadow:#0000002e}.SD8qLW_overlay[data-gs-theme=cyberpunk-dark]{--gs-bg:#0b0417;--gs-panel:#14082a;--gs-raise:#1f0d3d;--gs-border:#3a1f6b;--gs-border-soft:#26124a;--gs-fg:#f0e6ff;--gs-fg-muted:#d5c2f5;--gs-fg-dim:#a98fd6;--gs-fg-faint:#7d64a8;--gs-fg-fainter:#56427a;--gs-accent:#00f0ff;--gs-on-accent:#0b0417;--gs-accent-bg:#00f0ff24;--gs-accent-border:#00f0ff80;--gs-add:#39ff88;--gs-del:#ff2e88;--gs-warn:#fc0;--gs-info:#00f0ff;--gs-add-bg:#39ff8824;--gs-del-bg:#ff2e8824;--gs-warn-bg:#ffcc0024;--gs-info-bg:#00f0ff24;--gs-add-line:#39ff881f;--gs-del-line:#ff2e881f;--gs-add-word:#39ff8857;--gs-del-word:#ff2e8857;--gs-hunk:#00f0ff1a;--gs-neutral-bg:#a98fd629;--gs-backdrop:#06020ead;--gs-shadow:#00f0ff24}.SD8qLW_overlay[data-gs-theme=cyberpunk-light]{--gs-bg:#fdfbff;--gs-panel:#f4eeff;--gs-raise:#e9dfff;--gs-border:#c9b3f0;--gs-border-soft:#e0d2f7;--gs-fg:#1a0b2e;--gs-fg-muted:#33195c;--gs-fg-dim:#6b4ba0;--gs-fg-faint:#8f74bd;--gs-fg-fainter:#b9a5d6;--gs-accent:#00a6b8;--gs-accent-bg:#00a6b81f;--gs-accent-border:#00a6b880;--gs-add:#00875a;--gs-del:#d6006e;--gs-warn:#b37a00;--gs-info:#00a6b8;--gs-add-bg:#00875a1f;--gs-del-bg:#d6006e1f;--gs-warn-bg:#b37a001f;--gs-info-bg:#00a6b81f;--gs-add-line:#00c88224;--gs-del-line:#ff2e881f;--gs-add-word:#00c88257;--gs-del-word:#ff2e884d;--gs-hunk:#00a6b814;--gs-neutral-bg:#6b4ba01f;--gs-backdrop:#1a0b2e47;--gs-shadow:#1a0b2e29}.SD8qLW_overlay[data-gs-theme=one-dark]{--gs-bg:#282c34;--gs-panel:#21252b;--gs-raise:#2c313a;--gs-border:#3e4451;--gs-border-soft:#2c313a;--gs-fg:#abb2bf;--gs-fg-muted:#b6bdca;--gs-fg-dim:#7f848e;--gs-fg-faint:#636d83;--gs-fg-fainter:#4b5263;--gs-accent:#61afef;--gs-accent-bg:#61afef24;--gs-accent-border:#61afef8c;--gs-add:#98c379;--gs-del:#e06c75;--gs-warn:#e5c07b;--gs-info:#56b6c2;--gs-add-bg:#98c37929;--gs-del-bg:#e06c7529;--gs-warn-bg:#e5c07b29;--gs-info-bg:#56b6c229;--gs-add-line:#98c37924;--gs-del-line:#e06c7524;--gs-add-word:#98c37961;--gs-del-word:#e06c7561;--gs-hunk:#61afef1a;--gs-neutral-bg:#7f848e2e;--gs-backdrop:#171a2199;--gs-shadow:#0f11158c}.SD8qLW_overlay[data-gs-theme=one-light]{--gs-bg:#fafafa;--gs-panel:#f0f0f0;--gs-raise:#e5e5e6;--gs-border:#d4d4d4;--gs-border-soft:#e5e5e6;--gs-fg:#383a42;--gs-fg-muted:#4a4c53;--gs-fg-dim:#696c77;--gs-fg-faint:#909196;--gs-fg-fainter:#b8b9bd;--gs-accent:#4078f2;--gs-accent-bg:#4078f21a;--gs-accent-border:#4078f273;--gs-add:#50a14f;--gs-del:#e45649;--gs-warn:#c18401;--gs-info:#0184bc;--gs-add-bg:#50a14f1f;--gs-del-bg:#e456491f;--gs-warn-bg:#c184011f;--gs-info-bg:#0184bc1f;--gs-add-line:#50a14f24;--gs-del-line:#e4564921;--gs-add-word:#50a14f57;--gs-del-word:#e4564952;--gs-hunk:#4078f212;--gs-neutral-bg:#696c771f;--gs-backdrop:#383a4242;--gs-shadow:#383a422e}.SD8qLW_overlay[data-gs-theme=solarized-dark]{--gs-bg:#002b36;--gs-panel:#073642;--gs-raise:#0a4553;--gs-border:#0f5666;--gs-border-soft:#073642;--gs-fg:#93a1a1;--gs-fg-muted:#839496;--gs-fg-dim:#657b83;--gs-fg-faint:#586e75;--gs-fg-fainter:#45636b;--gs-accent:#268bd2;--gs-accent-bg:#268bd229;--gs-accent-border:#268bd28c;--gs-add:#859900;--gs-del:#dc322f;--gs-warn:#b58900;--gs-info:#2aa198;--gs-add-bg:#85990033;--gs-del-bg:#dc322f2e;--gs-warn-bg:#b589002e;--gs-info-bg:#2aa1982e;--gs-add-line:#85990029;--gs-del-line:#dc322f26;--gs-add-word:#85990066;--gs-del-word:#dc322f61;--gs-hunk:#268bd21f;--gs-neutral-bg:#657b8333;--gs-backdrop:#00141a9e;--gs-shadow:#00141a8c}.SD8qLW_overlay[data-gs-theme=solarized-light]{--gs-bg:#fdf6e3;--gs-panel:#eee8d5;--gs-raise:#e3ddca;--gs-border:#d5cfbb;--gs-border-soft:#eee8d5;--gs-fg:#586e75;--gs-fg-muted:#657b83;--gs-fg-dim:#839496;--gs-fg-faint:#93a1a1;--gs-fg-fainter:#b5b0a0;--gs-accent:#268bd2;--gs-accent-bg:#268bd21f;--gs-accent-border:#268bd273;--gs-add:#6c7c00;--gs-del:#cb2825;--gs-warn:#9a7400;--gs-info:#21867f;--gs-add-bg:#8599002e;--gs-del-bg:#dc322f24;--gs-warn-bg:#b5890029;--gs-info-bg:#2aa19824;--gs-add-line:#85990029;--gs-del-line:#dc322f1f;--gs-add-word:#85990061;--gs-del-word:#dc322f4d;--gs-hunk:#268bd214;--gs-neutral-bg:#586e7524;--gs-backdrop:#586e7542;--gs-shadow:#586e7533}.SD8qLW_overlay[data-gs-theme=nord-dark]{--gs-bg:#2e3440;--gs-panel:#3b4252;--gs-raise:#434c5e;--gs-border:#4c566a;--gs-border-soft:#3b4252;--gs-fg:#eceff4;--gs-fg-muted:#d8dee9;--gs-fg-dim:#9aa5b8;--gs-fg-faint:#7b88a1;--gs-fg-fainter:#5d6a82;--gs-accent:#88c0d0;--gs-on-accent:#2e3440;--gs-accent-bg:#88c0d024;--gs-accent-border:#88c0d08c;--gs-add:#a3be8c;--gs-del:#bf616a;--gs-warn:#ebcb8b;--gs-info:#81a1c1;--gs-add-bg:#a3be8c29;--gs-del-bg:#bf616a2e;--gs-warn-bg:#ebcb8b29;--gs-info-bg:#81a1c129;--gs-add-line:#a3be8c24;--gs-del-line:#bf616a26;--gs-add-word:#a3be8c61;--gs-del-word:#bf616a66;--gs-hunk:#88c0d01a;--gs-neutral-bg:#9aa5b829;--gs-backdrop:#1d232d9e;--gs-shadow:#1419218c}.SD8qLW_overlay[data-gs-theme=nord-light]{--gs-bg:#eceff4;--gs-panel:#e5e9f0;--gs-raise:#d8dee9;--gs-border:#c3cbd8;--gs-border-soft:#dfe4ec;--gs-fg:#2e3440;--gs-fg-muted:#3b4252;--gs-fg-dim:#4c566a;--gs-fg-faint:#6b7689;--gs-fg-fainter:#9aa4b5;--gs-accent:#5e81ac;--gs-accent-bg:#5e81ac1f;--gs-accent-border:#5e81ac80;--gs-add:#5e7d47;--gs-del:#a5424c;--gs-warn:#97701f;--gs-info:#4c7a8c;--gs-add-bg:#5e7d4724;--gs-del-bg:#a5424c21;--gs-warn-bg:#97701f24;--gs-info-bg:#4c7a8c21;--gs-add-line:#5e7d4724;--gs-del-line:#a5424c1f;--gs-add-word:#5e7d4757;--gs-del-word:#a5424c52;--gs-hunk:#5e81ac17;--gs-neutral-bg:#4c566a21;--gs-backdrop:#2e344042;--gs-shadow:#2e34402e}.SD8qLW_overlay{--gs-inset:14px;--gs-h-control:28px;--gs-h-compact:24px;--gs-pad-control:0 12px;--gs-pad-compact:0 10px;--gs-on-accent:#fff;--gs-graph-0:#58a6ff;--gs-graph-1:#3fb950;--gs-graph-2:#d29922;--gs-graph-3:#bc8cff;--gs-graph-4:#f778ba;--gs-graph-5:#39c5cf;--gs-r-pill:999px;--gs-r-control:8px;--gs-r-surface:12px;--gs-r-drawer:14px;--gs-t-meta:11px;--gs-t-dense:12px;--gs-t-ui:13px;--gs-gutter:16px;--gs-gutter-pane:12px;z-index:1000;padding:var(--gs-inset);box-sizing:border-box;background:var(--gs-backdrop);justify-content:flex-end;align-items:stretch;gap:12px;animation:.16s ease-out SD8qLW_gsFade;display:flex;position:fixed;inset:0}.SD8qLW_drawer{box-sizing:border-box;width:min(1600px,94vw);height:100%;color:var(--gs-fg);background:var(--gs-bg);border:1px solid var(--gs-border);border-radius:var(--gs-r-drawer);box-shadow:0 24px 64px var(--gs-shadow);font-family:var(--dsw-font-ui,-apple-system, BlinkMacSystemFont, \"Segoe UI\", Helvetica, Arial, sans-serif);--gs-surface:var(--gs-bg);--gs-surface-2:var(--gs-panel);flex-direction:column;animation:.18s cubic-bezier(.22,1,.36,1) SD8qLW_gsSlide;display:flex;position:relative;overflow:hidden}.SD8qLW_drawer[data-gs-bg]{--gs-surface:color-mix(in srgb, var(--gs-bg) var(--gs-veil), transparent);--gs-surface-2:color-mix(in srgb, var(--gs-panel) var(--gs-veil), transparent)}.SD8qLW_drawer[data-gs-bg]:before{content:\"\";z-index:0;background-image:var(--gs-bg-image);filter:blur(var(--gs-bg-blur));pointer-events:none;background-position:50%;background-size:cover;position:absolute;inset:0;transform:scale(1.12)}.SD8qLW_drawer>:not(.SD8qLW_resizer){z-index:1;position:relative}.SD8qLW_drawer>.SD8qLW_header{z-index:24}.SD8qLW_drawer>.SD8qLW_tabs{z-index:23}.SD8qLW_drawer>.SD8qLW_compareBar{z-index:22}.SD8qLW_drawer>.SD8qLW_syncBar{z-index:20}.SD8qLW_drawer>.SD8qLW_confirmScrim{z-index:40;position:absolute;inset:0}.SD8qLW_overlayMax{gap:0;padding:0}.SD8qLW_overlayMax .SD8qLW_drawer{border-width:0 0 0 1px;border-radius:0;flex:auto;width:auto;min-width:0}@keyframes SD8qLW_gsFade{0%{opacity:0}}@keyframes SD8qLW_gsSlide{0%{opacity:0;transform:translate(24px)}}.SD8qLW_resizer{z-index:30;cursor:col-resize;touch-action:none;justify-content:center;align-items:center;width:10px;display:flex;position:absolute;top:0;bottom:0;left:0}.SD8qLW_resizer:after{content:\"\";background:var(--gs-fg-fainter);opacity:0;border-radius:999px;width:3px;height:32px;transition:opacity .14s,height .14s}.SD8qLW_resizer:hover:after{opacity:.6}.SD8qLW_resizerActive:after{opacity:.9;height:56px}.SD8qLW_paneDivider{z-index:5;cursor:col-resize;touch-action:none;flex:none;justify-content:center;align-items:center;width:7px;display:flex;position:relative}.SD8qLW_paneDivider:before{content:\"\";background:var(--gs-border-soft);width:1px;position:absolute;top:0;bottom:0;left:3px}.SD8qLW_paneDivider:after{content:\"\";background:var(--gs-fg-fainter);opacity:0;border-radius:999px;width:3px;height:28px;transition:opacity .14s,height .14s;position:relative}.SD8qLW_paneDivider:hover:after{opacity:.6}.SD8qLW_paneDividerActive:after{opacity:.9;height:48px}.SD8qLW_paneDividerY{cursor:row-resize;width:auto;height:7px}.SD8qLW_paneDividerY:before{width:auto;height:1px;inset:3px 0 auto}.SD8qLW_paneDividerY:after{width:28px;height:3px;transition:opacity .14s,width .14s}.SD8qLW_paneDividerY.SD8qLW_paneDividerActive:after{width:48px;height:3px}.SD8qLW_header{padding:10px var(--gs-gutter);border-bottom:1px solid var(--gs-border);background:var(--gs-surface-2);font-family:var(--dsw-font-ui,system-ui, sans-serif);font-size:var(--gs-t-ui);flex:none;justify-content:space-between;align-items:center;gap:12px;display:flex}.SD8qLW_headerLeft{flex-wrap:wrap;align-items:center;gap:10px;min-width:0;display:flex}.SD8qLW_headerBranch{border:1px solid var(--gs-accent-border);border-radius:var(--gs-r-pill);background:var(--gs-accent-bg);color:var(--gs-accent);align-items:center;gap:6px;padding:2px 10px;font-weight:600;display:inline-flex}.SD8qLW_refButton.SD8qLW_headerPicker{border-color:var(--gs-accent-border);background:var(--gs-accent-bg);max-width:420px;color:var(--gs-accent);font-weight:600}.SD8qLW_refButton.SD8qLW_headerPicker:hover{background:var(--gs-accent-bg);color:var(--gs-accent);border-color:var(--gs-accent)}.SD8qLW_elide{flex:0 auto;align-items:baseline;min-width:0;display:inline-flex}.SD8qLW_elideHead{white-space:nowrap;text-overflow:ellipsis;flex:0 999 auto;min-width:0;overflow:hidden}.SD8qLW_elideTail{white-space:nowrap;text-overflow:ellipsis;flex:0 auto;min-width:0;overflow:hidden}.SD8qLW_headerPathMain{color:var(--gs-fg-faint);font-size:var(--gs-t-meta)}.SD8qLW_headerPathMain .SD8qLW_elideTail{color:var(--gs-fg-dim)}.SD8qLW_headerViewRef{max-width:160px}.SD8qLW_headerView{border-radius:var(--gs-r-pill);background:var(--gs-neutral-bg);color:var(--gs-fg-muted);font-size:var(--gs-t-meta);font-variant-numeric:tabular-nums;flex:none;padding:1px 8px}.SD8qLW_headerDetached{border-radius:var(--gs-r-pill);background:var(--gs-warn-bg);color:var(--gs-warn);font-size:var(--gs-t-meta);letter-spacing:.02em;padding:1px 8px}.SD8qLW_headerTotals{font-variant-numeric:tabular-nums}.SD8qLW_headerTotalsAdd{color:var(--gs-add);font-weight:600}.SD8qLW_headerTotalsDel{color:var(--gs-del);font-weight:600}.SD8qLW_headerTotalsDim{color:var(--gs-fg-dim);font-size:var(--gs-t-dense)}.SD8qLW_headerRight{flex:none;gap:8px;display:flex;position:relative}.SD8qLW_theme{display:inline-flex;position:relative}.SD8qLW_refPop.SD8qLW_settingsPop{width:320px;max-width:calc(100vw - 32px);max-height:min(560px,100vh - 120px);top:calc(100% + 6px);left:auto;right:0}.SD8qLW_themeRail{min-height:0;font-family:var(--dsw-font-ui,system-ui, sans-serif);flex-direction:column;flex:1;gap:14px;padding:12px 14px 16px;display:flex;overflow-y:auto}.SD8qLW_themeGroup{flex-direction:column;gap:6px;display:flex}.SD8qLW_themeLabel{color:var(--gs-fg-faint);font-size:var(--gs-t-meta);letter-spacing:.04em;text-transform:uppercase;font-weight:600}.SD8qLW_themeRowSplit{justify-content:space-between;align-items:center;gap:8px;display:flex}.SD8qLW_segmented{gap:6px;display:flex}.SD8qLW_segment{box-sizing:border-box;border:1px solid var(--gs-border);border-radius:var(--gs-r-control);color:var(--gs-fg-dim);font-family:inherit;font-size:var(--gs-t-meta);cursor:pointer;background:0 0;flex-direction:column;flex:1 1 0;align-items:stretch;gap:4px;padding:4px;transition:background .12s,color .12s,border-color .12s;display:flex}.SD8qLW_segment:hover{background:var(--gs-raise);border-color:var(--gs-fg-fainter);color:var(--gs-fg)}.SD8qLW_segment:focus-visible{outline:2px solid var(--gs-accent);outline-offset:1px}.SD8qLW_segmentChip{border-radius:calc(var(--gs-r-control) - 4px);border:1px solid #80808073;height:20px}.SD8qLW_chipLight{background:#fff}.SD8qLW_chipDark{background:#0b0b0d}.SD8qLW_chipSystem{background:linear-gradient(105deg,#fff 0 50%,#0b0b0d 50% 100%)}.SD8qLW_paletteRow{box-sizing:border-box;border-radius:var(--gs-r-control);width:100%;color:var(--gs-fg-muted);font-family:inherit;font-size:var(--gs-t-dense);text-align:left;cursor:pointer;background:0 0;border:0;align-items:center;gap:8px;padding:5px 8px;display:flex}.SD8qLW_paletteRow:hover{background:var(--gs-raise);color:var(--gs-fg)}.SD8qLW_swatch{border:1px solid var(--gs-border);border-radius:3px;flex:none;width:26px;height:12px;display:inline-flex;overflow:hidden}.SD8qLW_swatch span{flex:1}.SD8qLW_scopeRow{gap:6px;display:flex}.SD8qLW_scopeHint{color:var(--gs-fg-faint);font-size:var(--gs-t-meta);overflow-wrap:anywhere}.SD8qLW_bgPreview{border:1px solid var(--gs-border);border-radius:var(--gs-r-control);background-color:var(--gs-bg);background-position:50%;background-size:cover;height:64px}.SD8qLW_bgEmpty{color:var(--gs-fg-faint);font-size:var(--gs-t-meta);justify-content:center;align-items:center;display:flex}.SD8qLW_sliderRow{font-size:var(--gs-t-meta);color:var(--gs-fg-dim);align-items:center;gap:8px;display:flex}.SD8qLW_sliderRow input{min-width:0;accent-color:var(--gs-accent);flex:1}.SD8qLW_sliderValue{text-align:right;font-variant-numeric:tabular-nums;flex:none;width:38px}.SD8qLW_cssArea{box-sizing:border-box;border:1px solid var(--gs-border);border-radius:var(--gs-r-control);background:var(--gs-bg);width:100%;min-height:96px;max-height:220px;color:var(--gs-fg);font-family:var(--dsw-font-mono,ui-monospace, Consolas, monospace);font-size:var(--gs-t-meta);resize:vertical;outline:none;padding:7px 8px}.SD8qLW_cssArea:focus{border-color:var(--gs-accent-border)}.SD8qLW_themeNote{color:var(--gs-warn);font-size:var(--gs-t-meta)}.SD8qLW_themeDirty{color:var(--gs-accent);font-size:var(--gs-t-meta)}.SD8qLW_wtCurrent{color:var(--gs-add);font-size:8px;line-height:1}.SD8qLW_commitCopy{margin-left:auto}.SD8qLW_commitPop{z-index:40;box-sizing:border-box;border:1px solid var(--gs-border);border-radius:var(--gs-r-surface);background:var(--gs-panel);width:min(380px,100vw - 24px);color:var(--gs-fg);box-shadow:0 16px 40px var(--gs-shadow);font-family:var(--dsw-font-ui,-apple-system, BlinkMacSystemFont, \"Segoe UI\", Helvetica, Arial, sans-serif);font-size:var(--gs-t-dense);flex-direction:column;gap:6px;padding:10px 12px 12px;display:flex;position:fixed;overflow:auto}.SD8qLW_commitPopTop{align-items:center;gap:8px;display:flex}.SD8qLW_commitPopTop .SD8qLW_commitWhen{margin-right:auto}.SD8qLW_commitPopMeta{color:var(--gs-fg-muted);font-size:var(--gs-t-dense);flex-direction:column;gap:2px;line-height:16px;display:flex}.SD8qLW_commitFilter{min-width:120px;height:var(--gs-h-control);box-sizing:border-box;border:1px solid var(--gs-border-soft);border-radius:var(--gs-r-control);background:var(--gs-bg);color:var(--gs-fg);font-family:inherit;font-size:var(--gs-t-dense);outline:none;flex:auto;padding:0 10px}.SD8qLW_commitFilter:focus{border-color:var(--gs-accent)}.SD8qLW_commitFilter::placeholder{color:var(--gs-fg-faint)}.SD8qLW_filterChips{border-bottom:1px solid var(--gs-border-soft);flex-wrap:wrap;flex:none;align-items:center;gap:6px;padding:6px 10px;display:flex}.SD8qLW_filterChip{border:1px solid var(--gs-border-soft);border-radius:var(--gs-r-control);background:var(--gs-surface-2);max-width:220px;font-size:var(--gs-t-dense);align-items:center;gap:2px;line-height:18px;display:inline-flex}.SD8qLW_filterChipLabel{text-overflow:ellipsis;white-space:nowrap;color:var(--gs-fg-muted);padding:2px 4px 2px 8px;overflow:hidden}.SD8qLW_filterChipRemove{border:none;border-left:1px solid var(--gs-border-soft);color:var(--gs-fg-dim);font-family:inherit;font-size:var(--gs-t-dense);cursor:pointer;background:0 0;flex:none;padding:0 6px;line-height:20px}.SD8qLW_filterChipRemove:hover{color:var(--gs-del)}.SD8qLW_filterClear{color:var(--gs-fg-faint);font-family:inherit;font-size:var(--gs-t-dense);cursor:pointer;background:0 0;border:none;padding:2px 4px;line-height:18px}.SD8qLW_filterClear:hover{color:var(--gs-fg)}.SD8qLW_funnel{display:inline-flex;position:relative}.SD8qLW_funnelButton.SD8qLW_funnelButtonActive{color:var(--gs-accent);border-color:var(--gs-accent)}.SD8qLW_funnelPop{z-index:40;box-sizing:border-box;border:1px solid var(--gs-border);border-radius:var(--gs-r-surface);background:var(--gs-panel);width:320px;max-width:calc(100vw - 24px);box-shadow:0 16px 40px var(--gs-shadow);font-size:var(--gs-t-dense);flex-direction:column;display:flex;position:fixed;overflow:hidden}.SD8qLW_funnelTabs{border:1px solid var(--gs-border-soft);border-radius:var(--gs-r-control);background:var(--gs-bg);flex:none;gap:2px;margin:8px 8px 0;padding:2px;display:flex}.SD8qLW_funnelTab{box-sizing:border-box;min-width:0;height:var(--gs-h-compact);border-radius:calc(var(--gs-r-control) - 3px);color:var(--gs-fg-dim);font-family:inherit;font-size:var(--gs-t-dense);white-space:nowrap;cursor:pointer;background:0 0;border:1px solid #0000;flex:1;padding:0 8px;line-height:1;transition:background .12s,color .12s}.SD8qLW_funnelTab:hover{color:var(--gs-fg)}.SD8qLW_funnelTab:focus-visible{outline:2px solid var(--gs-accent);outline-offset:1px}.SD8qLW_funnelTabCount{color:var(--gs-accent);font-variant-numeric:tabular-nums;margin-left:4px}.SD8qLW_funnelPane{flex-direction:column;flex:auto;gap:6px;min-height:0;padding:8px;display:flex}.SD8qLW_funnelCaption{color:var(--gs-fg-faint);font-size:var(--gs-t-meta);letter-spacing:.04em;text-transform:uppercase;flex:none;line-height:14px}.SD8qLW_funnelBounds{border:1px solid var(--gs-border-soft);border-radius:var(--gs-r-control);background:var(--gs-bg);flex:none;gap:2px;padding:2px;display:flex}.SD8qLW_funnelBoundBtn{box-sizing:border-box;min-width:0;height:var(--gs-h-compact);border-radius:calc(var(--gs-r-control) - 3px);color:var(--gs-fg-dim);font-family:inherit;font-size:var(--gs-t-dense);cursor:pointer;background:0 0;border:1px solid #0000;flex:1;padding:0 6px;line-height:1;transition:background .12s,color .12s}.SD8qLW_funnelBoundBtn:hover{color:var(--gs-fg)}.SD8qLW_cal{flex-direction:column;flex:none;gap:4px;display:flex}.SD8qLW_calHead{align-items:center;gap:4px;display:flex}.SD8qLW_calTitle{text-align:center;color:var(--gs-fg);font-size:var(--gs-t-dense);flex:1;line-height:20px}.SD8qLW_calNav{width:var(--gs-h-compact);height:var(--gs-h-compact);border-radius:var(--gs-r-control);color:var(--gs-fg-dim);font-family:inherit;font-size:var(--gs-t-ui);cursor:pointer;background:0 0;border:none;flex:none;padding:0}.SD8qLW_calNav:hover{color:var(--gs-fg);background:var(--gs-raise)}.SD8qLW_calWeek,.SD8qLW_calGrid{grid-template-columns:repeat(7,1fr);gap:2px;display:grid}.SD8qLW_calWeek span{text-align:center;color:var(--gs-fg-faint);font-size:var(--gs-t-meta);line-height:14px}.SD8qLW_calGrid button{height:var(--gs-h-compact);border-radius:var(--gs-r-control);color:var(--gs-fg-muted);font-family:inherit;font-size:var(--gs-t-dense);font-variant-numeric:tabular-nums;cursor:pointer;background:0 0;border:none}.SD8qLW_calGrid button:hover{background:var(--gs-raise);color:var(--gs-fg)}.SD8qLW_calGrid button.SD8qLW_calOut{color:var(--gs-fg-fainter)}.SD8qLW_calGrid button.SD8qLW_calToday{color:var(--gs-accent);font-weight:600}.SD8qLW_calGrid button.SD8qLW_calIn{background:var(--gs-accent-bg);color:var(--gs-fg)}.SD8qLW_calGrid button.SD8qLW_calMark{background:var(--gs-accent);color:var(--gs-on-accent);font-weight:600}.SD8qLW_funnelBoundRows{flex:none;grid-template-columns:1fr 1fr;gap:6px;display:grid}.SD8qLW_funnelBoundRow{box-sizing:border-box;border:1px solid var(--gs-border-soft);border-radius:var(--gs-r-control);background:var(--gs-bg);min-width:0;font-size:var(--gs-t-meta);align-items:center;gap:4px;padding:3px 6px;line-height:16px;display:flex}.SD8qLW_funnelBoundKey{color:var(--gs-fg-faint);flex:none}.SD8qLW_funnelBoundVal{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--gs-fg-faint);font-variant-numeric:tabular-nums;flex:1;overflow:hidden}.SD8qLW_funnelBoundValSet{color:var(--gs-fg)}.SD8qLW_funnelBoundClear{color:var(--gs-fg-dim);font-family:inherit;font-size:var(--gs-t-dense);cursor:pointer;background:0 0;border:none;flex:none;padding:0 2px;line-height:1}.SD8qLW_funnelBoundClear:hover{color:var(--gs-del)}.SD8qLW_funnelSearch{box-sizing:border-box;height:var(--gs-h-compact);border:1px solid var(--gs-border-soft);border-radius:var(--gs-r-control);background:var(--gs-bg);color:var(--gs-fg);font-family:inherit;font-size:var(--gs-t-dense);outline:none;flex:none;padding:0 8px}.SD8qLW_funnelSearch::placeholder{color:var(--gs-fg-faint)}.SD8qLW_funnelSearch:focus{border-color:var(--gs-accent);box-shadow:0 0 0 2px var(--gs-accent-bg)}.SD8qLW_funnelList{overscroll-behavior:contain;scrollbar-width:thin;scrollbar-color:var(--gs-fg-fainter) transparent;flex-direction:column;flex:auto;gap:1px;min-height:0;margin:0 -4px;padding:0 4px;display:flex;overflow-y:auto}.SD8qLW_funnelList::-webkit-scrollbar{width:10px}.SD8qLW_funnelList::-webkit-scrollbar-track{background:0 0}.SD8qLW_funnelList::-webkit-scrollbar-thumb{background:var(--gs-fg-fainter);border-radius:var(--gs-r-pill);background-clip:content-box;border:3px solid #0000}.SD8qLW_funnelRow{box-sizing:border-box;border-radius:var(--gs-r-control);cursor:pointer;align-items:center;gap:6px;min-height:24px;padding:0 4px;display:flex}.SD8qLW_funnelRow:hover{background:var(--gs-raise)}.SD8qLW_funnelRow:has(input[type=checkbox]:checked) .SD8qLW_funnelName,.SD8qLW_funnelRow:has(input[type=checkbox]:indeterminate) .SD8qLW_funnelName{color:var(--gs-fg)}.SD8qLW_funnelRow input[type=checkbox]{-webkit-appearance:none;appearance:none;box-sizing:border-box;border:1px solid var(--gs-fg-fainter);cursor:pointer;background:0 0;border-radius:3px;flex:none;width:14px;height:14px;margin:0;transition:background .12s,border-color .12s;position:relative}.SD8qLW_funnelRow input[type=checkbox]:hover{border-color:var(--gs-fg-dim)}.SD8qLW_funnelRow input[type=checkbox]:checked,.SD8qLW_funnelRow input[type=checkbox]:indeterminate{background:var(--gs-accent);border-color:var(--gs-accent)}.SD8qLW_funnelRow input[type=checkbox]:focus-visible{outline:2px solid var(--gs-accent);outline-offset:1px}.SD8qLW_funnelRow input[type=checkbox]:checked:after{content:\"\";border:solid var(--gs-on-accent);border-width:0 1.5px 1.5px 0;width:3px;height:7px;position:absolute;top:1px;left:4px;transform:rotate(42deg)}.SD8qLW_funnelRow input[type=checkbox]:indeterminate:after{content:\"\";background:var(--gs-on-accent);border-radius:1px;width:8px;height:2px;position:absolute;top:5px;left:2px}.SD8qLW_pathNode,.SD8qLW_pathChildren{flex-direction:column;display:flex}.SD8qLW_pathFileGlyph,.SD8qLW_pathDirGlyph{width:16px;height:16px;color:var(--gs-fg-dim);flex:none}.SD8qLW_funnelRow:hover .SD8qLW_pathFileGlyph,.SD8qLW_funnelRow:hover .SD8qLW_pathDirGlyph{color:var(--gs-fg-muted)}.SD8qLW_funnelName{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--gs-fg-muted);flex:1;overflow:hidden}.SD8qLW_funnelCount{color:var(--gs-fg-faint);font-size:var(--gs-t-meta);font-variant-numeric:tabular-nums;flex:none}.SD8qLW_funnelMore{color:var(--gs-fg-faint);padding:4px 6px}.SD8qLW_funnelChevron{width:14px;color:var(--gs-fg-faint);cursor:pointer;background:0 0;border:none;flex:none;padding:0;font-family:inherit;font-size:9px;line-height:16px}.SD8qLW_funnelChevron:hover:not(:disabled){color:var(--gs-fg)}.SD8qLW_funnelChevron:disabled{cursor:default}.SD8qLW_funnelPresets{flex:none;gap:4px;display:flex}.SD8qLW_funnelPreset{flex:1 1 0;min-width:0;padding:0 6px}.SD8qLW_funnelFoot{border-top:1px solid var(--gs-border-soft);background:var(--gs-bg);font-size:var(--gs-t-meta);flex:none;justify-content:space-between;align-items:center;gap:8px;padding:6px 10px;line-height:16px;display:flex}.SD8qLW_funnelFootCount{color:var(--gs-fg-faint);font-variant-numeric:tabular-nums}.SD8qLW_funnelFootCountOn{color:var(--gs-fg-muted)}.SD8qLW_funnelFootClear{border-radius:var(--gs-r-control);color:var(--gs-fg-dim);font-family:inherit;font-size:var(--gs-t-meta);cursor:pointer;background:0 0;border:none;flex:none;padding:2px 6px;line-height:16px}.SD8qLW_funnelFootClear:hover:not(:disabled){color:var(--gs-fg);background:var(--gs-raise)}.SD8qLW_funnelFootClear:disabled{color:var(--gs-fg-fainter);cursor:default}.SD8qLW_commitPopSubject{color:var(--gs-fg);font-size:var(--gs-t-ui);white-space:pre-wrap;overflow-wrap:anywhere;user-select:text;font-weight:600;line-height:18px}.SD8qLW_commitPopBody{color:var(--gs-fg-muted);font-family:inherit;font-size:var(--gs-t-dense);white-space:pre-wrap;overflow-wrap:anywhere;user-select:text;margin:0;line-height:18px}.SD8qLW_tabs{padding:0 var(--gs-gutter);border-bottom:1px solid var(--gs-border-soft);background:var(--gs-surface-2);flex:none;gap:24px;font-family:inherit;display:flex}.SD8qLW_tab{font-family:inherit;font-size:var(--gs-t-ui);color:var(--gs-fg-dim);cursor:pointer;background:0 0;border:none;padding:8px 0 9px;font-weight:500;line-height:16px;position:relative}.SD8qLW_tab:after{content:\"\";background:0 0;border-radius:2px;height:2px;position:absolute;bottom:1px;left:0;right:0}.SD8qLW_tabActive{color:var(--gs-accent)}.SD8qLW_tabActive:after{background:var(--gs-accent)}.SD8qLW_compareBar{padding:8px var(--gs-gutter);border-bottom:1px solid var(--gs-border-soft);background:var(--gs-surface-2);color:var(--gs-fg-dim);font-family:var(--dsw-font-ui,system-ui, sans-serif);font-size:var(--gs-t-dense);flex-wrap:wrap;flex:none;align-items:center;gap:10px;display:flex}.SD8qLW_compareArrow{color:var(--gs-fg-faint)}.SD8qLW_refPicker{align-items:center;gap:6px;display:inline-flex;position:relative}.SD8qLW_refLabel{color:var(--gs-fg-faint);flex:none}.SD8qLW_refButton{justify-content:space-between;max-width:260px}.SD8qLW_refValue{min-width:0;overflow:hidden}.SD8qLW_refCaret{color:var(--gs-fg-faint);flex:none;font-size:9px}.SD8qLW_refPop{z-index:10;border:1px solid var(--gs-border);border-radius:var(--gs-r-control);background:var(--gs-panel);width:300px;max-width:80vw;box-shadow:0 12px 32px var(--gs-shadow);flex-direction:column;display:flex;position:absolute;top:calc(100% + 4px);left:0;overflow:hidden}.SD8qLW_menuPop{width:auto;min-width:100%;padding:4px;left:auto;right:0}.SD8qLW_refSearch{border:0;border-bottom:1px solid var(--gs-border-soft);background:var(--gs-bg);color:var(--gs-fg);font-family:inherit;font-size:var(--gs-t-dense);outline:none;flex:none;padding:7px 10px}.SD8qLW_refSearch::placeholder{color:var(--gs-fg-faint)}.SD8qLW_refList{flex:1;max-height:280px;padding:4px;overflow-y:auto}.SD8qLW_refGroup{color:var(--gs-fg-faint);font-size:var(--gs-t-meta);letter-spacing:.04em;text-transform:uppercase;padding:6px 8px 3px;font-weight:600}.SD8qLW_refRow{box-sizing:border-box;border-radius:var(--gs-r-control);width:100%;color:var(--gs-fg-muted);font-family:inherit;font-size:var(--gs-t-dense);text-align:left;cursor:pointer;background:0 0;border:0;align-items:center;gap:6px;padding:5px 8px;display:flex}.SD8qLW_refRow:hover{background:var(--gs-raise);color:var(--gs-fg)}.SD8qLW_refRowSpacer{flex:none;width:12px}.SD8qLW_refRowName{flex:auto;min-width:0;overflow:hidden}.SD8qLW_refEmpty{color:var(--gs-fg-faint);font-size:var(--gs-t-dense);padding:14px 10px}.SD8qLW_refFoot{border-top:1px solid var(--gs-border-soft);color:var(--gs-fg-faint);font-size:var(--gs-t-meta);flex:none;padding:5px 10px}.SD8qLW_commitsPane{box-sizing:border-box;width:26%;min-height:0;min-width:var(--gs-min-commits);background:var(--gs-surface);flex-direction:column;flex:0 auto;max-width:340px;display:flex}.SD8qLW_paneHead{box-sizing:border-box;min-height:37px;padding:6px var(--gs-gutter-pane);border-bottom:1px solid var(--gs-border-soft);color:var(--gs-fg-dim);font-family:var(--dsw-font-ui,system-ui, sans-serif);font-size:var(--gs-t-dense);flex-wrap:wrap;flex:none;align-items:center;gap:8px;display:flex}.SD8qLW_paneTitle{font-weight:600}.SD8qLW_commitsSentinel{flex:none;height:1px}.SD8qLW_commitsFoot{color:var(--gs-fg-faint);font-family:var(--dsw-font-ui,system-ui, sans-serif);font-size:var(--gs-t-meta);text-align:center;flex:none;min-height:16px;padding:8px}.SD8qLW_commits{flex-direction:column;flex:1;min-height:0;padding:4px 6px 4px 0;display:flex;overflow-y:auto}.SD8qLW_commitLine{height:var(--gs-commit-row);flex:none;align-items:stretch;display:flex}.SD8qLW_graphCell{flex:none;display:block}.SD8qLW_commit{box-sizing:border-box;border-radius:var(--gs-r-surface);text-align:left;cursor:pointer;min-width:0;height:100%;font-family:inherit;font-size:var(--gs-t-dense);background:0 0;border:1px solid #0000;flex:auto;align-items:center;gap:10px;margin:1px 0;padding:4px 8px;transition:background .12s,border-color .12s;display:flex;overflow:hidden}.SD8qLW_commitsPane[data-layout=columns] .SD8qLW_commit{flex-direction:column;justify-content:center;align-items:stretch;gap:2px}.SD8qLW_commitsPane[data-layout=columns] .SD8qLW_commitSubjectRow{flex:none}.SD8qLW_commitTop{justify-content:space-between;align-items:center;gap:8px;min-width:0;display:flex}.SD8qLW_commit:hover{background:var(--gs-raise)}.SD8qLW_commitMeta{flex:none;align-items:baseline;gap:8px;display:flex}.SD8qLW_commitHash{color:var(--gs-info);flex:none}.SD8qLW_commitSubjectRow{flex:auto;align-items:baseline;gap:4px;min-width:0;display:flex}.SD8qLW_commitSubject{white-space:nowrap;text-overflow:ellipsis;min-width:0;color:var(--gs-fg-muted);flex:0 auto;overflow:hidden}.SD8qLW_commitHasBody{color:var(--gs-fg-faint);letter-spacing:.04em;flex:none}.SD8qLW_commitRef{white-space:nowrap;text-overflow:ellipsis;border:1px solid var(--gs-accent-border);border-radius:var(--gs-r-pill);background:var(--gs-accent-bg);max-width:96px;color:var(--gs-accent);font-size:var(--gs-t-meta);flex:none;padding:0 5px;line-height:15px;overflow:hidden}.SD8qLW_commitWhen{color:var(--gs-fg-faint);flex:none}.SD8qLW_commitAuthor{text-overflow:ellipsis;white-space:nowrap;max-width:120px;color:var(--gs-fg-dim);flex:none;overflow:hidden}.SD8qLW_body{z-index:1;flex:1;min-height:0;display:flex}.SD8qLW_body[data-stacked]{flex-direction:column}.SD8qLW_bodyRow{flex:1 1 0;min-width:0;min-height:0;display:flex}.SD8qLW_body[data-stacked] .SD8qLW_commitsPane{width:auto;min-width:0;max-width:none;height:34%;min-height:var(--gs-min-commits-tall);max-height:max(var(--gs-min-commits-tall), calc(100% - var(--gs-min-stacked-lower)));flex:none}.SD8qLW_treeCol{box-sizing:border-box;width:28%;min-height:0;min-width:var(--gs-min-tree);background:var(--gs-surface);flex-direction:column;flex:0 auto;max-width:400px;display:flex}.SD8qLW_treeWrap{box-sizing:border-box;flex-direction:column;flex:1;min-width:0;min-height:0;display:flex}.SD8qLW_treeTools{box-sizing:border-box;min-height:37px;padding:6px var(--gs-gutter-pane);border-bottom:1px solid var(--gs-border-soft);flex-wrap:wrap;flex:none;justify-content:space-between;align-items:center;gap:6px;display:flex}.SD8qLW_treeActions{flex-wrap:wrap;align-items:center;gap:6px;display:flex}.SD8qLW_treeLead{align-items:center;gap:4px;min-width:0;display:flex}.SD8qLW_treeLabel{white-space:nowrap;color:var(--gs-fg-dim);font-size:var(--gs-t-dense);flex:none}.SD8qLW_treeFilter{padding:6px var(--gs-gutter-pane);border-bottom:1px solid var(--gs-border-soft);flex:none;align-items:center;display:flex;position:relative}.SD8qLW_treeFilterInput{min-width:0;height:var(--gs-h-compact);box-sizing:border-box;border:1px solid var(--gs-border-soft);border-radius:var(--gs-r-control);background:var(--gs-bg);color:var(--gs-fg);font-family:inherit;font-size:var(--gs-t-dense);outline:none;flex:auto;padding:0 24px 0 8px}.SD8qLW_treeFilterInput:focus{border-color:var(--gs-accent)}.SD8qLW_treeFilterInput::placeholder{color:var(--gs-fg-faint)}.SD8qLW_treeFilterClear{right:calc(var(--gs-gutter-pane) + 6px);border-radius:var(--gs-r-pill);width:16px;height:16px;color:var(--gs-fg-faint);font-size:var(--gs-t-ui);cursor:pointer;background:0 0;border:0;justify-content:center;align-items:center;padding:0;line-height:1;display:flex;position:absolute}.SD8qLW_treeFilterClear:hover{color:var(--gs-fg)}.SD8qLW_tree{flex:1;min-height:0;margin:0;padding:6px 0 16px;list-style:none;overflow:auto}.SD8qLW_treeEmpty{min-height:0;color:var(--gs-fg-faint);font-size:var(--gs-t-ui);flex:1;justify-content:center;align-items:center;display:flex}.SD8qLW_treeSub{margin:0;padding:0;list-style:none;position:relative}.SD8qLW_treeSub:before{content:\"\";top:0;bottom:0;left:var(--gs-rail,0);background:var(--gs-border-soft);width:1px;position:absolute}.SD8qLW_treeDirLi{position:relative}.SD8qLW_treeDir{box-sizing:border-box;border-radius:var(--gs-r-control);width:100%;color:var(--gs-fg-dim);font-family:inherit;font-size:var(--gs-t-dense);text-align:left;cursor:pointer;background:0 0;border:0;align-items:center;gap:6px;padding:4px 12px 4px 8px;font-weight:600;display:flex}.SD8qLW_treeDir:hover{background:var(--gs-raise);color:var(--gs-fg-muted)}.SD8qLW_treeDirActive{color:var(--gs-fg-muted)}.SD8qLW_chevron{width:10px;color:var(--gs-fg-fainter);font-size:var(--gs-t-meta);flex:none;transition:transform .12s;display:inline-block}.SD8qLW_chevronOpen{transform:rotate(90deg)}.SD8qLW_treeDirName{white-space:nowrap;text-overflow:ellipsis;flex:1;min-width:0;overflow:hidden}.SD8qLW_treeDirCount{border-radius:var(--gs-r-pill);background:var(--gs-neutral-bg);color:var(--gs-fg-dim);font-size:var(--gs-t-meta);flex:none;padding:0 6px;font-weight:600;line-height:16px}.SD8qLW_treeDirCounts{font-size:var(--gs-t-meta);font-variant-numeric:tabular-nums;flex:none}.SD8qLW_file{box-sizing:border-box;border-radius:var(--gs-r-control);width:100%;color:var(--gs-fg-muted);font-family:inherit;font-size:var(--gs-t-dense);text-align:left;cursor:pointer;background:0 0;border:0;border-left:2px solid #0000;align-items:center;gap:8px;padding:5px 14px;display:flex}.SD8qLW_file:hover{background:var(--gs-raise)}.SD8qLW_fileStatus{border-radius:var(--gs-r-control);width:18px;height:18px;font-weight:700;font-size:var(--gs-t-meta);flex:none;justify-content:center;align-items:center;line-height:1;display:inline-flex}.SD8qLW_stAdded,.SD8qLW_stUntracked{color:var(--gs-add);background:var(--gs-add-bg)}.SD8qLW_stDeleted{color:var(--gs-del);background:var(--gs-del-bg)}.SD8qLW_stModified{color:var(--gs-warn);background:var(--gs-warn-bg)}.SD8qLW_stRenamed{color:var(--gs-info);background:var(--gs-info-bg)}.SD8qLW_filePath{white-space:nowrap;text-overflow:ellipsis;flex:1;min-width:0;overflow:hidden}.SD8qLW_fileBinary{border-radius:var(--gs-r-control);background:var(--gs-neutral-bg);color:var(--gs-fg-dim);letter-spacing:.06em;flex:none;padding:0 5px;font-size:9px;font-weight:700}.SD8qLW_fileCounts{font-size:var(--gs-t-meta);font-variant-numeric:tabular-nums;flex:none}.SD8qLW_fileCountAdd{color:var(--gs-add)}.SD8qLW_fileCountDel{color:var(--gs-del)}.SD8qLW_diffPane{min-width:var(--gs-min-diff);background:var(--gs-surface);flex-direction:column;flex:1 1 0;display:flex;overflow:auto}.SD8qLW_diffWrap{flex-direction:column;flex:auto;width:100%;min-height:0;display:flex}.SD8qLW_diffScroll{outline:none;flex:1 1 0;min-height:0;overflow:auto}.SD8qLW_diffNav{border-bottom:1px solid var(--gs-border-soft);flex:none;justify-content:flex-end;align-items:center;gap:4px;padding:3px 12px 3px 0;display:flex}.SD8qLW_diffNav .SD8qLW_blockBtn{padding-inline:6px;line-height:0}.SD8qLW_diffPre{width:max-content;min-width:100%;font-family:ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace;font-size:var(--gs-t-dense);font-variant-ligatures:none;font-feature-settings:\"liga\" 0, \"calt\" 0;tab-size:4;flex-direction:column;margin:0;padding:8px 0 16px;font-weight:400;line-height:20px;display:flex}.SD8qLW_renameLine{border-bottom:1px solid var(--gs-border-soft);color:var(--gs-info);font-size:var(--gs-t-dense);flex:none;padding:8px 16px}.SD8qLW_renameLine code{color:var(--gs-fg)}.SD8qLW_line{white-space:nowrap;align-items:stretch;width:max-content;min-width:100%;min-height:20px;line-height:20px;display:flex}.SD8qLW_lnOld,.SD8qLW_lnNew{box-sizing:border-box;text-align:right;width:3.2em;color:var(--gs-fg-fainter);user-select:none;font-variant-numeric:tabular-nums;flex:none;padding:0 8px}.SD8qLW_line:hover .SD8qLW_lnOld,.SD8qLW_line:hover .SD8qLW_lnNew{color:var(--gs-fg-dim)}.SD8qLW_gutter{text-align:center;user-select:none;flex:none;width:1.4em}.SD8qLW_code{white-space:pre;flex:1 0 auto;padding:0 16px 0 10px}.SD8qLW_lineAdd{background:var(--gs-add-line)}.SD8qLW_lineDel{background:var(--gs-del-line)}.SD8qLW_lineAdd .SD8qLW_lnOld,.SD8qLW_lineAdd .SD8qLW_lnNew,.SD8qLW_lineAdd .SD8qLW_gutter{background:var(--gs-add-num,var(--gs-add-line))}.SD8qLW_lineDel .SD8qLW_lnOld,.SD8qLW_lineDel .SD8qLW_lnNew,.SD8qLW_lineDel .SD8qLW_gutter{background:var(--gs-del-num,var(--gs-del-line))}.SD8qLW_lineContext{color:var(--gs-fg-muted)}.SD8qLW_lineHunk{background:var(--gs-hunk)}.SD8qLW_lineHunk .SD8qLW_code{color:var(--gs-fg-dim)}.SD8qLW_lineHunk .SD8qLW_lnOld,.SD8qLW_lineHunk .SD8qLW_lnNew,.SD8qLW_lineHunk .SD8qLW_gutter{background:var(--gs-hunk-num,var(--gs-hunk))}.SD8qLW_signAdd{color:var(--gs-add)}.SD8qLW_signDel{color:var(--gs-del)}.SD8qLW_wordAdd{background:var(--gs-add-word);border-radius:2px}.SD8qLW_wordDel{background:var(--gs-del-word);border-radius:2px}.SD8qLW_crMark{color:var(--gs-fg-faint);user-select:none;font-size:.9em}.SD8qLW_sidePane{flex-direction:column;width:100%;min-width:0;height:100%;display:flex}.SD8qLW_sideScroll{flex:1 1 0;min-height:0;overflow:hidden auto}.SD8qLW_sideCols{align-items:stretch;min-height:100%;display:flex}.SD8qLW_sideCol{flex:none;min-width:0;overflow-x:auto}.SD8qLW_sideColRight{flex:1 1 0}.SD8qLW_sideColGrid{width:max-content;min-width:100%;font-family:ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace;font-size:var(--gs-t-dense);font-variant-ligatures:none;font-feature-settings:\"liga\" 0, \"calt\" 0;tab-size:4;grid-template-columns:3.2em 1fr;align-content:start;padding:8px 0 16px;font-weight:400;line-height:20px;display:grid}.SD8qLW_sideColGridBlame{grid-template-columns:13em 3.2em 1fr}.SD8qLW_blameCell{box-sizing:border-box;border-right:1px solid var(--gs-border-soft);color:var(--gs-fg-faint);font-size:var(--gs-t-meta);white-space:pre;text-overflow:ellipsis;user-select:none;padding:0 8px 0 10px;overflow:hidden}.SD8qLW_sideTabs{z-index:5;border-bottom:1px solid var(--gs-border-soft);background:var(--gs-surface-2);flex-wrap:wrap;flex:none;align-items:flex-start;gap:0 16px;padding:6px 16px 0;display:flex}.SD8qLW_sideTab{font-family:inherit;font-size:var(--gs-t-meta);color:var(--gs-fg-dim);cursor:pointer;background:0 0;border:none;padding:2px 0 5px;font-weight:500;line-height:16px;position:relative}.SD8qLW_sideTab:after{content:\"\";background:0 0;border-radius:2px;height:2px;position:absolute;bottom:1px;left:0;right:0}.SD8qLW_sideTabActive{color:var(--gs-accent)}.SD8qLW_sideTabActive:after{background:var(--gs-accent)}.SD8qLW_sideNotice{border-bottom:1px solid var(--gs-border-soft);color:var(--gs-info);font-size:var(--gs-t-dense);flex:none;padding:8px 16px}.SD8qLW_sideNum{box-sizing:border-box;text-align:right;color:var(--gs-fg-fainter);user-select:none;font-variant-numeric:tabular-nums;padding:0 8px}.SD8qLW_sideNumAdd{background:var(--gs-add-num,var(--gs-add-line))}.SD8qLW_sideNumDel{background:var(--gs-del-num,var(--gs-del-line))}.SD8qLW_sideCode{white-space:pre;min-height:20px;padding:0 16px 0 10px}.SD8qLW_sideSpacer{grid-column:1/-1}.SD8qLW_diffSpacer{flex:none}.SD8qLW_sideCodeSame{color:var(--gs-fg-muted)}.SD8qLW_sideCodeAdd{background:var(--gs-add-line)}.SD8qLW_sideCodeDel{background:var(--gs-del-line)}.SD8qLW_sideCellBlock{position:relative}.SD8qLW_sideNum.SD8qLW_sideBlockHot{box-shadow:inset 1px 0 var(--gs-accent)}.SD8qLW_sideCode.SD8qLW_sideBlockHot{box-shadow:inset -1px 0 var(--gs-accent)}.SD8qLW_sideNum.SD8qLW_sideBlockHot.SD8qLW_sideBlockHotFirst{box-shadow:inset 1px 0 var(--gs-accent), inset 0 1px var(--gs-accent)}.SD8qLW_sideCode.SD8qLW_sideBlockHot.SD8qLW_sideBlockHotFirst{box-shadow:inset -1px 0 var(--gs-accent), inset 0 1px var(--gs-accent)}.SD8qLW_sideNum.SD8qLW_sideBlockHot.SD8qLW_sideBlockHotLast{box-shadow:inset 1px 0 var(--gs-accent), inset 0 -1px var(--gs-accent)}.SD8qLW_sideCode.SD8qLW_sideBlockHot.SD8qLW_sideBlockHotLast{box-shadow:inset -1px 0 var(--gs-accent), inset 0 -1px var(--gs-accent)}.SD8qLW_sideNum.SD8qLW_sideBlockHot.SD8qLW_sideBlockHotFirst.SD8qLW_sideBlockHotLast{box-shadow:inset 1px 0 var(--gs-accent), inset 0 1px var(--gs-accent), inset 0 -1px var(--gs-accent)}.SD8qLW_sideCode.SD8qLW_sideBlockHot.SD8qLW_sideBlockHotFirst.SD8qLW_sideBlockHotLast{box-shadow:inset -1px 0 var(--gs-accent), inset 0 1px var(--gs-accent), inset 0 -1px var(--gs-accent)}.SD8qLW_blockBar{z-index:4;border:1px solid var(--gs-border);border-radius:var(--gs-r-control);background:var(--gs-surface-2,var(--gs-bg));box-shadow:0 4px 14px var(--gs-shadow);white-space:nowrap;gap:4px;padding:2px;display:flex;position:absolute;left:0}.SD8qLW_blockBtn{border:1px solid var(--gs-border);border-radius:var(--gs-r-pill);background:var(--gs-bg);color:var(--gs-fg-dim);font-family:inherit;font-size:var(--gs-t-meta);cursor:pointer;padding:0 8px;line-height:16px}.SD8qLW_blockBtn:hover:not(:disabled){color:var(--gs-fg);border-color:var(--gs-accent)}.SD8qLW_blockBtn:disabled{opacity:.45;cursor:default}.SD8qLW_blockBtnDanger{color:var(--gs-del);border-color:var(--gs-del-bg,var(--gs-border))}.SD8qLW_blockBtnDanger:hover:not(:disabled){color:var(--gs-del);border-color:var(--gs-del)}.SD8qLW_sideArmable{cursor:text}.SD8qLW_cmHost{position:relative}.SD8qLW_cmHost[data-editable]:before{content:\"\";background:var(--gs-accent);opacity:.32;pointer-events:none;z-index:201;border-radius:1px;width:2px;transition:opacity .14s;position:absolute;top:0;bottom:0;left:0}.SD8qLW_cmHost[data-editable]:focus-within:before{opacity:1}.SD8qLW_sideNav{align-items:center;gap:4px;margin-left:auto;padding:2px 0 5px;display:flex}.SD8qLW_sideNav .SD8qLW_blockBtn{padding-inline:6px;line-height:0}.SD8qLW_sideNavCount{color:var(--gs-fg-faint);font-size:var(--gs-t-meta);white-space:nowrap}.SD8qLW_sideCurrentBlockActions{flex-wrap:wrap;align-items:flex-start;gap:4px;margin-left:4px;padding:2px 0 5px;display:flex}.SD8qLW_sideActions{align-items:flex-start;gap:4px;margin-left:auto;padding:2px 0 5px;display:flex}.SD8qLW_sideActionsAdjacent{margin-left:0}.SD8qLW_sideSaveReady{color:var(--gs-accent);border-color:var(--gs-accent)}.SD8qLW_sideBanner{border-bottom:1px solid var(--gs-border-soft);background:var(--gs-del-bg,transparent);color:var(--gs-del);font-size:var(--gs-t-dense);flex-direction:column;flex:none;gap:6px;padding:8px 16px;display:flex}.SD8qLW_sideBannerTitle{font-weight:600}.SD8qLW_sideBannerActs{gap:4px;display:flex}.SD8qLW_sideEditCell{position:relative}.SD8qLW_empty{color:var(--gs-fg-faint);font-size:var(--gs-t-ui);padding:32px 24px}.SD8qLW_syncBar{padding:8px var(--gs-gutter);border-bottom:1px solid var(--gs-border-soft);background:var(--gs-surface-2);font-size:var(--gs-t-dense);color:var(--gs-fg-dim);flex-wrap:wrap;flex:none;align-items:center;gap:8px;display:flex}.SD8qLW_syncUpstream{white-space:nowrap;text-overflow:ellipsis;max-width:260px;color:var(--gs-fg-muted);font-variant-numeric:tabular-nums;overflow:hidden}.SD8qLW_syncLevel{color:var(--gs-fg-faint)}.SD8qLW_syncSpacer{flex:auto}.SD8qLW_btn:disabled,.SD8qLW_treeIcon:disabled,.SD8qLW_miniBtn:disabled,.SD8qLW_refButton:disabled,.SD8qLW_funnelButton:disabled{opacity:.45;cursor:default}.SD8qLW_btn[data-quiet]:disabled,.SD8qLW_refButton[data-quiet]:disabled{opacity:1}.SD8qLW_opBanner{padding:8px var(--gs-gutter);border-bottom:1px solid var(--gs-border-soft);font-size:var(--gs-t-dense);white-space:pre-wrap;overflow-wrap:anywhere;user-select:text;flex:none;line-height:18px}.SD8qLW_opBannerOk{background:var(--gs-add-bg);color:var(--gs-add)}.SD8qLW_opBannerBad{background:var(--gs-del-bg);color:var(--gs-del)}.SD8qLW_fileLi{align-items:stretch;display:flex}.SD8qLW_fileLi .SD8qLW_file{flex:auto;min-width:0}.SD8qLW_fileDiscard{width:22px;color:var(--gs-fg-faint);opacity:0;cursor:pointer;background:0 0;border:0;flex:none;justify-content:center;align-items:center;padding:0;transition:opacity .12s,color .12s;display:flex}.SD8qLW_fileLi:hover .SD8qLW_fileDiscard,.SD8qLW_fileDiscard:focus-visible{opacity:1}.SD8qLW_fileDiscard:hover{color:var(--gs-del)}.SD8qLW_fileDiscard:focus-visible{outline:2px solid var(--gs-accent);outline-offset:-2px;border-radius:var(--gs-r-control)}.SD8qLW_treeRow{align-items:stretch;display:flex}.SD8qLW_treeRow .SD8qLW_treeDir{flex:auto;min-width:0}.SD8qLW_checkBox{cursor:pointer;background:0 0;border:0;flex:none;justify-content:center;align-items:center;width:22px;padding:0;display:flex}.SD8qLW_checkMark{box-sizing:border-box;border:1px solid var(--gs-fg-faint);background:var(--gs-bg);color:#0000;border-radius:3px;justify-content:center;align-items:center;width:14px;height:14px;font-size:10px;font-weight:700;line-height:1;transition:background .12s,border-color .12s;display:flex}.SD8qLW_checkBox:hover .SD8qLW_checkMark{border-color:var(--gs-accent)}.SD8qLW_checkBox:focus-visible{outline:none}.SD8qLW_checkBox:focus-visible .SD8qLW_checkMark{outline:2px solid var(--gs-accent);outline-offset:1px}.SD8qLW_checkMarkOn,.SD8qLW_checkMarkPartial{border-color:var(--gs-accent);background:var(--gs-accent);color:var(--gs-on-accent)}.SD8qLW_commitBox{padding:8px var(--gs-gutter-pane) 10px;border-top:1px solid var(--gs-border);background:var(--gs-surface-2);flex-direction:column;flex:none;gap:6px;display:flex}.SD8qLW_commitMessage{box-sizing:border-box;border:1px solid var(--gs-border);border-radius:var(--gs-r-control);background:var(--gs-bg);width:100%;min-height:46px;max-height:160px;color:var(--gs-fg);font-family:inherit;font-size:var(--gs-t-dense);resize:vertical;outline:none;padding:6px 8px;line-height:18px}.SD8qLW_commitMessage:focus{border-color:var(--gs-accent-border)}.SD8qLW_commitMessage::placeholder{color:var(--gs-fg-faint)}.SD8qLW_commitRow{align-items:center;gap:8px;display:flex}.SD8qLW_commitAmend{color:var(--gs-fg-dim);font-size:var(--gs-t-meta);cursor:pointer;align-items:center;gap:4px;display:inline-flex}.SD8qLW_commitAmend input{accent-color:var(--gs-accent);cursor:pointer}.SD8qLW_commitStaged{color:var(--gs-fg-faint);font-size:var(--gs-t-meta);margin-left:auto}.SD8qLW_commitLead{color:var(--gs-fg-faint);font-size:var(--gs-t-meta);margin:0;line-height:15px}.SD8qLW_commitBtn{box-sizing:border-box;min-width:92px;height:var(--gs-h-control);border-radius:var(--gs-r-control);background:var(--gs-accent);color:var(--gs-on-accent);font-family:inherit;font-size:var(--gs-t-ui);white-space:nowrap;cursor:pointer;border:1px solid #0000;flex:none;justify-content:center;align-items:center;padding:0 16px;font-weight:600;line-height:1;transition:filter .12s,opacity .12s;display:inline-flex}.SD8qLW_commitBtn:hover:not(:disabled){filter:brightness(1.1)}.SD8qLW_commitBtn:focus-visible{outline:2px solid var(--gs-accent);outline-offset:2px}.SD8qLW_commitBtn:disabled{background:var(--gs-raise);color:var(--gs-fg-faint);border-color:var(--gs-border);cursor:default}.SD8qLW_btn,.SD8qLW_miniBtn,.SD8qLW_treeIcon,.SD8qLW_commitCopy,.SD8qLW_scopeBtn,.SD8qLW_refButton,.SD8qLW_funnelButton,.SD8qLW_funnelPreset,.SD8qLW_layoutButton{box-sizing:border-box;height:var(--gs-h-control);padding:var(--gs-pad-control);border:1px solid var(--gs-border);border-radius:var(--gs-r-control);color:var(--gs-fg-dim);font-family:inherit;font-size:var(--gs-t-ui);white-space:nowrap;cursor:pointer;background:0 0;flex:none;justify-content:center;align-items:center;gap:6px;line-height:1;transition:background .12s,color .12s,border-color .12s;display:inline-flex}.SD8qLW_btn:hover,.SD8qLW_miniBtn:hover,.SD8qLW_treeIcon:hover,.SD8qLW_commitCopy:hover,.SD8qLW_scopeBtn:hover,.SD8qLW_refButton:hover,.SD8qLW_funnelButton:hover,.SD8qLW_funnelPreset:hover,.SD8qLW_layoutButton:hover{background:var(--gs-raise);color:var(--gs-fg);border-color:var(--gs-fg-fainter)}.SD8qLW_btn:focus-visible,.SD8qLW_miniBtn:focus-visible,.SD8qLW_treeIcon:focus-visible,.SD8qLW_commitCopy:focus-visible,.SD8qLW_scopeBtn:focus-visible,.SD8qLW_refButton:focus-visible,.SD8qLW_funnelPreset:focus-visible,.SD8qLW_layoutButton:focus-visible{outline:2px solid var(--gs-accent);outline-offset:1px}.SD8qLW_btn,.SD8qLW_refButton{border-radius:var(--gs-r-pill)}.SD8qLW_treeIcon,.SD8qLW_commitCopy,.SD8qLW_funnelPreset,.SD8qLW_layoutButton{height:var(--gs-h-compact);padding:var(--gs-pad-compact);font-size:var(--gs-t-dense)}.SD8qLW_treeIcon{width:var(--gs-h-compact);padding:0}.SD8qLW_layoutSwitch{flex:none;gap:2px;margin-left:auto;display:inline-flex}.SD8qLW_layoutButton{width:var(--gs-h-compact);padding:0}.SD8qLW_layoutButton.SD8qLW_layoutButtonOn{color:var(--gs-accent);border-color:var(--gs-accent)}.SD8qLW_layoutGlyph{display:block}.SD8qLW_treeIcon.SD8qLW_treeIconOn{color:var(--gs-accent);border-color:var(--gs-accent)}.SD8qLW_treeIconGlyph{font-size:var(--gs-t-meta);line-height:1;display:block}.SD8qLW_treeIconDown{transform:rotate(90deg)}.SD8qLW_scopeBtn{flex:1 1 0}.SD8qLW_scopeBtnActive,.SD8qLW_miniBtnPrimary,.SD8qLW_segmentActive,.SD8qLW_refRowActive,.SD8qLW_paletteRowActive,.SD8qLW_fileActive,.SD8qLW_commitActive,.SD8qLW_funnelTabActive,.SD8qLW_funnelBoundBtnActive,.SD8qLW_funnelPresetActive,.SD8qLW_fbRow.SD8qLW_fbRowActive{border-color:var(--gs-accent-border);background:var(--gs-accent-bg);color:var(--gs-accent);font-weight:600}.SD8qLW_btnIcon{width:var(--gs-h-control);padding:0}.SD8qLW_btnIcon svg{display:block}.SD8qLW_btnClose:hover:not(:disabled){border-color:var(--gs-del);background:var(--gs-del-bg);color:var(--gs-del)}.SD8qLW_btnBehind{border-color:var(--gs-warn);background:var(--gs-warn-bg);color:var(--gs-warn);font-weight:600}.SD8qLW_btnBehind:hover:not(:disabled){background:var(--gs-warn-bg);color:var(--gs-warn);border-color:var(--gs-warn)}.SD8qLW_btnAhead{border-color:var(--gs-add);background:var(--gs-add-bg);color:var(--gs-add);font-weight:600}.SD8qLW_btnAhead:hover:not(:disabled){background:var(--gs-add-bg);color:var(--gs-add);border-color:var(--gs-add)}.SD8qLW_btnPrimary{border-color:var(--gs-accent);background:var(--gs-accent);color:var(--gs-on-accent);font-weight:600}.SD8qLW_btnPrimary:hover:not(:disabled){background:var(--gs-accent);color:var(--gs-on-accent);border-color:var(--gs-accent)}.SD8qLW_btnCount{font-variant-numeric:tabular-nums;opacity:.85;border-left:1px solid;margin-left:1px;padding-left:6px}.SD8qLW_pullGroup{flex:none;align-items:center;display:inline-flex}.SD8qLW_pullGroup>.SD8qLW_refPicker>.SD8qLW_refButton{border-right-color:#0000;border-top-right-radius:0;border-bottom-right-radius:0}.SD8qLW_pullGroup>.SD8qLW_btn{border-top-left-radius:0;border-bottom-left-radius:0;margin-left:-1px}.SD8qLW_drawer{scrollbar-width:thin;scrollbar-color:var(--gs-border) transparent}.SD8qLW_drawer ::-webkit-scrollbar{width:10px;height:10px}.SD8qLW_drawer ::-webkit-scrollbar-track,.SD8qLW_drawer ::-webkit-scrollbar-corner{background:0 0}.SD8qLW_drawer ::-webkit-scrollbar-thumb{background:var(--gs-border);border-radius:var(--gs-r-pill);background-clip:padding-box;border:3px solid #0000}.SD8qLW_drawer ::-webkit-scrollbar-thumb:hover{background:var(--gs-fg-faint);background-clip:padding-box}.SD8qLW_commitRefMore{border-radius:var(--gs-r-pill);background:var(--gs-neutral-bg);color:var(--gs-fg-dim);font-size:var(--gs-t-meta);cursor:default;flex:none;padding:0 5px;line-height:15px}.SD8qLW_confirmScrim{background:var(--gs-backdrop);justify-content:center;align-items:center;padding:24px;animation:.12s ease-out SD8qLW_gsFade;display:flex}.SD8qLW_confirmBox{box-sizing:border-box;border:1px solid var(--gs-border);border-radius:var(--gs-r-drawer);background:var(--gs-bg);width:min(440px,100%);box-shadow:0 18px 48px var(--gs-shadow);flex-direction:column;gap:10px;padding:18px;display:flex}.SD8qLW_confirmTitle{color:var(--gs-fg);font-size:var(--gs-t-ui);font-weight:600}.SD8qLW_confirmBody{color:var(--gs-fg-dim);font-size:var(--gs-t-dense);overflow-wrap:anywhere;line-height:1.55}.SD8qLW_confirmActions{flex-direction:row-reverse;gap:8px;margin-top:2px;display:flex}.SD8qLW_btn.SD8qLW_btnDanger{border-color:var(--gs-del);background:var(--gs-del);color:var(--gs-on-accent);font-weight:600}.SD8qLW_btn.SD8qLW_btnDanger:hover:not(:disabled){border-color:var(--gs-del);background:var(--gs-del);color:var(--gs-on-accent)}.SD8qLW_fbTree{min-width:var(--gs-min-tree);background:var(--gs-surface-2);flex-direction:column;flex:none;gap:4px;padding:6px;display:flex;overflow:auto}.SD8qLW_fbSearch{box-sizing:border-box;width:100%;font:inherit;font-size:var(--gs-t-meta);color:var(--gs-fg);background:var(--gs-surface);border:1px solid var(--gs-border);border-radius:var(--gs-r-control);flex:none;padding:4px 6px}.SD8qLW_fbSearch:focus{border-color:var(--gs-accent);outline:none}.SD8qLW_fbNote{font-size:var(--gs-t-meta);color:var(--gs-fg-dim);flex:none;padding:2px 4px}.SD8qLW_fbList{margin:0;padding:0;list-style:none}.SD8qLW_fbRow{width:100%;font:inherit;font-size:var(--gs-t-dense);color:var(--gs-fg-dim);text-align:left;border-radius:var(--gs-r-control);cursor:pointer;white-space:nowrap;text-overflow:ellipsis;background:0 0;border:0;align-items:center;gap:4px;padding:2px 6px 2px 4px;display:flex;overflow:hidden}.SD8qLW_fbRow:hover{background:var(--gs-raise)}.SD8qLW_fbDirName,.SD8qLW_fbFileName{text-overflow:ellipsis;overflow:hidden}.SD8qLW_fbMain{min-width:var(--gs-min-diff);background:var(--gs-surface);flex-direction:column;flex:1 1 0;min-height:0;display:flex}.SD8qLW_fbHeader{border-bottom:1px solid var(--gs-border);flex:none;align-items:flex-start;gap:8px;padding:4px 8px 0;display:flex}.SD8qLW_fbPath{font-size:var(--gs-t-meta);color:var(--gs-fg-dim);text-overflow:ellipsis;white-space:nowrap;padding:4px 0;overflow:hidden}.SD8qLW_fbBody{flex:1 1 0;min-height:0;padding:4px 8px;overflow:auto}.SD8qLW_fbCommit{font-size:var(--gs-t-meta);color:var(--gs-fg-dim);background:var(--gs-surface-2);border-bottom:1px solid var(--gs-border);flex:none;align-items:baseline;gap:8px;padding:4px 8px;display:flex}.SD8qLW_fbCommitLine{color:var(--gs-fg-faint);font-variant-numeric:tabular-nums;flex:none}.SD8qLW_fbCommitWho{color:var(--gs-fg);flex:none;font-weight:600}.SD8qLW_fbCommitWhen{font-variant-numeric:tabular-nums;flex:none}.SD8qLW_fbCommitHash{color:var(--gs-fg-faint);flex:none;font-family:inherit}.SD8qLW_fbCommitWhat{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--gs-fg);flex:auto;overflow:hidden}.SD8qLW_fbCommitHint{color:var(--gs-fg-faint)}.SD8qLW_fbMore{font-size:var(--gs-t-meta);color:var(--gs-fg-faint);padding:2px 6px 4px 4px;font-style:italic;display:block}.SD8qLW_imgPane{flex-direction:column;gap:8px;height:100%;min-height:0;display:flex}.SD8qLW_imgStage{border-radius:var(--gs-r-control);background-color:var(--gs-surface-2);background-image:linear-gradient(45deg, var(--gs-border-soft) 25%, transparent 25%, transparent 75%, var(--gs-border-soft) 75%), linear-gradient(45deg, var(--gs-border-soft) 25%, transparent 25%, transparent 75%, var(--gs-border-soft) 75%);background-position:0 0,8px 8px;background-size:16px 16px;flex:auto;justify-content:center;align-items:center;min-height:0;padding:12px;display:flex;overflow:auto}.SD8qLW_imgShot{object-fit:contain;image-rendering:auto;max-width:100%;max-height:100%}.SD8qLW_imgStage[data-actual]{justify-content:flex-start;align-items:flex-start}.SD8qLW_imgStage[data-actual] .SD8qLW_imgShot{object-fit:none;max-width:none;max-height:none}.SD8qLW_imgCaption{font-size:var(--gs-t-meta);color:var(--gs-fg-dim);font-variant-numeric:tabular-nums;flex:none;align-items:center;gap:8px;display:flex}";
|
|
462
|
+
const css = ".SD8qLW_card{border:1px solid var(--dsw-alias-border-l2);min-height:28px;color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;cursor:pointer;background:0 0;border-radius:8px;align-items:center;gap:7px;padding:3px 10px;font-size:12px;line-height:18px;transition:background .12s,border-color .12s;display:inline-flex}.SD8qLW_card:hover,.SD8qLW_card:focus-visible{background:var(--dsw-alias-interactive-bg-hover);border-color:var(--dsw-alias-border-l3)}.SD8qLW_cardBranch{max-width:220px;color:var(--dsw-alias-label-primary);align-items:center;gap:4px;font-weight:550;display:inline-flex;overflow:hidden}.SD8qLW_cardBranchName{min-width:0;overflow:hidden}.SD8qLW_cardGlyph{opacity:.7;flex:none}.SD8qLW_cardDetached{background:var(--dsw-alias-state-warning-bg,#bb800926);color:var(--dsw-alias-state-warning-primary,#d29922);letter-spacing:.02em;border-radius:999px;padding:0 6px;font-size:10px;line-height:16px}.SD8qLW_cardWt{background:var(--dsw-alias-state-business-bg,#388bfd29);max-width:150px;color:var(--dsw-alias-state-business-primary,#58a6ff);letter-spacing:.02em;white-space:nowrap;text-overflow:ellipsis;border-radius:999px;align-items:center;gap:3px;padding:0 6px;font-size:10px;line-height:16px;display:inline-flex;overflow:hidden}.SD8qLW_cardAhead,.SD8qLW_cardBehind{color:var(--dsw-alias-label-tertiary);font-size:11px}.SD8qLW_cardAhead{color:var(--dsw-alias-state-success-primary)}.SD8qLW_cardBehind{color:var(--dsw-alias-state-attention-primary,#d29922)}.SD8qLW_cardSep{background:var(--dsw-alias-border-l2);width:1px;height:14px}.SD8qLW_cardAdded{color:var(--dsw-alias-state-success-primary)}.SD8qLW_cardDeleted{color:var(--dsw-alias-state-error-primary)}.SD8qLW_cardFiles{color:var(--dsw-alias-label-tertiary)}.SD8qLW_overlay[data-gs-theme=github-dark]{--gs-bg:#0d1117;--gs-panel:#161b22;--gs-raise:#21262d;--gs-border:#30363d;--gs-border-soft:#21262d;--gs-fg:#e6edf3;--gs-fg-muted:#c9d1d9;--gs-fg-dim:#8b949e;--gs-fg-faint:#6e7681;--gs-fg-fainter:#484f58;--gs-accent:#58a6ff;--gs-accent-bg:#388bfd24;--gs-accent-border:#388bfd8c;--gs-add:#3fb950;--gs-del:#f85149;--gs-warn:#d29922;--gs-info:#79c0ff;--gs-add-bg:#2ea04329;--gs-del-bg:#f8514929;--gs-warn-bg:#bb800929;--gs-info-bg:#388bfd29;--gs-add-line:#12261e;--gs-del-line:#25181c;--gs-add-word:#1a4a29;--gs-del-word:#6b2b2b;--gs-add-num:#1c4428;--gs-del-num:#542426;--gs-hunk:#111d2e;--gs-hunk-num:#0c2d6b;--gs-neutral-bg:#6e76812e;--gs-backdrop:#01040999;--gs-shadow:#0104098c}.SD8qLW_overlay[data-gs-theme=github-light]{--gs-bg:#fff;--gs-panel:#f6f8fa;--gs-raise:#eaeef2;--gs-border:#d0d7de;--gs-border-soft:#eaeef2;--gs-fg:#1f2328;--gs-fg-muted:#32383f;--gs-fg-dim:#656d76;--gs-fg-faint:#8c959f;--gs-fg-fainter:#afb8c1;--gs-accent:#0969da;--gs-accent-bg:#0969da1a;--gs-accent-border:#0969da73;--gs-add:#1a7f37;--gs-del:#cf222e;--gs-warn:#9a6700;--gs-info:#0550ae;--gs-add-bg:#1a7f371f;--gs-del-bg:#cf222e1f;--gs-warn-bg:#9a67001f;--gs-info-bg:#0969da1f;--gs-add-line:#dafbe1;--gs-del-line:#ffebe9;--gs-add-word:#aceebb;--gs-del-word:#ffcecb;--gs-add-num:#aceebb;--gs-del-num:#ffcecb;--gs-hunk:#ddf4ff;--gs-hunk-num:#b6e3ff;--gs-neutral-bg:#6e76811f;--gs-backdrop:#1f232847;--gs-shadow:#1f232838}.SD8qLW_overlay[data-gs-theme=idea-dark]{--gs-bg:#1e1f22;--gs-panel:#2b2d30;--gs-raise:#393b40;--gs-border:#393b40;--gs-border-soft:#2b2d30;--gs-fg:#dfe1e5;--gs-fg-muted:#ced0d6;--gs-fg-dim:#9da0a8;--gs-fg-faint:#6f737a;--gs-fg-fainter:#4e5157;--gs-accent:#548af7;--gs-accent-bg:#548af729;--gs-accent-border:#548af78c;--gs-add:#5fad65;--gs-del:#e26e6e;--gs-warn:#f0a732;--gs-info:#3592c4;--gs-add-bg:#5fad6529;--gs-del-bg:#e26e6e29;--gs-warn-bg:#f0a73229;--gs-info-bg:#3592c429;--gs-add-line:#293c2e;--gs-del-line:#3d2b2b;--gs-add-word:#3d6640;--gs-del-word:#6b3838;--gs-hunk:#548af71a;--gs-neutral-bg:#9da0a82e;--gs-backdrop:#10111399;--gs-shadow:#00000080}.SD8qLW_overlay[data-gs-theme=idea-light]{--gs-bg:#fff;--gs-panel:#f7f8fa;--gs-raise:#ebecf0;--gs-border:#d3d5db;--gs-border-soft:#ebecf0;--gs-fg:#1e1f22;--gs-fg-muted:#3c3f44;--gs-fg-dim:#6c707e;--gs-fg-faint:#818594;--gs-fg-fainter:#a8adbd;--gs-accent:#3574f0;--gs-accent-bg:#3574f01a;--gs-accent-border:#3574f073;--gs-add:#398a4a;--gs-del:#cc4a4a;--gs-warn:#a8760b;--gs-info:#2b7fb8;--gs-add-bg:#398a4a1f;--gs-del-bg:#cc4a4a1f;--gs-warn-bg:#a8760b1f;--gs-info-bg:#2b7fb81f;--gs-add-line:#e6f5e9;--gs-del-line:#fbe9ea;--gs-add-word:#c2e5c9;--gs-del-word:#f5c9cc;--gs-hunk:#3574f012;--gs-neutral-bg:#6c707e1f;--gs-backdrop:#1e1f2242;--gs-shadow:#1e1f222e}.SD8qLW_overlay[data-gs-theme=vscode-dark]{--gs-bg:#1e1e1e;--gs-panel:#252526;--gs-raise:#2d2d30;--gs-border:#3e3e42;--gs-border-soft:#2d2d30;--gs-fg:#d4d4d4;--gs-fg-muted:#ccc;--gs-fg-dim:#9d9d9d;--gs-fg-faint:gray;--gs-fg-fainter:#5a5a5a;--gs-accent:#0098ff;--gs-accent-bg:#007acc3d;--gs-accent-border:#0098ff99;--gs-add:#89d185;--gs-del:#f14c4c;--gs-warn:#cca700;--gs-info:#75beff;--gs-add-bg:#89d1852e;--gs-del-bg:#f14c4c2e;--gs-warn-bg:#cca7002e;--gs-info-bg:#75beff2e;--gs-add-line:#9bb9552e;--gs-del-line:#ff000029;--gs-add-word:#9bb95566;--gs-del-word:#ff00005c;--gs-hunk:#007acc24;--gs-neutral-bg:#bebebe24;--gs-backdrop:#0000008c;--gs-shadow:#0009}.SD8qLW_overlay[data-gs-theme=vscode-light]{--gs-bg:#fff;--gs-panel:#f3f3f3;--gs-raise:#e8e8e8;--gs-border:#cecece;--gs-border-soft:#e8e8e8;--gs-fg:#1e1e1e;--gs-fg-muted:#333;--gs-fg-dim:#616161;--gs-fg-faint:#767676;--gs-fg-fainter:#a0a0a0;--gs-accent:#005fb8;--gs-accent-bg:#005fb81a;--gs-accent-border:#005fb873;--gs-add:#10793f;--gs-del:#b5200d;--gs-warn:#855b00;--gs-info:#005fb8;--gs-add-bg:#10793f1f;--gs-del-bg:#b5200d1f;--gs-warn-bg:#855b001f;--gs-info-bg:#005fb81f;--gs-add-line:#9bb95538;--gs-del-line:#ff000021;--gs-add-word:#9bb95573;--gs-del-word:#ff00004d;--gs-hunk:#005fb812;--gs-neutral-bg:#6161611f;--gs-backdrop:#00000040;--gs-shadow:#0000002e}.SD8qLW_overlay[data-gs-theme=cyberpunk-dark]{--gs-bg:#0b0417;--gs-panel:#14082a;--gs-raise:#1f0d3d;--gs-border:#3a1f6b;--gs-border-soft:#26124a;--gs-fg:#f0e6ff;--gs-fg-muted:#d5c2f5;--gs-fg-dim:#a98fd6;--gs-fg-faint:#7d64a8;--gs-fg-fainter:#56427a;--gs-accent:#00f0ff;--gs-on-accent:#0b0417;--gs-accent-bg:#00f0ff24;--gs-accent-border:#00f0ff80;--gs-add:#39ff88;--gs-del:#ff2e88;--gs-warn:#fc0;--gs-info:#00f0ff;--gs-add-bg:#39ff8824;--gs-del-bg:#ff2e8824;--gs-warn-bg:#ffcc0024;--gs-info-bg:#00f0ff24;--gs-add-line:#39ff881f;--gs-del-line:#ff2e881f;--gs-add-word:#39ff8857;--gs-del-word:#ff2e8857;--gs-hunk:#00f0ff1a;--gs-neutral-bg:#a98fd629;--gs-backdrop:#06020ead;--gs-shadow:#00f0ff24}.SD8qLW_overlay[data-gs-theme=cyberpunk-light]{--gs-bg:#fdfbff;--gs-panel:#f4eeff;--gs-raise:#e9dfff;--gs-border:#c9b3f0;--gs-border-soft:#e0d2f7;--gs-fg:#1a0b2e;--gs-fg-muted:#33195c;--gs-fg-dim:#6b4ba0;--gs-fg-faint:#8f74bd;--gs-fg-fainter:#b9a5d6;--gs-accent:#00a6b8;--gs-accent-bg:#00a6b81f;--gs-accent-border:#00a6b880;--gs-add:#00875a;--gs-del:#d6006e;--gs-warn:#b37a00;--gs-info:#00a6b8;--gs-add-bg:#00875a1f;--gs-del-bg:#d6006e1f;--gs-warn-bg:#b37a001f;--gs-info-bg:#00a6b81f;--gs-add-line:#00c88224;--gs-del-line:#ff2e881f;--gs-add-word:#00c88257;--gs-del-word:#ff2e884d;--gs-hunk:#00a6b814;--gs-neutral-bg:#6b4ba01f;--gs-backdrop:#1a0b2e47;--gs-shadow:#1a0b2e29}.SD8qLW_overlay[data-gs-theme=one-dark]{--gs-bg:#282c34;--gs-panel:#21252b;--gs-raise:#2c313a;--gs-border:#3e4451;--gs-border-soft:#2c313a;--gs-fg:#abb2bf;--gs-fg-muted:#b6bdca;--gs-fg-dim:#7f848e;--gs-fg-faint:#636d83;--gs-fg-fainter:#4b5263;--gs-accent:#61afef;--gs-accent-bg:#61afef24;--gs-accent-border:#61afef8c;--gs-add:#98c379;--gs-del:#e06c75;--gs-warn:#e5c07b;--gs-info:#56b6c2;--gs-add-bg:#98c37929;--gs-del-bg:#e06c7529;--gs-warn-bg:#e5c07b29;--gs-info-bg:#56b6c229;--gs-add-line:#98c37924;--gs-del-line:#e06c7524;--gs-add-word:#98c37961;--gs-del-word:#e06c7561;--gs-hunk:#61afef1a;--gs-neutral-bg:#7f848e2e;--gs-backdrop:#171a2199;--gs-shadow:#0f11158c}.SD8qLW_overlay[data-gs-theme=one-light]{--gs-bg:#fafafa;--gs-panel:#f0f0f0;--gs-raise:#e5e5e6;--gs-border:#d4d4d4;--gs-border-soft:#e5e5e6;--gs-fg:#383a42;--gs-fg-muted:#4a4c53;--gs-fg-dim:#696c77;--gs-fg-faint:#909196;--gs-fg-fainter:#b8b9bd;--gs-accent:#4078f2;--gs-accent-bg:#4078f21a;--gs-accent-border:#4078f273;--gs-add:#50a14f;--gs-del:#e45649;--gs-warn:#c18401;--gs-info:#0184bc;--gs-add-bg:#50a14f1f;--gs-del-bg:#e456491f;--gs-warn-bg:#c184011f;--gs-info-bg:#0184bc1f;--gs-add-line:#50a14f24;--gs-del-line:#e4564921;--gs-add-word:#50a14f57;--gs-del-word:#e4564952;--gs-hunk:#4078f212;--gs-neutral-bg:#696c771f;--gs-backdrop:#383a4242;--gs-shadow:#383a422e}.SD8qLW_overlay[data-gs-theme=solarized-dark]{--gs-bg:#002b36;--gs-panel:#073642;--gs-raise:#0a4553;--gs-border:#0f5666;--gs-border-soft:#073642;--gs-fg:#93a1a1;--gs-fg-muted:#839496;--gs-fg-dim:#657b83;--gs-fg-faint:#586e75;--gs-fg-fainter:#45636b;--gs-accent:#268bd2;--gs-accent-bg:#268bd229;--gs-accent-border:#268bd28c;--gs-add:#859900;--gs-del:#dc322f;--gs-warn:#b58900;--gs-info:#2aa198;--gs-add-bg:#85990033;--gs-del-bg:#dc322f2e;--gs-warn-bg:#b589002e;--gs-info-bg:#2aa1982e;--gs-add-line:#85990029;--gs-del-line:#dc322f26;--gs-add-word:#85990066;--gs-del-word:#dc322f61;--gs-hunk:#268bd21f;--gs-neutral-bg:#657b8333;--gs-backdrop:#00141a9e;--gs-shadow:#00141a8c}.SD8qLW_overlay[data-gs-theme=solarized-light]{--gs-bg:#fdf6e3;--gs-panel:#eee8d5;--gs-raise:#e3ddca;--gs-border:#d5cfbb;--gs-border-soft:#eee8d5;--gs-fg:#586e75;--gs-fg-muted:#657b83;--gs-fg-dim:#839496;--gs-fg-faint:#93a1a1;--gs-fg-fainter:#b5b0a0;--gs-accent:#268bd2;--gs-accent-bg:#268bd21f;--gs-accent-border:#268bd273;--gs-add:#6c7c00;--gs-del:#cb2825;--gs-warn:#9a7400;--gs-info:#21867f;--gs-add-bg:#8599002e;--gs-del-bg:#dc322f24;--gs-warn-bg:#b5890029;--gs-info-bg:#2aa19824;--gs-add-line:#85990029;--gs-del-line:#dc322f1f;--gs-add-word:#85990061;--gs-del-word:#dc322f4d;--gs-hunk:#268bd214;--gs-neutral-bg:#586e7524;--gs-backdrop:#586e7542;--gs-shadow:#586e7533}.SD8qLW_overlay[data-gs-theme=nord-dark]{--gs-bg:#2e3440;--gs-panel:#3b4252;--gs-raise:#434c5e;--gs-border:#4c566a;--gs-border-soft:#3b4252;--gs-fg:#eceff4;--gs-fg-muted:#d8dee9;--gs-fg-dim:#9aa5b8;--gs-fg-faint:#7b88a1;--gs-fg-fainter:#5d6a82;--gs-accent:#88c0d0;--gs-on-accent:#2e3440;--gs-accent-bg:#88c0d024;--gs-accent-border:#88c0d08c;--gs-add:#a3be8c;--gs-del:#bf616a;--gs-warn:#ebcb8b;--gs-info:#81a1c1;--gs-add-bg:#a3be8c29;--gs-del-bg:#bf616a2e;--gs-warn-bg:#ebcb8b29;--gs-info-bg:#81a1c129;--gs-add-line:#a3be8c24;--gs-del-line:#bf616a26;--gs-add-word:#a3be8c61;--gs-del-word:#bf616a66;--gs-hunk:#88c0d01a;--gs-neutral-bg:#9aa5b829;--gs-backdrop:#1d232d9e;--gs-shadow:#1419218c}.SD8qLW_overlay[data-gs-theme=nord-light]{--gs-bg:#eceff4;--gs-panel:#e5e9f0;--gs-raise:#d8dee9;--gs-border:#c3cbd8;--gs-border-soft:#dfe4ec;--gs-fg:#2e3440;--gs-fg-muted:#3b4252;--gs-fg-dim:#4c566a;--gs-fg-faint:#6b7689;--gs-fg-fainter:#9aa4b5;--gs-accent:#5e81ac;--gs-accent-bg:#5e81ac1f;--gs-accent-border:#5e81ac80;--gs-add:#5e7d47;--gs-del:#a5424c;--gs-warn:#97701f;--gs-info:#4c7a8c;--gs-add-bg:#5e7d4724;--gs-del-bg:#a5424c21;--gs-warn-bg:#97701f24;--gs-info-bg:#4c7a8c21;--gs-add-line:#5e7d4724;--gs-del-line:#a5424c1f;--gs-add-word:#5e7d4757;--gs-del-word:#a5424c52;--gs-hunk:#5e81ac17;--gs-neutral-bg:#4c566a21;--gs-backdrop:#2e344042;--gs-shadow:#2e34402e}.SD8qLW_overlay{--gs-inset:14px;--gs-h-control:28px;--gs-h-compact:24px;--gs-pad-control:0 12px;--gs-pad-compact:0 10px;--gs-on-accent:#fff;--gs-graph-0:#58a6ff;--gs-graph-1:#3fb950;--gs-graph-2:#d29922;--gs-graph-3:#bc8cff;--gs-graph-4:#f778ba;--gs-graph-5:#39c5cf;--gs-r-pill:999px;--gs-r-control:8px;--gs-r-surface:12px;--gs-r-drawer:14px;--gs-t-meta:11px;--gs-t-dense:12px;--gs-t-ui:13px;--gs-gutter:16px;--gs-gutter-pane:12px;z-index:1000;padding:var(--gs-inset);box-sizing:border-box;background:var(--gs-backdrop);justify-content:flex-end;align-items:stretch;gap:12px;animation:.16s ease-out SD8qLW_gsFade;display:flex;position:fixed;inset:0}.SD8qLW_drawer{box-sizing:border-box;width:min(1600px,94vw);height:100%;color:var(--gs-fg);background:var(--gs-bg);border:1px solid var(--gs-border);border-radius:var(--gs-r-drawer);box-shadow:0 24px 64px var(--gs-shadow);font-family:var(--dsw-font-ui,-apple-system, BlinkMacSystemFont, \"Segoe UI\", Helvetica, Arial, sans-serif);--gs-surface:var(--gs-bg);--gs-surface-2:var(--gs-panel);flex-direction:column;animation:.18s cubic-bezier(.22,1,.36,1) SD8qLW_gsSlide;display:flex;position:relative;overflow:hidden}.SD8qLW_drawer[data-gs-bg]{--gs-surface:color-mix(in srgb, var(--gs-bg) var(--gs-veil), transparent);--gs-surface-2:color-mix(in srgb, var(--gs-panel) var(--gs-veil), transparent)}.SD8qLW_drawer[data-gs-bg]:before{content:\"\";z-index:0;background-image:var(--gs-bg-image);filter:blur(var(--gs-bg-blur));pointer-events:none;background-position:50%;background-size:cover;position:absolute;inset:0;transform:scale(1.12)}.SD8qLW_drawer>:not(.SD8qLW_resizer){z-index:1;position:relative}.SD8qLW_drawer>.SD8qLW_header{z-index:24}.SD8qLW_drawer>.SD8qLW_tabs{z-index:23}.SD8qLW_drawer>.SD8qLW_compareBar{z-index:22}.SD8qLW_drawer>.SD8qLW_syncBar{z-index:20}.SD8qLW_drawer>.SD8qLW_confirmScrim{z-index:40;position:absolute;inset:0}.SD8qLW_overlayMax{gap:0;padding:0}.SD8qLW_overlayMax .SD8qLW_drawer{border-width:0 0 0 1px;border-radius:0;flex:auto;width:auto;min-width:0}@keyframes SD8qLW_gsFade{0%{opacity:0}}@keyframes SD8qLW_gsSlide{0%{opacity:0;transform:translate(24px)}}.SD8qLW_resizer{z-index:30;cursor:col-resize;touch-action:none;justify-content:center;align-items:center;width:10px;display:flex;position:absolute;top:0;bottom:0;left:0}.SD8qLW_resizer:after{content:\"\";background:var(--gs-fg-fainter);opacity:0;border-radius:999px;width:3px;height:32px;transition:opacity .14s,height .14s}.SD8qLW_resizer:hover:after{opacity:.6}.SD8qLW_resizerActive:after{opacity:.9;height:56px}.SD8qLW_paneDivider{z-index:5;cursor:col-resize;touch-action:none;flex:none;justify-content:center;align-items:center;width:7px;display:flex;position:relative}.SD8qLW_paneDivider:before{content:\"\";background:var(--gs-border-soft);width:1px;position:absolute;top:0;bottom:0;left:3px}.SD8qLW_paneDivider:after{content:\"\";background:var(--gs-fg-fainter);opacity:0;border-radius:999px;width:3px;height:28px;transition:opacity .14s,height .14s;position:relative}.SD8qLW_paneDivider:hover:after{opacity:.6}.SD8qLW_paneDividerActive:after{opacity:.9;height:48px}.SD8qLW_paneDividerY{cursor:row-resize;width:auto;height:7px}.SD8qLW_paneDividerY:before{width:auto;height:1px;inset:3px 0 auto}.SD8qLW_paneDividerY:after{width:28px;height:3px;transition:opacity .14s,width .14s}.SD8qLW_paneDividerY.SD8qLW_paneDividerActive:after{width:48px;height:3px}.SD8qLW_header{padding:10px var(--gs-gutter);border-bottom:1px solid var(--gs-border);background:var(--gs-surface-2);font-family:var(--dsw-font-ui,system-ui, sans-serif);font-size:var(--gs-t-ui);flex:none;justify-content:space-between;align-items:center;gap:12px;display:flex}.SD8qLW_headerLeft{flex-wrap:wrap;align-items:center;gap:10px;min-width:0;display:flex}.SD8qLW_headerBranch{border:1px solid var(--gs-accent-border);border-radius:var(--gs-r-pill);background:var(--gs-accent-bg);color:var(--gs-accent);align-items:center;gap:6px;padding:2px 10px;font-weight:600;display:inline-flex}.SD8qLW_refButton.SD8qLW_headerPicker{border-color:var(--gs-accent-border);background:var(--gs-accent-bg);max-width:420px;color:var(--gs-accent);font-weight:600}.SD8qLW_refButton.SD8qLW_headerPicker:hover{background:var(--gs-accent-bg);color:var(--gs-accent);border-color:var(--gs-accent)}.SD8qLW_elide{flex:0 auto;align-items:baseline;min-width:0;display:inline-flex}.SD8qLW_elideHead{white-space:nowrap;text-overflow:ellipsis;flex:0 999 auto;min-width:0;overflow:hidden}.SD8qLW_elideTail{white-space:nowrap;text-overflow:ellipsis;flex:0 auto;min-width:0;overflow:hidden}.SD8qLW_headerPathMain{color:var(--gs-fg-faint);font-size:var(--gs-t-meta)}.SD8qLW_headerPathMain .SD8qLW_elideTail{color:var(--gs-fg-dim)}.SD8qLW_headerViewRef{max-width:160px}.SD8qLW_headerView{border-radius:var(--gs-r-pill);background:var(--gs-neutral-bg);color:var(--gs-fg-muted);font-size:var(--gs-t-meta);font-variant-numeric:tabular-nums;flex:none;padding:1px 8px}.SD8qLW_headerDetached{border-radius:var(--gs-r-pill);background:var(--gs-warn-bg);color:var(--gs-warn);font-size:var(--gs-t-meta);letter-spacing:.02em;padding:1px 8px}.SD8qLW_headerTotals{font-variant-numeric:tabular-nums}.SD8qLW_headerTotalsAdd{color:var(--gs-add);font-weight:600}.SD8qLW_headerTotalsDel{color:var(--gs-del);font-weight:600}.SD8qLW_headerTotalsDim{color:var(--gs-fg-dim);font-size:var(--gs-t-dense)}.SD8qLW_headerRight{flex:none;gap:8px;display:flex;position:relative}.SD8qLW_theme{display:inline-flex;position:relative}.SD8qLW_refPop.SD8qLW_settingsPop{width:320px;max-width:calc(100vw - 32px);max-height:min(560px,100vh - 120px);top:calc(100% + 6px);left:auto;right:0}.SD8qLW_themeRail{min-height:0;font-family:var(--dsw-font-ui,system-ui, sans-serif);flex-direction:column;flex:1;gap:14px;padding:12px 14px 16px;display:flex;overflow-y:auto}.SD8qLW_themeGroup{flex-direction:column;gap:6px;display:flex}.SD8qLW_themeLabel{color:var(--gs-fg-faint);font-size:var(--gs-t-meta);letter-spacing:.04em;text-transform:uppercase;font-weight:600}.SD8qLW_themeRowSplit{justify-content:space-between;align-items:center;gap:8px;display:flex}.SD8qLW_segmented{gap:6px;display:flex}.SD8qLW_segment{box-sizing:border-box;border:1px solid var(--gs-border);border-radius:var(--gs-r-control);color:var(--gs-fg-dim);font-family:inherit;font-size:var(--gs-t-meta);cursor:pointer;background:0 0;flex-direction:column;flex:1 1 0;align-items:stretch;gap:4px;padding:4px;transition:background .12s,color .12s,border-color .12s;display:flex}.SD8qLW_segment:hover{background:var(--gs-raise);border-color:var(--gs-fg-fainter);color:var(--gs-fg)}.SD8qLW_segment:focus-visible{outline:2px solid var(--gs-accent);outline-offset:1px}.SD8qLW_segmentChip{border-radius:calc(var(--gs-r-control) - 4px);border:1px solid #80808073;height:20px}.SD8qLW_chipLight{background:#fff}.SD8qLW_chipDark{background:#0b0b0d}.SD8qLW_chipSystem{background:linear-gradient(105deg,#fff 0 50%,#0b0b0d 50% 100%)}.SD8qLW_paletteRow{box-sizing:border-box;border-radius:var(--gs-r-control);width:100%;color:var(--gs-fg-muted);font-family:inherit;font-size:var(--gs-t-dense);text-align:left;cursor:pointer;background:0 0;border:0;align-items:center;gap:8px;padding:5px 8px;display:flex}.SD8qLW_paletteRow:hover{background:var(--gs-raise);color:var(--gs-fg)}.SD8qLW_swatch{border:1px solid var(--gs-border);border-radius:3px;flex:none;width:26px;height:12px;display:inline-flex;overflow:hidden}.SD8qLW_swatch span{flex:1}.SD8qLW_scopeRow{gap:6px;display:flex}.SD8qLW_scopeHint{color:var(--gs-fg-faint);font-size:var(--gs-t-meta);overflow-wrap:anywhere}.SD8qLW_bgPreview{border:1px solid var(--gs-border);border-radius:var(--gs-r-control);background-color:var(--gs-bg);background-position:50%;background-size:cover;height:64px}.SD8qLW_bgEmpty{color:var(--gs-fg-faint);font-size:var(--gs-t-meta);justify-content:center;align-items:center;display:flex}.SD8qLW_sliderRow{font-size:var(--gs-t-meta);color:var(--gs-fg-dim);align-items:center;gap:8px;display:flex}.SD8qLW_sliderRow input{min-width:0;accent-color:var(--gs-accent);flex:1}.SD8qLW_sliderValue{text-align:right;font-variant-numeric:tabular-nums;flex:none;width:38px}.SD8qLW_cssArea{box-sizing:border-box;border:1px solid var(--gs-border);border-radius:var(--gs-r-control);background:var(--gs-bg);width:100%;min-height:96px;max-height:220px;color:var(--gs-fg);font-family:var(--dsw-font-mono,ui-monospace, Consolas, monospace);font-size:var(--gs-t-meta);resize:vertical;outline:none;padding:7px 8px}.SD8qLW_cssArea:focus{border-color:var(--gs-accent-border)}.SD8qLW_themeNote{color:var(--gs-warn);font-size:var(--gs-t-meta)}.SD8qLW_themeDirty{color:var(--gs-accent);font-size:var(--gs-t-meta)}.SD8qLW_wtCurrent{color:var(--gs-add);font-size:8px;line-height:1}.SD8qLW_commitCopy{margin-left:auto}.SD8qLW_commitPop{z-index:40;box-sizing:border-box;border:1px solid var(--gs-border);border-radius:var(--gs-r-surface);background:var(--gs-panel);width:min(380px,100vw - 24px);color:var(--gs-fg);box-shadow:0 16px 40px var(--gs-shadow);font-family:var(--dsw-font-ui,-apple-system, BlinkMacSystemFont, \"Segoe UI\", Helvetica, Arial, sans-serif);font-size:var(--gs-t-dense);flex-direction:column;gap:6px;padding:10px 12px 12px;display:flex;position:fixed;overflow:auto}.SD8qLW_commitPopTop{align-items:center;gap:8px;display:flex}.SD8qLW_commitPopTop .SD8qLW_commitWhen{margin-right:auto}.SD8qLW_commitPopMeta{color:var(--gs-fg-muted);font-size:var(--gs-t-dense);flex-direction:column;gap:2px;line-height:16px;display:flex}.SD8qLW_commitFilter{min-width:120px;height:var(--gs-h-control);box-sizing:border-box;border:1px solid var(--gs-border-soft);border-radius:var(--gs-r-control);background:var(--gs-bg);color:var(--gs-fg);font-family:inherit;font-size:var(--gs-t-dense);outline:none;flex:auto;padding:0 10px}.SD8qLW_commitFilter:focus{border-color:var(--gs-accent)}.SD8qLW_commitFilter::placeholder{color:var(--gs-fg-faint)}.SD8qLW_filterChips{border-bottom:1px solid var(--gs-border-soft);flex-wrap:wrap;flex:none;align-items:center;gap:6px;padding:6px 10px;display:flex}.SD8qLW_filterChip{border:1px solid var(--gs-border-soft);border-radius:var(--gs-r-control);background:var(--gs-surface-2);max-width:220px;font-size:var(--gs-t-dense);align-items:center;gap:2px;line-height:18px;display:inline-flex}.SD8qLW_filterChipLabel{text-overflow:ellipsis;white-space:nowrap;color:var(--gs-fg-muted);padding:2px 4px 2px 8px;overflow:hidden}.SD8qLW_filterChipRemove{border:none;border-left:1px solid var(--gs-border-soft);color:var(--gs-fg-dim);font-family:inherit;font-size:var(--gs-t-dense);cursor:pointer;background:0 0;flex:none;padding:0 6px;line-height:20px}.SD8qLW_filterChipRemove:hover{color:var(--gs-del)}.SD8qLW_filterClear{color:var(--gs-fg-faint);font-family:inherit;font-size:var(--gs-t-dense);cursor:pointer;background:0 0;border:none;padding:2px 4px;line-height:18px}.SD8qLW_filterClear:hover{color:var(--gs-fg)}.SD8qLW_funnel{display:inline-flex;position:relative}.SD8qLW_funnelButton.SD8qLW_funnelButtonActive{color:var(--gs-accent);border-color:var(--gs-accent)}.SD8qLW_funnelPop{z-index:40;box-sizing:border-box;border:1px solid var(--gs-border);border-radius:var(--gs-r-surface);background:var(--gs-panel);width:320px;max-width:calc(100vw - 24px);box-shadow:0 16px 40px var(--gs-shadow);font-size:var(--gs-t-dense);flex-direction:column;display:flex;position:fixed;overflow:hidden}.SD8qLW_funnelTabs{border:1px solid var(--gs-border-soft);border-radius:var(--gs-r-control);background:var(--gs-bg);flex:none;gap:2px;margin:8px 8px 0;padding:2px;display:flex}.SD8qLW_funnelTab{box-sizing:border-box;min-width:0;height:var(--gs-h-compact);border-radius:calc(var(--gs-r-control) - 3px);color:var(--gs-fg-dim);font-family:inherit;font-size:var(--gs-t-dense);white-space:nowrap;cursor:pointer;background:0 0;border:1px solid #0000;flex:1;padding:0 8px;line-height:1;transition:background .12s,color .12s}.SD8qLW_funnelTab:hover{color:var(--gs-fg)}.SD8qLW_funnelTab:focus-visible{outline:2px solid var(--gs-accent);outline-offset:1px}.SD8qLW_funnelTabCount{color:var(--gs-accent);font-variant-numeric:tabular-nums;margin-left:4px}.SD8qLW_funnelPane{flex-direction:column;flex:auto;gap:6px;min-height:0;padding:8px;display:flex}.SD8qLW_funnelCaption{color:var(--gs-fg-faint);font-size:var(--gs-t-meta);letter-spacing:.04em;text-transform:uppercase;flex:none;line-height:14px}.SD8qLW_funnelBounds{border:1px solid var(--gs-border-soft);border-radius:var(--gs-r-control);background:var(--gs-bg);flex:none;gap:2px;padding:2px;display:flex}.SD8qLW_funnelBoundBtn{box-sizing:border-box;min-width:0;height:var(--gs-h-compact);border-radius:calc(var(--gs-r-control) - 3px);color:var(--gs-fg-dim);font-family:inherit;font-size:var(--gs-t-dense);cursor:pointer;background:0 0;border:1px solid #0000;flex:1;padding:0 6px;line-height:1;transition:background .12s,color .12s}.SD8qLW_funnelBoundBtn:hover{color:var(--gs-fg)}.SD8qLW_cal{flex-direction:column;flex:none;gap:4px;display:flex}.SD8qLW_calHead{align-items:center;gap:4px;display:flex}.SD8qLW_calTitle{text-align:center;color:var(--gs-fg);font-size:var(--gs-t-dense);flex:1;line-height:20px}.SD8qLW_calNav{width:var(--gs-h-compact);height:var(--gs-h-compact);border-radius:var(--gs-r-control);color:var(--gs-fg-dim);font-family:inherit;font-size:var(--gs-t-ui);cursor:pointer;background:0 0;border:none;flex:none;padding:0}.SD8qLW_calNav:hover{color:var(--gs-fg);background:var(--gs-raise)}.SD8qLW_calWeek,.SD8qLW_calGrid{grid-template-columns:repeat(7,1fr);gap:2px;display:grid}.SD8qLW_calWeek span{text-align:center;color:var(--gs-fg-faint);font-size:var(--gs-t-meta);line-height:14px}.SD8qLW_calGrid button{height:var(--gs-h-compact);border-radius:var(--gs-r-control);color:var(--gs-fg-muted);font-family:inherit;font-size:var(--gs-t-dense);font-variant-numeric:tabular-nums;cursor:pointer;background:0 0;border:none}.SD8qLW_calGrid button:hover{background:var(--gs-raise);color:var(--gs-fg)}.SD8qLW_calGrid button.SD8qLW_calOut{color:var(--gs-fg-fainter)}.SD8qLW_calGrid button.SD8qLW_calToday{color:var(--gs-accent);font-weight:600}.SD8qLW_calGrid button.SD8qLW_calIn{background:var(--gs-accent-bg);color:var(--gs-fg)}.SD8qLW_calGrid button.SD8qLW_calMark{background:var(--gs-accent);color:var(--gs-on-accent);font-weight:600}.SD8qLW_funnelBoundRows{flex:none;grid-template-columns:1fr 1fr;gap:6px;display:grid}.SD8qLW_funnelBoundRow{box-sizing:border-box;border:1px solid var(--gs-border-soft);border-radius:var(--gs-r-control);background:var(--gs-bg);min-width:0;font-size:var(--gs-t-meta);align-items:center;gap:4px;padding:3px 6px;line-height:16px;display:flex}.SD8qLW_funnelBoundKey{color:var(--gs-fg-faint);flex:none}.SD8qLW_funnelBoundVal{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--gs-fg-faint);font-variant-numeric:tabular-nums;flex:1;overflow:hidden}.SD8qLW_funnelBoundValSet{color:var(--gs-fg)}.SD8qLW_funnelBoundClear{color:var(--gs-fg-dim);font-family:inherit;font-size:var(--gs-t-dense);cursor:pointer;background:0 0;border:none;flex:none;padding:0 2px;line-height:1}.SD8qLW_funnelBoundClear:hover{color:var(--gs-del)}.SD8qLW_funnelSearch{box-sizing:border-box;height:var(--gs-h-compact);border:1px solid var(--gs-border-soft);border-radius:var(--gs-r-control);background:var(--gs-bg);color:var(--gs-fg);font-family:inherit;font-size:var(--gs-t-dense);outline:none;flex:none;padding:0 8px}.SD8qLW_funnelSearch::placeholder{color:var(--gs-fg-faint)}.SD8qLW_funnelSearch:focus{border-color:var(--gs-accent);box-shadow:0 0 0 2px var(--gs-accent-bg)}.SD8qLW_funnelList{overscroll-behavior:contain;scrollbar-width:thin;scrollbar-color:var(--gs-fg-fainter) transparent;flex-direction:column;flex:auto;gap:1px;min-height:0;margin:0 -4px;padding:0 4px;display:flex;overflow-y:auto}.SD8qLW_funnelList::-webkit-scrollbar{width:10px}.SD8qLW_funnelList::-webkit-scrollbar-track{background:0 0}.SD8qLW_funnelList::-webkit-scrollbar-thumb{background:var(--gs-fg-fainter);border-radius:var(--gs-r-pill);background-clip:content-box;border:3px solid #0000}.SD8qLW_funnelRow{box-sizing:border-box;border-radius:var(--gs-r-control);cursor:pointer;align-items:center;gap:6px;min-height:24px;padding:0 4px;display:flex}.SD8qLW_funnelRow:hover{background:var(--gs-raise)}.SD8qLW_funnelRow:has(input[type=checkbox]:checked) .SD8qLW_funnelName,.SD8qLW_funnelRow:has(input[type=checkbox]:indeterminate) .SD8qLW_funnelName{color:var(--gs-fg)}.SD8qLW_funnelRow input[type=checkbox]{-webkit-appearance:none;appearance:none;box-sizing:border-box;border:1px solid var(--gs-fg-fainter);cursor:pointer;background:0 0;border-radius:3px;flex:none;width:14px;height:14px;margin:0;transition:background .12s,border-color .12s;position:relative}.SD8qLW_funnelRow input[type=checkbox]:hover{border-color:var(--gs-fg-dim)}.SD8qLW_funnelRow input[type=checkbox]:checked,.SD8qLW_funnelRow input[type=checkbox]:indeterminate{background:var(--gs-accent);border-color:var(--gs-accent)}.SD8qLW_funnelRow input[type=checkbox]:focus-visible{outline:2px solid var(--gs-accent);outline-offset:1px}.SD8qLW_funnelRow input[type=checkbox]:checked:after{content:\"\";border:solid var(--gs-on-accent);border-width:0 1.5px 1.5px 0;width:3px;height:7px;position:absolute;top:1px;left:4px;transform:rotate(42deg)}.SD8qLW_funnelRow input[type=checkbox]:indeterminate:after{content:\"\";background:var(--gs-on-accent);border-radius:1px;width:8px;height:2px;position:absolute;top:5px;left:2px}.SD8qLW_pathNode,.SD8qLW_pathChildren{flex-direction:column;display:flex}.SD8qLW_pathFileGlyph,.SD8qLW_pathDirGlyph{width:16px;height:16px;color:var(--gs-fg-dim);flex:none}.SD8qLW_funnelRow:hover .SD8qLW_pathFileGlyph,.SD8qLW_funnelRow:hover .SD8qLW_pathDirGlyph{color:var(--gs-fg-muted)}.SD8qLW_funnelName{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--gs-fg-muted);flex:1;overflow:hidden}.SD8qLW_funnelCount{color:var(--gs-fg-faint);font-size:var(--gs-t-meta);font-variant-numeric:tabular-nums;flex:none}.SD8qLW_funnelMore{color:var(--gs-fg-faint);padding:4px 6px}.SD8qLW_funnelChevron{width:14px;color:var(--gs-fg-faint);cursor:pointer;background:0 0;border:none;flex:none;padding:0;font-family:inherit;font-size:9px;line-height:16px}.SD8qLW_funnelChevron:hover:not(:disabled){color:var(--gs-fg)}.SD8qLW_funnelChevron:disabled{cursor:default}.SD8qLW_funnelPresets{flex:none;gap:4px;display:flex}.SD8qLW_funnelPreset{flex:1 1 0;min-width:0;padding:0 6px}.SD8qLW_funnelFoot{border-top:1px solid var(--gs-border-soft);background:var(--gs-bg);font-size:var(--gs-t-meta);flex:none;justify-content:space-between;align-items:center;gap:8px;padding:6px 10px;line-height:16px;display:flex}.SD8qLW_funnelFootCount{color:var(--gs-fg-faint);font-variant-numeric:tabular-nums}.SD8qLW_funnelFootCountOn{color:var(--gs-fg-muted)}.SD8qLW_funnelFootClear{border-radius:var(--gs-r-control);color:var(--gs-fg-dim);font-family:inherit;font-size:var(--gs-t-meta);cursor:pointer;background:0 0;border:none;flex:none;padding:2px 6px;line-height:16px}.SD8qLW_funnelFootClear:hover:not(:disabled){color:var(--gs-fg);background:var(--gs-raise)}.SD8qLW_funnelFootClear:disabled{color:var(--gs-fg-fainter);cursor:default}.SD8qLW_commitPopSubject{color:var(--gs-fg);font-size:var(--gs-t-ui);white-space:pre-wrap;overflow-wrap:anywhere;user-select:text;font-weight:600;line-height:18px}.SD8qLW_commitPopBody{color:var(--gs-fg-muted);font-family:inherit;font-size:var(--gs-t-dense);white-space:pre-wrap;overflow-wrap:anywhere;user-select:text;margin:0;line-height:18px}.SD8qLW_tabs{padding:0 var(--gs-gutter);border-bottom:1px solid var(--gs-border-soft);background:var(--gs-surface-2);flex:none;gap:24px;font-family:inherit;display:flex}.SD8qLW_tab{font-family:inherit;font-size:var(--gs-t-ui);color:var(--gs-fg-dim);cursor:pointer;background:0 0;border:none;padding:8px 0 9px;font-weight:500;line-height:16px;position:relative}.SD8qLW_tab:after{content:\"\";background:0 0;border-radius:2px;height:2px;position:absolute;bottom:1px;left:0;right:0}.SD8qLW_tabActive{color:var(--gs-accent)}.SD8qLW_tabActive:after{background:var(--gs-accent)}.SD8qLW_compareBar{padding:8px var(--gs-gutter);border-bottom:1px solid var(--gs-border-soft);background:var(--gs-surface-2);color:var(--gs-fg-dim);font-family:var(--dsw-font-ui,system-ui, sans-serif);font-size:var(--gs-t-dense);flex-wrap:wrap;flex:none;align-items:center;gap:10px;display:flex}.SD8qLW_compareArrow{color:var(--gs-fg-faint)}.SD8qLW_refPicker{align-items:center;gap:6px;display:inline-flex;position:relative}.SD8qLW_refLabel{color:var(--gs-fg-faint);flex:none}.SD8qLW_refButton{justify-content:space-between;max-width:260px}.SD8qLW_refValue{min-width:0;overflow:hidden}.SD8qLW_refCaret{color:var(--gs-fg-faint);flex:none;font-size:9px}.SD8qLW_refPop{z-index:10;border:1px solid var(--gs-border);border-radius:var(--gs-r-control);background:var(--gs-panel);width:300px;max-width:80vw;box-shadow:0 12px 32px var(--gs-shadow);flex-direction:column;display:flex;position:absolute;top:calc(100% + 4px);left:0;overflow:hidden}.SD8qLW_menuPop{width:auto;min-width:100%;padding:4px;left:auto;right:0}.SD8qLW_refSearch{border:0;border-bottom:1px solid var(--gs-border-soft);background:var(--gs-bg);color:var(--gs-fg);font-family:inherit;font-size:var(--gs-t-dense);outline:none;flex:none;padding:7px 10px}.SD8qLW_refSearch::placeholder{color:var(--gs-fg-faint)}.SD8qLW_refList{flex:1;max-height:280px;padding:4px;overflow-y:auto}.SD8qLW_refGroup{color:var(--gs-fg-faint);font-size:var(--gs-t-meta);letter-spacing:.04em;text-transform:uppercase;padding:6px 8px 3px;font-weight:600}.SD8qLW_refRow{box-sizing:border-box;border-radius:var(--gs-r-control);width:100%;color:var(--gs-fg-muted);font-family:inherit;font-size:var(--gs-t-dense);text-align:left;cursor:pointer;background:0 0;border:0;align-items:center;gap:6px;padding:5px 8px;display:flex}.SD8qLW_refRow:hover{background:var(--gs-raise);color:var(--gs-fg)}.SD8qLW_refRowSpacer{flex:none;width:12px}.SD8qLW_refRowName{flex:auto;min-width:0;overflow:hidden}.SD8qLW_refEmpty{color:var(--gs-fg-faint);font-size:var(--gs-t-dense);padding:14px 10px}.SD8qLW_refFoot{border-top:1px solid var(--gs-border-soft);color:var(--gs-fg-faint);font-size:var(--gs-t-meta);flex:none;padding:5px 10px}.SD8qLW_commitsPane{box-sizing:border-box;width:26%;min-height:0;min-width:var(--gs-min-commits);background:var(--gs-surface);flex-direction:column;flex:0 auto;max-width:340px;display:flex}.SD8qLW_paneHead{box-sizing:border-box;min-height:37px;padding:6px var(--gs-gutter-pane);border-bottom:1px solid var(--gs-border-soft);color:var(--gs-fg-dim);font-family:var(--dsw-font-ui,system-ui, sans-serif);font-size:var(--gs-t-dense);flex-wrap:wrap;flex:none;align-items:center;gap:8px;display:flex}.SD8qLW_paneTitle{font-weight:600}.SD8qLW_commitsSentinel{flex:none;height:1px}.SD8qLW_commitsFoot{color:var(--gs-fg-faint);font-family:var(--dsw-font-ui,system-ui, sans-serif);font-size:var(--gs-t-meta);text-align:center;flex:none;min-height:16px;padding:8px}.SD8qLW_commits{flex-direction:column;flex:1;min-height:0;padding:4px 6px 4px 0;display:flex;overflow-y:auto}.SD8qLW_commitLine{height:var(--gs-commit-row);flex:none;align-items:stretch;display:flex}.SD8qLW_graphCell{flex:none;display:block}.SD8qLW_commit{box-sizing:border-box;border-radius:var(--gs-r-surface);text-align:left;cursor:pointer;min-width:0;height:100%;font-family:inherit;font-size:var(--gs-t-dense);background:0 0;border:1px solid #0000;flex:auto;align-items:center;gap:10px;margin:1px 0;padding:4px 8px;transition:background .12s,border-color .12s;display:flex;overflow:hidden}.SD8qLW_commitsPane[data-layout=columns] .SD8qLW_commit{flex-direction:column;justify-content:center;align-items:stretch;gap:2px}.SD8qLW_commitsPane[data-layout=columns] .SD8qLW_commitSubjectRow{flex:none}.SD8qLW_commitTop{justify-content:space-between;align-items:center;gap:8px;min-width:0;display:flex}.SD8qLW_commit:hover{background:var(--gs-raise)}.SD8qLW_commitMeta{flex:none;align-items:baseline;gap:8px;display:flex}.SD8qLW_commitHash{color:var(--gs-info);flex:none}.SD8qLW_commitSubjectRow{flex:auto;align-items:baseline;gap:4px;min-width:0;display:flex}.SD8qLW_commitSubject{white-space:nowrap;text-overflow:ellipsis;min-width:0;color:var(--gs-fg-muted);flex:0 auto;overflow:hidden}.SD8qLW_commitHasBody{color:var(--gs-fg-faint);letter-spacing:.04em;flex:none}.SD8qLW_commitRef{white-space:nowrap;text-overflow:ellipsis;border:1px solid var(--gs-accent-border);border-radius:var(--gs-r-pill);background:var(--gs-accent-bg);max-width:96px;color:var(--gs-accent);font-size:var(--gs-t-meta);flex:none;padding:0 5px;line-height:15px;overflow:hidden}.SD8qLW_commitWhen{color:var(--gs-fg-faint);flex:none}.SD8qLW_commitAuthor{text-overflow:ellipsis;white-space:nowrap;max-width:120px;color:var(--gs-fg-dim);flex:none;overflow:hidden}.SD8qLW_body{z-index:1;flex:1;min-height:0;display:flex}.SD8qLW_body[data-stacked]{flex-direction:column}.SD8qLW_bodyRow{flex:1 1 0;min-width:0;min-height:0;display:flex}.SD8qLW_body[data-stacked] .SD8qLW_commitsPane{width:auto;min-width:0;max-width:none;height:34%;min-height:var(--gs-min-commits-tall);max-height:max(var(--gs-min-commits-tall), calc(100% - var(--gs-min-stacked-lower)));flex:none}.SD8qLW_treeCol{box-sizing:border-box;width:28%;min-height:0;min-width:var(--gs-min-tree);background:var(--gs-surface);flex-direction:column;flex:0 auto;max-width:400px;display:flex}.SD8qLW_treeWrap{box-sizing:border-box;flex-direction:column;flex:1;min-width:0;min-height:0;display:flex}.SD8qLW_treeTools{box-sizing:border-box;min-height:37px;padding:6px var(--gs-gutter-pane);border-bottom:1px solid var(--gs-border-soft);flex-wrap:wrap;flex:none;justify-content:space-between;align-items:center;gap:6px;display:flex}.SD8qLW_treeActions{flex-wrap:wrap;align-items:center;gap:6px;display:flex}.SD8qLW_treeLead{align-items:center;gap:4px;min-width:0;display:flex}.SD8qLW_treeLabel{white-space:nowrap;color:var(--gs-fg-dim);font-size:var(--gs-t-dense);flex:none}.SD8qLW_treeFilter{padding:6px var(--gs-gutter-pane);border-bottom:1px solid var(--gs-border-soft);flex:none;align-items:center;display:flex;position:relative}.SD8qLW_treeFilterInput{min-width:0;height:var(--gs-h-compact);box-sizing:border-box;border:1px solid var(--gs-border-soft);border-radius:var(--gs-r-control);background:var(--gs-bg);color:var(--gs-fg);font-family:inherit;font-size:var(--gs-t-dense);outline:none;flex:auto;padding:0 24px 0 8px}.SD8qLW_treeFilterInput:focus{border-color:var(--gs-accent)}.SD8qLW_treeFilterInput::placeholder{color:var(--gs-fg-faint)}.SD8qLW_treeFilterClear{right:calc(var(--gs-gutter-pane) + 6px);border-radius:var(--gs-r-pill);width:16px;height:16px;color:var(--gs-fg-faint);font-size:var(--gs-t-ui);cursor:pointer;background:0 0;border:0;justify-content:center;align-items:center;padding:0;line-height:1;display:flex;position:absolute}.SD8qLW_treeFilterClear:hover{color:var(--gs-fg)}.SD8qLW_tree{flex:1;min-height:0;margin:0;padding:6px 0 16px;list-style:none;overflow:auto}.SD8qLW_treeEmpty{min-height:0;color:var(--gs-fg-faint);font-size:var(--gs-t-ui);flex:1;justify-content:center;align-items:center;display:flex}.SD8qLW_treeSub{margin:0;padding:0;list-style:none;position:relative}.SD8qLW_treeSub:before{content:\"\";top:0;bottom:0;left:var(--gs-rail,0);background:var(--gs-border-soft);width:1px;position:absolute}.SD8qLW_treeDirLi{position:relative}.SD8qLW_treeDir{box-sizing:border-box;border-radius:var(--gs-r-control);width:100%;color:var(--gs-fg-dim);font-family:inherit;font-size:var(--gs-t-dense);text-align:left;cursor:pointer;background:0 0;border:0;align-items:center;gap:6px;padding:4px 12px 4px 8px;font-weight:600;display:flex}.SD8qLW_treeDir:hover{background:var(--gs-raise);color:var(--gs-fg-muted)}.SD8qLW_treeDirActive{color:var(--gs-fg-muted)}.SD8qLW_chevron{width:10px;color:var(--gs-fg-fainter);font-size:var(--gs-t-meta);flex:none;transition:transform .12s;display:inline-block}.SD8qLW_chevronOpen{transform:rotate(90deg)}.SD8qLW_treeDirName{white-space:nowrap;text-overflow:ellipsis;flex:1;min-width:0;overflow:hidden}.SD8qLW_treeDirCount{border-radius:var(--gs-r-pill);background:var(--gs-neutral-bg);color:var(--gs-fg-dim);font-size:var(--gs-t-meta);flex:none;padding:0 6px;font-weight:600;line-height:16px}.SD8qLW_treeDirCounts{font-size:var(--gs-t-meta);font-variant-numeric:tabular-nums;flex:none}.SD8qLW_file{box-sizing:border-box;border-radius:var(--gs-r-control);width:100%;color:var(--gs-fg-muted);font-family:inherit;font-size:var(--gs-t-dense);text-align:left;cursor:pointer;background:0 0;border:0;border-left:2px solid #0000;align-items:center;gap:8px;padding:5px 14px;display:flex}.SD8qLW_file:hover{background:var(--gs-raise)}.SD8qLW_fileStatus{border-radius:var(--gs-r-control);width:18px;height:18px;font-weight:700;font-size:var(--gs-t-meta);flex:none;justify-content:center;align-items:center;line-height:1;display:inline-flex}.SD8qLW_stAdded,.SD8qLW_stUntracked{color:var(--gs-add);background:var(--gs-add-bg)}.SD8qLW_stDeleted{color:var(--gs-del);background:var(--gs-del-bg)}.SD8qLW_stModified{color:var(--gs-warn);background:var(--gs-warn-bg)}.SD8qLW_stRenamed{color:var(--gs-info);background:var(--gs-info-bg)}.SD8qLW_filePath{white-space:nowrap;text-overflow:ellipsis;flex:1;min-width:0;overflow:hidden}.SD8qLW_fileBinary{border-radius:var(--gs-r-control);background:var(--gs-neutral-bg);color:var(--gs-fg-dim);letter-spacing:.06em;flex:none;padding:0 5px;font-size:9px;font-weight:700}.SD8qLW_fileCounts{font-size:var(--gs-t-meta);font-variant-numeric:tabular-nums;flex:none}.SD8qLW_fileCountAdd{color:var(--gs-add)}.SD8qLW_fileCountDel{color:var(--gs-del)}.SD8qLW_diffPane{min-width:var(--gs-min-diff);background:var(--gs-surface);flex-direction:column;flex:1 1 0;display:flex;overflow:auto}.SD8qLW_diffWrap{flex-direction:column;flex:auto;width:100%;min-height:0;display:flex}.SD8qLW_diffScroll{outline:none;flex:1 1 0;min-height:0;overflow:auto}.SD8qLW_diffNav{border-bottom:1px solid var(--gs-border-soft);flex:none;justify-content:flex-end;align-items:center;gap:4px;padding:3px 12px 3px 0;display:flex}.SD8qLW_diffNav .SD8qLW_blockBtn{padding-inline:6px;line-height:0}.SD8qLW_diffPre{width:max-content;min-width:100%;font-family:ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace;font-size:var(--gs-t-dense);font-variant-ligatures:none;font-feature-settings:\"liga\" 0, \"calt\" 0;tab-size:4;flex-direction:column;margin:0;padding:8px 0 16px;font-weight:400;line-height:20px;display:flex}.SD8qLW_renameLine{border-bottom:1px solid var(--gs-border-soft);color:var(--gs-info);font-size:var(--gs-t-dense);flex:none;padding:8px 16px}.SD8qLW_renameLine code{color:var(--gs-fg)}.SD8qLW_line{white-space:nowrap;align-items:stretch;width:max-content;min-width:100%;min-height:20px;line-height:20px;display:flex}.SD8qLW_lnOld,.SD8qLW_lnNew{box-sizing:border-box;text-align:right;width:3.2em;color:var(--gs-fg-fainter);user-select:none;font-variant-numeric:tabular-nums;flex:none;padding:0 8px}.SD8qLW_line:hover .SD8qLW_lnOld,.SD8qLW_line:hover .SD8qLW_lnNew{color:var(--gs-fg-dim)}.SD8qLW_gutter{text-align:center;user-select:none;flex:none;width:1.4em}.SD8qLW_code{white-space:pre;flex:1 0 auto;padding:0 16px 0 10px}.SD8qLW_diffPreWrap{width:100%;min-width:0}.SD8qLW_diffPreWrap .SD8qLW_line{align-items:flex-start}.SD8qLW_diffPreWrap .SD8qLW_code{white-space:pre-wrap;overflow-wrap:anywhere;flex:1 1 0;min-width:0}.SD8qLW_lineAdd{background:var(--gs-add-line)}.SD8qLW_lineDel{background:var(--gs-del-line)}.SD8qLW_lineAdd .SD8qLW_lnOld,.SD8qLW_lineAdd .SD8qLW_lnNew,.SD8qLW_lineAdd .SD8qLW_gutter{background:var(--gs-add-num,var(--gs-add-line))}.SD8qLW_lineDel .SD8qLW_lnOld,.SD8qLW_lineDel .SD8qLW_lnNew,.SD8qLW_lineDel .SD8qLW_gutter{background:var(--gs-del-num,var(--gs-del-line))}.SD8qLW_lineContext{color:var(--gs-fg-muted)}.SD8qLW_lineHunk{background:var(--gs-hunk)}.SD8qLW_lineHunk .SD8qLW_code{color:var(--gs-fg-dim)}.SD8qLW_lineHunk .SD8qLW_lnOld,.SD8qLW_lineHunk .SD8qLW_lnNew,.SD8qLW_lineHunk .SD8qLW_gutter{background:var(--gs-hunk-num,var(--gs-hunk))}.SD8qLW_signAdd{color:var(--gs-add)}.SD8qLW_signDel{color:var(--gs-del)}.SD8qLW_wordAdd{background:var(--gs-add-word);border-radius:2px}.SD8qLW_wordDel{background:var(--gs-del-word);border-radius:2px}.SD8qLW_crMark{color:var(--gs-fg-faint);user-select:none;font-size:.9em}.SD8qLW_sidePane{flex-direction:column;width:100%;min-width:0;height:100%;display:flex}.SD8qLW_sideScroll{flex:1 1 0;min-height:0;overflow:hidden auto}.SD8qLW_sideCols{align-items:stretch;min-height:100%;display:flex}.SD8qLW_sideCol{scrollbar-width:none;flex:none;min-width:0;overflow-x:auto}.SD8qLW_sideCol::-webkit-scrollbar{display:none}.SD8qLW_sideColRight{flex:1 1 0}.SD8qLW_sideColGrid{width:max-content;min-width:100%;font-family:ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace;font-size:var(--gs-t-dense);font-variant-ligatures:none;font-feature-settings:\"liga\" 0, \"calt\" 0;tab-size:4;grid-template-columns:3.2em 1fr;align-content:start;padding:8px 0 16px;font-weight:400;line-height:20px;display:grid}.SD8qLW_sideColGridBlame{grid-template-columns:13em 3.2em 1fr}.SD8qLW_blameCell{box-sizing:border-box;border-right:1px solid var(--gs-border-soft);color:var(--gs-fg-faint);font-size:var(--gs-t-meta);white-space:pre;text-overflow:ellipsis;user-select:none;padding:0 8px 0 10px;overflow:hidden}.SD8qLW_sideTabs{z-index:5;border-bottom:1px solid var(--gs-border-soft);background:var(--gs-surface-2);flex-wrap:wrap;flex:none;align-items:flex-start;gap:0 16px;padding:6px 16px 0;display:flex}.SD8qLW_sideTab{font-family:inherit;font-size:var(--gs-t-meta);color:var(--gs-fg-dim);cursor:pointer;background:0 0;border:none;padding:2px 0 5px;font-weight:500;line-height:16px;position:relative}.SD8qLW_sideTab:after{content:\"\";background:0 0;border-radius:2px;height:2px;position:absolute;bottom:1px;left:0;right:0}.SD8qLW_sideTabActive{color:var(--gs-accent)}.SD8qLW_sideTabActive:after{background:var(--gs-accent)}.SD8qLW_sideNotice{border-bottom:1px solid var(--gs-border-soft);color:var(--gs-info);font-size:var(--gs-t-dense);flex:none;padding:8px 16px}.SD8qLW_sideNum{box-sizing:border-box;text-align:right;color:var(--gs-fg-fainter);user-select:none;font-variant-numeric:tabular-nums;padding:0 8px}.SD8qLW_sideNumAdd{background:var(--gs-add-num,var(--gs-add-line))}.SD8qLW_sideNumDel{background:var(--gs-del-num,var(--gs-del-line))}.SD8qLW_sideCode{white-space:pre;min-height:20px;padding:0 16px 0 10px}.SD8qLW_sideColWrap{overflow-x:hidden}.SD8qLW_sideColGridWrap{width:100%;min-width:0}.SD8qLW_sideColGridWrap .SD8qLW_sideCode{white-space:pre-wrap;overflow-wrap:anywhere;min-width:0}.SD8qLW_sideFlow{height:auto;display:block}.SD8qLW_sideSpacer{grid-column:1/-1}.SD8qLW_diffSpacer{flex:none}.SD8qLW_sideCodeSame{color:var(--gs-fg-muted)}.SD8qLW_sideCodeAdd{background:var(--gs-add-line)}.SD8qLW_sideCodeDel{background:var(--gs-del-line)}.SD8qLW_sideCellBlock{position:relative}.SD8qLW_sideNum.SD8qLW_sideBlockHot{box-shadow:inset 1px 0 var(--gs-accent)}.SD8qLW_sideCode.SD8qLW_sideBlockHot{box-shadow:inset -1px 0 var(--gs-accent)}.SD8qLW_sideNum.SD8qLW_sideBlockHot.SD8qLW_sideBlockHotFirst{box-shadow:inset 1px 0 var(--gs-accent), inset 0 1px var(--gs-accent)}.SD8qLW_sideCode.SD8qLW_sideBlockHot.SD8qLW_sideBlockHotFirst{box-shadow:inset -1px 0 var(--gs-accent), inset 0 1px var(--gs-accent)}.SD8qLW_sideNum.SD8qLW_sideBlockHot.SD8qLW_sideBlockHotLast{box-shadow:inset 1px 0 var(--gs-accent), inset 0 -1px var(--gs-accent)}.SD8qLW_sideCode.SD8qLW_sideBlockHot.SD8qLW_sideBlockHotLast{box-shadow:inset -1px 0 var(--gs-accent), inset 0 -1px var(--gs-accent)}.SD8qLW_sideNum.SD8qLW_sideBlockHot.SD8qLW_sideBlockHotFirst.SD8qLW_sideBlockHotLast{box-shadow:inset 1px 0 var(--gs-accent), inset 0 1px var(--gs-accent), inset 0 -1px var(--gs-accent)}.SD8qLW_sideCode.SD8qLW_sideBlockHot.SD8qLW_sideBlockHotFirst.SD8qLW_sideBlockHotLast{box-shadow:inset -1px 0 var(--gs-accent), inset 0 1px var(--gs-accent), inset 0 -1px var(--gs-accent)}.SD8qLW_blockBar{z-index:4;border:1px solid var(--gs-border);border-radius:var(--gs-r-control);background:var(--gs-surface-2,var(--gs-bg));box-shadow:0 4px 14px var(--gs-shadow);white-space:nowrap;gap:4px;padding:2px;display:flex;position:absolute;left:0}.SD8qLW_blockBtn{border:1px solid var(--gs-border);border-radius:var(--gs-r-pill);background:var(--gs-bg);color:var(--gs-fg-dim);font-family:inherit;font-size:var(--gs-t-meta);cursor:pointer;padding:0 8px;line-height:16px}.SD8qLW_blockBtn:hover:not(:disabled){color:var(--gs-fg);border-color:var(--gs-accent)}.SD8qLW_blockBtn:disabled{opacity:.45;cursor:default}.SD8qLW_blockBtnDanger{color:var(--gs-del);border-color:var(--gs-del-bg,var(--gs-border))}.SD8qLW_blockBtnDanger:hover:not(:disabled){color:var(--gs-del);border-color:var(--gs-del)}.SD8qLW_sideArmable{cursor:text}.SD8qLW_cmHost{position:relative}.SD8qLW_cmHost[data-editable]:before{content:\"\";background:var(--gs-accent);opacity:.32;pointer-events:none;z-index:201;border-radius:1px;width:2px;transition:opacity .14s;position:absolute;top:0;bottom:0;left:0}.SD8qLW_cmHost[data-editable]:focus-within:before{opacity:1}.SD8qLW_sideNav{align-items:center;gap:4px;margin-left:auto;padding:2px 0 5px;display:flex}.SD8qLW_sideNav .SD8qLW_blockBtn{padding-inline:6px;line-height:0}.SD8qLW_sideNavCount{color:var(--gs-fg-faint);font-size:var(--gs-t-meta);white-space:nowrap}.SD8qLW_sideCurrentBlockActions{flex-wrap:wrap;align-items:flex-start;gap:4px;margin-left:4px;padding:2px 0 5px;display:flex}.SD8qLW_sideActions{align-items:flex-start;gap:4px;margin-left:auto;padding:2px 0 5px;display:flex}.SD8qLW_sideActionsAdjacent{margin-left:0}.SD8qLW_sideSaveReady{color:var(--gs-accent);border-color:var(--gs-accent)}.SD8qLW_sideBanner{border-bottom:1px solid var(--gs-border-soft);background:var(--gs-del-bg,transparent);color:var(--gs-del);font-size:var(--gs-t-dense);flex-direction:column;flex:none;gap:6px;padding:8px 16px;display:flex}.SD8qLW_sideBannerTitle{font-weight:600}.SD8qLW_sideBannerActs{gap:4px;display:flex}.SD8qLW_sideEditCell{position:relative}.SD8qLW_empty{color:var(--gs-fg-faint);font-size:var(--gs-t-ui);padding:32px 24px}.SD8qLW_sideRails{z-index:6;align-items:stretch;height:0;display:flex;position:sticky;bottom:0;overflow:hidden}.SD8qLW_sideRailsOn{background:var(--gs-surface);height:12px;margin-top:-12px;overflow:visible}.SD8qLW_sideRail{flex:none;min-width:0;overflow:auto hidden}@supports ((-moz-appearance:none)){.SD8qLW_sideRail{scrollbar-width:thin;scrollbar-color:var(--gs-fg-fainter) transparent}}.SD8qLW_sideRail::-webkit-scrollbar{height:10px}.SD8qLW_sideRail::-webkit-scrollbar-track{background:0 0}.SD8qLW_sideRail::-webkit-scrollbar-thumb{background:var(--gs-fg-fainter);border-radius:var(--gs-r-pill);background-clip:padding-box;border:3px solid #0000}.SD8qLW_sideRail:hover::-webkit-scrollbar-thumb{background:var(--gs-fg-faint);background-clip:padding-box}.SD8qLW_sideRailRight{flex:1 1 0}.SD8qLW_sideRailGap{flex:none;width:7px}.SD8qLW_sideRailSpan{height:1px}.SD8qLW_syncBar{padding:8px var(--gs-gutter);border-bottom:1px solid var(--gs-border-soft);background:var(--gs-surface-2);font-size:var(--gs-t-dense);color:var(--gs-fg-dim);flex-wrap:wrap;flex:none;align-items:center;gap:8px;display:flex}.SD8qLW_syncUpstream{white-space:nowrap;text-overflow:ellipsis;max-width:260px;color:var(--gs-fg-muted);font-variant-numeric:tabular-nums;overflow:hidden}.SD8qLW_syncLevel{color:var(--gs-fg-faint)}.SD8qLW_syncSpacer{flex:auto}.SD8qLW_btn:disabled,.SD8qLW_treeIcon:disabled,.SD8qLW_miniBtn:disabled,.SD8qLW_refButton:disabled,.SD8qLW_funnelButton:disabled{opacity:.45;cursor:default}.SD8qLW_btn[data-quiet]:disabled,.SD8qLW_refButton[data-quiet]:disabled{opacity:1}.SD8qLW_opBanner{padding:8px var(--gs-gutter);border-bottom:1px solid var(--gs-border-soft);font-size:var(--gs-t-dense);white-space:pre-wrap;overflow-wrap:anywhere;user-select:text;flex:none;line-height:18px}.SD8qLW_opBannerOk{background:var(--gs-add-bg);color:var(--gs-add)}.SD8qLW_opBannerBad{background:var(--gs-del-bg);color:var(--gs-del)}.SD8qLW_fileLi{align-items:stretch;display:flex}.SD8qLW_fileLi .SD8qLW_file{flex:auto;min-width:0}.SD8qLW_fileDiscard{width:22px;color:var(--gs-fg-faint);opacity:0;cursor:pointer;background:0 0;border:0;flex:none;justify-content:center;align-items:center;padding:0;transition:opacity .12s,color .12s;display:flex}.SD8qLW_fileLi:hover .SD8qLW_fileDiscard,.SD8qLW_fileDiscard:focus-visible{opacity:1}.SD8qLW_fileDiscard:hover{color:var(--gs-del)}.SD8qLW_fileDiscard:focus-visible{outline:2px solid var(--gs-accent);outline-offset:-2px;border-radius:var(--gs-r-control)}.SD8qLW_treeRow{align-items:stretch;display:flex}.SD8qLW_treeRow .SD8qLW_treeDir{flex:auto;min-width:0}.SD8qLW_checkBox{cursor:pointer;background:0 0;border:0;flex:none;justify-content:center;align-items:center;width:22px;padding:0;display:flex}.SD8qLW_checkMark{box-sizing:border-box;border:1px solid var(--gs-fg-faint);background:var(--gs-bg);color:#0000;border-radius:3px;justify-content:center;align-items:center;width:14px;height:14px;font-size:10px;font-weight:700;line-height:1;transition:background .12s,border-color .12s;display:flex}.SD8qLW_checkBox:hover .SD8qLW_checkMark{border-color:var(--gs-accent)}.SD8qLW_checkBox:focus-visible{outline:none}.SD8qLW_checkBox:focus-visible .SD8qLW_checkMark{outline:2px solid var(--gs-accent);outline-offset:1px}.SD8qLW_checkMarkOn,.SD8qLW_checkMarkPartial{border-color:var(--gs-accent);background:var(--gs-accent);color:var(--gs-on-accent)}.SD8qLW_commitBox{padding:8px var(--gs-gutter-pane) 10px;border-top:1px solid var(--gs-border);background:var(--gs-surface-2);flex-direction:column;flex:none;gap:6px;display:flex}.SD8qLW_commitMessage{box-sizing:border-box;border:1px solid var(--gs-border);border-radius:var(--gs-r-control);background:var(--gs-bg);width:100%;min-height:46px;max-height:160px;color:var(--gs-fg);font-family:inherit;font-size:var(--gs-t-dense);resize:vertical;outline:none;padding:6px 8px;line-height:18px}.SD8qLW_commitMessage:focus{border-color:var(--gs-accent-border)}.SD8qLW_commitMessage::placeholder{color:var(--gs-fg-faint)}.SD8qLW_commitRow{align-items:center;gap:8px;display:flex}.SD8qLW_commitAmend{color:var(--gs-fg-dim);font-size:var(--gs-t-meta);cursor:pointer;align-items:center;gap:4px;display:inline-flex}.SD8qLW_commitAmend input{accent-color:var(--gs-accent);cursor:pointer}.SD8qLW_commitStaged{color:var(--gs-fg-faint);font-size:var(--gs-t-meta);margin-left:auto}.SD8qLW_commitLead{color:var(--gs-fg-faint);font-size:var(--gs-t-meta);margin:0;line-height:15px}.SD8qLW_commitBtn{box-sizing:border-box;min-width:92px;height:var(--gs-h-control);border-radius:var(--gs-r-control);background:var(--gs-accent);color:var(--gs-on-accent);font-family:inherit;font-size:var(--gs-t-ui);white-space:nowrap;cursor:pointer;border:1px solid #0000;flex:none;justify-content:center;align-items:center;padding:0 16px;font-weight:600;line-height:1;transition:filter .12s,opacity .12s;display:inline-flex}.SD8qLW_commitBtn:hover:not(:disabled){filter:brightness(1.1)}.SD8qLW_commitBtn:focus-visible{outline:2px solid var(--gs-accent);outline-offset:2px}.SD8qLW_commitBtn:disabled{background:var(--gs-raise);color:var(--gs-fg-faint);border-color:var(--gs-border);cursor:default}.SD8qLW_btn,.SD8qLW_miniBtn,.SD8qLW_treeIcon,.SD8qLW_commitCopy,.SD8qLW_scopeBtn,.SD8qLW_refButton,.SD8qLW_funnelButton,.SD8qLW_funnelPreset,.SD8qLW_layoutButton{box-sizing:border-box;height:var(--gs-h-control);padding:var(--gs-pad-control);border:1px solid var(--gs-border);border-radius:var(--gs-r-control);color:var(--gs-fg-dim);font-family:inherit;font-size:var(--gs-t-ui);white-space:nowrap;cursor:pointer;background:0 0;flex:none;justify-content:center;align-items:center;gap:6px;line-height:1;transition:background .12s,color .12s,border-color .12s;display:inline-flex}.SD8qLW_btn:hover,.SD8qLW_miniBtn:hover,.SD8qLW_treeIcon:hover,.SD8qLW_commitCopy:hover,.SD8qLW_scopeBtn:hover,.SD8qLW_refButton:hover,.SD8qLW_funnelButton:hover,.SD8qLW_funnelPreset:hover,.SD8qLW_layoutButton:hover{background:var(--gs-raise);color:var(--gs-fg);border-color:var(--gs-fg-fainter)}.SD8qLW_btn:focus-visible,.SD8qLW_miniBtn:focus-visible,.SD8qLW_treeIcon:focus-visible,.SD8qLW_commitCopy:focus-visible,.SD8qLW_scopeBtn:focus-visible,.SD8qLW_refButton:focus-visible,.SD8qLW_funnelPreset:focus-visible,.SD8qLW_layoutButton:focus-visible{outline:2px solid var(--gs-accent);outline-offset:1px}.SD8qLW_btn,.SD8qLW_refButton{border-radius:var(--gs-r-pill)}.SD8qLW_treeIcon,.SD8qLW_commitCopy,.SD8qLW_funnelPreset,.SD8qLW_layoutButton{height:var(--gs-h-compact);padding:var(--gs-pad-compact);font-size:var(--gs-t-dense)}.SD8qLW_treeIcon{width:var(--gs-h-compact);padding:0}.SD8qLW_layoutSwitch{flex:none;gap:2px;margin-left:auto;display:inline-flex}.SD8qLW_layoutButton{width:var(--gs-h-compact);padding:0}.SD8qLW_layoutButton.SD8qLW_layoutButtonOn{color:var(--gs-accent);border-color:var(--gs-accent)}.SD8qLW_layoutGlyph{display:block}.SD8qLW_treeIcon.SD8qLW_treeIconOn{color:var(--gs-accent);border-color:var(--gs-accent)}.SD8qLW_treeIconGlyph{font-size:var(--gs-t-meta);line-height:1;display:block}.SD8qLW_treeIconDown{transform:rotate(90deg)}.SD8qLW_scopeBtn{flex:1 1 0}.SD8qLW_scopeBtnActive,.SD8qLW_miniBtnPrimary,.SD8qLW_segmentActive,.SD8qLW_refRowActive,.SD8qLW_paletteRowActive,.SD8qLW_fileActive,.SD8qLW_commitActive,.SD8qLW_funnelTabActive,.SD8qLW_funnelBoundBtnActive,.SD8qLW_funnelPresetActive,.SD8qLW_fbRow.SD8qLW_fbRowActive{border-color:var(--gs-accent-border);background:var(--gs-accent-bg);color:var(--gs-accent);font-weight:600}.SD8qLW_btnIcon{width:var(--gs-h-control);padding:0}.SD8qLW_btnIcon svg{display:block}.SD8qLW_btnIcon.SD8qLW_btnIconOn{color:var(--gs-accent);border-color:var(--gs-accent)}.SD8qLW_btnClose:hover:not(:disabled){border-color:var(--gs-del);background:var(--gs-del-bg);color:var(--gs-del)}.SD8qLW_btnBehind{border-color:var(--gs-warn);background:var(--gs-warn-bg);color:var(--gs-warn);font-weight:600}.SD8qLW_btnBehind:hover:not(:disabled){background:var(--gs-warn-bg);color:var(--gs-warn);border-color:var(--gs-warn)}.SD8qLW_btnAhead{border-color:var(--gs-add);background:var(--gs-add-bg);color:var(--gs-add);font-weight:600}.SD8qLW_btnAhead:hover:not(:disabled){background:var(--gs-add-bg);color:var(--gs-add);border-color:var(--gs-add)}.SD8qLW_btnPrimary{border-color:var(--gs-accent);background:var(--gs-accent);color:var(--gs-on-accent);font-weight:600}.SD8qLW_btnPrimary:hover:not(:disabled){background:var(--gs-accent);color:var(--gs-on-accent);border-color:var(--gs-accent)}.SD8qLW_btnCount{font-variant-numeric:tabular-nums;opacity:.85;border-left:1px solid;margin-left:1px;padding-left:6px}.SD8qLW_pullGroup{flex:none;align-items:center;display:inline-flex}.SD8qLW_pullGroup>.SD8qLW_refPicker>.SD8qLW_refButton{border-right-color:#0000;border-top-right-radius:0;border-bottom-right-radius:0}.SD8qLW_pullGroup>.SD8qLW_btn{border-top-left-radius:0;border-bottom-left-radius:0;margin-left:-1px}.SD8qLW_drawer{scrollbar-width:thin;scrollbar-color:var(--gs-border) transparent}.SD8qLW_drawer ::-webkit-scrollbar{width:10px;height:10px}.SD8qLW_drawer ::-webkit-scrollbar-track,.SD8qLW_drawer ::-webkit-scrollbar-corner{background:0 0}.SD8qLW_drawer ::-webkit-scrollbar-thumb{background:var(--gs-border);border-radius:var(--gs-r-pill);background-clip:padding-box;border:3px solid #0000}.SD8qLW_drawer ::-webkit-scrollbar-thumb:hover{background:var(--gs-fg-faint);background-clip:padding-box}.SD8qLW_commitRefMore{border-radius:var(--gs-r-pill);background:var(--gs-neutral-bg);color:var(--gs-fg-dim);font-size:var(--gs-t-meta);cursor:default;flex:none;padding:0 5px;line-height:15px}.SD8qLW_confirmScrim{background:var(--gs-backdrop);justify-content:center;align-items:center;padding:24px;animation:.12s ease-out SD8qLW_gsFade;display:flex}.SD8qLW_confirmBox{box-sizing:border-box;border:1px solid var(--gs-border);border-radius:var(--gs-r-drawer);background:var(--gs-bg);width:min(440px,100%);box-shadow:0 18px 48px var(--gs-shadow);flex-direction:column;gap:10px;padding:18px;display:flex}.SD8qLW_confirmTitle{color:var(--gs-fg);font-size:var(--gs-t-ui);font-weight:600}.SD8qLW_confirmBody{color:var(--gs-fg-dim);font-size:var(--gs-t-dense);overflow-wrap:anywhere;line-height:1.55}.SD8qLW_confirmActions{flex-direction:row-reverse;gap:8px;margin-top:2px;display:flex}.SD8qLW_btn.SD8qLW_btnDanger{border-color:var(--gs-del);background:var(--gs-del);color:var(--gs-on-accent);font-weight:600}.SD8qLW_btn.SD8qLW_btnDanger:hover:not(:disabled){border-color:var(--gs-del);background:var(--gs-del);color:var(--gs-on-accent)}.SD8qLW_fbTree{min-width:var(--gs-min-tree);background:var(--gs-surface-2);flex-direction:column;flex:none;gap:4px;padding:6px;display:flex;overflow:auto}.SD8qLW_fbSearch{box-sizing:border-box;width:100%;font:inherit;font-size:var(--gs-t-meta);color:var(--gs-fg);background:var(--gs-surface);border:1px solid var(--gs-border);border-radius:var(--gs-r-control);flex:none;padding:4px 6px}.SD8qLW_fbSearch:focus{border-color:var(--gs-accent);outline:none}.SD8qLW_fbNote{font-size:var(--gs-t-meta);color:var(--gs-fg-dim);flex:none;padding:2px 4px}.SD8qLW_fbList{margin:0;padding:0;list-style:none}.SD8qLW_fbRow{width:100%;font:inherit;font-size:var(--gs-t-dense);color:var(--gs-fg-dim);text-align:left;border-radius:var(--gs-r-control);cursor:pointer;white-space:nowrap;text-overflow:ellipsis;background:0 0;border:0;align-items:center;gap:4px;padding:2px 6px 2px 4px;display:flex;overflow:hidden}.SD8qLW_fbRow:hover{background:var(--gs-raise)}.SD8qLW_fbRow.SD8qLW_fbRowIgnored{opacity:.55}.SD8qLW_fbDirName,.SD8qLW_fbFileName{text-overflow:ellipsis;overflow:hidden}.SD8qLW_fbMain{min-width:var(--gs-min-diff);background:var(--gs-surface);flex-direction:column;flex:1 1 0;min-height:0;display:flex}.SD8qLW_fbHeader{border-bottom:1px solid var(--gs-border);flex:none;align-items:flex-start;gap:8px;padding:4px 8px 0;display:flex}.SD8qLW_fbPath{font-size:var(--gs-t-meta);color:var(--gs-fg-dim);text-overflow:ellipsis;white-space:nowrap;padding:4px 0;overflow:hidden}.SD8qLW_fbBody{flex:1 1 0;min-height:0;padding:4px 8px;overflow:auto}.SD8qLW_fbCommit{font-size:var(--gs-t-meta);color:var(--gs-fg-dim);background:var(--gs-surface-2);border-bottom:1px solid var(--gs-border);flex:none;align-items:baseline;gap:8px;padding:4px 8px;display:flex}.SD8qLW_fbCommitLine{color:var(--gs-fg-faint);font-variant-numeric:tabular-nums;flex:none}.SD8qLW_fbCommitWho{color:var(--gs-fg);flex:none;font-weight:600}.SD8qLW_fbCommitWhen{font-variant-numeric:tabular-nums;flex:none}.SD8qLW_fbCommitHash{color:var(--gs-fg-faint);flex:none;font-family:inherit}.SD8qLW_fbCommitWhat{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--gs-fg);flex:auto;overflow:hidden}.SD8qLW_fbCommitHint{color:var(--gs-fg-faint)}.SD8qLW_fbMore{font-size:var(--gs-t-meta);color:var(--gs-fg-faint);padding:2px 6px 4px 4px;font-style:italic;display:block}.SD8qLW_imgPane{flex-direction:column;gap:8px;height:100%;min-height:0;display:flex}.SD8qLW_imgStage{border-radius:var(--gs-r-control);background-color:var(--gs-surface-2);background-image:linear-gradient(45deg, var(--gs-border-soft) 25%, transparent 25%, transparent 75%, var(--gs-border-soft) 75%), linear-gradient(45deg, var(--gs-border-soft) 25%, transparent 25%, transparent 75%, var(--gs-border-soft) 75%);background-position:0 0,8px 8px;background-size:16px 16px;flex:auto;justify-content:center;align-items:center;min-height:0;padding:12px;display:flex;overflow:auto}.SD8qLW_imgShot{object-fit:contain;image-rendering:auto;max-width:100%;max-height:100%}.SD8qLW_imgStage[data-actual]{justify-content:flex-start;align-items:flex-start}.SD8qLW_imgStage[data-actual] .SD8qLW_imgShot{object-fit:none;max-width:none;max-height:none}.SD8qLW_imgCaption{font-size:var(--gs-t-meta);color:var(--gs-fg-dim);font-variant-numeric:tabular-nums;flex:none;align-items:center;gap:8px;display:flex}";
|
|
463
463
|
const tagId = "@young1lin/dsh-ui-gitworkbench/GitWorkbenchPanel.module.css";
|
|
464
464
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
465
465
|
const tag = document.createElement("style");
|
|
@@ -469,337 +469,349 @@ window.__ModuleLoader__.load({
|
|
|
469
469
|
document.head.appendChild(tag);
|
|
470
470
|
}
|
|
471
471
|
var GitWorkbenchPanel_module_css_default = {
|
|
472
|
-
"
|
|
473
|
-
"
|
|
474
|
-
"fbCommitWho": "SD8qLW_fbCommitWho",
|
|
475
|
-
"funnelCount": "SD8qLW_funnelCount",
|
|
476
|
-
"headerPathMain": "SD8qLW_headerPathMain",
|
|
472
|
+
"themeRowSplit": "SD8qLW_themeRowSplit",
|
|
473
|
+
"scopeBtnActive": "SD8qLW_scopeBtnActive",
|
|
477
474
|
"fbPath": "SD8qLW_fbPath",
|
|
478
|
-
"
|
|
479
|
-
"
|
|
480
|
-
"
|
|
481
|
-
"
|
|
482
|
-
"cal": "SD8qLW_cal",
|
|
475
|
+
"commitActive": "SD8qLW_commitActive",
|
|
476
|
+
"fbRow": "SD8qLW_fbRow",
|
|
477
|
+
"lineDel": "SD8qLW_lineDel",
|
|
478
|
+
"cmHost": "SD8qLW_cmHost",
|
|
483
479
|
"funnelBoundClear": "SD8qLW_funnelBoundClear",
|
|
484
|
-
"
|
|
485
|
-
"
|
|
480
|
+
"chevron": "SD8qLW_chevron",
|
|
481
|
+
"headerViewRef": "SD8qLW_headerViewRef",
|
|
482
|
+
"cardDeleted": "SD8qLW_cardDeleted",
|
|
483
|
+
"headerTotalsAdd": "SD8qLW_headerTotalsAdd",
|
|
484
|
+
"commitHasBody": "SD8qLW_commitHasBody",
|
|
485
|
+
"funnelPresetActive": "SD8qLW_funnelPresetActive",
|
|
486
|
+
"blameCell": "SD8qLW_blameCell",
|
|
487
|
+
"sideCodeAdd": "SD8qLW_sideCodeAdd",
|
|
488
|
+
"fileCounts": "SD8qLW_fileCounts",
|
|
489
|
+
"lineHunk": "SD8qLW_lineHunk",
|
|
486
490
|
"graphCell": "SD8qLW_graphCell",
|
|
487
|
-
"
|
|
488
|
-
"
|
|
489
|
-
"
|
|
490
|
-
"
|
|
491
|
-
"fbFileName": "SD8qLW_fbFileName",
|
|
492
|
-
"commitLine": "SD8qLW_commitLine",
|
|
493
|
-
"imgPane": "SD8qLW_imgPane",
|
|
494
|
-
"calIn": "SD8qLW_calIn",
|
|
495
|
-
"diffNav": "SD8qLW_diffNav",
|
|
496
|
-
"pathNode": "SD8qLW_pathNode",
|
|
497
|
-
"calGrid": "SD8qLW_calGrid",
|
|
498
|
-
"commitPopSubject": "SD8qLW_commitPopSubject",
|
|
491
|
+
"headerView": "SD8qLW_headerView",
|
|
492
|
+
"signAdd": "SD8qLW_signAdd",
|
|
493
|
+
"sideTabs": "SD8qLW_sideTabs",
|
|
494
|
+
"funnelBounds": "SD8qLW_funnelBounds",
|
|
499
495
|
"commitRef": "SD8qLW_commitRef",
|
|
500
|
-
"crMark": "SD8qLW_crMark",
|
|
501
|
-
"sideColGrid": "SD8qLW_sideColGrid",
|
|
502
|
-
"sideBannerTitle": "SD8qLW_sideBannerTitle",
|
|
503
|
-
"paneDividerActive": "SD8qLW_paneDividerActive",
|
|
504
|
-
"lineAdd": "SD8qLW_lineAdd",
|
|
505
|
-
"sideNumAdd": "SD8qLW_sideNumAdd",
|
|
506
|
-
"lnOld": "SD8qLW_lnOld",
|
|
507
|
-
"commits": "SD8qLW_commits",
|
|
508
|
-
"funnelFootClear": "SD8qLW_funnelFootClear",
|
|
509
|
-
"themeLabel": "SD8qLW_themeLabel",
|
|
510
|
-
"funnelTabs": "SD8qLW_funnelTabs",
|
|
511
|
-
"tree": "SD8qLW_tree",
|
|
512
|
-
"menuPop": "SD8qLW_menuPop",
|
|
513
|
-
"bgPreview": "SD8qLW_bgPreview",
|
|
514
|
-
"filterClear": "SD8qLW_filterClear",
|
|
515
|
-
"overlay": "SD8qLW_overlay",
|
|
516
|
-
"fbMore": "SD8qLW_fbMore",
|
|
517
|
-
"pullGroup": "SD8qLW_pullGroup",
|
|
518
|
-
"sideTab": "SD8qLW_sideTab",
|
|
519
|
-
"fbCommitLine": "SD8qLW_fbCommitLine",
|
|
520
|
-
"elide": "SD8qLW_elide",
|
|
521
|
-
"commitPopTop": "SD8qLW_commitPopTop",
|
|
522
|
-
"paneHead": "SD8qLW_paneHead",
|
|
523
|
-
"commitMeta": "SD8qLW_commitMeta",
|
|
524
|
-
"compareBar": "SD8qLW_compareBar",
|
|
525
|
-
"headerLeft": "SD8qLW_headerLeft",
|
|
526
|
-
"filterChipLabel": "SD8qLW_filterChipLabel",
|
|
527
|
-
"funnelTab": "SD8qLW_funnelTab",
|
|
528
|
-
"sliderValue": "SD8qLW_sliderValue",
|
|
529
|
-
"refRow": "SD8qLW_refRow",
|
|
530
|
-
"compareArrow": "SD8qLW_compareArrow",
|
|
531
|
-
"line": "SD8qLW_line",
|
|
532
|
-
"commitPopBody": "SD8qLW_commitPopBody",
|
|
533
|
-
"filterChip": "SD8qLW_filterChip",
|
|
534
|
-
"headerBranch": "SD8qLW_headerBranch",
|
|
535
|
-
"commitAuthor": "SD8qLW_commitAuthor",
|
|
536
|
-
"refFoot": "SD8qLW_refFoot",
|
|
537
|
-
"sideNotice": "SD8qLW_sideNotice",
|
|
538
|
-
"checkMark": "SD8qLW_checkMark",
|
|
539
|
-
"funnelBoundKey": "SD8qLW_funnelBoundKey",
|
|
540
|
-
"checkMarkPartial": "SD8qLW_checkMarkPartial",
|
|
541
|
-
"commitStaged": "SD8qLW_commitStaged",
|
|
542
|
-
"funnelPresetActive": "SD8qLW_funnelPresetActive",
|
|
543
|
-
"fbRowActive": "SD8qLW_fbRowActive",
|
|
544
496
|
"btnIcon": "SD8qLW_btnIcon",
|
|
545
|
-
"
|
|
546
|
-
"
|
|
547
|
-
"
|
|
548
|
-
"
|
|
549
|
-
"treeEmpty": "SD8qLW_treeEmpty",
|
|
550
|
-
"tabs": "SD8qLW_tabs",
|
|
551
|
-
"commitSubject": "SD8qLW_commitSubject",
|
|
552
|
-
"opBanner": "SD8qLW_opBanner",
|
|
553
|
-
"fbMain": "SD8qLW_fbMain",
|
|
554
|
-
"segment": "SD8qLW_segment",
|
|
555
|
-
"refRowName": "SD8qLW_refRowName",
|
|
556
|
-
"treeIconGlyph": "SD8qLW_treeIconGlyph",
|
|
557
|
-
"fileDiscard": "SD8qLW_fileDiscard",
|
|
497
|
+
"cardGlyph": "SD8qLW_cardGlyph",
|
|
498
|
+
"commitPopMeta": "SD8qLW_commitPopMeta",
|
|
499
|
+
"cal": "SD8qLW_cal",
|
|
500
|
+
"imgCaption": "SD8qLW_imgCaption",
|
|
558
501
|
"fbList": "SD8qLW_fbList",
|
|
559
|
-
"
|
|
560
|
-
"
|
|
561
|
-
"
|
|
562
|
-
"
|
|
563
|
-
"
|
|
564
|
-
"
|
|
565
|
-
"funnelBoundBtnActive": "SD8qLW_funnelBoundBtnActive",
|
|
566
|
-
"commitWhen": "SD8qLW_commitWhen",
|
|
567
|
-
"empty": "SD8qLW_empty",
|
|
568
|
-
"fileLi": "SD8qLW_fileLi",
|
|
569
|
-
"calHead": "SD8qLW_calHead",
|
|
570
|
-
"gsFade": "SD8qLW_gsFade",
|
|
571
|
-
"funnelChevron": "SD8qLW_funnelChevron",
|
|
572
|
-
"diffSpacer": "SD8qLW_diffSpacer",
|
|
573
|
-
"fbCommit": "SD8qLW_fbCommit",
|
|
574
|
-
"cardBehind": "SD8qLW_cardBehind",
|
|
575
|
-
"headerPicker": "SD8qLW_headerPicker",
|
|
576
|
-
"paneDividerY": "SD8qLW_paneDividerY",
|
|
577
|
-
"cardWt": "SD8qLW_cardWt",
|
|
578
|
-
"diffScroll": "SD8qLW_diffScroll",
|
|
579
|
-
"refRowSpacer": "SD8qLW_refRowSpacer",
|
|
580
|
-
"sideNavCount": "SD8qLW_sideNavCount",
|
|
581
|
-
"commitSubjectRow": "SD8qLW_commitSubjectRow",
|
|
582
|
-
"chipDark": "SD8qLW_chipDark",
|
|
583
|
-
"cardFiles": "SD8qLW_cardFiles",
|
|
584
|
-
"paneDivider": "SD8qLW_paneDivider",
|
|
585
|
-
"themeRowSplit": "SD8qLW_themeRowSplit",
|
|
586
|
-
"pathChildren": "SD8qLW_pathChildren",
|
|
587
|
-
"fbCommitHash": "SD8qLW_fbCommitHash",
|
|
588
|
-
"header": "SD8qLW_header",
|
|
589
|
-
"sideColGridBlame": "SD8qLW_sideColGridBlame",
|
|
590
|
-
"paletteRowActive": "SD8qLW_paletteRowActive",
|
|
591
|
-
"swatch": "SD8qLW_swatch",
|
|
592
|
-
"fbHeader": "SD8qLW_fbHeader",
|
|
593
|
-
"commitTop": "SD8qLW_commitTop",
|
|
594
|
-
"fbDirName": "SD8qLW_fbDirName",
|
|
595
|
-
"chipSystem": "SD8qLW_chipSystem",
|
|
596
|
-
"sliderRow": "SD8qLW_sliderRow",
|
|
597
|
-
"miniBtn": "SD8qLW_miniBtn",
|
|
598
|
-
"commitRow": "SD8qLW_commitRow",
|
|
502
|
+
"sidePane": "SD8qLW_sidePane",
|
|
503
|
+
"treeActions": "SD8qLW_treeActions",
|
|
504
|
+
"overlay": "SD8qLW_overlay",
|
|
505
|
+
"funnel": "SD8qLW_funnel",
|
|
506
|
+
"funnelTabCount": "SD8qLW_funnelTabCount",
|
|
507
|
+
"compareArrow": "SD8qLW_compareArrow",
|
|
599
508
|
"funnelName": "SD8qLW_funnelName",
|
|
600
|
-
"
|
|
601
|
-
"
|
|
602
|
-
"
|
|
509
|
+
"sideCols": "SD8qLW_sideCols",
|
|
510
|
+
"funnelSearch": "SD8qLW_funnelSearch",
|
|
511
|
+
"treeIcon": "SD8qLW_treeIcon",
|
|
512
|
+
"btnClose": "SD8qLW_btnClose",
|
|
513
|
+
"bgEmpty": "SD8qLW_bgEmpty",
|
|
514
|
+
"treeDirCounts": "SD8qLW_treeDirCounts",
|
|
515
|
+
"layoutGlyph": "SD8qLW_layoutGlyph",
|
|
516
|
+
"menuPop": "SD8qLW_menuPop",
|
|
517
|
+
"refButton": "SD8qLW_refButton",
|
|
518
|
+
"funnelPresets": "SD8qLW_funnelPresets",
|
|
519
|
+
"bodyRow": "SD8qLW_bodyRow",
|
|
520
|
+
"sideNavCount": "SD8qLW_sideNavCount",
|
|
521
|
+
"treeIconDown": "SD8qLW_treeIconDown",
|
|
522
|
+
"layoutSwitch": "SD8qLW_layoutSwitch",
|
|
523
|
+
"chevronOpen": "SD8qLW_chevronOpen",
|
|
524
|
+
"lineContext": "SD8qLW_lineContext",
|
|
525
|
+
"calOut": "SD8qLW_calOut",
|
|
603
526
|
"sideEditCell": "SD8qLW_sideEditCell",
|
|
604
|
-
"
|
|
527
|
+
"syncLevel": "SD8qLW_syncLevel",
|
|
528
|
+
"fbCommitHash": "SD8qLW_fbCommitHash",
|
|
605
529
|
"layoutButton": "SD8qLW_layoutButton",
|
|
530
|
+
"swatch": "SD8qLW_swatch",
|
|
531
|
+
"diffPre": "SD8qLW_diffPre",
|
|
532
|
+
"lnOld": "SD8qLW_lnOld",
|
|
533
|
+
"lnNew": "SD8qLW_lnNew",
|
|
534
|
+
"sideBanner": "SD8qLW_sideBanner",
|
|
535
|
+
"elideHead": "SD8qLW_elideHead",
|
|
536
|
+
"headerLeft": "SD8qLW_headerLeft",
|
|
537
|
+
"paneDividerY": "SD8qLW_paneDividerY",
|
|
538
|
+
"sideNum": "SD8qLW_sideNum",
|
|
539
|
+
"pathDirGlyph": "SD8qLW_pathDirGlyph",
|
|
540
|
+
"filterChips": "SD8qLW_filterChips",
|
|
541
|
+
"diffScroll": "SD8qLW_diffScroll",
|
|
606
542
|
"paletteRow": "SD8qLW_paletteRow",
|
|
607
|
-
"
|
|
608
|
-
"
|
|
609
|
-
"
|
|
610
|
-
"
|
|
611
|
-
"
|
|
612
|
-
"
|
|
613
|
-
"
|
|
614
|
-
"fileCountDel": "SD8qLW_fileCountDel",
|
|
615
|
-
"btnBehind": "SD8qLW_btnBehind",
|
|
616
|
-
"fbCommitWhen": "SD8qLW_fbCommitWhen",
|
|
617
|
-
"funnelPresets": "SD8qLW_funnelPresets",
|
|
618
|
-
"treeFilterClear": "SD8qLW_treeFilterClear",
|
|
619
|
-
"refEmpty": "SD8qLW_refEmpty",
|
|
620
|
-
"body": "SD8qLW_body",
|
|
621
|
-
"miniBtnPrimary": "SD8qLW_miniBtnPrimary",
|
|
622
|
-
"commit": "SD8qLW_commit",
|
|
623
|
-
"blockBtnDanger": "SD8qLW_blockBtnDanger",
|
|
624
|
-
"layoutGlyph": "SD8qLW_layoutGlyph",
|
|
625
|
-
"refGroup": "SD8qLW_refGroup",
|
|
626
|
-
"commitBtn": "SD8qLW_commitBtn",
|
|
627
|
-
"syncBar": "SD8qLW_syncBar",
|
|
628
|
-
"lineContext": "SD8qLW_lineContext",
|
|
629
|
-
"commitsFoot": "SD8qLW_commitsFoot",
|
|
630
|
-
"signAdd": "SD8qLW_signAdd",
|
|
631
|
-
"cardDetached": "SD8qLW_cardDetached",
|
|
632
|
-
"treeIconOn": "SD8qLW_treeIconOn",
|
|
633
|
-
"confirmScrim": "SD8qLW_confirmScrim",
|
|
634
|
-
"sideSaveReady": "SD8qLW_sideSaveReady",
|
|
635
|
-
"headerTotalsAdd": "SD8qLW_headerTotalsAdd",
|
|
636
|
-
"funnelFoot": "SD8qLW_funnelFoot",
|
|
637
|
-
"wordAdd": "SD8qLW_wordAdd",
|
|
638
|
-
"confirmBox": "SD8qLW_confirmBox",
|
|
543
|
+
"sideCodeSame": "SD8qLW_sideCodeSame",
|
|
544
|
+
"commitsPane": "SD8qLW_commitsPane",
|
|
545
|
+
"resizer": "SD8qLW_resizer",
|
|
546
|
+
"btn": "SD8qLW_btn",
|
|
547
|
+
"chipSystem": "SD8qLW_chipSystem",
|
|
548
|
+
"sliderValue": "SD8qLW_sliderValue",
|
|
549
|
+
"themeDirty": "SD8qLW_themeDirty",
|
|
639
550
|
"layoutButtonOn": "SD8qLW_layoutButtonOn",
|
|
640
|
-
"
|
|
641
|
-
"
|
|
642
|
-
"stDeleted": "SD8qLW_stDeleted",
|
|
643
|
-
"commitMessage": "SD8qLW_commitMessage",
|
|
644
|
-
"funnelPop": "SD8qLW_funnelPop",
|
|
551
|
+
"fileStatus": "SD8qLW_fileStatus",
|
|
552
|
+
"commitBox": "SD8qLW_commitBox",
|
|
645
553
|
"sideNav": "SD8qLW_sideNav",
|
|
646
|
-
"
|
|
647
|
-
"
|
|
648
|
-
"
|
|
649
|
-
"
|
|
650
|
-
"
|
|
651
|
-
"
|
|
652
|
-
"
|
|
653
|
-
"fileCountAdd": "SD8qLW_fileCountAdd",
|
|
654
|
-
"sideBlockHotLast": "SD8qLW_sideBlockHotLast",
|
|
554
|
+
"fbMain": "SD8qLW_fbMain",
|
|
555
|
+
"chipDark": "SD8qLW_chipDark",
|
|
556
|
+
"sideColGrid": "SD8qLW_sideColGrid",
|
|
557
|
+
"sideColGridWrap": "SD8qLW_sideColGridWrap",
|
|
558
|
+
"segmentActive": "SD8qLW_segmentActive",
|
|
559
|
+
"syncUpstream": "SD8qLW_syncUpstream",
|
|
560
|
+
"treeDir": "SD8qLW_treeDir",
|
|
655
561
|
"fbBody": "SD8qLW_fbBody",
|
|
656
|
-
"
|
|
657
|
-
"
|
|
658
|
-
"
|
|
659
|
-
"
|
|
660
|
-
"
|
|
661
|
-
"tabActive": "SD8qLW_tabActive",
|
|
662
|
-
"segmentChip": "SD8qLW_segmentChip",
|
|
562
|
+
"commitMessage": "SD8qLW_commitMessage",
|
|
563
|
+
"diffPane": "SD8qLW_diffPane",
|
|
564
|
+
"miniBtnPrimary": "SD8qLW_miniBtnPrimary",
|
|
565
|
+
"pathNode": "SD8qLW_pathNode",
|
|
566
|
+
"compareBar": "SD8qLW_compareBar",
|
|
663
567
|
"wtCurrent": "SD8qLW_wtCurrent",
|
|
664
|
-
"
|
|
665
|
-
"
|
|
666
|
-
"
|
|
667
|
-
"
|
|
668
|
-
"
|
|
669
|
-
"
|
|
670
|
-
"
|
|
671
|
-
"
|
|
672
|
-
"
|
|
568
|
+
"calTitle": "SD8qLW_calTitle",
|
|
569
|
+
"sideColRight": "SD8qLW_sideColRight",
|
|
570
|
+
"cardAhead": "SD8qLW_cardAhead",
|
|
571
|
+
"fbCommitWho": "SD8qLW_fbCommitWho",
|
|
572
|
+
"cardWt": "SD8qLW_cardWt",
|
|
573
|
+
"sideActions": "SD8qLW_sideActions",
|
|
574
|
+
"fileDiscard": "SD8qLW_fileDiscard",
|
|
575
|
+
"sideColGridBlame": "SD8qLW_sideColGridBlame",
|
|
576
|
+
"resizerActive": "SD8qLW_resizerActive",
|
|
577
|
+
"sideRails": "SD8qLW_sideRails",
|
|
578
|
+
"sideNotice": "SD8qLW_sideNotice",
|
|
579
|
+
"fbNote": "SD8qLW_fbNote",
|
|
580
|
+
"headerBranch": "SD8qLW_headerBranch",
|
|
581
|
+
"treeFilter": "SD8qLW_treeFilter",
|
|
582
|
+
"funnelBoundBtnActive": "SD8qLW_funnelBoundBtnActive",
|
|
583
|
+
"funnelButton": "SD8qLW_funnelButton",
|
|
584
|
+
"body": "SD8qLW_body",
|
|
585
|
+
"scopeBtn": "SD8qLW_scopeBtn",
|
|
586
|
+
"commits": "SD8qLW_commits",
|
|
587
|
+
"funnelBoundVal": "SD8qLW_funnelBoundVal",
|
|
588
|
+
"sideRail": "SD8qLW_sideRail",
|
|
673
589
|
"signDel": "SD8qLW_signDel",
|
|
674
|
-
"commitsSentinel": "SD8qLW_commitsSentinel",
|
|
675
|
-
"sideCodeSame": "SD8qLW_sideCodeSame",
|
|
676
|
-
"sideBlockHotFirst": "SD8qLW_sideBlockHotFirst",
|
|
677
|
-
"sideActionsAdjacent": "SD8qLW_sideActionsAdjacent",
|
|
678
|
-
"funnelBoundValSet": "SD8qLW_funnelBoundValSet",
|
|
679
|
-
"headerViewRef": "SD8qLW_headerViewRef",
|
|
680
|
-
"commitHasBody": "SD8qLW_commitHasBody",
|
|
681
|
-
"gutter": "SD8qLW_gutter",
|
|
682
590
|
"checkBox": "SD8qLW_checkBox",
|
|
683
|
-
"
|
|
684
|
-
"
|
|
685
|
-
"
|
|
686
|
-
"
|
|
591
|
+
"sideRailSpan": "SD8qLW_sideRailSpan",
|
|
592
|
+
"gsFade": "SD8qLW_gsFade",
|
|
593
|
+
"funnelCount": "SD8qLW_funnelCount",
|
|
594
|
+
"funnelRow": "SD8qLW_funnelRow",
|
|
595
|
+
"treeIconGlyph": "SD8qLW_treeIconGlyph",
|
|
596
|
+
"fbMore": "SD8qLW_fbMore",
|
|
597
|
+
"treeFilterInput": "SD8qLW_treeFilterInput",
|
|
598
|
+
"paneDivider": "SD8qLW_paneDivider",
|
|
599
|
+
"funnelBoundBtn": "SD8qLW_funnelBoundBtn",
|
|
600
|
+
"commitPopBody": "SD8qLW_commitPopBody",
|
|
601
|
+
"diffPreWrap": "SD8qLW_diffPreWrap",
|
|
602
|
+
"treeLabel": "SD8qLW_treeLabel",
|
|
603
|
+
"miniBtn": "SD8qLW_miniBtn",
|
|
604
|
+
"themeLabel": "SD8qLW_themeLabel",
|
|
605
|
+
"themeRail": "SD8qLW_themeRail",
|
|
606
|
+
"sideArmable": "SD8qLW_sideArmable",
|
|
607
|
+
"refEmpty": "SD8qLW_refEmpty",
|
|
608
|
+
"file": "SD8qLW_file",
|
|
687
609
|
"funnelButtonActive": "SD8qLW_funnelButtonActive",
|
|
688
|
-
"
|
|
689
|
-
"
|
|
610
|
+
"opBannerOk": "SD8qLW_opBannerOk",
|
|
611
|
+
"header": "SD8qLW_header",
|
|
612
|
+
"sideCode": "SD8qLW_sideCode",
|
|
690
613
|
"headerTotalsDel": "SD8qLW_headerTotalsDel",
|
|
691
|
-
"
|
|
692
|
-
"
|
|
693
|
-
"
|
|
694
|
-
"fbCommitHint": "SD8qLW_fbCommitHint",
|
|
695
|
-
"imgCaption": "SD8qLW_imgCaption",
|
|
696
|
-
"cardDeleted": "SD8qLW_cardDeleted",
|
|
697
|
-
"treeCol": "SD8qLW_treeCol",
|
|
698
|
-
"lineDel": "SD8qLW_lineDel",
|
|
699
|
-
"sideArmable": "SD8qLW_sideArmable",
|
|
700
|
-
"scopeBtn": "SD8qLW_scopeBtn",
|
|
701
|
-
"imgStage": "SD8qLW_imgStage",
|
|
702
|
-
"drawer": "SD8qLW_drawer",
|
|
703
|
-
"card": "SD8qLW_card",
|
|
704
|
-
"refSearch": "SD8qLW_refSearch",
|
|
614
|
+
"fbCommitWhat": "SD8qLW_fbCommitWhat",
|
|
615
|
+
"sideRailsOn": "SD8qLW_sideRailsOn",
|
|
616
|
+
"calWeek": "SD8qLW_calWeek",
|
|
705
617
|
"treeLead": "SD8qLW_treeLead",
|
|
706
|
-
"
|
|
618
|
+
"refRowSpacer": "SD8qLW_refRowSpacer",
|
|
619
|
+
"code": "SD8qLW_code",
|
|
620
|
+
"fbCommitHint": "SD8qLW_fbCommitHint",
|
|
621
|
+
"settingsPop": "SD8qLW_settingsPop",
|
|
622
|
+
"treeRow": "SD8qLW_treeRow",
|
|
623
|
+
"blockBtnDanger": "SD8qLW_blockBtnDanger",
|
|
624
|
+
"funnelTabs": "SD8qLW_funnelTabs",
|
|
625
|
+
"fileCountAdd": "SD8qLW_fileCountAdd",
|
|
626
|
+
"sideBlockHotFirst": "SD8qLW_sideBlockHotFirst",
|
|
627
|
+
"sideBlockHotLast": "SD8qLW_sideBlockHotLast",
|
|
628
|
+
"paneDividerActive": "SD8qLW_paneDividerActive",
|
|
629
|
+
"filterChipLabel": "SD8qLW_filterChipLabel",
|
|
630
|
+
"checkMark": "SD8qLW_checkMark",
|
|
631
|
+
"filterChipRemove": "SD8qLW_filterChipRemove",
|
|
632
|
+
"imgPane": "SD8qLW_imgPane",
|
|
633
|
+
"sideCellBlock": "SD8qLW_sideCellBlock",
|
|
634
|
+
"sideCol": "SD8qLW_sideCol",
|
|
635
|
+
"commitSubjectRow": "SD8qLW_commitSubjectRow",
|
|
636
|
+
"fbFileName": "SD8qLW_fbFileName",
|
|
637
|
+
"refList": "SD8qLW_refList",
|
|
638
|
+
"cardDetached": "SD8qLW_cardDetached",
|
|
639
|
+
"cardSep": "SD8qLW_cardSep",
|
|
640
|
+
"calMark": "SD8qLW_calMark",
|
|
641
|
+
"stRenamed": "SD8qLW_stRenamed",
|
|
707
642
|
"filePath": "SD8qLW_filePath",
|
|
708
|
-
"
|
|
709
|
-
"
|
|
710
|
-
"
|
|
643
|
+
"funnelFoot": "SD8qLW_funnelFoot",
|
|
644
|
+
"fileLi": "SD8qLW_fileLi",
|
|
645
|
+
"headerTotalsDim": "SD8qLW_headerTotalsDim",
|
|
646
|
+
"sideColWrap": "SD8qLW_sideColWrap",
|
|
711
647
|
"stModified": "SD8qLW_stModified",
|
|
712
|
-
"
|
|
713
|
-
"
|
|
714
|
-
"
|
|
715
|
-
"
|
|
648
|
+
"fbHeader": "SD8qLW_fbHeader",
|
|
649
|
+
"cardFiles": "SD8qLW_cardFiles",
|
|
650
|
+
"treeEmpty": "SD8qLW_treeEmpty",
|
|
651
|
+
"commitWhen": "SD8qLW_commitWhen",
|
|
652
|
+
"fileBinary": "SD8qLW_fileBinary",
|
|
653
|
+
"commitBtn": "SD8qLW_commitBtn",
|
|
654
|
+
"refValue": "SD8qLW_refValue",
|
|
716
655
|
"funnelPane": "SD8qLW_funnelPane",
|
|
717
|
-
"
|
|
656
|
+
"commitFilter": "SD8qLW_commitFilter",
|
|
657
|
+
"commitPopSubject": "SD8qLW_commitPopSubject",
|
|
658
|
+
"commitAuthor": "SD8qLW_commitAuthor",
|
|
659
|
+
"fileCountDel": "SD8qLW_fileCountDel",
|
|
660
|
+
"confirmBox": "SD8qLW_confirmBox",
|
|
661
|
+
"confirmBody": "SD8qLW_confirmBody",
|
|
662
|
+
"refSearch": "SD8qLW_refSearch",
|
|
663
|
+
"fbSearch": "SD8qLW_fbSearch",
|
|
664
|
+
"opBannerBad": "SD8qLW_opBannerBad",
|
|
665
|
+
"treeIconOn": "SD8qLW_treeIconOn",
|
|
666
|
+
"elide": "SD8qLW_elide",
|
|
667
|
+
"headerRight": "SD8qLW_headerRight",
|
|
668
|
+
"sideScroll": "SD8qLW_sideScroll",
|
|
669
|
+
"tabActive": "SD8qLW_tabActive",
|
|
670
|
+
"themeNote": "SD8qLW_themeNote",
|
|
718
671
|
"btnDanger": "SD8qLW_btnDanger",
|
|
719
|
-
"
|
|
720
|
-
"
|
|
721
|
-
"
|
|
722
|
-
"
|
|
672
|
+
"drawer": "SD8qLW_drawer",
|
|
673
|
+
"fbCommitLine": "SD8qLW_fbCommitLine",
|
|
674
|
+
"funnelFootCount": "SD8qLW_funnelFootCount",
|
|
675
|
+
"refFoot": "SD8qLW_refFoot",
|
|
676
|
+
"paletteRowActive": "SD8qLW_paletteRowActive",
|
|
677
|
+
"tabs": "SD8qLW_tabs",
|
|
723
678
|
"stAdded": "SD8qLW_stAdded",
|
|
724
|
-
"
|
|
725
|
-
"
|
|
726
|
-
"
|
|
727
|
-
"
|
|
728
|
-
"
|
|
729
|
-
"
|
|
730
|
-
"
|
|
731
|
-
"funnelMore": "SD8qLW_funnelMore",
|
|
732
|
-
"headerView": "SD8qLW_headerView",
|
|
733
|
-
"sideTabActive": "SD8qLW_sideTabActive",
|
|
734
|
-
"commitBox": "SD8qLW_commitBox",
|
|
735
|
-
"commitLead": "SD8qLW_commitLead",
|
|
736
|
-
"scopeBtnActive": "SD8qLW_scopeBtnActive",
|
|
679
|
+
"refRowName": "SD8qLW_refRowName",
|
|
680
|
+
"theme": "SD8qLW_theme",
|
|
681
|
+
"commitRow": "SD8qLW_commitRow",
|
|
682
|
+
"syncSpacer": "SD8qLW_syncSpacer",
|
|
683
|
+
"commitHash": "SD8qLW_commitHash",
|
|
684
|
+
"treeDirLi": "SD8qLW_treeDirLi",
|
|
685
|
+
"btnCount": "SD8qLW_btnCount",
|
|
737
686
|
"commitRefMore": "SD8qLW_commitRefMore",
|
|
738
|
-
"
|
|
739
|
-
"
|
|
740
|
-
"
|
|
741
|
-
"
|
|
742
|
-
"segmentActive": "SD8qLW_segmentActive",
|
|
743
|
-
"code": "SD8qLW_code",
|
|
744
|
-
"lineHunk": "SD8qLW_lineHunk",
|
|
745
|
-
"treeFilter": "SD8qLW_treeFilter",
|
|
746
|
-
"resizerActive": "SD8qLW_resizerActive",
|
|
687
|
+
"elideTail": "SD8qLW_elideTail",
|
|
688
|
+
"tree": "SD8qLW_tree",
|
|
689
|
+
"headerTotals": "SD8qLW_headerTotals",
|
|
690
|
+
"treeSub": "SD8qLW_treeSub",
|
|
747
691
|
"blockBar": "SD8qLW_blockBar",
|
|
692
|
+
"treeTools": "SD8qLW_treeTools",
|
|
693
|
+
"diffNav": "SD8qLW_diffNav",
|
|
694
|
+
"commitsFoot": "SD8qLW_commitsFoot",
|
|
695
|
+
"sideNumDel": "SD8qLW_sideNumDel",
|
|
696
|
+
"sideBannerTitle": "SD8qLW_sideBannerTitle",
|
|
697
|
+
"fileActive": "SD8qLW_fileActive",
|
|
698
|
+
"card": "SD8qLW_card",
|
|
699
|
+
"commitsSentinel": "SD8qLW_commitsSentinel",
|
|
700
|
+
"refGroup": "SD8qLW_refGroup",
|
|
701
|
+
"calIn": "SD8qLW_calIn",
|
|
702
|
+
"sideRailRight": "SD8qLW_sideRailRight",
|
|
703
|
+
"funnelBoundRow": "SD8qLW_funnelBoundRow",
|
|
704
|
+
"refRowActive": "SD8qLW_refRowActive",
|
|
705
|
+
"calHead": "SD8qLW_calHead",
|
|
706
|
+
"funnelBoundKey": "SD8qLW_funnelBoundKey",
|
|
707
|
+
"filterChip": "SD8qLW_filterChip",
|
|
708
|
+
"fbCommitWhen": "SD8qLW_fbCommitWhen",
|
|
709
|
+
"treeWrap": "SD8qLW_treeWrap",
|
|
710
|
+
"cardBranchName": "SD8qLW_cardBranchName",
|
|
711
|
+
"calNav": "SD8qLW_calNav",
|
|
712
|
+
"calToday": "SD8qLW_calToday",
|
|
713
|
+
"tab": "SD8qLW_tab",
|
|
714
|
+
"segmented": "SD8qLW_segmented",
|
|
715
|
+
"sideNumAdd": "SD8qLW_sideNumAdd",
|
|
716
|
+
"opBanner": "SD8qLW_opBanner",
|
|
717
|
+
"commitStaged": "SD8qLW_commitStaged",
|
|
718
|
+
"lineAdd": "SD8qLW_lineAdd",
|
|
719
|
+
"calGrid": "SD8qLW_calGrid",
|
|
720
|
+
"paneHead": "SD8qLW_paneHead",
|
|
721
|
+
"btnBehind": "SD8qLW_btnBehind",
|
|
722
|
+
"fbRowIgnored": "SD8qLW_fbRowIgnored",
|
|
723
|
+
"commitPopTop": "SD8qLW_commitPopTop",
|
|
748
724
|
"refCaret": "SD8qLW_refCaret",
|
|
749
|
-
"
|
|
750
|
-
"
|
|
751
|
-
"
|
|
752
|
-
"
|
|
753
|
-
"
|
|
754
|
-
"
|
|
755
|
-
"
|
|
756
|
-
"
|
|
757
|
-
"
|
|
758
|
-
"
|
|
759
|
-
"
|
|
760
|
-
"
|
|
725
|
+
"fbDirName": "SD8qLW_fbDirName",
|
|
726
|
+
"cardBehind": "SD8qLW_cardBehind",
|
|
727
|
+
"commitLine": "SD8qLW_commitLine",
|
|
728
|
+
"scopeHint": "SD8qLW_scopeHint",
|
|
729
|
+
"fbTree": "SD8qLW_fbTree",
|
|
730
|
+
"funnelList": "SD8qLW_funnelList",
|
|
731
|
+
"commitTop": "SD8qLW_commitTop",
|
|
732
|
+
"themeGroup": "SD8qLW_themeGroup",
|
|
733
|
+
"funnelPop": "SD8qLW_funnelPop",
|
|
734
|
+
"wordDel": "SD8qLW_wordDel",
|
|
735
|
+
"sliderRow": "SD8qLW_sliderRow",
|
|
736
|
+
"commitSubject": "SD8qLW_commitSubject",
|
|
737
|
+
"sideBlockHot": "SD8qLW_sideBlockHot",
|
|
761
738
|
"checkMarkOn": "SD8qLW_checkMarkOn",
|
|
762
|
-
"
|
|
763
|
-
"
|
|
764
|
-
"
|
|
765
|
-
"
|
|
766
|
-
"
|
|
767
|
-
"
|
|
768
|
-
"
|
|
739
|
+
"pathFileGlyph": "SD8qLW_pathFileGlyph",
|
|
740
|
+
"checkMarkPartial": "SD8qLW_checkMarkPartial",
|
|
741
|
+
"treeDirActive": "SD8qLW_treeDirActive",
|
|
742
|
+
"gutter": "SD8qLW_gutter",
|
|
743
|
+
"fbCommit": "SD8qLW_fbCommit",
|
|
744
|
+
"sideTab": "SD8qLW_sideTab",
|
|
745
|
+
"pathChildren": "SD8qLW_pathChildren",
|
|
746
|
+
"cssArea": "SD8qLW_cssArea",
|
|
747
|
+
"stDeleted": "SD8qLW_stDeleted",
|
|
748
|
+
"empty": "SD8qLW_empty",
|
|
749
|
+
"btnIconOn": "SD8qLW_btnIconOn",
|
|
750
|
+
"imgStage": "SD8qLW_imgStage",
|
|
751
|
+
"btnAhead": "SD8qLW_btnAhead",
|
|
752
|
+
"chipLight": "SD8qLW_chipLight",
|
|
753
|
+
"commit": "SD8qLW_commit",
|
|
754
|
+
"scopeRow": "SD8qLW_scopeRow",
|
|
755
|
+
"funnelTab": "SD8qLW_funnelTab",
|
|
769
756
|
"overlayMax": "SD8qLW_overlayMax",
|
|
770
|
-
"
|
|
771
|
-
"
|
|
772
|
-
"
|
|
773
|
-
"sideSpacer": "SD8qLW_sideSpacer",
|
|
774
|
-
"btn": "SD8qLW_btn",
|
|
775
|
-
"opBannerOk": "SD8qLW_opBannerOk",
|
|
776
|
-
"commitCopy": "SD8qLW_commitCopy",
|
|
777
|
-
"sideCurrentBlockActions": "SD8qLW_sideCurrentBlockActions",
|
|
778
|
-
"cardGlyph": "SD8qLW_cardGlyph",
|
|
779
|
-
"sideBlockHot": "SD8qLW_sideBlockHot",
|
|
780
|
-
"theme": "SD8qLW_theme",
|
|
781
|
-
"pathDirGlyph": "SD8qLW_pathDirGlyph",
|
|
782
|
-
"cardBranchName": "SD8qLW_cardBranchName",
|
|
757
|
+
"crMark": "SD8qLW_crMark",
|
|
758
|
+
"fbRowActive": "SD8qLW_fbRowActive",
|
|
759
|
+
"treeFilterClear": "SD8qLW_treeFilterClear",
|
|
783
760
|
"cardBranch": "SD8qLW_cardBranch",
|
|
784
|
-
"
|
|
785
|
-
"
|
|
786
|
-
"
|
|
787
|
-
"
|
|
788
|
-
"
|
|
761
|
+
"syncBar": "SD8qLW_syncBar",
|
|
762
|
+
"segment": "SD8qLW_segment",
|
|
763
|
+
"refPicker": "SD8qLW_refPicker",
|
|
764
|
+
"refPop": "SD8qLW_refPop",
|
|
765
|
+
"paneTitle": "SD8qLW_paneTitle",
|
|
766
|
+
"commitLead": "SD8qLW_commitLead",
|
|
767
|
+
"refLabel": "SD8qLW_refLabel",
|
|
789
768
|
"treeDirCount": "SD8qLW_treeDirCount",
|
|
790
|
-
"
|
|
791
|
-
"
|
|
792
|
-
"
|
|
793
|
-
"
|
|
794
|
-
"fbRow": "SD8qLW_fbRow",
|
|
795
|
-
"treeSub": "SD8qLW_treeSub",
|
|
796
|
-
"funnelTabCount": "SD8qLW_funnelTabCount",
|
|
797
|
-
"sideCode": "SD8qLW_sideCode",
|
|
798
|
-
"sideCellBlock": "SD8qLW_sideCellBlock",
|
|
769
|
+
"sideSaveReady": "SD8qLW_sideSaveReady",
|
|
770
|
+
"confirmScrim": "SD8qLW_confirmScrim",
|
|
771
|
+
"sideFlow": "SD8qLW_sideFlow",
|
|
772
|
+
"imgShot": "SD8qLW_imgShot",
|
|
799
773
|
"cardAdded": "SD8qLW_cardAdded",
|
|
800
|
-
"
|
|
801
|
-
"
|
|
802
|
-
"
|
|
774
|
+
"headerPathMain": "SD8qLW_headerPathMain",
|
|
775
|
+
"treeDirName": "SD8qLW_treeDirName",
|
|
776
|
+
"funnelChevron": "SD8qLW_funnelChevron",
|
|
777
|
+
"commitMeta": "SD8qLW_commitMeta",
|
|
778
|
+
"confirmTitle": "SD8qLW_confirmTitle",
|
|
779
|
+
"filterClear": "SD8qLW_filterClear",
|
|
780
|
+
"stUntracked": "SD8qLW_stUntracked",
|
|
781
|
+
"wordAdd": "SD8qLW_wordAdd",
|
|
782
|
+
"headerPicker": "SD8qLW_headerPicker",
|
|
783
|
+
"bgPreview": "SD8qLW_bgPreview",
|
|
784
|
+
"funnelMore": "SD8qLW_funnelMore",
|
|
785
|
+
"renameLine": "SD8qLW_renameLine",
|
|
786
|
+
"sideActionsAdjacent": "SD8qLW_sideActionsAdjacent",
|
|
787
|
+
"sideBannerActs": "SD8qLW_sideBannerActs",
|
|
788
|
+
"funnelFootClear": "SD8qLW_funnelFootClear",
|
|
789
|
+
"commitPop": "SD8qLW_commitPop",
|
|
790
|
+
"sideTabActive": "SD8qLW_sideTabActive",
|
|
791
|
+
"pullGroup": "SD8qLW_pullGroup",
|
|
792
|
+
"diffSpacer": "SD8qLW_diffSpacer",
|
|
793
|
+
"headerDetached": "SD8qLW_headerDetached",
|
|
794
|
+
"funnelCaption": "SD8qLW_funnelCaption",
|
|
795
|
+
"refRow": "SD8qLW_refRow",
|
|
796
|
+
"funnelTabActive": "SD8qLW_funnelTabActive",
|
|
797
|
+
"confirmActions": "SD8qLW_confirmActions",
|
|
798
|
+
"commitAmend": "SD8qLW_commitAmend",
|
|
799
|
+
"sideCodeDel": "SD8qLW_sideCodeDel",
|
|
800
|
+
"sideCurrentBlockActions": "SD8qLW_sideCurrentBlockActions",
|
|
801
|
+
"line": "SD8qLW_line",
|
|
802
|
+
"funnelPreset": "SD8qLW_funnelPreset",
|
|
803
|
+
"funnelBoundRows": "SD8qLW_funnelBoundRows",
|
|
804
|
+
"funnelFootCountOn": "SD8qLW_funnelFootCountOn",
|
|
805
|
+
"blockBtn": "SD8qLW_blockBtn",
|
|
806
|
+
"funnelBoundValSet": "SD8qLW_funnelBoundValSet",
|
|
807
|
+
"sideSpacer": "SD8qLW_sideSpacer",
|
|
808
|
+
"segmentChip": "SD8qLW_segmentChip",
|
|
809
|
+
"gsSlide": "SD8qLW_gsSlide",
|
|
810
|
+
"commitCopy": "SD8qLW_commitCopy",
|
|
811
|
+
"treeCol": "SD8qLW_treeCol",
|
|
812
|
+
"sideRailGap": "SD8qLW_sideRailGap",
|
|
813
|
+
"btnPrimary": "SD8qLW_btnPrimary",
|
|
814
|
+
"diffWrap": "SD8qLW_diffWrap"
|
|
803
815
|
};
|
|
804
816
|
//#endregion
|
|
805
817
|
//#region node_modules/.pnpm/@marijn+find-cluster-break@1.0.3/node_modules/@marijn/find-cluster-break/src/index.js
|
|
@@ -19807,6 +19819,9 @@ window.__ModuleLoader__.load({
|
|
|
19807
19819
|
* {@link paintCompartment} — when the file, the language or the theme moves. */
|
|
19808
19820
|
const paintFacet = Facet.define({ combine: (values) => values.length > 0 ? values[0] : null });
|
|
19809
19821
|
const paintCompartment = new Compartment();
|
|
19822
|
+
/** Soft wrap, in and out without rebuilding the view — the caret, the undo
|
|
19823
|
+
* stack and the selection all survive the toggle. */
|
|
19824
|
+
const wrapCompartment = new Compartment();
|
|
19810
19825
|
/**
|
|
19811
19826
|
* How long after the last keystroke the editor recomputes what it paints.
|
|
19812
19827
|
*
|
|
@@ -20096,7 +20111,7 @@ window.__ModuleLoader__.load({
|
|
|
20096
20111
|
},
|
|
20097
20112
|
...SEARCH_PANEL_THEME
|
|
20098
20113
|
});
|
|
20099
|
-
function CodeEditor({ value, original, onChange, paint, indent, ariaLabel, onSave, blame, notCommitted, readOnly, onBlameClick }) {
|
|
20114
|
+
function CodeEditor({ value, original, onChange, paint, indent, ariaLabel, onSave, blame, notCommitted, readOnly, onBlameClick, wrap }) {
|
|
20100
20115
|
/**
|
|
20101
20116
|
* Editable, and SAID to be editable, from one boolean.
|
|
20102
20117
|
*
|
|
@@ -20137,6 +20152,7 @@ window.__ModuleLoader__.load({
|
|
|
20137
20152
|
searchCount,
|
|
20138
20153
|
highlightActiveLine(),
|
|
20139
20154
|
paintCompartment.of(paintFacet.of(paint)),
|
|
20155
|
+
wrapCompartment.of(wrap === true ? EditorView.lineWrapping : []),
|
|
20140
20156
|
painter,
|
|
20141
20157
|
blameField,
|
|
20142
20158
|
blameCompartment.of([]),
|
|
@@ -20211,6 +20227,11 @@ window.__ModuleLoader__.load({
|
|
|
20211
20227
|
if (current === null) return;
|
|
20212
20228
|
current.dispatch({ effects: paintCompartment.reconfigure(paintFacet.of(paint)) });
|
|
20213
20229
|
}, [paint]);
|
|
20230
|
+
(0, react.useEffect)(() => {
|
|
20231
|
+
const current = view.current;
|
|
20232
|
+
if (current === null) return;
|
|
20233
|
+
current.dispatch({ effects: wrapCompartment.reconfigure(wrap === true ? EditorView.lineWrapping : []) });
|
|
20234
|
+
}, [wrap]);
|
|
20214
20235
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
20215
20236
|
ref: host,
|
|
20216
20237
|
className: GitWorkbenchPanel_module_css_default.cmHost,
|
|
@@ -20223,10 +20244,20 @@ window.__ModuleLoader__.load({
|
|
|
20223
20244
|
* Fold a flat path list into a sorted directory tree carrying its files.
|
|
20224
20245
|
* Root-level files live on no directory; the SEARCH ({@link searchPaths}) is
|
|
20225
20246
|
* where they surface.
|
|
20247
|
+
*
|
|
20248
|
+
* `dirHints` names directories that exist with NO file under them yet — the
|
|
20249
|
+
* collapsed entries of the ignored listing (`node_modules/`), whose children
|
|
20250
|
+
* are only read when the reader expands them. A path list cannot express
|
|
20251
|
+
* that: a node with no files and no children is indistinguishable from a
|
|
20252
|
+
* path that was never mentioned. Hints only ever ADD an empty directory; a
|
|
20253
|
+
* hint that lands on a name the path list recorded as a file is skipped,
|
|
20254
|
+
* because the list is the primary source and a hint is hearsay next to it.
|
|
20255
|
+
*
|
|
20226
20256
|
* @param paths - repo-relative file paths, any order, no duplicates assumed.
|
|
20257
|
+
* @param dirHints - repo-relative directory paths to show even while empty.
|
|
20227
20258
|
* @returns the top-level directories, children and files sorted by name.
|
|
20228
20259
|
*/
|
|
20229
|
-
function buildDirTree(paths) {
|
|
20260
|
+
function buildDirTree(paths, dirHints) {
|
|
20230
20261
|
const rootNode = {
|
|
20231
20262
|
name: "",
|
|
20232
20263
|
path: "",
|
|
@@ -20253,6 +20284,37 @@ window.__ModuleLoader__.load({
|
|
|
20253
20284
|
}
|
|
20254
20285
|
node.files.push(parts[parts.length - 1]);
|
|
20255
20286
|
}
|
|
20287
|
+
const addHint = (hint) => {
|
|
20288
|
+
if (hint.length === 0) return;
|
|
20289
|
+
const parts = hint.split("/");
|
|
20290
|
+
let node = rootNode;
|
|
20291
|
+
for (let i = 0; i < parts.length - 1; i += 1) {
|
|
20292
|
+
const name = parts[i];
|
|
20293
|
+
const child = node.children.get(name);
|
|
20294
|
+
if (child !== void 0) {
|
|
20295
|
+
node = child;
|
|
20296
|
+
continue;
|
|
20297
|
+
}
|
|
20298
|
+
if (node.files.includes(name)) return;
|
|
20299
|
+
const created = {
|
|
20300
|
+
name,
|
|
20301
|
+
path: parts.slice(0, i + 1).join("/"),
|
|
20302
|
+
files: [],
|
|
20303
|
+
children: /* @__PURE__ */ new Map()
|
|
20304
|
+
};
|
|
20305
|
+
node.children.set(name, created);
|
|
20306
|
+
node = created;
|
|
20307
|
+
}
|
|
20308
|
+
const last = parts[parts.length - 1];
|
|
20309
|
+
if (node.children.has(last) || node.files.includes(last)) return;
|
|
20310
|
+
node.children.set(last, {
|
|
20311
|
+
name: last,
|
|
20312
|
+
path: hint,
|
|
20313
|
+
files: [],
|
|
20314
|
+
children: /* @__PURE__ */ new Map()
|
|
20315
|
+
});
|
|
20316
|
+
};
|
|
20317
|
+
if (dirHints !== void 0) for (const hint of dirHints) addHint(hint);
|
|
20256
20318
|
const freeze = (node) => {
|
|
20257
20319
|
const children = [...node.children.values()].sort((a, b) => a.name.localeCompare(b.name)).map(freeze);
|
|
20258
20320
|
const files = [...node.files].sort((a, b) => a.localeCompare(b));
|
|
@@ -20423,6 +20485,41 @@ window.__ModuleLoader__.load({
|
|
|
20423
20485
|
}
|
|
20424
20486
|
return out;
|
|
20425
20487
|
}
|
|
20488
|
+
/** What `git ls-files --others --ignored --exclude-standard --directory`
|
|
20489
|
+
* returned, split by kind: every ignored FILE (any depth, as long as no rule
|
|
20490
|
+
* swallowed its whole directory) and every directory git collapsed to one
|
|
20491
|
+
* line because it is ignored as a whole — the trailing slash is the only
|
|
20492
|
+
* thing that tells them apart, so it is the whole test.
|
|
20493
|
+
* @param entries - the listing verbatim, as `repoTree` carried it.
|
|
20494
|
+
*/
|
|
20495
|
+
function splitIgnored(entries) {
|
|
20496
|
+
const files = [];
|
|
20497
|
+
const dirs = [];
|
|
20498
|
+
for (const entry of entries) {
|
|
20499
|
+
if (entry.length === 0) continue;
|
|
20500
|
+
if (entry.endsWith("/")) dirs.push(entry.slice(0, -1));
|
|
20501
|
+
else files.push(entry);
|
|
20502
|
+
}
|
|
20503
|
+
return {
|
|
20504
|
+
files,
|
|
20505
|
+
dirs
|
|
20506
|
+
};
|
|
20507
|
+
}
|
|
20508
|
+
/**
|
|
20509
|
+
* Whether a row is gitignored territory: an ignored file itself, a directory
|
|
20510
|
+
* the listing collapsed, or anything living under one. Everything under a
|
|
20511
|
+
* collapsed directory is ignored by inheritance, which is what makes the
|
|
20512
|
+
* ancestor walk the whole rule.
|
|
20513
|
+
*
|
|
20514
|
+
* @param path - the row's repo-relative path.
|
|
20515
|
+
* @param files - ignored file paths, from {@link splitIgnored}.
|
|
20516
|
+
* @param dirs - collapsed directory paths, from {@link splitIgnored}.
|
|
20517
|
+
*/
|
|
20518
|
+
function isIgnoredPath(path, files, dirs) {
|
|
20519
|
+
if (files.has(path) || dirs.has(path)) return true;
|
|
20520
|
+
for (const dir of ancestorsOf(path)) if (dirs.has(dir)) return true;
|
|
20521
|
+
return false;
|
|
20522
|
+
}
|
|
20426
20523
|
/**
|
|
20427
20524
|
* The browsable path list: everything git tracks, plus files that exist on
|
|
20428
20525
|
* disk but not in HEAD.
|
|
@@ -20442,6 +20539,155 @@ window.__ModuleLoader__.load({
|
|
|
20442
20539
|
return [...all].sort((a, b) => a.localeCompare(b));
|
|
20443
20540
|
}
|
|
20444
20541
|
//#endregion
|
|
20542
|
+
//#region src/client/ignored-cache.ts
|
|
20543
|
+
/** Nothing read yet. One instance, so an untouched worktree does not
|
|
20544
|
+
* re-render the browser on every pass. */
|
|
20545
|
+
const NO_IGNORED_READS = {
|
|
20546
|
+
reads: {},
|
|
20547
|
+
order: [],
|
|
20548
|
+
size: 0
|
|
20549
|
+
};
|
|
20550
|
+
/**
|
|
20551
|
+
* Most entries held across all directories at once. A real level is a few
|
|
20552
|
+
* hundred, so reaching this takes dozens of expansions of pathological
|
|
20553
|
+
* directories; it is the fuse, not a working number.
|
|
20554
|
+
*/
|
|
20555
|
+
const IGNORED_CACHE_CAP = 2e4;
|
|
20556
|
+
/**
|
|
20557
|
+
* Record one directory's children, evicting the oldest reads that nobody is
|
|
20558
|
+
* looking at until the cache is back under the cap.
|
|
20559
|
+
*
|
|
20560
|
+
* @param cache - the cache as it stands.
|
|
20561
|
+
* @param dir - repo-relative directory the read belongs to.
|
|
20562
|
+
* @param read - what the host answered.
|
|
20563
|
+
* @param keep - directories that must survive eviction: the ones expanded on
|
|
20564
|
+
* screen, and the ancestors of the open file (whose path must
|
|
20565
|
+
* stay in the browsable list or the editor would report it
|
|
20566
|
+
* vanished). The directory being written is always kept.
|
|
20567
|
+
* @param cap - most entries to hold in total.
|
|
20568
|
+
*/
|
|
20569
|
+
function rememberDir(cache, dir, read, keep, cap = IGNORED_CACHE_CAP) {
|
|
20570
|
+
const reads = {
|
|
20571
|
+
...cache.reads,
|
|
20572
|
+
[dir]: read
|
|
20573
|
+
};
|
|
20574
|
+
const order = [...cache.order.filter((key) => key !== dir), dir];
|
|
20575
|
+
let size = cache.size - (cache.reads[dir]?.entries.length ?? 0) + read.entries.length;
|
|
20576
|
+
let index = 0;
|
|
20577
|
+
while (size > cap && index < order.length) {
|
|
20578
|
+
const victim = order[index];
|
|
20579
|
+
if (victim === dir || keep.has(victim)) {
|
|
20580
|
+
index += 1;
|
|
20581
|
+
continue;
|
|
20582
|
+
}
|
|
20583
|
+
size -= reads[victim]?.entries.length ?? 0;
|
|
20584
|
+
delete reads[victim];
|
|
20585
|
+
order.splice(index, 1);
|
|
20586
|
+
}
|
|
20587
|
+
return {
|
|
20588
|
+
reads,
|
|
20589
|
+
order,
|
|
20590
|
+
size
|
|
20591
|
+
};
|
|
20592
|
+
}
|
|
20593
|
+
/** Whether any directory still held was cut at the host's per-directory cap.
|
|
20594
|
+
* Derived rather than sticky: a cut directory that has been evicted, or a
|
|
20595
|
+
* refresh that replaced the cache, stops claiming it. */
|
|
20596
|
+
function anyDirTruncated(cache) {
|
|
20597
|
+
for (const read of Object.values(cache.reads)) if (read.truncated) return true;
|
|
20598
|
+
return false;
|
|
20599
|
+
}
|
|
20600
|
+
/** Files plus subtree counts — the invariant every {@link DirEntry} carries. */
|
|
20601
|
+
function countOf(files, children) {
|
|
20602
|
+
return files.length + children.reduce((sum, child) => sum + child.fileCount, 0);
|
|
20603
|
+
}
|
|
20604
|
+
/** Merge one directory's read into the node that stands for it. Names the
|
|
20605
|
+
* node already has win: the path list is the primary source, and a read that
|
|
20606
|
+
* disagrees with it must not split one name into two rows. */
|
|
20607
|
+
function withChildren(entry, read) {
|
|
20608
|
+
const haveDirs = new Set(entry.children.map((child) => child.name));
|
|
20609
|
+
const haveFiles = new Set(entry.files);
|
|
20610
|
+
const files = [...entry.files];
|
|
20611
|
+
const children = [...entry.children];
|
|
20612
|
+
for (const child of read.entries) {
|
|
20613
|
+
if (haveDirs.has(child.name) || haveFiles.has(child.name)) continue;
|
|
20614
|
+
if (child.dir) {
|
|
20615
|
+
haveDirs.add(child.name);
|
|
20616
|
+
children.push({
|
|
20617
|
+
name: child.name,
|
|
20618
|
+
path: `${entry.path}/${child.name}`,
|
|
20619
|
+
fileCount: 0,
|
|
20620
|
+
files: [],
|
|
20621
|
+
children: []
|
|
20622
|
+
});
|
|
20623
|
+
} else {
|
|
20624
|
+
haveFiles.add(child.name);
|
|
20625
|
+
files.push(child.name);
|
|
20626
|
+
}
|
|
20627
|
+
}
|
|
20628
|
+
files.sort((a, b) => a.localeCompare(b));
|
|
20629
|
+
children.sort((a, b) => a.name.localeCompare(b.name));
|
|
20630
|
+
return {
|
|
20631
|
+
...entry,
|
|
20632
|
+
files,
|
|
20633
|
+
children,
|
|
20634
|
+
fileCount: countOf(files, children)
|
|
20635
|
+
};
|
|
20636
|
+
}
|
|
20637
|
+
/** Rebuild only the spine down to `parts`, leaving every other node — and
|
|
20638
|
+
* every other subtree's identity — exactly as it was. Null when the path is
|
|
20639
|
+
* not in the tree, which is how a read for a directory a refresh dropped
|
|
20640
|
+
* becomes a no-op instead of an error. */
|
|
20641
|
+
function replaceAt(dirs, parts, depth, apply) {
|
|
20642
|
+
const name = parts[depth];
|
|
20643
|
+
const index = dirs.findIndex((dir) => dir.name === name);
|
|
20644
|
+
if (index === -1) return null;
|
|
20645
|
+
const current = dirs[index];
|
|
20646
|
+
let next;
|
|
20647
|
+
if (depth === parts.length - 1) next = apply(current);
|
|
20648
|
+
else {
|
|
20649
|
+
const grafted = replaceAt(current.children, parts, depth + 1, apply);
|
|
20650
|
+
if (grafted === null) return null;
|
|
20651
|
+
next = {
|
|
20652
|
+
...current,
|
|
20653
|
+
children: grafted,
|
|
20654
|
+
fileCount: countOf(current.files, grafted)
|
|
20655
|
+
};
|
|
20656
|
+
}
|
|
20657
|
+
const out = [...dirs];
|
|
20658
|
+
out[index] = next;
|
|
20659
|
+
return out;
|
|
20660
|
+
}
|
|
20661
|
+
/**
|
|
20662
|
+
* Graft every read directory's children onto the tree built from the path
|
|
20663
|
+
* list.
|
|
20664
|
+
*
|
|
20665
|
+
* This is the reason expanding an ignored directory is not O(repository):
|
|
20666
|
+
* rebuilding the tree from a merged path list meant a fresh `Set`, a fresh
|
|
20667
|
+
* `localeCompare` sort and a fresh walk over EVERY path on every click —
|
|
20668
|
+
* measured at 140ms on a 50,000-path repository, synchronously, on the click.
|
|
20669
|
+
* Grafting touches only the nodes on the path to each read directory, so the
|
|
20670
|
+
* cost is the depth of what was clicked plus the width of what came back.
|
|
20671
|
+
*
|
|
20672
|
+
* Shallow directories are grafted first, so the empty node a parent's read
|
|
20673
|
+
* creates exists by the time its own read is grafted onto it.
|
|
20674
|
+
*
|
|
20675
|
+
* @param tree - the tree from {@link buildDirTree} over the path list.
|
|
20676
|
+
* @param cache - the directories read so far.
|
|
20677
|
+
*/
|
|
20678
|
+
function attachReads(tree, cache) {
|
|
20679
|
+
const dirs = Object.keys(cache.reads);
|
|
20680
|
+
if (dirs.length === 0) return tree;
|
|
20681
|
+
const shallowFirst = [...dirs].sort((a, b) => a.split("/").length - b.split("/").length);
|
|
20682
|
+
let out = tree;
|
|
20683
|
+
for (const dir of shallowFirst) {
|
|
20684
|
+
if (dir.length === 0) continue;
|
|
20685
|
+
const grafted = replaceAt(out, dir.split("/"), 0, (entry) => withChildren(entry, cache.reads[dir]));
|
|
20686
|
+
if (grafted !== null) out = grafted;
|
|
20687
|
+
}
|
|
20688
|
+
return out;
|
|
20689
|
+
}
|
|
20690
|
+
//#endregion
|
|
20445
20691
|
//#region src/client/files-place.ts
|
|
20446
20692
|
/**
|
|
20447
20693
|
* Where the reader is in the Files tab — the file they have open, the folders
|
|
@@ -32883,9 +33129,9 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
32883
33129
|
* The history filter's path picker has capped at this number since it
|
|
32884
33130
|
* shipped; the search box is the way to a file in a crowded directory. */
|
|
32885
33131
|
const FILES_PER_DIR = 100;
|
|
32886
|
-
function FileBrowser({ t, palette, statsPath, extraPaths, gen, treeStyle, treeRef, divider, place, onPlace, cached, onTree, fetchRepoTree, fetchFileSides, writeChecked, fetchBlame, fetchFileImage, onSaved, onDirtyChange, onShowHistory }) {
|
|
33132
|
+
function FileBrowser({ t, palette, statsPath, extraPaths, gen, treeStyle, treeRef, divider, place, onPlace, cached, onTree, wrap, fetchRepoTree, fetchIgnoredDir, fetchFileSides, writeChecked, fetchBlame, fetchFileImage, onSaved, onDirtyChange, onShowHistory }) {
|
|
32887
33133
|
const { open, query, blameOn } = place;
|
|
32888
|
-
const { paths, truncated } = cached;
|
|
33134
|
+
const { paths, truncated, ignored, ignoredTruncated, ignoredError, children } = cached;
|
|
32889
33135
|
const expanded = (0, react.useMemo)(() => new Set(place.expanded), [place.expanded]);
|
|
32890
33136
|
/** A file that was open and is not in the repository any more. Reported
|
|
32891
33137
|
* rather than silently applied: a selection that clears itself with no
|
|
@@ -32938,10 +33184,14 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
32938
33184
|
let alive = true;
|
|
32939
33185
|
fetchRepoTree(statsPath, ctrl.signal).then((answer) => {
|
|
32940
33186
|
if (!alive || answer === null) return;
|
|
32941
|
-
onTree({
|
|
33187
|
+
onTree(() => ({
|
|
32942
33188
|
paths: answer.paths,
|
|
32943
|
-
truncated: answer.truncated
|
|
32944
|
-
|
|
33189
|
+
truncated: answer.truncated,
|
|
33190
|
+
ignored: answer.ignored ?? [],
|
|
33191
|
+
ignoredTruncated: answer.ignoredTruncated ?? false,
|
|
33192
|
+
...answer.ignoredError !== void 0 ? { ignoredError: answer.ignoredError } : {},
|
|
33193
|
+
children: NO_IGNORED_READS
|
|
33194
|
+
}));
|
|
32945
33195
|
}).catch(() => {});
|
|
32946
33196
|
return () => {
|
|
32947
33197
|
alive = false;
|
|
@@ -33066,9 +33316,48 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
33066
33316
|
const extraHeld = (0, react.useRef)(extraPaths);
|
|
33067
33317
|
if (!sameList(extraHeld.current, extraPaths)) extraHeld.current = extraPaths;
|
|
33068
33318
|
const steadyExtra = extraHeld.current;
|
|
33069
|
-
|
|
33070
|
-
|
|
33071
|
-
|
|
33319
|
+
/** The ignored half of the listing, split by the trailing slash that is its
|
|
33320
|
+
* only kind marker: ignored files join the browsable list (they open,
|
|
33321
|
+
* edit and save through the same path untracked files already take);
|
|
33322
|
+
* collapsed directories become tree hints the rows below render as
|
|
33323
|
+
* expandable folders. */
|
|
33324
|
+
const { files: ignoredFiles, dirs: collapsedDirs } = (0, react.useMemo)(() => splitIgnored(ignored), [ignored]);
|
|
33325
|
+
const ignoredFilesOf = (0, react.useMemo)(() => new Set(ignoredFiles), [ignoredFiles]);
|
|
33326
|
+
const collapsedOf = (0, react.useMemo)(() => new Set(collapsedDirs), [collapsedDirs]);
|
|
33327
|
+
/**
|
|
33328
|
+
* The list git can speak for, and the tree over it. Both change only when
|
|
33329
|
+
* the REPOSITORY is re-read — never when a folder is expanded, which is the
|
|
33330
|
+
* whole point of the split below: merging the lazy children back into this
|
|
33331
|
+
* list meant a fresh `Set`, a fresh `localeCompare` sort and a fresh tree
|
|
33332
|
+
* walk over every path in the repository on every click (140ms at 50,000
|
|
33333
|
+
* paths, measured, synchronously on the click).
|
|
33334
|
+
*/
|
|
33335
|
+
const base = (0, react.useMemo)(() => mergePaths(mergePaths(paths, steadyExtra), ignoredFiles), [
|
|
33336
|
+
paths,
|
|
33337
|
+
steadyExtra,
|
|
33338
|
+
ignoredFiles
|
|
33339
|
+
]);
|
|
33340
|
+
/** Collapsed directories exist with nothing under them YET, and a path list
|
|
33341
|
+
* cannot express that; tracked directories are all implied by their files
|
|
33342
|
+
* and never need a hint. */
|
|
33343
|
+
const baseTree = (0, react.useMemo)(() => buildDirTree(base, collapsedOf), [base, collapsedOf]);
|
|
33344
|
+
/** Everything read since, grafted onto the nodes it belongs to — work
|
|
33345
|
+
* proportional to what was clicked, not to the repository. */
|
|
33346
|
+
const tree = (0, react.useMemo)(() => attachReads(baseTree, children), [baseTree, children]);
|
|
33347
|
+
const roots = (0, react.useMemo)(() => rootFiles(base), [base]);
|
|
33348
|
+
/** Lazy children as ordinary openable paths. The search and the
|
|
33349
|
+
* open-file reconciliation both read a flat list, so they get one — a
|
|
33350
|
+
* CONCATENATION, deliberately: `base` is already sorted and deduped, and
|
|
33351
|
+
* nothing under a collapsed directory can appear in it (git lists neither
|
|
33352
|
+
* ignored files nor untracked ones from inside a collapsed directory). */
|
|
33353
|
+
const lazyFiles = (0, react.useMemo)(() => {
|
|
33354
|
+
const out = [];
|
|
33355
|
+
for (const [dir, read] of Object.entries(children.reads)) for (const child of read.entries) if (!child.dir) out.push(`${dir}/${child.name}`);
|
|
33356
|
+
return out.sort((a, b) => a.localeCompare(b));
|
|
33357
|
+
}, [children]);
|
|
33358
|
+
const all = (0, react.useMemo)(() => lazyFiles.length === 0 ? base : [...base, ...lazyFiles], [base, lazyFiles]);
|
|
33359
|
+
/** Whether a directory the reader can still see was cut at the host's cap. */
|
|
33360
|
+
const dirCut = (0, react.useMemo)(() => anyDirTruncated(children), [children]);
|
|
33072
33361
|
const rows = (0, react.useMemo)(() => query.trim().length > 0 ? searchRows(all, query, SEARCH_CAP) : treeRows(tree, roots, expanded, FILES_PER_DIR), [
|
|
33073
33362
|
query,
|
|
33074
33363
|
all,
|
|
@@ -33184,9 +33473,30 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
33184
33473
|
setVanished(null);
|
|
33185
33474
|
onPlace(openAt(place, path));
|
|
33186
33475
|
};
|
|
33476
|
+
/** Directories whose children are in flight, so the effect further down
|
|
33477
|
+
* does not ask twice for the same one. */
|
|
33478
|
+
const pendingDirs = (0, react.useRef)(/* @__PURE__ */ new Set());
|
|
33479
|
+
/**
|
|
33480
|
+
* How many times each directory has been expanded. A read belongs to ONE
|
|
33481
|
+
* attempt: fold a directory while its read is in flight, expand it again,
|
|
33482
|
+
* and the first read's answer — including its decision to fold the row back
|
|
33483
|
+
* on failure — would otherwise land on the second attempt and undo the
|
|
33484
|
+
* reader's click.
|
|
33485
|
+
*/
|
|
33486
|
+
const attempts = (0, react.useRef)(/* @__PURE__ */ new Map());
|
|
33187
33487
|
const foldDir = (path) => {
|
|
33488
|
+
if (place.expanded.includes(path)) {
|
|
33489
|
+
attempts.current.set(path, (attempts.current.get(path) ?? 0) + 1);
|
|
33490
|
+
pendingDirs.current.delete(path);
|
|
33491
|
+
}
|
|
33188
33492
|
onPlace(toggleDir(place, path));
|
|
33189
33493
|
};
|
|
33494
|
+
/** Collapse a directory only if it stands open — the failure path of a
|
|
33495
|
+
* lazy read, where a plain toggle would re-open what the reader already
|
|
33496
|
+
* folded while the read was in flight. */
|
|
33497
|
+
const foldIfOpen = (path) => {
|
|
33498
|
+
if (place.expanded.includes(path)) onPlace(toggleDir(place, path));
|
|
33499
|
+
};
|
|
33190
33500
|
const idRef = (0, react.useRef)(0);
|
|
33191
33501
|
(0, react.useEffect)(() => {
|
|
33192
33502
|
idRef.current += 1;
|
|
@@ -33230,12 +33540,65 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
33230
33540
|
*/
|
|
33231
33541
|
const acts = (0, react.useRef)({
|
|
33232
33542
|
foldDir,
|
|
33233
|
-
openFile
|
|
33543
|
+
openFile,
|
|
33544
|
+
foldIfOpen
|
|
33234
33545
|
});
|
|
33235
33546
|
acts.current = {
|
|
33236
33547
|
foldDir,
|
|
33237
|
-
openFile
|
|
33238
|
-
|
|
33548
|
+
openFile,
|
|
33549
|
+
foldIfOpen
|
|
33550
|
+
};
|
|
33551
|
+
/** What eviction must not touch: the directories standing open, and the
|
|
33552
|
+
* ancestors of the open file — whose path has to stay in the browsable
|
|
33553
|
+
* list, or the reconciliation below would report the open file vanished. */
|
|
33554
|
+
const keepRef = (0, react.useRef)(/* @__PURE__ */ new Set());
|
|
33555
|
+
keepRef.current = (0, react.useMemo)(() => /* @__PURE__ */ new Set([...place.expanded, ...open === null ? [] : ancestorsOf(open)]), [place.expanded, open]);
|
|
33556
|
+
/** Read one ignored directory's children into the tree cache. A no-op when
|
|
33557
|
+
* they are already there or in flight. */
|
|
33558
|
+
const loadDirChildren = (0, react.useCallback)((dir) => {
|
|
33559
|
+
if (pendingDirs.current.has(dir)) return;
|
|
33560
|
+
pendingDirs.current.add(dir);
|
|
33561
|
+
const attempt = (attempts.current.get(dir) ?? 0) + 1;
|
|
33562
|
+
attempts.current.set(dir, attempt);
|
|
33563
|
+
const settle = () => {
|
|
33564
|
+
pendingDirs.current.delete(dir);
|
|
33565
|
+
return attempts.current.get(dir) === attempt;
|
|
33566
|
+
};
|
|
33567
|
+
fetchIgnoredDir(statsPath, dir, new AbortController().signal).then((answer) => {
|
|
33568
|
+
if (!settle()) return;
|
|
33569
|
+
if (answer === null) {
|
|
33570
|
+
acts.current.foldIfOpen(dir);
|
|
33571
|
+
return;
|
|
33572
|
+
}
|
|
33573
|
+
onTree((prev) => ({
|
|
33574
|
+
...prev,
|
|
33575
|
+
children: rememberDir(prev.children, dir, answer, keepRef.current)
|
|
33576
|
+
}));
|
|
33577
|
+
}).catch(() => {
|
|
33578
|
+
settle();
|
|
33579
|
+
});
|
|
33580
|
+
}, [
|
|
33581
|
+
statsPath,
|
|
33582
|
+
fetchIgnoredDir,
|
|
33583
|
+
onTree
|
|
33584
|
+
]);
|
|
33585
|
+
(0, react.useEffect)(() => {
|
|
33586
|
+
for (const dir of place.expanded) if (children.reads[dir] === void 0 && isIgnoredPath(dir, ignoredFilesOf, collapsedOf)) loadDirChildren(dir);
|
|
33587
|
+
}, [
|
|
33588
|
+
place.expanded,
|
|
33589
|
+
children,
|
|
33590
|
+
ignoredFilesOf,
|
|
33591
|
+
collapsedOf,
|
|
33592
|
+
loadDirChildren
|
|
33593
|
+
]);
|
|
33594
|
+
/**
|
|
33595
|
+
* `t` arrives in the host's slot props and its identity is not ours to rely
|
|
33596
|
+
* on, so the memo watches the STRING it produces instead: that is what has
|
|
33597
|
+
* to change when the language does, and it costs one lookup per render.
|
|
33598
|
+
*/
|
|
33599
|
+
const langKey = t("filesMore", { count: 0 });
|
|
33600
|
+
/** Same trick for the ignored rows' title suffix. */
|
|
33601
|
+
const ignoredLabel = t("filesIgnored");
|
|
33239
33602
|
/**
|
|
33240
33603
|
* The rendered rows.
|
|
33241
33604
|
*
|
|
@@ -33246,33 +33609,42 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
33246
33609
|
* the reader opens — the shape of "it gets laggy once there are a lot of
|
|
33247
33610
|
* files".
|
|
33248
33611
|
*/
|
|
33249
|
-
const list = (0, react.useMemo)(() => rows.map((row) =>
|
|
33250
|
-
|
|
33251
|
-
|
|
33252
|
-
|
|
33253
|
-
|
|
33254
|
-
|
|
33255
|
-
|
|
33256
|
-
|
|
33257
|
-
|
|
33258
|
-
|
|
33259
|
-
|
|
33260
|
-
|
|
33261
|
-
|
|
33262
|
-
|
|
33263
|
-
|
|
33264
|
-
|
|
33265
|
-
|
|
33266
|
-
|
|
33267
|
-
"
|
|
33268
|
-
|
|
33269
|
-
|
|
33270
|
-
children:
|
|
33271
|
-
|
|
33272
|
-
|
|
33612
|
+
const list = (0, react.useMemo)(() => rows.map((row) => {
|
|
33613
|
+
/** Ignored territory, by file or by descent from a collapsed directory.
|
|
33614
|
+
* The active row is exempt in the className below: being the file on
|
|
33615
|
+
* screen is the louder state, and the two must not fight. */
|
|
33616
|
+
const ignored = row.kind !== "more" && isIgnoredPath(row.path, ignoredFilesOf, collapsedOf);
|
|
33617
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: row.kind === "more" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
33618
|
+
className: GitWorkbenchPanel_module_css_default.fbMore,
|
|
33619
|
+
style: { paddingLeft: `${.4 + row.depth * INDENT_EM}em` },
|
|
33620
|
+
children: t("filesMore", { count: row.hidden ?? 0 })
|
|
33621
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
33622
|
+
type: "button",
|
|
33623
|
+
title: ignored ? `${row.path} — ${ignoredLabel}` : row.path,
|
|
33624
|
+
"aria-expanded": row.kind === "dir" ? row.open : void 0,
|
|
33625
|
+
className: row.kind === "file" && row.path === open ? `${GitWorkbenchPanel_module_css_default.fbRow} ${GitWorkbenchPanel_module_css_default.fbRowActive}` : ignored ? `${GitWorkbenchPanel_module_css_default.fbRow} ${GitWorkbenchPanel_module_css_default.fbRowIgnored}` : GitWorkbenchPanel_module_css_default.fbRow,
|
|
33626
|
+
style: { paddingLeft: `${.4 + row.depth * INDENT_EM}em` },
|
|
33627
|
+
onClick: () => {
|
|
33628
|
+
row.kind === "dir" ? acts.current.foldDir(row.path) : acts.current.openFile(row.path);
|
|
33629
|
+
},
|
|
33630
|
+
children: [row.kind === "dir" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
33631
|
+
className: `${GitWorkbenchPanel_module_css_default.chevron} ${row.open ? GitWorkbenchPanel_module_css_default.chevronOpen : ""}`,
|
|
33632
|
+
children: "▸"
|
|
33633
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PathDirGlyph, {})] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
33634
|
+
className: GitWorkbenchPanel_module_css_default.chevron,
|
|
33635
|
+
"aria-hidden": "true"
|
|
33636
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PathFileGlyph, { path: row.path })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
33637
|
+
className: row.kind === "dir" ? GitWorkbenchPanel_module_css_default.fbDirName : GitWorkbenchPanel_module_css_default.fbFileName,
|
|
33638
|
+
children: row.name
|
|
33639
|
+
})]
|
|
33640
|
+
}) }, rowKey(row));
|
|
33641
|
+
}), [
|
|
33273
33642
|
rows,
|
|
33274
33643
|
open,
|
|
33275
|
-
|
|
33644
|
+
langKey,
|
|
33645
|
+
ignoredLabel,
|
|
33646
|
+
ignoredFilesOf,
|
|
33647
|
+
collapsedOf
|
|
33276
33648
|
]);
|
|
33277
33649
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
33278
33650
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -33294,10 +33666,18 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
33294
33666
|
});
|
|
33295
33667
|
}
|
|
33296
33668
|
}),
|
|
33297
|
-
truncated ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
33669
|
+
truncated || ignoredTruncated ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
33298
33670
|
className: GitWorkbenchPanel_module_css_default.fbNote,
|
|
33299
33671
|
children: t("filesTruncated")
|
|
33300
33672
|
}) : null,
|
|
33673
|
+
dirCut ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
33674
|
+
className: GitWorkbenchPanel_module_css_default.fbNote,
|
|
33675
|
+
children: t("filesIgnoredCut")
|
|
33676
|
+
}) : null,
|
|
33677
|
+
ignoredError !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
33678
|
+
className: GitWorkbenchPanel_module_css_default.fbNote,
|
|
33679
|
+
children: t("filesIgnoredFailed")
|
|
33680
|
+
}) : null,
|
|
33301
33681
|
rows.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
33302
33682
|
className: GitWorkbenchPanel_module_css_default.empty,
|
|
33303
33683
|
children: all.length === 0 ? t("filesEmpty") : t("filesNoMatch")
|
|
@@ -33517,7 +33897,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
33517
33897
|
setPicked(line);
|
|
33518
33898
|
},
|
|
33519
33899
|
notCommitted: t("blameUncommitted"),
|
|
33520
|
-
readOnly
|
|
33900
|
+
readOnly,
|
|
33901
|
+
wrap
|
|
33521
33902
|
}, open)
|
|
33522
33903
|
})
|
|
33523
33904
|
] })
|
|
@@ -35586,6 +35967,25 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
35586
35967
|
//#endregion
|
|
35587
35968
|
//#region src/client/diff-model.ts
|
|
35588
35969
|
/**
|
|
35970
|
+
* Whether an empty per-file diff is the line-ending phantom.
|
|
35971
|
+
*
|
|
35972
|
+
* autocrlf / `eol` attributes make git's stat check and its clean filter
|
|
35973
|
+
* disagree, so a file can sit in the tree as modified forever while every
|
|
35974
|
+
* content diff comes back empty — the classic always-modified file of a
|
|
35975
|
+
* Windows checkout. Opening it must explain that, not fall to the generic
|
|
35976
|
+
* "no text changes" a broken pane also shows.
|
|
35977
|
+
*
|
|
35978
|
+
* Only `modified` + an empty WHOLE-FILE segment is the phantom: a fully
|
|
35979
|
+
* staged file has an empty unstaged layer but a non-empty HEAD-diff (the
|
|
35980
|
+
* reader is one click from the content), and every other status always has
|
|
35981
|
+
* a diff or a synthesized one.
|
|
35982
|
+
* @param status - the tree row's status for the open file.
|
|
35983
|
+
* @param segment - the whole-file diff text (HEAD vs worktree).
|
|
35984
|
+
*/
|
|
35985
|
+
function isPhantomModified(status, segment) {
|
|
35986
|
+
return status === "modified" && segment.length === 0;
|
|
35987
|
+
}
|
|
35988
|
+
/**
|
|
35589
35989
|
* Parse a unified diff segment into typed rows, tracking line numbers.
|
|
35590
35990
|
* @param segment - one file's `diff --git` text (headers are skipped).
|
|
35591
35991
|
*/
|
|
@@ -36294,7 +36694,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
36294
36694
|
* @param offset - px above the first row, e.g. the grid's top padding.
|
|
36295
36695
|
* @returns the first row of each block, in the order the blocks appear.
|
|
36296
36696
|
*/
|
|
36297
|
-
function blockTopsFromRows(blocks, rowH, offset = 0) {
|
|
36697
|
+
function blockTopsFromRows(blocks, rowH, offset = 0, topOf) {
|
|
36298
36698
|
const tops = [];
|
|
36299
36699
|
const seen = /* @__PURE__ */ new Set();
|
|
36300
36700
|
for (let i = 0; i < blocks.length; i += 1) {
|
|
@@ -36303,7 +36703,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
36303
36703
|
seen.add(block);
|
|
36304
36704
|
tops.push({
|
|
36305
36705
|
block,
|
|
36306
|
-
top: offset + i * rowH
|
|
36706
|
+
top: offset + (topOf === void 0 ? i * rowH : topOf(i))
|
|
36307
36707
|
});
|
|
36308
36708
|
}
|
|
36309
36709
|
return tops;
|
|
@@ -36349,7 +36749,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
36349
36749
|
* until the height is known would flash an empty pane; a screenful is both
|
|
36350
36750
|
* safe and close.
|
|
36351
36751
|
*/
|
|
36352
|
-
const ASSUMED_VIEWPORT_PX = 1200;
|
|
36752
|
+
const ASSUMED_VIEWPORT_PX$1 = 1200;
|
|
36353
36753
|
/** Whether two windows paint the same rows AND reserve the same total height.
|
|
36354
36754
|
* Comparing only start/end leaves a previous file's bottom spacer behind when
|
|
36355
36755
|
* two long files happen to expose the same viewport-sized row range. */
|
|
@@ -36365,7 +36765,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
36365
36765
|
* @param fallback - used when it is neither finite nor usable.
|
|
36366
36766
|
* @returns a finite, non-negative number.
|
|
36367
36767
|
*/
|
|
36368
|
-
function sane(value, fallback) {
|
|
36768
|
+
function sane$1(value, fallback) {
|
|
36369
36769
|
return Number.isFinite(value) && value > 0 ? value : fallback;
|
|
36370
36770
|
}
|
|
36371
36771
|
/**
|
|
@@ -36380,7 +36780,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
36380
36780
|
*/
|
|
36381
36781
|
function rowWindow(scrollTop, viewportH, rowCount, rowH = 20, overscan = 40) {
|
|
36382
36782
|
const rows = Math.max(0, Math.trunc(rowCount));
|
|
36383
|
-
const height = sane(rowH, 20);
|
|
36783
|
+
const height = sane$1(rowH, 20);
|
|
36384
36784
|
if (rows <= 400) return {
|
|
36385
36785
|
start: 0,
|
|
36386
36786
|
end: rows,
|
|
@@ -36388,7 +36788,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
36388
36788
|
padBottom: 0
|
|
36389
36789
|
};
|
|
36390
36790
|
const top = Number.isFinite(scrollTop) && scrollTop > 0 ? scrollTop : 0;
|
|
36391
|
-
const view = sane(viewportH, ASSUMED_VIEWPORT_PX);
|
|
36791
|
+
const view = sane$1(viewportH, ASSUMED_VIEWPORT_PX$1);
|
|
36392
36792
|
const pad = Math.max(0, Math.trunc(overscan));
|
|
36393
36793
|
const first = Math.max(0, Math.floor(top / height) - pad);
|
|
36394
36794
|
const last = Math.min(rows, Math.ceil((top + view) / height) + pad);
|
|
@@ -36540,6 +36940,154 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
36540
36940
|
});
|
|
36541
36941
|
}
|
|
36542
36942
|
//#endregion
|
|
36943
|
+
//#region src/client/h-rail.ts
|
|
36944
|
+
/** Before anything has been measured, and for a column that is not mounted. */
|
|
36945
|
+
const NO_RAIL = {
|
|
36946
|
+
view: 0,
|
|
36947
|
+
content: 0
|
|
36948
|
+
};
|
|
36949
|
+
/**
|
|
36950
|
+
* Whether a column overflows by enough to be worth a scrollbar.
|
|
36951
|
+
*
|
|
36952
|
+
* The one-pixel slack is not tidiness: a grid track rounds to a fraction, so a
|
|
36953
|
+
* column whose longest line exactly fits still reports a scroll width a third
|
|
36954
|
+
* of a pixel wider than its client width. Without the slack every file gets a
|
|
36955
|
+
* rail, and every one of those rails scrolls nowhere.
|
|
36956
|
+
*
|
|
36957
|
+
* @param metric - the column's measured widths.
|
|
36958
|
+
* @returns true when a rail should be shown for it.
|
|
36959
|
+
*/
|
|
36960
|
+
function railNeeded(metric) {
|
|
36961
|
+
const { view, content } = metric;
|
|
36962
|
+
if (!Number.isFinite(view) || !Number.isFinite(content)) return false;
|
|
36963
|
+
if (view <= 0) return false;
|
|
36964
|
+
return content > view + 1;
|
|
36965
|
+
}
|
|
36966
|
+
/** Whether the rail row is shown at all — either column overflowing is enough,
|
|
36967
|
+
* since the row is one sticky strip and a lone rail still needs its space. */
|
|
36968
|
+
function railsShown(left, right) {
|
|
36969
|
+
return railNeeded(left) || railNeeded(right);
|
|
36970
|
+
}
|
|
36971
|
+
/**
|
|
36972
|
+
* Whether two measurements are the same.
|
|
36973
|
+
*
|
|
36974
|
+
* The measuring effect runs on every render, so this is what keeps it from
|
|
36975
|
+
* setting state on every render and rendering again forever.
|
|
36976
|
+
*
|
|
36977
|
+
* @param a - the measurement held in state.
|
|
36978
|
+
* @param b - the one just read from the DOM.
|
|
36979
|
+
*/
|
|
36980
|
+
function sameMetric(a, b) {
|
|
36981
|
+
return a.view === b.view && a.content === b.content;
|
|
36982
|
+
}
|
|
36983
|
+
//#endregion
|
|
36984
|
+
//#region src/client/SideRails.tsx
|
|
36985
|
+
/**
|
|
36986
|
+
* Measure one column and keep its rail's scroll position tied to it.
|
|
36987
|
+
*
|
|
36988
|
+
* The measurement runs on EVERY render rather than on a dependency list: the
|
|
36989
|
+
* content width changes for reasons no list can name — a window scrolled to
|
|
36990
|
+
* longer rows, syntax spans replacing plain text, the editor mounting into the
|
|
36991
|
+
* right column, wrap turning on. Two integer reads is a cheap price for never
|
|
36992
|
+
* being stale, and {@link sameMetric} is what keeps setting state on every
|
|
36993
|
+
* render from becoming a render on every render.
|
|
36994
|
+
*
|
|
36995
|
+
* @param colRef - the column, which clips and scrolls its own content.
|
|
36996
|
+
* @param railRef - the strip at the bottom of the pane that stands in for it.
|
|
36997
|
+
* @returns the column's measured widths.
|
|
36998
|
+
*/
|
|
36999
|
+
function useRail(colRef, railRef) {
|
|
37000
|
+
const [metric, setMetric] = (0, react.useState)(NO_RAIL);
|
|
37001
|
+
const measure = (col) => {
|
|
37002
|
+
const next = {
|
|
37003
|
+
view: col.clientWidth,
|
|
37004
|
+
content: col.scrollWidth
|
|
37005
|
+
};
|
|
37006
|
+
setMetric((prev) => sameMetric(prev, next) ? prev : next);
|
|
37007
|
+
};
|
|
37008
|
+
(0, react.useLayoutEffect)(() => {
|
|
37009
|
+
const col = colRef.current;
|
|
37010
|
+
if (col !== null) measure(col);
|
|
37011
|
+
});
|
|
37012
|
+
(0, react.useEffect)(() => {
|
|
37013
|
+
const col = colRef.current;
|
|
37014
|
+
if (col === null) return;
|
|
37015
|
+
const observer = new ResizeObserver(() => {
|
|
37016
|
+
measure(col);
|
|
37017
|
+
});
|
|
37018
|
+
observer.observe(col);
|
|
37019
|
+
return () => {
|
|
37020
|
+
observer.disconnect();
|
|
37021
|
+
};
|
|
37022
|
+
}, [colRef]);
|
|
37023
|
+
(0, react.useEffect)(() => {
|
|
37024
|
+
const col = colRef.current;
|
|
37025
|
+
const rail = railRef.current;
|
|
37026
|
+
if (col === null || rail === null) return;
|
|
37027
|
+
const toRail = () => {
|
|
37028
|
+
if (rail.scrollLeft !== col.scrollLeft) rail.scrollLeft = col.scrollLeft;
|
|
37029
|
+
};
|
|
37030
|
+
const toCol = () => {
|
|
37031
|
+
if (col.scrollLeft !== rail.scrollLeft) col.scrollLeft = rail.scrollLeft;
|
|
37032
|
+
};
|
|
37033
|
+
col.addEventListener("scroll", toRail, { passive: true });
|
|
37034
|
+
rail.addEventListener("scroll", toCol, { passive: true });
|
|
37035
|
+
toRail();
|
|
37036
|
+
return () => {
|
|
37037
|
+
col.removeEventListener("scroll", toRail);
|
|
37038
|
+
rail.removeEventListener("scroll", toCol);
|
|
37039
|
+
};
|
|
37040
|
+
}, [colRef, railRef]);
|
|
37041
|
+
return metric;
|
|
37042
|
+
}
|
|
37043
|
+
/**
|
|
37044
|
+
* The side-by-side pane's horizontal scrollbars, stuck to the bottom of the
|
|
37045
|
+
* pane instead of the bottom of the file — see `h-rail.ts` for why they are
|
|
37046
|
+
* here at all.
|
|
37047
|
+
*
|
|
37048
|
+
* Always rendered, never conditionally: the strip collapses to nothing through
|
|
37049
|
+
* a class when neither column overflows, so both rails keep their elements and
|
|
37050
|
+
* the effects above keep stable dependencies. A rail that mounted and
|
|
37051
|
+
* unmounted with the measurement would re-attach its listeners on every file.
|
|
37052
|
+
*
|
|
37053
|
+
* @param leftRef - the left column.
|
|
37054
|
+
* @param rightRef - the right column.
|
|
37055
|
+
* @param split - the divider's position, as a fraction of the pane's width;
|
|
37056
|
+
* the rails carry the same flex sizing so each sits under the
|
|
37057
|
+
* column it scrolls.
|
|
37058
|
+
* @returns the sticky rail strip.
|
|
37059
|
+
*/
|
|
37060
|
+
function SideRails({ leftRef, rightRef, split }) {
|
|
37061
|
+
const leftRailRef = (0, react.useRef)(null);
|
|
37062
|
+
const rightRailRef = (0, react.useRef)(null);
|
|
37063
|
+
const left = useRail(leftRef, leftRailRef);
|
|
37064
|
+
const right = useRail(rightRef, rightRailRef);
|
|
37065
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
37066
|
+
className: railsShown(left, right) ? `${GitWorkbenchPanel_module_css_default.sideRails} ${GitWorkbenchPanel_module_css_default.sideRailsOn}` : GitWorkbenchPanel_module_css_default.sideRails,
|
|
37067
|
+
"aria-hidden": "true",
|
|
37068
|
+
children: [
|
|
37069
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
37070
|
+
ref: leftRailRef,
|
|
37071
|
+
className: GitWorkbenchPanel_module_css_default.sideRail,
|
|
37072
|
+
style: { flexBasis: `${split * 100}%` },
|
|
37073
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
37074
|
+
className: GitWorkbenchPanel_module_css_default.sideRailSpan,
|
|
37075
|
+
style: { width: left.content }
|
|
37076
|
+
})
|
|
37077
|
+
}),
|
|
37078
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: GitWorkbenchPanel_module_css_default.sideRailGap }),
|
|
37079
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
37080
|
+
ref: rightRailRef,
|
|
37081
|
+
className: `${GitWorkbenchPanel_module_css_default.sideRail} ${GitWorkbenchPanel_module_css_default.sideRailRight}`,
|
|
37082
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
37083
|
+
className: GitWorkbenchPanel_module_css_default.sideRailSpan,
|
|
37084
|
+
style: { width: right.content }
|
|
37085
|
+
})
|
|
37086
|
+
})
|
|
37087
|
+
]
|
|
37088
|
+
});
|
|
37089
|
+
}
|
|
37090
|
+
//#endregion
|
|
36543
37091
|
//#region src/client/use-row-window.ts
|
|
36544
37092
|
/**
|
|
36545
37093
|
* The rows a diff actually has to put in the DOM, tracked against its scroller.
|
|
@@ -36555,9 +37103,13 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
36555
37103
|
*
|
|
36556
37104
|
* @param scrollRef - the element that scrolls the rows.
|
|
36557
37105
|
* @param rowCount - how many rows the diff has.
|
|
37106
|
+
* @param enabled - false while soft wrap is on, when the rows are no longer a
|
|
37107
|
+
* fixed height and `use-variable-row-window.ts` answers
|
|
37108
|
+
* instead. Attaching both panes' listeners at once would put
|
|
37109
|
+
* two readers on the same scroll.
|
|
36558
37110
|
* @returns the rows to render and the spacer heights standing in for the rest.
|
|
36559
37111
|
*/
|
|
36560
|
-
function useRowWindow(scrollRef, rowCount, mountKey) {
|
|
37112
|
+
function useRowWindow(scrollRef, rowCount, mountKey, enabled = true) {
|
|
36561
37113
|
const count = Number.isFinite(rowCount) ? Math.max(0, Math.trunc(rowCount)) : 0;
|
|
36562
37114
|
const [held, setHeld] = (0, react.useState)(() => ({
|
|
36563
37115
|
mountKey,
|
|
@@ -36567,7 +37119,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
36567
37119
|
const visible = rowWindowForMount(held, count, mountKey);
|
|
36568
37120
|
(0, react.useEffect)(() => {
|
|
36569
37121
|
const el = scrollRef.current;
|
|
36570
|
-
if (el === null) return;
|
|
37122
|
+
if (el === null || !enabled) return;
|
|
36571
37123
|
const read = () => {
|
|
36572
37124
|
const next = rowWindow(el.scrollTop, el.clientHeight, count);
|
|
36573
37125
|
setHeld((prev) => prev.mountKey === mountKey && prev.rowCount === count && sameRowWindow(prev.win, next) ? prev : {
|
|
@@ -36587,11 +37139,475 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
36587
37139
|
}, [
|
|
36588
37140
|
scrollRef,
|
|
36589
37141
|
count,
|
|
36590
|
-
mountKey
|
|
37142
|
+
mountKey,
|
|
37143
|
+
enabled
|
|
36591
37144
|
]);
|
|
36592
37145
|
return visible;
|
|
36593
37146
|
}
|
|
36594
37147
|
//#endregion
|
|
37148
|
+
//#region src/client/row-heights.ts
|
|
37149
|
+
/**
|
|
37150
|
+
* Row offsets when the rows are NOT all the same height — what soft wrap makes
|
|
37151
|
+
* of a diff pane.
|
|
37152
|
+
*
|
|
37153
|
+
* `row-window.ts` places row `i` at `i * 20px` with no measuring at all, and
|
|
37154
|
+
* says so: the panes guarantee it by writing `white-space: pre`, so nothing
|
|
37155
|
+
* ever wraps. Turn wrapping on and that guarantee is gone — one row can be
|
|
37156
|
+
* five lines tall — and every number the window computes from it (which rows
|
|
37157
|
+
* are visible, how tall the spacers are, where a change sits) is wrong.
|
|
37158
|
+
*
|
|
37159
|
+
* The replacement keeps the same shape and the same rule: work proportional to
|
|
37160
|
+
* the VIEWPORT. Heights are MEASURED, but only for rows that are actually in
|
|
37161
|
+
* the DOM, which is the window plus its overscan; every other row carries an
|
|
37162
|
+
* estimate computed from its text. So a 20,000-row file costs one array and
|
|
37163
|
+
* some arithmetic, not 20,000 measurements.
|
|
37164
|
+
*
|
|
37165
|
+
* The prefix sums are a Fenwick tree rather than a running array, because both
|
|
37166
|
+
* things this is asked for happen on the scroll path and must not be linear:
|
|
37167
|
+
* "where does row i start" is a prefix query, "which row is at y" is a search
|
|
37168
|
+
* for a prefix, and a measurement that lands changes one row's height. All
|
|
37169
|
+
* three are O(log n) here; as a plain array of running totals, the third would
|
|
37170
|
+
* rewrite every entry after the row that moved.
|
|
37171
|
+
*
|
|
37172
|
+
* Pure: no React, no DOM. `tests/row-heights.test.ts` loads it directly.
|
|
37173
|
+
*
|
|
37174
|
+
* @module @young1lin/dsh-ui-gitworkbench/client/row-heights
|
|
37175
|
+
*/
|
|
37176
|
+
/** A viewport height to assume before the scroller has been measured, matching
|
|
37177
|
+
* `row-window.ts`: rendering nothing until the height is known flashes an
|
|
37178
|
+
* empty pane, and a screenful is both safe and close. */
|
|
37179
|
+
const ASSUMED_VIEWPORT_PX = 1200;
|
|
37180
|
+
/**
|
|
37181
|
+
* How many display columns a line occupies.
|
|
37182
|
+
*
|
|
37183
|
+
* Only for the ESTIMATE of rows nobody has measured, so it does not have to
|
|
37184
|
+
* agree with the browser to the character — it has to be close enough that
|
|
37185
|
+
* the scrollbar is the right length and a jump to the middle of the file lands
|
|
37186
|
+
* near where it should. Tabs advance to the next stop (`tab-size: 4` in the
|
|
37187
|
+
* panes' grid) and full-width characters take two columns, which are the two
|
|
37188
|
+
* ways a naive `text.length` is badly wrong rather than slightly wrong.
|
|
37189
|
+
*
|
|
37190
|
+
* @param text - one row's text.
|
|
37191
|
+
* @param tabSize - columns a tab advances to the next multiple of.
|
|
37192
|
+
*/
|
|
37193
|
+
function displayColumns(text, tabSize = 4) {
|
|
37194
|
+
let columns = 0;
|
|
37195
|
+
for (const char of text) {
|
|
37196
|
+
if (char === " ") {
|
|
37197
|
+
columns += tabSize - columns % tabSize;
|
|
37198
|
+
continue;
|
|
37199
|
+
}
|
|
37200
|
+
columns += isWide(char) ? 2 : 1;
|
|
37201
|
+
}
|
|
37202
|
+
return columns;
|
|
37203
|
+
}
|
|
37204
|
+
/**
|
|
37205
|
+
* Whether a character takes two columns in a monospace font: CJK, Hangul,
|
|
37206
|
+
* kana, the full-width forms, and the emoji blocks. The ranges rather than a
|
|
37207
|
+
* table because this runs over a file's worth of text and the answer only
|
|
37208
|
+
* feeds an estimate.
|
|
37209
|
+
*/
|
|
37210
|
+
function isWide(char) {
|
|
37211
|
+
const code = char.codePointAt(0) ?? 0;
|
|
37212
|
+
return code >= 4352 && code <= 4447 || code >= 11904 && code <= 42191 || code >= 44032 && code <= 55203 || code >= 63744 && code <= 64255 || code >= 65072 && code <= 65135 || code >= 65280 && code <= 65376 || code >= 65504 && code <= 65510 || code >= 127744 && code <= 129535;
|
|
37213
|
+
}
|
|
37214
|
+
/**
|
|
37215
|
+
* The height a row is guessed to have before it has been measured.
|
|
37216
|
+
*
|
|
37217
|
+
* @param text - the row's text.
|
|
37218
|
+
* @param columns - how many columns fit across the pane; 0 or less means the
|
|
37219
|
+
* pane has not been measured yet, and one line is assumed.
|
|
37220
|
+
* @param rowH - one line's height in px.
|
|
37221
|
+
*/
|
|
37222
|
+
function estimateRowHeight(text, columns, rowH) {
|
|
37223
|
+
if (!Number.isFinite(columns) || columns <= 0) return rowH;
|
|
37224
|
+
return Math.max(1, Math.ceil(displayColumns(text) / columns)) * rowH;
|
|
37225
|
+
}
|
|
37226
|
+
/**
|
|
37227
|
+
* Per-row heights with O(log n) offsets, backed by a Fenwick tree.
|
|
37228
|
+
*
|
|
37229
|
+
* Bounded by construction: two arrays of `rowCount`, which the panes already
|
|
37230
|
+
* cap. {@link measured} reports how much of it is real rather than guessed, so
|
|
37231
|
+
* a test can prove the measuring stays viewport-sized instead of trusting it.
|
|
37232
|
+
*/
|
|
37233
|
+
var RowHeights = class {
|
|
37234
|
+
/** Each row's height. */
|
|
37235
|
+
heights;
|
|
37236
|
+
/** Fenwick sums, 1-based; `tree[i]` covers a block ending at row `i - 1`. */
|
|
37237
|
+
tree;
|
|
37238
|
+
/** Rows whose height came from the DOM rather than from an estimate. */
|
|
37239
|
+
real;
|
|
37240
|
+
realCount = 0;
|
|
37241
|
+
/**
|
|
37242
|
+
* @param initial - each row's starting height, normally an estimate.
|
|
37243
|
+
*/
|
|
37244
|
+
constructor(initial) {
|
|
37245
|
+
const n = initial.length;
|
|
37246
|
+
this.heights = new Float64Array(n);
|
|
37247
|
+
this.tree = new Float64Array(n + 1);
|
|
37248
|
+
this.real = new Uint8Array(n);
|
|
37249
|
+
for (let i = 0; i < n; i += 1) this.heights[i] = sane(initial[i]);
|
|
37250
|
+
for (let i = 1; i <= n; i += 1) {
|
|
37251
|
+
this.tree[i] += this.heights[i - 1];
|
|
37252
|
+
const parent = i + (i & -i);
|
|
37253
|
+
if (parent <= n) this.tree[parent] += this.tree[i];
|
|
37254
|
+
}
|
|
37255
|
+
}
|
|
37256
|
+
/** How many rows there are. */
|
|
37257
|
+
get count() {
|
|
37258
|
+
return this.heights.length;
|
|
37259
|
+
}
|
|
37260
|
+
/** How many rows carry a measured height rather than an estimate. */
|
|
37261
|
+
measured() {
|
|
37262
|
+
return this.realCount;
|
|
37263
|
+
}
|
|
37264
|
+
/**
|
|
37265
|
+
* Record one row's real height.
|
|
37266
|
+
* @returns whether anything moved, so a caller can avoid a re-render.
|
|
37267
|
+
*/
|
|
37268
|
+
set(index, px) {
|
|
37269
|
+
if (!Number.isInteger(index) || index < 0 || index >= this.count) return false;
|
|
37270
|
+
const next = sane(px);
|
|
37271
|
+
if (this.real[index] === 0) {
|
|
37272
|
+
this.real[index] = 1;
|
|
37273
|
+
this.realCount += 1;
|
|
37274
|
+
}
|
|
37275
|
+
const delta = next - this.heights[index];
|
|
37276
|
+
if (delta === 0) return false;
|
|
37277
|
+
this.heights[index] = next;
|
|
37278
|
+
for (let i = index + 1; i <= this.count; i += i & -i) this.tree[i] += delta;
|
|
37279
|
+
return true;
|
|
37280
|
+
}
|
|
37281
|
+
/** One row's height. */
|
|
37282
|
+
heightAt(index) {
|
|
37283
|
+
if (index < 0 || index >= this.count) return 0;
|
|
37284
|
+
return this.heights[index];
|
|
37285
|
+
}
|
|
37286
|
+
/** Where a row starts, measured from the top of the scrolled content. */
|
|
37287
|
+
topAt(index) {
|
|
37288
|
+
let sum = 0;
|
|
37289
|
+
for (let i = Math.max(0, Math.min(index, this.count)); i > 0; i -= i & -i) sum += this.tree[i];
|
|
37290
|
+
return sum;
|
|
37291
|
+
}
|
|
37292
|
+
/** Every row's height together. */
|
|
37293
|
+
total() {
|
|
37294
|
+
return this.topAt(this.count);
|
|
37295
|
+
}
|
|
37296
|
+
/**
|
|
37297
|
+
* The row that contains `y`, by binary lifting over the tree — the same
|
|
37298
|
+
* search a running-totals array would do, without the array.
|
|
37299
|
+
*/
|
|
37300
|
+
rowAt(y) {
|
|
37301
|
+
if (this.count === 0) return 0;
|
|
37302
|
+
let remaining = Number.isFinite(y) && y > 0 ? y : 0;
|
|
37303
|
+
let index = 0;
|
|
37304
|
+
let step = 1;
|
|
37305
|
+
while (step * 2 <= this.count) step *= 2;
|
|
37306
|
+
for (; step > 0; step = Math.floor(step / 2)) {
|
|
37307
|
+
const probe = index + step;
|
|
37308
|
+
if (probe <= this.count && this.tree[probe] <= remaining) {
|
|
37309
|
+
remaining -= this.tree[probe];
|
|
37310
|
+
index = probe;
|
|
37311
|
+
}
|
|
37312
|
+
}
|
|
37313
|
+
return Math.min(index, this.count - 1);
|
|
37314
|
+
}
|
|
37315
|
+
};
|
|
37316
|
+
/** @param value - a number from the DOM, which can be NaN or negative. */
|
|
37317
|
+
function sane(value) {
|
|
37318
|
+
return Number.isFinite(value) && value > 0 ? value : 0;
|
|
37319
|
+
}
|
|
37320
|
+
/**
|
|
37321
|
+
* The window of rows to render when the rows are not all one height.
|
|
37322
|
+
*
|
|
37323
|
+
* Same answer shape as {@link rowWindow}, and the same short-circuit below
|
|
37324
|
+
* {@link WINDOW_WHOLE_BELOW}: windowing has costs of its own, and a file that
|
|
37325
|
+
* was never slow should render exactly as it did before.
|
|
37326
|
+
*
|
|
37327
|
+
* @param scrollTop - the scroller's current offset in px.
|
|
37328
|
+
* @param viewportH - the scroller's visible height in px; 0 before measuring.
|
|
37329
|
+
* @param heights - the rows' heights.
|
|
37330
|
+
* @param overscan - rows to keep beyond each edge.
|
|
37331
|
+
*/
|
|
37332
|
+
function variableRowWindow(scrollTop, viewportH, heights, overscan = 40) {
|
|
37333
|
+
const rows = heights.count;
|
|
37334
|
+
if (rows <= 400) return {
|
|
37335
|
+
start: 0,
|
|
37336
|
+
end: rows,
|
|
37337
|
+
padTop: 0,
|
|
37338
|
+
padBottom: 0
|
|
37339
|
+
};
|
|
37340
|
+
const top = Number.isFinite(scrollTop) && scrollTop > 0 ? scrollTop : 0;
|
|
37341
|
+
const view = Number.isFinite(viewportH) && viewportH > 0 ? viewportH : ASSUMED_VIEWPORT_PX;
|
|
37342
|
+
const pad = Math.max(0, Math.trunc(overscan));
|
|
37343
|
+
const start = Math.max(0, heights.rowAt(top) - pad);
|
|
37344
|
+
const end = Math.min(rows, heights.rowAt(top + view) + 1 + pad);
|
|
37345
|
+
const safeEnd = Math.max(start, end);
|
|
37346
|
+
return {
|
|
37347
|
+
start,
|
|
37348
|
+
end: safeEnd,
|
|
37349
|
+
padTop: heights.topAt(start),
|
|
37350
|
+
padBottom: Math.max(0, heights.total() - heights.topAt(safeEnd))
|
|
37351
|
+
};
|
|
37352
|
+
}
|
|
37353
|
+
//#endregion
|
|
37354
|
+
//#region src/client/use-variable-row-window.ts
|
|
37355
|
+
/**
|
|
37356
|
+
* The windowing hook for panes whose rows are not all one height — a diff
|
|
37357
|
+
* pane with soft wrap on.
|
|
37358
|
+
*
|
|
37359
|
+
* The fixed-height hook beside this one (`use-row-window.ts`) needs nothing
|
|
37360
|
+
* from the DOM but the scroll offset, because `i * 20px` is the answer. Once
|
|
37361
|
+
* lines wrap, only the DOM knows how tall a row came out, so this one measures
|
|
37362
|
+
* — and measures ONLY the rows it just rendered, which is the window plus its
|
|
37363
|
+
* overscan. Every other row carries an estimate computed from its text, so the
|
|
37364
|
+
* scrollbar is close from the first paint instead of growing as the reader
|
|
37365
|
+
* scrolls.
|
|
37366
|
+
*
|
|
37367
|
+
* A measurement that replaces an estimate for a row ABOVE the viewport moves
|
|
37368
|
+
* everything below it, including what the reader is looking at. The scroll
|
|
37369
|
+
* offset is corrected by the same delta in the same layout pass, so the rows
|
|
37370
|
+
* on screen stay under the eye rather than sliding.
|
|
37371
|
+
*
|
|
37372
|
+
* @module @young1lin/dsh-ui-gitworkbench/client/use-variable-row-window
|
|
37373
|
+
*/
|
|
37374
|
+
/** Attribute a pane puts on each measurable element, as `scope:index`. */
|
|
37375
|
+
const ROW_INDEX_ATTR = "data-gw-row";
|
|
37376
|
+
/**
|
|
37377
|
+
* What a pane writes on an element it wants measured.
|
|
37378
|
+
*
|
|
37379
|
+
* The scope is half the value rather than a second attribute because two
|
|
37380
|
+
* height models can be mounted inside one scroller — the aligned diff and the
|
|
37381
|
+
* dense index column beside the editor — and a bare index would let each read
|
|
37382
|
+
* the other's rows as its own.
|
|
37383
|
+
*
|
|
37384
|
+
* @param scope - which height model the element belongs to.
|
|
37385
|
+
* @param index - the row's index WITHIN that model.
|
|
37386
|
+
*/
|
|
37387
|
+
function rowMark(scope, index) {
|
|
37388
|
+
return { [ROW_INDEX_ATTR]: `${scope}:${index}` };
|
|
37389
|
+
}
|
|
37390
|
+
/**
|
|
37391
|
+
* Columns that fit across a pane, from its width and one character's advance.
|
|
37392
|
+
*
|
|
37393
|
+
* Measured off a probe rather than assumed: the panes' font size is a theme
|
|
37394
|
+
* variable a reader can change, so a hard-coded character width would put the
|
|
37395
|
+
* estimate out by a third on the smallest setting.
|
|
37396
|
+
*
|
|
37397
|
+
* @param grid - the element the rows are laid out in.
|
|
37398
|
+
* @returns columns across, or 0 when the element is not laid out yet.
|
|
37399
|
+
*/
|
|
37400
|
+
function columnsAcross(grid) {
|
|
37401
|
+
if (grid === null) return 0;
|
|
37402
|
+
const width = grid.clientWidth;
|
|
37403
|
+
if (!Number.isFinite(width) || width <= 0) return 0;
|
|
37404
|
+
const probe = document.createElement("span");
|
|
37405
|
+
probe.textContent = "0".repeat(100);
|
|
37406
|
+
probe.style.cssText = "position:absolute;visibility:hidden;white-space:pre;pointer-events:none";
|
|
37407
|
+
grid.appendChild(probe);
|
|
37408
|
+
const advance = probe.getBoundingClientRect().width / 100;
|
|
37409
|
+
probe.remove();
|
|
37410
|
+
if (!Number.isFinite(advance) || advance <= 0) return 0;
|
|
37411
|
+
return Math.max(1, Math.floor(width / advance));
|
|
37412
|
+
}
|
|
37413
|
+
function useVariableRowWindow({ scrollRef, rowsRef, widthRef, texts, mountKey, scope, enabled, rowH = 20 }) {
|
|
37414
|
+
/** Columns across the pane. State, because the estimate depends on it and a
|
|
37415
|
+
* dragged divider changes it. */
|
|
37416
|
+
const [columns, setColumns] = (0, react.useState)(0);
|
|
37417
|
+
/**
|
|
37418
|
+
* Bumped when a measurement moved a row.
|
|
37419
|
+
*
|
|
37420
|
+
* The heights live in a mutable structure, so changing one changes no
|
|
37421
|
+
* identity React watches — and the side-by-side pane reads them DURING
|
|
37422
|
+
* render, to impose each row's height on both of its cells. Without this
|
|
37423
|
+
* the first pass would measure correctly and then never re-render to apply
|
|
37424
|
+
* what it measured, which is a row that is one line taller on one side than
|
|
37425
|
+
* on the other. Bumped only when something actually moved, and imposing a
|
|
37426
|
+
* height does not change what is measured (the measured box is inside the
|
|
37427
|
+
* cell), so it settles in one extra pass.
|
|
37428
|
+
*/
|
|
37429
|
+
const [, bumpHeights] = (0, react.useState)(0);
|
|
37430
|
+
const [win, setWin] = (0, react.useState)(() => ({
|
|
37431
|
+
start: 0,
|
|
37432
|
+
end: texts.length,
|
|
37433
|
+
padTop: 0,
|
|
37434
|
+
padBottom: 0
|
|
37435
|
+
}));
|
|
37436
|
+
/** Rebuilt only when the diff or the width really changes — never on scroll. */
|
|
37437
|
+
const heights = (0, react.useMemo)(() => new RowHeights(enabled ? texts.map((text) => estimateRowHeight(text, columns, rowH)) : []), [
|
|
37438
|
+
texts,
|
|
37439
|
+
columns,
|
|
37440
|
+
rowH,
|
|
37441
|
+
mountKey,
|
|
37442
|
+
enabled
|
|
37443
|
+
]);
|
|
37444
|
+
const read = (0, react.useCallback)(() => {
|
|
37445
|
+
const el = scrollRef.current;
|
|
37446
|
+
if (el === null || heights.count === 0) return;
|
|
37447
|
+
const next = variableRowWindow(el.scrollTop, el.clientHeight, heights);
|
|
37448
|
+
setWin((prev) => sameRowWindow(prev, next) ? prev : next);
|
|
37449
|
+
}, [scrollRef, heights]);
|
|
37450
|
+
(0, react.useEffect)(() => {
|
|
37451
|
+
const el = scrollRef.current;
|
|
37452
|
+
if (el === null || !enabled) return;
|
|
37453
|
+
read();
|
|
37454
|
+
const observer = new ResizeObserver(() => {
|
|
37455
|
+
read();
|
|
37456
|
+
setColumns((prev) => {
|
|
37457
|
+
const measured = columnsAcross((widthRef ?? rowsRef).current);
|
|
37458
|
+
return measured === 0 || measured === prev ? prev : measured;
|
|
37459
|
+
});
|
|
37460
|
+
});
|
|
37461
|
+
el.addEventListener("scroll", read, { passive: true });
|
|
37462
|
+
observer.observe(el);
|
|
37463
|
+
return () => {
|
|
37464
|
+
el.removeEventListener("scroll", read);
|
|
37465
|
+
observer.disconnect();
|
|
37466
|
+
};
|
|
37467
|
+
}, [
|
|
37468
|
+
scrollRef,
|
|
37469
|
+
rowsRef,
|
|
37470
|
+
widthRef,
|
|
37471
|
+
read,
|
|
37472
|
+
enabled
|
|
37473
|
+
]);
|
|
37474
|
+
(0, react.useLayoutEffect)(() => {
|
|
37475
|
+
const root = rowsRef.current;
|
|
37476
|
+
const scroller = scrollRef.current;
|
|
37477
|
+
if (!enabled || root === null || scroller === null) return;
|
|
37478
|
+
const before = heights.topAt(win.start);
|
|
37479
|
+
const tallest = /* @__PURE__ */ new Map();
|
|
37480
|
+
for (const node of root.querySelectorAll(`[${ROW_INDEX_ATTR}^="${scope}:"]`)) {
|
|
37481
|
+
const index = Number(node.getAttribute(ROW_INDEX_ATTR)?.slice(scope.length + 1));
|
|
37482
|
+
if (!Number.isInteger(index)) continue;
|
|
37483
|
+
tallest.set(index, Math.max(tallest.get(index) ?? 0, node.getBoundingClientRect().height));
|
|
37484
|
+
}
|
|
37485
|
+
let moved = false;
|
|
37486
|
+
for (const [index, height] of tallest) if (heights.set(index, height)) moved = true;
|
|
37487
|
+
if (!moved) return;
|
|
37488
|
+
const after = heights.topAt(win.start);
|
|
37489
|
+
if (after !== before) scroller.scrollTop += after - before;
|
|
37490
|
+
bumpHeights((version) => version + 1);
|
|
37491
|
+
read();
|
|
37492
|
+
});
|
|
37493
|
+
return {
|
|
37494
|
+
win,
|
|
37495
|
+
rowTop: (0, react.useCallback)((index) => enabled ? heights.topAt(index) : Math.max(0, Math.trunc(index)) * rowH, [
|
|
37496
|
+
enabled,
|
|
37497
|
+
heights,
|
|
37498
|
+
rowH
|
|
37499
|
+
]),
|
|
37500
|
+
rowHeight: (0, react.useCallback)((index) => enabled ? heights.heightAt(index) : rowH, [
|
|
37501
|
+
enabled,
|
|
37502
|
+
heights,
|
|
37503
|
+
rowH
|
|
37504
|
+
])
|
|
37505
|
+
};
|
|
37506
|
+
}
|
|
37507
|
+
//#endregion
|
|
37508
|
+
//#region src/client/diff-cells.tsx
|
|
37509
|
+
/** Classes that paint only a block's OUTER perimeter. Internal rows carry the
|
|
37510
|
+
* vertical edges but no top/bottom line, avoiding the blue ladder a large
|
|
37511
|
+
* addition block used to draw. Absent side-cells return no class at all. */
|
|
37512
|
+
function blockHotClass(rows, index, side, hot) {
|
|
37513
|
+
if (!hot) return "";
|
|
37514
|
+
const edge = blockEdge(rows, index, side);
|
|
37515
|
+
if (edge === null) return "";
|
|
37516
|
+
const first = edge === "first" || edge === "single" ? ` ${GitWorkbenchPanel_module_css_default.sideBlockHotFirst}` : "";
|
|
37517
|
+
const last = edge === "last" || edge === "single" ? ` ${GitWorkbenchPanel_module_css_default.sideBlockHotLast}` : "";
|
|
37518
|
+
return ` ${GitWorkbenchPanel_module_css_default.sideBlockHot}${first}${last}`;
|
|
37519
|
+
}
|
|
37520
|
+
/** Line-number cell class: a PRESENT cell of a changed row carries its side's
|
|
37521
|
+
* tint into the gutter; an absent one stays blank, the way a split diff shows
|
|
37522
|
+
* a one-sided change with an empty opposite pane rather than a tinted void. */
|
|
37523
|
+
function sideNumClass(row, side) {
|
|
37524
|
+
if ((side === "left" ? row.left : row.right) === null || row.kind === "same") return GitWorkbenchPanel_module_css_default.sideNum;
|
|
37525
|
+
return `${GitWorkbenchPanel_module_css_default.sideNum} ${side === "left" ? GitWorkbenchPanel_module_css_default.sideNumDel : GitWorkbenchPanel_module_css_default.sideNumAdd}`;
|
|
37526
|
+
}
|
|
37527
|
+
/** Code cell class: deletions tint left, additions right, context stays quiet. */
|
|
37528
|
+
function sideCodeClass(row, side) {
|
|
37529
|
+
if ((side === "left" ? row.left : row.right) === null || row.kind === "same") return GitWorkbenchPanel_module_css_default.sideCodeSame;
|
|
37530
|
+
return `${side === "left" ? GitWorkbenchPanel_module_css_default.sideCodeDel : GitWorkbenchPanel_module_css_default.sideCodeAdd} ${GitWorkbenchPanel_module_css_default.sideCellBlock}`;
|
|
37531
|
+
}
|
|
37532
|
+
/** One text with every carriage return drawn as the CR glyph. No CR means
|
|
37533
|
+
* the text comes back untouched — the common line, on both sides, costs one
|
|
37534
|
+
* `includes`. The glyph spans are aria-hidden and unselectable, so copying a
|
|
37535
|
+
* line copies code, not markers. */
|
|
37536
|
+
function renderWithCrMarks(text) {
|
|
37537
|
+
const parts = splitOnCr(text);
|
|
37538
|
+
if (parts.length === 1) return text;
|
|
37539
|
+
const out = [parts[0]];
|
|
37540
|
+
for (let i = 1; i < parts.length; i += 1) {
|
|
37541
|
+
out.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
37542
|
+
className: GitWorkbenchPanel_module_css_default.crMark,
|
|
37543
|
+
"aria-hidden": "true",
|
|
37544
|
+
children: "␍"
|
|
37545
|
+
}, `cr${i}`));
|
|
37546
|
+
out.push(parts[i]);
|
|
37547
|
+
}
|
|
37548
|
+
return out;
|
|
37549
|
+
}
|
|
37550
|
+
/** One cell's Shiki runs, or its plain text when no tokens exist; either way
|
|
37551
|
+
* each carriage return in the cell is drawn, so a line whose only change is
|
|
37552
|
+
* its ending shows the difference instead of two identical-looking cells. */
|
|
37553
|
+
function renderSideCode(cell, tokens) {
|
|
37554
|
+
if (cell === null) return "";
|
|
37555
|
+
if (tokens === void 0 || tokens.length === 0) return renderWithCrMarks(cell.text);
|
|
37556
|
+
if (tokens.length === 1 && tokens[0].color === void 0 && !tokens[0].italic) return renderWithCrMarks(cell.text);
|
|
37557
|
+
return tokens.map((tok, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
37558
|
+
style: tok.color === void 0 && !tok.italic ? void 0 : {
|
|
37559
|
+
color: tok.color,
|
|
37560
|
+
fontStyle: tok.italic ? "italic" : void 0
|
|
37561
|
+
},
|
|
37562
|
+
children: renderWithCrMarks(tok.text)
|
|
37563
|
+
}, i));
|
|
37564
|
+
}
|
|
37565
|
+
/**
|
|
37566
|
+
* The spacer standing in for the rows above or below the window.
|
|
37567
|
+
*
|
|
37568
|
+
* It spans every column of the grid, so a blame gutter does not change it.
|
|
37569
|
+
* @param height - px of rows it stands in for; nothing is rendered for 0.
|
|
37570
|
+
*/
|
|
37571
|
+
function RowSpacer({ height }) {
|
|
37572
|
+
if (height <= 0) return null;
|
|
37573
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
37574
|
+
className: GitWorkbenchPanel_module_css_default.sideSpacer,
|
|
37575
|
+
style: { height: `${height}px` },
|
|
37576
|
+
"aria-hidden": "true"
|
|
37577
|
+
});
|
|
37578
|
+
}
|
|
37579
|
+
/**
|
|
37580
|
+
* One side of one aligned row: its line-number cell and its code cell.
|
|
37581
|
+
*
|
|
37582
|
+
* Written once and used by all three columns the pane draws — the left side of
|
|
37583
|
+
* a diff, the right side, and the dense index column beside the editor —
|
|
37584
|
+
* because the three differ only in which cell they read, what hangs the block
|
|
37585
|
+
* bar and whether a click arms the editor. Everything else about them, from
|
|
37586
|
+
* the block outline to the CR markers, is the same in all three and was
|
|
37587
|
+
* previously the same three times.
|
|
37588
|
+
*/
|
|
37589
|
+
function SideCells({ row, side, index, rows, current, tokens, mark, minHeight, bar, armable, onArm }) {
|
|
37590
|
+
const hot = blockHotClass(rows, index, side, current);
|
|
37591
|
+
const cell = side === "left" ? row.left : row.right;
|
|
37592
|
+
const code = renderSideCode(cell, tokens);
|
|
37593
|
+
const box = minHeight !== void 0 && minHeight > 0 ? { minHeight: `${minHeight}px` } : void 0;
|
|
37594
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
37595
|
+
className: `${sideNumClass(row, side)}${hot}`,
|
|
37596
|
+
style: box,
|
|
37597
|
+
children: cell === null ? "" : cell.line
|
|
37598
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
37599
|
+
className: `${GitWorkbenchPanel_module_css_default.sideCode} ${sideCodeClass(row, side)}${hot}${armable === true ? ` ${GitWorkbenchPanel_module_css_default.sideArmable}` : ""}`,
|
|
37600
|
+
style: box,
|
|
37601
|
+
"data-block": cell !== null && row.block >= 0 ? row.block : void 0,
|
|
37602
|
+
onClick: onArm,
|
|
37603
|
+
children: [mark === void 0 ? code : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
37604
|
+
className: GitWorkbenchPanel_module_css_default.sideFlow,
|
|
37605
|
+
...mark,
|
|
37606
|
+
children: code
|
|
37607
|
+
}), bar]
|
|
37608
|
+
})] });
|
|
37609
|
+
}
|
|
37610
|
+
//#endregion
|
|
36595
37611
|
//#region src/client/DiffViews.tsx
|
|
36596
37612
|
const SPLIT_MIN = .15;
|
|
36597
37613
|
const SPLIT_MAX = .85;
|
|
@@ -36632,14 +37648,24 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
36632
37648
|
* a block child of a scroller is only ever as wide as the scrollport. A header
|
|
36633
37649
|
* outside the scrolled box has neither problem.
|
|
36634
37650
|
*/
|
|
36635
|
-
function DiffView({ segment, path, palette, t }) {
|
|
37651
|
+
function DiffView({ segment, path, palette, t, wrap }) {
|
|
36636
37652
|
const lang = shikiLangOf(path);
|
|
36637
37653
|
const shikiTheme = shikiThemeOf(palette);
|
|
36638
37654
|
const grammarGen = (0, react.useSyncExternalStore)(subscribeGrammarLoaded, grammarLoadCount);
|
|
36639
37655
|
const rowsWithWords = (0, react.useMemo)(() => attachWordRanges(parseRows(segment)), [segment]);
|
|
36640
37656
|
const sides = (0, react.useMemo)(() => gutterSides(rowsWithWords), [rowsWithWords]);
|
|
36641
37657
|
const scrollRef = (0, react.useRef)(null);
|
|
36642
|
-
const
|
|
37658
|
+
const preRef = (0, react.useRef)(null);
|
|
37659
|
+
const fixed = useRowWindow(scrollRef, rowsWithWords.length, path, !wrap);
|
|
37660
|
+
const flow = useVariableRowWindow({
|
|
37661
|
+
scrollRef,
|
|
37662
|
+
rowsRef: preRef,
|
|
37663
|
+
texts: (0, react.useMemo)(() => rowsWithWords.map((row) => row.text), [rowsWithWords]),
|
|
37664
|
+
mountKey: path,
|
|
37665
|
+
scope: "u",
|
|
37666
|
+
enabled: wrap
|
|
37667
|
+
});
|
|
37668
|
+
const win = wrap ? flow.win : fixed;
|
|
36643
37669
|
const syntax = (0, react.useMemo)(() => highlightForRowsWindow(rowsWithWords, lang, shikiTheme, win.start, win.end), [
|
|
36644
37670
|
rowsWithWords,
|
|
36645
37671
|
lang,
|
|
@@ -36652,7 +37678,9 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
36652
37678
|
const changes = (0, react.useMemo)(() => countBlocks(blocks), [blocks]);
|
|
36653
37679
|
const blocksForNav = (0, react.useRef)(blocks);
|
|
36654
37680
|
blocksForNav.current = blocks;
|
|
36655
|
-
const
|
|
37681
|
+
const placeRow = (0, react.useRef)(void 0);
|
|
37682
|
+
placeRow.current = wrap ? flow.rowTop : void 0;
|
|
37683
|
+
const { goToChange } = useChangeNav(scrollRef, (0, react.useCallback)(() => blockTopsFromRows(blocksForNav.current, 20, 8, placeRow.current), []));
|
|
36656
37684
|
const walk = (0, react.useRef)(goToChange);
|
|
36657
37685
|
walk.current = goToChange;
|
|
36658
37686
|
(0, react.useEffect)(() => {
|
|
@@ -36703,7 +37731,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
36703
37731
|
className: GitWorkbenchPanel_module_css_default.diffScroll,
|
|
36704
37732
|
tabIndex: -1,
|
|
36705
37733
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("pre", {
|
|
36706
|
-
|
|
37734
|
+
ref: preRef,
|
|
37735
|
+
className: wrap ? `${GitWorkbenchPanel_module_css_default.diffPre} ${GitWorkbenchPanel_module_css_default.diffPreWrap}` : GitWorkbenchPanel_module_css_default.diffPre,
|
|
36707
37736
|
children: [
|
|
36708
37737
|
win.padTop > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
36709
37738
|
className: GitWorkbenchPanel_module_css_default.diffSpacer,
|
|
@@ -36715,6 +37744,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
36715
37744
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
36716
37745
|
className: `${GitWorkbenchPanel_module_css_default.line} ${rowClass(row.kind)}`,
|
|
36717
37746
|
"data-block": blocks[i] >= 0 ? blocks[i] : void 0,
|
|
37747
|
+
...rowMark("u", i),
|
|
36718
37748
|
children: [
|
|
36719
37749
|
sides.old ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
36720
37750
|
className: GitWorkbenchPanel_module_css_default.lnOld,
|
|
@@ -36799,7 +37829,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
36799
37829
|
* (history and compare keep it unconditionally), with a notice — a silently
|
|
36800
37830
|
* different view reads as a broken one, not a guarded one.
|
|
36801
37831
|
*/
|
|
36802
|
-
function SideBySideView({ t, path, palette, statsPath, fetchSides, writeChecked, scopeKey, gen, fallbackSegment, fallbackLoading, onBlockAction, onSaved, onDirtyChange }) {
|
|
37832
|
+
function SideBySideView({ t, path, palette, wrap, statsPath, fetchSides, writeChecked, scopeKey, gen, fallbackSegment, fallbackLoading, phantomListed, onBlockAction, onSaved, onDirtyChange }) {
|
|
36803
37833
|
const [layer, setLayer] = (0, react.useState)("unstaged");
|
|
36804
37834
|
const [split, setSplit] = (0, react.useState)(.5);
|
|
36805
37835
|
const colsRef = (0, react.useRef)(null);
|
|
@@ -36898,7 +37928,25 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
36898
37928
|
const alignedBlockTops = (0, react.useMemo)(() => blockTopsFromRows(rows.map((row) => row.block), 20, navOffset), [rows, navOffset]);
|
|
36899
37929
|
const editorBlockTops = (0, react.useMemo)(() => blockTopsFromSideRows(rows, "right", 20, navOffset), [rows, navOffset]);
|
|
36900
37930
|
const rowWindowKey = `${scopeKey}\x1f${path}\x1f${layer}\x1f${sides?.diffSha ?? ""}`;
|
|
36901
|
-
const
|
|
37931
|
+
const alignedGridRef = (0, react.useRef)(null);
|
|
37932
|
+
const denseGridRef = (0, react.useRef)(null);
|
|
37933
|
+
const leftColRef = (0, react.useRef)(null);
|
|
37934
|
+
const rightColRef = (0, react.useRef)(null);
|
|
37935
|
+
const fixedWin = useRowWindow(scrollRef, rows.length, rowWindowKey, !wrap);
|
|
37936
|
+
const flow = useVariableRowWindow({
|
|
37937
|
+
scrollRef,
|
|
37938
|
+
rowsRef: colsRef,
|
|
37939
|
+
widthRef: alignedGridRef,
|
|
37940
|
+
texts: (0, react.useMemo)(() => rows.map((row) => {
|
|
37941
|
+
const left = row.left?.text ?? "";
|
|
37942
|
+
const right = row.right?.text ?? "";
|
|
37943
|
+
return left.length >= right.length ? left : right;
|
|
37944
|
+
}), [rows]),
|
|
37945
|
+
mountKey: rowWindowKey,
|
|
37946
|
+
scope: "a",
|
|
37947
|
+
enabled: wrap
|
|
37948
|
+
});
|
|
37949
|
+
const win = wrap ? flow.win : fixedWin;
|
|
36902
37950
|
const leftLines = (0, react.useMemo)(() => rows.map((row) => row.left === null ? "" : row.left.text), [rows]);
|
|
36903
37951
|
const rightLines = (0, react.useMemo)(() => rows.map((row) => row.right === null ? "" : row.right.text), [rows]);
|
|
36904
37952
|
const leftSyntax = (0, react.useMemo)(() => highlightWindow(leftLines, lang, shikiTheme, win.start, win.end), [
|
|
@@ -36949,7 +37997,16 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
36949
37997
|
row,
|
|
36950
37998
|
i
|
|
36951
37999
|
})).filter((entry) => entry.row.left !== null), [rows]);
|
|
36952
|
-
const
|
|
38000
|
+
const fixedLeftWin = useRowWindow(scrollRef, leftRows.length, rowWindowKey, !wrap);
|
|
38001
|
+
const leftFlow = useVariableRowWindow({
|
|
38002
|
+
scrollRef,
|
|
38003
|
+
rowsRef: denseGridRef,
|
|
38004
|
+
texts: (0, react.useMemo)(() => leftRows.map((entry) => entry.row.left?.text ?? ""), [leftRows]),
|
|
38005
|
+
mountKey: rowWindowKey,
|
|
38006
|
+
scope: "d",
|
|
38007
|
+
enabled: wrap
|
|
38008
|
+
});
|
|
38009
|
+
const leftWin = wrap ? leftFlow.win : fixedLeftWin;
|
|
36953
38010
|
/** Arm the editor from the payload on screen; the unstaged tab, and only
|
|
36954
38011
|
* for a payload `editableSides` accepts — armEdit itself refuses the rest,
|
|
36955
38012
|
* so even a stray call cannot put CRLF text into the buffer. */
|
|
@@ -37144,10 +38201,11 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
37144
38201
|
segment: fallbackSegment,
|
|
37145
38202
|
path,
|
|
37146
38203
|
palette,
|
|
37147
|
-
t
|
|
38204
|
+
t,
|
|
38205
|
+
wrap
|
|
37148
38206
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
37149
38207
|
className: GitWorkbenchPanel_module_css_default.empty,
|
|
37150
|
-
children: fallbackLoading ? t("loadingDiff") : t("noTextDiff")
|
|
38208
|
+
children: fallbackLoading ? t("loadingDiff") : phantomListed ? t("phantomNotice") : t("noTextDiff")
|
|
37151
38209
|
});
|
|
37152
38210
|
if (failed) return unifiedFallback();
|
|
37153
38211
|
if (sides === null) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -37369,8 +38427,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
37369
38427
|
className: GitWorkbenchPanel_module_css_default.sideScroll,
|
|
37370
38428
|
children: bodyState.kind === "empty" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
37371
38429
|
className: GitWorkbenchPanel_module_css_default.empty,
|
|
37372
|
-
children: t("noTextDiff")
|
|
37373
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
38430
|
+
children: phantomListed ? t("phantomNotice") : t("noTextDiff")
|
|
38431
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
37374
38432
|
ref: colsRef,
|
|
37375
38433
|
className: GitWorkbenchPanel_module_css_default.sideCols,
|
|
37376
38434
|
onMouseOver: onBodyHover,
|
|
@@ -37380,29 +38438,31 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
37380
38438
|
},
|
|
37381
38439
|
children: [
|
|
37382
38440
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
37383
|
-
|
|
38441
|
+
ref: leftColRef,
|
|
38442
|
+
className: wrap ? `${GitWorkbenchPanel_module_css_default.sideCol} ${GitWorkbenchPanel_module_css_default.sideColWrap}` : GitWorkbenchPanel_module_css_default.sideCol,
|
|
37384
38443
|
style: {
|
|
37385
38444
|
flexBasis: `${split * 100}%`,
|
|
37386
38445
|
paddingTop: blockBarClearance
|
|
37387
38446
|
},
|
|
37388
38447
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
37389
|
-
|
|
38448
|
+
ref: bodyState.kind === "editor" ? denseGridRef : alignedGridRef,
|
|
38449
|
+
className: wrap ? `${GitWorkbenchPanel_module_css_default.sideColGrid} ${GitWorkbenchPanel_module_css_default.sideColGridWrap}` : GitWorkbenchPanel_module_css_default.sideColGrid,
|
|
37390
38450
|
children: bodyState.kind === "editor" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
37391
38451
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowSpacer, { height: leftWin.padTop }),
|
|
37392
38452
|
leftRows.slice(leftWin.start, leftWin.end).map((entry, kk) => {
|
|
37393
38453
|
const k = leftWin.start + kk;
|
|
37394
38454
|
const { row, i } = entry;
|
|
37395
38455
|
const hot = hotBlock !== null && row.block === hotBlock;
|
|
37396
|
-
|
|
37397
|
-
|
|
37398
|
-
|
|
37399
|
-
|
|
37400
|
-
|
|
37401
|
-
|
|
37402
|
-
|
|
37403
|
-
|
|
37404
|
-
|
|
37405
|
-
}
|
|
38456
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SideCells, {
|
|
38457
|
+
row,
|
|
38458
|
+
side: "left",
|
|
38459
|
+
index: i,
|
|
38460
|
+
rows,
|
|
38461
|
+
current: row.block >= 0 && row.block === currentBlock,
|
|
38462
|
+
tokens: leftSyntax?.[i],
|
|
38463
|
+
mark: wrap ? rowMark("d", k) : void 0,
|
|
38464
|
+
bar: hot && k === hotFirstLeft ? blockBar(row.block) : null
|
|
38465
|
+
}, `l${i}`);
|
|
37406
38466
|
}),
|
|
37407
38467
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowSpacer, { height: leftWin.padBottom })
|
|
37408
38468
|
] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
@@ -37410,17 +38470,17 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
37410
38470
|
rows.slice(win.start, win.end).map((row, k) => {
|
|
37411
38471
|
const i = win.start + k;
|
|
37412
38472
|
const hot = hotBlock !== null && row.block === hotBlock;
|
|
37413
|
-
|
|
37414
|
-
|
|
37415
|
-
|
|
37416
|
-
|
|
37417
|
-
|
|
37418
|
-
|
|
37419
|
-
|
|
37420
|
-
|
|
37421
|
-
|
|
37422
|
-
|
|
37423
|
-
}
|
|
38473
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SideCells, {
|
|
38474
|
+
row,
|
|
38475
|
+
side: "left",
|
|
38476
|
+
index: i,
|
|
38477
|
+
rows,
|
|
38478
|
+
current: row.block >= 0 && row.block === currentBlock,
|
|
38479
|
+
tokens: leftSyntax?.[i],
|
|
38480
|
+
mark: wrap ? rowMark("a", i) : void 0,
|
|
38481
|
+
minHeight: wrap ? flow.rowHeight(i) : void 0,
|
|
38482
|
+
bar: hot && i === hotFirst && row.right === null ? blockBar(row.block) : null
|
|
38483
|
+
}, i);
|
|
37424
38484
|
}),
|
|
37425
38485
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowSpacer, { height: win.padBottom })
|
|
37426
38486
|
] })
|
|
@@ -37431,7 +38491,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
37431
38491
|
onDrag: onSplitDrag
|
|
37432
38492
|
}),
|
|
37433
38493
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
37434
|
-
|
|
38494
|
+
ref: rightColRef,
|
|
38495
|
+
className: wrap ? `${GitWorkbenchPanel_module_css_default.sideCol} ${GitWorkbenchPanel_module_css_default.sideColRight} ${GitWorkbenchPanel_module_css_default.sideColWrap}` : `${GitWorkbenchPanel_module_css_default.sideCol} ${GitWorkbenchPanel_module_css_default.sideColRight}`,
|
|
37435
38496
|
style: { paddingTop: blockBarClearance },
|
|
37436
38497
|
children: bodyState.kind === "editor" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CodeEditor, {
|
|
37437
38498
|
value: edit.buffer,
|
|
@@ -37447,33 +38508,39 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
37447
38508
|
ariaLabel: path,
|
|
37448
38509
|
onSave: () => {
|
|
37449
38510
|
if (dirty && !saving) runSave(edit.baseSha);
|
|
37450
|
-
}
|
|
38511
|
+
},
|
|
38512
|
+
wrap
|
|
37451
38513
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
37452
|
-
className: GitWorkbenchPanel_module_css_default.sideColGrid,
|
|
38514
|
+
className: wrap ? `${GitWorkbenchPanel_module_css_default.sideColGrid} ${GitWorkbenchPanel_module_css_default.sideColGridWrap}` : GitWorkbenchPanel_module_css_default.sideColGrid,
|
|
37453
38515
|
children: [
|
|
37454
38516
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowSpacer, { height: win.padTop }),
|
|
37455
38517
|
rows.slice(win.start, win.end).map((row, k) => {
|
|
37456
38518
|
const i = win.start + k;
|
|
37457
38519
|
const hot = hotBlock !== null && row.block === hotBlock;
|
|
37458
|
-
|
|
37459
|
-
|
|
37460
|
-
|
|
37461
|
-
|
|
37462
|
-
|
|
37463
|
-
|
|
37464
|
-
|
|
37465
|
-
|
|
37466
|
-
|
|
37467
|
-
|
|
37468
|
-
|
|
37469
|
-
|
|
38520
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SideCells, {
|
|
38521
|
+
row,
|
|
38522
|
+
side: "right",
|
|
38523
|
+
index: i,
|
|
38524
|
+
rows,
|
|
38525
|
+
current: row.block >= 0 && row.block === currentBlock,
|
|
38526
|
+
tokens: rightSyntax?.[i],
|
|
38527
|
+
mark: wrap ? rowMark("a", i) : void 0,
|
|
38528
|
+
minHeight: wrap ? flow.rowHeight(i) : void 0,
|
|
38529
|
+
bar: hot && i === hotFirst && row.right !== null ? blockBar(row.block) : null,
|
|
38530
|
+
armable: layer === "unstaged" && armable,
|
|
38531
|
+
onArm: layer === "unstaged" && armable ? armFromCell : void 0
|
|
38532
|
+
}, i);
|
|
37470
38533
|
}),
|
|
37471
38534
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowSpacer, { height: win.padBottom })
|
|
37472
38535
|
]
|
|
37473
38536
|
})
|
|
37474
38537
|
})
|
|
37475
38538
|
]
|
|
37476
|
-
})
|
|
38539
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SideRails, {
|
|
38540
|
+
leftRef: leftColRef,
|
|
38541
|
+
rightRef: rightColRef,
|
|
38542
|
+
split
|
|
38543
|
+
})] })
|
|
37477
38544
|
}),
|
|
37478
38545
|
pendingLayer !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LeaveEditsConfirm, {
|
|
37479
38546
|
t,
|
|
@@ -37547,76 +38614,6 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
37547
38614
|
})
|
|
37548
38615
|
});
|
|
37549
38616
|
}
|
|
37550
|
-
/** Classes that paint only a block's OUTER perimeter. Internal rows carry the
|
|
37551
|
-
* vertical edges but no top/bottom line, avoiding the blue ladder a large
|
|
37552
|
-
* addition block used to draw. Absent side-cells return no class at all. */
|
|
37553
|
-
function blockHotClass(rows, index, side, hot) {
|
|
37554
|
-
if (!hot) return "";
|
|
37555
|
-
const edge = blockEdge(rows, index, side);
|
|
37556
|
-
if (edge === null) return "";
|
|
37557
|
-
const first = edge === "first" || edge === "single" ? ` ${GitWorkbenchPanel_module_css_default.sideBlockHotFirst}` : "";
|
|
37558
|
-
const last = edge === "last" || edge === "single" ? ` ${GitWorkbenchPanel_module_css_default.sideBlockHotLast}` : "";
|
|
37559
|
-
return ` ${GitWorkbenchPanel_module_css_default.sideBlockHot}${first}${last}`;
|
|
37560
|
-
}
|
|
37561
|
-
/** Line-number cell class: a PRESENT cell of a changed row carries its side's
|
|
37562
|
-
* tint into the gutter; an absent one stays blank, the way a split diff shows
|
|
37563
|
-
* a one-sided change with an empty opposite pane rather than a tinted void. */
|
|
37564
|
-
function sideNumClass(row, side) {
|
|
37565
|
-
if ((side === "left" ? row.left : row.right) === null || row.kind === "same") return GitWorkbenchPanel_module_css_default.sideNum;
|
|
37566
|
-
return `${GitWorkbenchPanel_module_css_default.sideNum} ${side === "left" ? GitWorkbenchPanel_module_css_default.sideNumDel : GitWorkbenchPanel_module_css_default.sideNumAdd}`;
|
|
37567
|
-
}
|
|
37568
|
-
/** Code cell class: deletions tint left, additions right, context stays quiet. */
|
|
37569
|
-
function sideCodeClass(row, side) {
|
|
37570
|
-
if ((side === "left" ? row.left : row.right) === null || row.kind === "same") return GitWorkbenchPanel_module_css_default.sideCodeSame;
|
|
37571
|
-
return `${side === "left" ? GitWorkbenchPanel_module_css_default.sideCodeDel : GitWorkbenchPanel_module_css_default.sideCodeAdd} ${GitWorkbenchPanel_module_css_default.sideCellBlock}`;
|
|
37572
|
-
}
|
|
37573
|
-
/** One text with every carriage return drawn as the CR glyph. No CR means
|
|
37574
|
-
* the text comes back untouched — the common line, on both sides, costs one
|
|
37575
|
-
* `includes`. The glyph spans are aria-hidden and unselectable, so copying a
|
|
37576
|
-
* line copies code, not markers. */
|
|
37577
|
-
function renderWithCrMarks(text) {
|
|
37578
|
-
const parts = splitOnCr(text);
|
|
37579
|
-
if (parts.length === 1) return text;
|
|
37580
|
-
const out = [parts[0]];
|
|
37581
|
-
for (let i = 1; i < parts.length; i += 1) {
|
|
37582
|
-
out.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
37583
|
-
className: GitWorkbenchPanel_module_css_default.crMark,
|
|
37584
|
-
"aria-hidden": "true",
|
|
37585
|
-
children: "␍"
|
|
37586
|
-
}, `cr${i}`));
|
|
37587
|
-
out.push(parts[i]);
|
|
37588
|
-
}
|
|
37589
|
-
return out;
|
|
37590
|
-
}
|
|
37591
|
-
/** One cell's Shiki runs, or its plain text when no tokens exist; either way
|
|
37592
|
-
* each carriage return in the cell is drawn, so a line whose only change is
|
|
37593
|
-
* its ending shows the difference instead of two identical-looking cells. */
|
|
37594
|
-
function renderSideCode(cell, tokens) {
|
|
37595
|
-
if (cell === null) return "";
|
|
37596
|
-
if (tokens === void 0 || tokens.length === 0) return renderWithCrMarks(cell.text);
|
|
37597
|
-
if (tokens.length === 1 && tokens[0].color === void 0 && !tokens[0].italic) return renderWithCrMarks(cell.text);
|
|
37598
|
-
return tokens.map((tok, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
37599
|
-
style: tok.color === void 0 && !tok.italic ? void 0 : {
|
|
37600
|
-
color: tok.color,
|
|
37601
|
-
fontStyle: tok.italic ? "italic" : void 0
|
|
37602
|
-
},
|
|
37603
|
-
children: renderWithCrMarks(tok.text)
|
|
37604
|
-
}, i));
|
|
37605
|
-
}
|
|
37606
|
-
/**
|
|
37607
|
-
* The spacer standing in for the rows above or below the window.
|
|
37608
|
-
*
|
|
37609
|
-
* It spans every column of the grid, so a blame gutter does not change it.
|
|
37610
|
-
* @param height - px of rows it stands in for; nothing is rendered for 0.
|
|
37611
|
-
*/
|
|
37612
|
-
function RowSpacer({ height }) {
|
|
37613
|
-
if (height <= 0) return null;
|
|
37614
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
37615
|
-
className: GitWorkbenchPanel_module_css_default.sideSpacer,
|
|
37616
|
-
style: { height: `${height}px` },
|
|
37617
|
-
"aria-hidden": "true"
|
|
37618
|
-
});
|
|
37619
|
-
}
|
|
37620
38617
|
//#endregion
|
|
37621
38618
|
//#region src/client/ChromeGlyph.tsx
|
|
37622
38619
|
/**
|
|
@@ -37632,7 +38629,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
37632
38629
|
maximize: "M1.5 1a.5.5 0 0 0-.5.5v4a.5.5 0 0 1-1 0v-4A1.5 1.5 0 0 1 1.5 0h4a.5.5 0 0 1 0 1h-4zM10 .5a.5.5 0 0 1 .5-.5h4A1.5 1.5 0 0 1 16 1.5v4a.5.5 0 0 1-1 0v-4a.5.5 0 0 0-.5-.5h-4a.5.5 0 0 1-.5-.5zM.5 10a.5.5 0 0 1 .5.5v4a.5.5 0 0 0 .5.5h4a.5.5 0 0 1 0 1h-4A1.5 1.5 0 0 1 0 14.5v-4a.5.5 0 0 1 .5-.5zm15 0a.5.5 0 0 1 .5.5v4a1.5 1.5 0 0 1-1.5 1.5h-4a.5.5 0 0 1 0-1h4a.5.5 0 0 0 .5-.5v-4a.5.5 0 0 1 .5-.5z",
|
|
37633
38630
|
restore: "M5.5 0a.5.5 0 0 1 .5.5v4A1.5 1.5 0 0 1 4.5 6h-4a.5.5 0 0 1 0-1h4a.5.5 0 0 0 .5-.5v-4a.5.5 0 0 1 .5-.5zm5 0a.5.5 0 0 1 .5.5v4a.5.5 0 0 0 .5.5h4a.5.5 0 0 1 0 1h-4A1.5 1.5 0 0 1 10 4.5v-4a.5.5 0 0 1 .5-.5zM0 10.5a.5.5 0 0 1 .5-.5h4A1.5 1.5 0 0 1 6 11.5v4a.5.5 0 0 1-1 0v-4a.5.5 0 0 0-.5-.5h-4a.5.5 0 0 1-.5-.5zm10 1a1.5 1.5 0 0 1 1.5-1.5h4a.5.5 0 0 1 0 1h-4a.5.5 0 0 0-.5.5v4a.5.5 0 0 1-1 0v-4z",
|
|
37634
38631
|
refresh: "M8 3a5 5 0 1 0 4.546 2.914.5.5 0 0 1 .908-.417A6 6 0 1 1 8 2v1z M8 4.466V.534a.25.25 0 0 1 .41-.192l2.36 1.966c.12.1.12.284 0 .384L8.41 4.658A.25.25 0 0 1 8 4.466z",
|
|
37635
|
-
close: "M2.146 2.854a.5.5 0 1 1 .708-.708L8 7.293l5.146-5.147a.5.5 0 0 1 .708.708L8.707 8l5.147 5.146a.5.5 0 0 1-.708.708L8 8.707l-5.146 5.147a.5.5 0 0 1-.708-.708L7.293 8 2.146 2.854Z"
|
|
38632
|
+
close: "M2.146 2.854a.5.5 0 1 1 .708-.708L8 7.293l5.146-5.147a.5.5 0 0 1 .708.708L8.707 8l5.147 5.146a.5.5 0 0 1-.708.708L8 8.707l-5.146 5.147a.5.5 0 0 1-.708-.708L7.293 8 2.146 2.854Z",
|
|
38633
|
+
wrap: "M1 3.5a.5.5 0 0 1 .5-.5h13a.5.5 0 0 1 0 1h-13a.5.5 0 0 1-.5-.5zM1 7.5a.5.5 0 0 1 .5-.5h11a2.5 2.5 0 0 1 0 5h-2.293l1.147 1.146a.5.5 0 0 1-.708.708l-2-2a.5.5 0 0 1 0-.708l2-2a.5.5 0 0 1 .708.708L10.207 11H12.5a1.5 1.5 0 0 0 0-3h-11a.5.5 0 0 1-.5-.5zM1 12.5a.5.5 0 0 1 .5-.5h4a.5.5 0 0 1 0 1h-4a.5.5 0 0 1-.5-.5z"
|
|
37636
38634
|
};
|
|
37637
38635
|
function ChromeGlyph({ of }) {
|
|
37638
38636
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
|
|
@@ -39251,6 +40249,10 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
39251
40249
|
* field of the appearance object: that one is about colour, and this choice
|
|
39252
40250
|
* has to survive a build that adds a palette. */
|
|
39253
40251
|
const STORE_HISTORY_LAYOUT = "dsh-ui-gitworkbench:history-layout";
|
|
40252
|
+
/** Soft wrap, on or off. A reading preference rather than a project setting:
|
|
40253
|
+
* it says how THIS person wants long lines shown, so it lives beside the
|
|
40254
|
+
* pane sizes in localStorage rather than in the shared style store. */
|
|
40255
|
+
const STORE_WRAP = "dsh-ui-gitworkbench:wrap";
|
|
39254
40256
|
const DEFAULT_PANES = {
|
|
39255
40257
|
commits: null,
|
|
39256
40258
|
tree: null,
|
|
@@ -39320,7 +40322,10 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
39320
40322
|
* unvisited worktree does not re-render the browser on every pass. */
|
|
39321
40323
|
const EMPTY_TREE = {
|
|
39322
40324
|
paths: [],
|
|
39323
|
-
truncated: false
|
|
40325
|
+
truncated: false,
|
|
40326
|
+
ignored: [],
|
|
40327
|
+
ignoredTruncated: false,
|
|
40328
|
+
children: NO_IGNORED_READS
|
|
39324
40329
|
};
|
|
39325
40330
|
/** The overlay with nothing on it — one instance, so an empty overlay never
|
|
39326
40331
|
* re-renders the tree that receives it. */
|
|
@@ -39346,7 +40351,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
39346
40351
|
for (const preferred of ["main", "master"]) if (branches.includes(preferred) && preferred !== head) return preferred;
|
|
39347
40352
|
return branches.find((branch) => branch !== head) ?? "";
|
|
39348
40353
|
}
|
|
39349
|
-
function GitWorkbenchPanel({ sessionId, useSessions, t, fetchStats, fetchFileDiff, fetchFileSides, writeChecked, fetchBlame, fetchFileImage, fetchWorktreeStatus, fetchSessionBinding, fetchCommitStats, fetchCommits, fetchAuthors, fetchRepoTree, fetchCompare, fetchStyle, saveStyle, fetchSync, runGitOp, fetchDiscardPlan }) {
|
|
40354
|
+
function GitWorkbenchPanel({ sessionId, useSessions, t, fetchStats, fetchFileDiff, fetchFileSides, writeChecked, fetchBlame, fetchFileImage, fetchWorktreeStatus, fetchSessionBinding, fetchCommitStats, fetchCommits, fetchAuthors, fetchRepoTree, fetchIgnoredDir, fetchCompare, fetchStyle, saveStyle, fetchSync, runGitOp, fetchDiscardPlan }) {
|
|
39350
40355
|
const worktreePath = useSessions((state) => state?.byId?.[sessionId]?.cwd);
|
|
39351
40356
|
/** Whether the session's agent has a turn in flight — the store mirrors it
|
|
39352
40357
|
* live, so it is the signal for polling faster while there is something to
|
|
@@ -39367,10 +40372,10 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
39367
40372
|
const rememberPlace = (0, react.useCallback)((key, next) => {
|
|
39368
40373
|
setFilesPlaces((prev) => withPlace(prev, key, next));
|
|
39369
40374
|
}, []);
|
|
39370
|
-
const rememberTree = (0, react.useCallback)((key,
|
|
40375
|
+
const rememberTree = (0, react.useCallback)((key, update) => {
|
|
39371
40376
|
setFilesTrees((prev) => {
|
|
39372
40377
|
const map = new Map(prev);
|
|
39373
|
-
map.set(key,
|
|
40378
|
+
map.set(key, update(prev.get(key) ?? EMPTY_TREE));
|
|
39374
40379
|
return map;
|
|
39375
40380
|
});
|
|
39376
40381
|
}, []);
|
|
@@ -39443,6 +40448,10 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
39443
40448
|
* the row height it implies is published from.
|
|
39444
40449
|
*/
|
|
39445
40450
|
const [historyLayout, setHistoryLayout] = (0, react.useState)(() => readStored(STORE_HISTORY_LAYOUT, isHistoryLayout, DEFAULT_HISTORY_LAYOUT));
|
|
40451
|
+
/** Soft wrap. Default OFF, which is what the panes have always done: code is
|
|
40452
|
+
* written in columns, and wrapping it is a choice about one long file, not
|
|
40453
|
+
* a better default for every file. */
|
|
40454
|
+
const [wrap, setWrap] = (0, react.useState)(() => readStored(STORE_WRAP, (value) => typeof value === "boolean", false));
|
|
39446
40455
|
/** Per-project and global styling; both scopes, unresolved. */
|
|
39447
40456
|
const [style, setStyle] = (0, react.useState)(EMPTY_SETTINGS);
|
|
39448
40457
|
/** Whether dsh's resolved palette is currently dark. */
|
|
@@ -40113,6 +41122,21 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
40113
41122
|
setHistoryLayout(next);
|
|
40114
41123
|
writeStored(STORE_HISTORY_LAYOUT, next);
|
|
40115
41124
|
};
|
|
41125
|
+
/**
|
|
41126
|
+
* Turn soft wrap on or off, and remember it.
|
|
41127
|
+
*
|
|
41128
|
+
* A plain function, like every other handler below the two guards above:
|
|
41129
|
+
* those `return null`s are the reason nothing past this point may be a HOOK.
|
|
41130
|
+
* A `useCallback` here rendered fewer hooks than the previous pass on the
|
|
41131
|
+
* frame the first stats arrived, which React reports as error #310 and the
|
|
41132
|
+
* shell reports as "slot entry crashed" — the chip simply vanishes.
|
|
41133
|
+
*/
|
|
41134
|
+
const toggleWrap = () => {
|
|
41135
|
+
setWrap((prev) => {
|
|
41136
|
+
writeStored(STORE_WRAP, !prev);
|
|
41137
|
+
return !prev;
|
|
41138
|
+
});
|
|
41139
|
+
};
|
|
40116
41140
|
/** Tab switch. No direction refetches the working tree: `viewKey` already
|
|
40117
41141
|
* separates the tabs' per-file diff caches, so bumping `gen` here only cost a
|
|
40118
41142
|
* redundant round trip. */
|
|
@@ -40212,6 +41236,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
40212
41236
|
onHistoryLayout: applyHistoryLayout,
|
|
40213
41237
|
onClose: () => setOpen(false),
|
|
40214
41238
|
onRefresh: refresh,
|
|
41239
|
+
wrap,
|
|
41240
|
+
onToggleWrap: toggleWrap,
|
|
40215
41241
|
commitDraft,
|
|
40216
41242
|
onCommitDraft: setCommitDraft,
|
|
40217
41243
|
commitAmend,
|
|
@@ -40229,6 +41255,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
40229
41255
|
writeChecked,
|
|
40230
41256
|
fetchBlame,
|
|
40231
41257
|
fetchFileImage,
|
|
41258
|
+
fetchIgnoredDir,
|
|
40232
41259
|
viewKey,
|
|
40233
41260
|
gen,
|
|
40234
41261
|
collapsed,
|
|
@@ -40290,7 +41317,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
40290
41317
|
]
|
|
40291
41318
|
});
|
|
40292
41319
|
}
|
|
40293
|
-
function Drawer({ stats, shown, tab, onSwitchTab, commits, commitHash, onSelectCommit, hasMoreCommits, loadingMore, onLoadMoreCommits, historyRef, onHistoryRef, historyQuery, onHistoryQuery, historyError, fetchAuthors, fetchRepoTree, branches, worktreeBranches, branchesTruncated, baseRef, headRef, onBaseRef, onHeadRef, comparable, t, binding, worktrees, sessionPath, statsPath, onSwitchSource, segments, selected, onSelect, maximized, onToggleMaximized, theme, mode, family, onMode, onFamily, style, background, onStyle, width, onWidth, panes, onPane, onCommitsTall, historyLayout, onHistoryLayout, onClose, onRefresh, commitDraft, onCommitDraft, commitAmend, onCommitAmend, sync, treeLoading, historyLoading, busy, opResult, runOp, fetchDiscardPlan, onOpError, pendingTicks, onTick, fetchFileDiff, fetchFileSides, writeChecked, fetchBlame, fetchFileImage, viewKey, gen, collapsed, onCollapsedChange, filesPlaces, onFilesPlace, filesTrees, onFilesTree }) {
|
|
41320
|
+
function Drawer({ stats, shown, tab, onSwitchTab, commits, commitHash, onSelectCommit, hasMoreCommits, loadingMore, onLoadMoreCommits, historyRef, onHistoryRef, historyQuery, onHistoryQuery, historyError, fetchAuthors, fetchRepoTree, fetchIgnoredDir, branches, worktreeBranches, branchesTruncated, baseRef, headRef, onBaseRef, onHeadRef, comparable, t, binding, worktrees, sessionPath, statsPath, onSwitchSource, segments, selected, onSelect, maximized, onToggleMaximized, theme, mode, family, onMode, onFamily, style, background, onStyle, width, onWidth, panes, onPane, onCommitsTall, historyLayout, onHistoryLayout, onClose, onRefresh, wrap, onToggleWrap, commitDraft, onCommitDraft, commitAmend, onCommitAmend, sync, treeLoading, historyLoading, busy, opResult, runOp, fetchDiscardPlan, onOpError, pendingTicks, onTick, fetchFileDiff, fetchFileSides, writeChecked, fetchBlame, fetchFileImage, viewKey, gen, collapsed, onCollapsedChange, filesPlaces, onFilesPlace, filesTrees, onFilesTree }) {
|
|
40294
41321
|
const body = shown ?? EMPTY_STATS;
|
|
40295
41322
|
/** The file list with ticks still awaiting git laid over them. The tree and
|
|
40296
41323
|
* the commit box read this, so a click moves its box and the "N ticked"
|
|
@@ -40315,8 +41342,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
40315
41342
|
const rememberPlaceHere = (0, react.useCallback)((next) => {
|
|
40316
41343
|
onFilesPlace(filesKey, next);
|
|
40317
41344
|
}, [onFilesPlace, filesKey]);
|
|
40318
|
-
const rememberTreeHere = (0, react.useCallback)((
|
|
40319
|
-
onFilesTree(filesKey,
|
|
41345
|
+
const rememberTreeHere = (0, react.useCallback)((update) => {
|
|
41346
|
+
onFilesTree(filesKey, update);
|
|
40320
41347
|
}, [onFilesTree, filesKey]);
|
|
40321
41348
|
const browsablePaths = (0, react.useMemo)(() => stats.files.filter((file) => file.status !== "deleted").map((file) => file.path), [stats.files]);
|
|
40322
41349
|
const active = preferredFile(body.files, activeFilterPaths, selected);
|
|
@@ -40329,6 +41356,11 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
40329
41356
|
const bundled = active === null ? "" : segments.get(active) ?? "";
|
|
40330
41357
|
const activeKey = active === null ? null : `${viewKey}\x1f${active}`;
|
|
40331
41358
|
const segment = bundled.length > 0 ? bundled : activeKey === null ? "" : fetched.get(activeKey) ?? "";
|
|
41359
|
+
/** The CRLF phantom: listed modified, whole-file diff empty (see
|
|
41360
|
+
* {@link isPhantomModified}). Changes-tab only — history and compare list
|
|
41361
|
+
* files from real ref diffs, where an empty segment means a failed fetch,
|
|
41362
|
+
* and the phantom notice would mislead. */
|
|
41363
|
+
const phantomListed = tab === "changes" && isPhantomModified(activeFile?.status, segment);
|
|
40332
41364
|
(0, react.useEffect)(() => {
|
|
40333
41365
|
const path = active;
|
|
40334
41366
|
if (path === null || activeKey === null || bundled.length > 0) return;
|
|
@@ -40683,6 +41715,15 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
40683
41715
|
onClick: onToggleMaximized,
|
|
40684
41716
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChromeGlyph, { of: maximized ? "restore" : "maximize" })
|
|
40685
41717
|
}),
|
|
41718
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
41719
|
+
type: "button",
|
|
41720
|
+
className: wrap ? `${GitWorkbenchPanel_module_css_default.btn} ${GitWorkbenchPanel_module_css_default.btnIcon} ${GitWorkbenchPanel_module_css_default.btnIconOn}` : `${GitWorkbenchPanel_module_css_default.btn} ${GitWorkbenchPanel_module_css_default.btnIcon}`,
|
|
41721
|
+
"aria-pressed": wrap,
|
|
41722
|
+
"aria-label": wrap ? t("wrapLinesOff") : t("wrapLines"),
|
|
41723
|
+
title: wrap ? t("wrapLinesOff") : t("wrapLines"),
|
|
41724
|
+
onClick: onToggleWrap,
|
|
41725
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChromeGlyph, { of: "wrap" })
|
|
41726
|
+
}),
|
|
40686
41727
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
40687
41728
|
type: "button",
|
|
40688
41729
|
className: `${GitWorkbenchPanel_module_css_default.btn} ${GitWorkbenchPanel_module_css_default.btnIcon}`,
|
|
@@ -40841,7 +41882,9 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
40841
41882
|
onPlace: rememberPlaceHere,
|
|
40842
41883
|
cached: filesTrees.get(filesKey) ?? EMPTY_TREE,
|
|
40843
41884
|
onTree: rememberTreeHere,
|
|
41885
|
+
wrap,
|
|
40844
41886
|
fetchRepoTree,
|
|
41887
|
+
fetchIgnoredDir,
|
|
40845
41888
|
fetchFileSides,
|
|
40846
41889
|
writeChecked,
|
|
40847
41890
|
fetchBlame,
|
|
@@ -40893,48 +41936,61 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
40893
41936
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
40894
41937
|
className: GitWorkbenchPanel_module_css_default.diffPane,
|
|
40895
41938
|
"data-gs-part": "diff",
|
|
40896
|
-
children: [
|
|
40897
|
-
|
|
40898
|
-
|
|
40899
|
-
|
|
40900
|
-
|
|
40901
|
-
|
|
40902
|
-
|
|
40903
|
-
|
|
40904
|
-
|
|
40905
|
-
|
|
40906
|
-
|
|
40907
|
-
|
|
40908
|
-
|
|
40909
|
-
|
|
40910
|
-
|
|
40911
|
-
|
|
40912
|
-
|
|
40913
|
-
|
|
40914
|
-
|
|
40915
|
-
|
|
40916
|
-
|
|
40917
|
-
|
|
40918
|
-
|
|
40919
|
-
|
|
40920
|
-
|
|
40921
|
-
|
|
40922
|
-
|
|
40923
|
-
|
|
40924
|
-
|
|
40925
|
-
|
|
40926
|
-
|
|
40927
|
-
|
|
40928
|
-
|
|
40929
|
-
|
|
40930
|
-
|
|
40931
|
-
|
|
40932
|
-
|
|
40933
|
-
|
|
40934
|
-
|
|
40935
|
-
|
|
40936
|
-
|
|
40937
|
-
|
|
41939
|
+
children: [
|
|
41940
|
+
tab === "compare" && !comparable ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
41941
|
+
className: GitWorkbenchPanel_module_css_default.empty,
|
|
41942
|
+
children: t("comparePick")
|
|
41943
|
+
}) : shown === null && tab !== "changes" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
41944
|
+
className: GitWorkbenchPanel_module_css_default.empty,
|
|
41945
|
+
children: tab === "compare" ? t("loadingCompare") : t("loadingCommit")
|
|
41946
|
+
}) : activeFile !== null && activeFile.previousPath !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
41947
|
+
className: GitWorkbenchPanel_module_css_default.renameLine,
|
|
41948
|
+
children: [
|
|
41949
|
+
t("renamedFrom"),
|
|
41950
|
+
" ",
|
|
41951
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", { children: activeFile.previousPath })
|
|
41952
|
+
]
|
|
41953
|
+
}) : null,
|
|
41954
|
+
tab === "compare" && comparable && shown !== null && body.files.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
41955
|
+
className: GitWorkbenchPanel_module_css_default.empty,
|
|
41956
|
+
children: t("compareEmptyHint", {
|
|
41957
|
+
base: baseRef ?? "",
|
|
41958
|
+
head: headRef ?? ""
|
|
41959
|
+
})
|
|
41960
|
+
}) : null,
|
|
41961
|
+
shown === null && tab !== "changes" || tab === "compare" && !comparable ? null : activeFile !== null && activeFile.binary ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
41962
|
+
className: GitWorkbenchPanel_module_css_default.empty,
|
|
41963
|
+
children: t("binaryFile")
|
|
41964
|
+
}) : tab === "changes" && active !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SideBySideView, {
|
|
41965
|
+
t,
|
|
41966
|
+
path: active,
|
|
41967
|
+
palette: theme,
|
|
41968
|
+
wrap,
|
|
41969
|
+
statsPath,
|
|
41970
|
+
fetchSides: fetchFileSides,
|
|
41971
|
+
writeChecked,
|
|
41972
|
+
scopeKey: viewKey,
|
|
41973
|
+
gen,
|
|
41974
|
+
fallbackSegment: segment,
|
|
41975
|
+
fallbackLoading: loading && segment.length === 0,
|
|
41976
|
+
phantomListed,
|
|
41977
|
+
onBlockAction: askBlockAction,
|
|
41978
|
+
onSaved: onRefresh,
|
|
41979
|
+
onDirtyChange: onSideDirty
|
|
41980
|
+
}) : loading && segment.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
41981
|
+
className: GitWorkbenchPanel_module_css_default.empty,
|
|
41982
|
+
children: t("loadingDiff")
|
|
41983
|
+
}) : segment.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DiffView, {
|
|
41984
|
+
segment,
|
|
41985
|
+
path: active ?? "",
|
|
41986
|
+
palette: theme,
|
|
41987
|
+
t,
|
|
41988
|
+
wrap
|
|
41989
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
41990
|
+
className: GitWorkbenchPanel_module_css_default.empty,
|
|
41991
|
+
children: t("noTextDiff")
|
|
41992
|
+
})
|
|
41993
|
+
]
|
|
40938
41994
|
})
|
|
40939
41995
|
] })
|
|
40940
41996
|
})]
|
|
@@ -40998,6 +42054,11 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
40998
42054
|
tabFiles: "文件",
|
|
40999
42055
|
fileSearchPlaceholder: "搜索文件…",
|
|
41000
42056
|
filesTruncated: "文件太多,列表已截断;用搜索找剩下的。",
|
|
42057
|
+
filesIgnored: "已被 gitignore",
|
|
42058
|
+
wrapLines: "自动换行",
|
|
42059
|
+
wrapLinesOff: "取消自动换行",
|
|
42060
|
+
filesIgnoredCut: "这个目录条目太多,已截断;搜索找不到没列出的部分。",
|
|
42061
|
+
filesIgnoredFailed: "无法列出被忽略的文件。",
|
|
41001
42062
|
filesEmpty: "这个仓库还没有文件",
|
|
41002
42063
|
filesNoMatch: "没有匹配的文件",
|
|
41003
42064
|
filesMore: "还有 {count} 个,用上面的搜索找",
|
|
@@ -41019,6 +42080,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
41019
42080
|
compareHead: "对比",
|
|
41020
42081
|
comparePick: "选择两个不同的分支进行对比",
|
|
41021
42082
|
compareCommits: "{count} 个提交(自共同祖先起)",
|
|
42083
|
+
compareEmptyHint: "{base}...{head} 比较的是自分叉点到 {head} 的变化,没有找到差异;想看另一方向的变化请交换两端。",
|
|
41022
42084
|
loadingCompare: "加载对比…",
|
|
41023
42085
|
noBranches: "没有可对比的分支",
|
|
41024
42086
|
refSearch: "筛选分支…",
|
|
@@ -41175,6 +42237,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
41175
42237
|
blameTruncated: "文件过长,追溯信息只显示了前面一部分。",
|
|
41176
42238
|
crlfNotice: "这个文件的行尾是 CRLF,暂不支持在线编辑(编辑框会把行尾统一成 LF,保存时整份文件都会被改写);建议把行尾统一成 LF。差异里的回车已用 ␍ 标出;查看和按块暂存/撤回不受影响。",
|
|
41177
42239
|
encodingNotice: "这个文件不是 UTF-8 编码(可能是 GBK、Shift JIS 之类),暂不支持在线编辑:页面上看到的文字是一次有损解码,保存回去会把文件里每一个非 ASCII 字节都改写掉,包括你没动过的行。查看和按块暂存/撤回不受影响。",
|
|
42240
|
+
phantomNotice: "git 把这个文件列为已修改,但行尾归一化(CRLF / autocrlf / eol 属性)之后没有内容差异——这是 Windows 检出常见的「永远已修改」幻影,不是显示故障。统一行尾(建议把行尾统一成 LF)或让 git 重新比对后,这一条目就会消失。",
|
|
41178
42241
|
saveFailed: "保存失败",
|
|
41179
42242
|
saveUnavailable: "当前宿主还不支持保存(需要重启 dsh web 加载新版宿主端)。",
|
|
41180
42243
|
saveRetry: "重试保存",
|
|
@@ -41212,6 +42275,11 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
41212
42275
|
tabFiles: "Files",
|
|
41213
42276
|
fileSearchPlaceholder: "Search files…",
|
|
41214
42277
|
filesTruncated: "Too many files to list; use the search for the rest.",
|
|
42278
|
+
filesIgnored: "Ignored (gitignore)",
|
|
42279
|
+
wrapLines: "Wrap long lines",
|
|
42280
|
+
wrapLinesOff: "Stop wrapping lines",
|
|
42281
|
+
filesIgnoredCut: "This directory has too many entries; the list is cut, and the search cannot reach the rest.",
|
|
42282
|
+
filesIgnoredFailed: "Could not list the ignored files.",
|
|
41215
42283
|
filesEmpty: "This repository has no files yet",
|
|
41216
42284
|
filesNoMatch: "No matching files",
|
|
41217
42285
|
filesMore: "and {count} more — use the search above",
|
|
@@ -41233,6 +42301,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
41233
42301
|
compareHead: "Compare",
|
|
41234
42302
|
comparePick: "Pick two different branches to compare",
|
|
41235
42303
|
compareCommits: "{count} commits since they diverged",
|
|
42304
|
+
compareEmptyHint: "{base}...{head} compares from the fork point up to {head} and found no differences; to see what changed on the other side, swap the two ends.",
|
|
41236
42305
|
loadingCompare: "Loading comparison…",
|
|
41237
42306
|
noBranches: "No branches to compare",
|
|
41238
42307
|
refSearch: "Filter branches…",
|
|
@@ -41389,6 +42458,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
41389
42458
|
blameTruncated: "The file is long, so blame is shown for the first part only.",
|
|
41390
42459
|
crlfNotice: "This file has CRLF line endings, which the editor does not support yet (the edit box would turn every ending into LF, so a save rewrites the whole file); normalising the endings to LF is recommended. Carriage returns are marked ␍ in the diff; viewing and block staging/rolling back still work.",
|
|
41391
42460
|
encodingNotice: "This file is not UTF-8 (GBK, Shift JIS or similar), so the editor is unavailable: the text shown is a lossy decode of it, and saving that back would rewrite every non-ASCII byte in the file, including lines you never touched. Viewing and block staging/rolling back still work.",
|
|
42461
|
+
phantomNotice: "git lists this file as modified, but after line-ending normalisation (CRLF / autocrlf / eol attributes) there is no content difference — the classic \"modified forever\" phantom of a Windows checkout, not a broken view. Once the endings agree (normalising the endings to LF is recommended) the entry disappears.",
|
|
41392
42462
|
saveFailed: "Save failed",
|
|
41393
42463
|
saveUnavailable: "This host does not support saving yet — restart dsh web to load the new host half.",
|
|
41394
42464
|
saveRetry: "Retry save",
|
|
@@ -41516,6 +42586,17 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
41516
42586
|
const result = await connection.rpc.call("/api", "gitWorkbench/repoTree", { args: { worktreePath: worktreePath ?? "" } }, signal);
|
|
41517
42587
|
return result.ok ? result.value : null;
|
|
41518
42588
|
},
|
|
42589
|
+
fetchIgnoredDir: async (worktreePath, dir, signal) => {
|
|
42590
|
+
try {
|
|
42591
|
+
const result = await connection.rpc.call("/api", "gitWorkbench/ignoredDir", { args: {
|
|
42592
|
+
worktreePath: worktreePath ?? "",
|
|
42593
|
+
dir
|
|
42594
|
+
} }, signal);
|
|
42595
|
+
return result.ok ? result.value : null;
|
|
42596
|
+
} catch {
|
|
42597
|
+
return null;
|
|
42598
|
+
}
|
|
42599
|
+
},
|
|
41519
42600
|
fetchCompare: async (worktreePath, base, head, signal) => {
|
|
41520
42601
|
const result = await connection.rpc.call("/api", "gitWorkbench/compareRefs", { args: {
|
|
41521
42602
|
worktreePath: worktreePath ?? "",
|