@young1lin/dsh-ui-gitworkbench 0.1.14 → 0.1.16
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 +23 -0
- package/CHANGELOG_EN.md +23 -0
- package/README.md +29 -3
- package/README_EN.md +1 -1
- package/lib/client.js +1512 -470
- package/lib/dir-listing.js +34 -0
- package/lib/fs-remove.js +5 -36
- package/lib/index.js +346 -117
- package/lib/path-lock.js +54 -0
- package/lib/repo-root.js +60 -0
- package/lib/worktree.js +83 -0
- package/lib/write-checked.js +1 -1
- package/package.json +5 -5
- package/src/client/ChromeGlyph.tsx +5 -0
- package/src/client/CodeEditor.tsx +19 -1
- package/src/client/DiffViews.tsx +116 -121
- package/src/client/FileBrowser.tsx +196 -23
- package/src/client/GitWorkbenchPanel.module.css +1 -0
- package/src/client/GitWorkbenchPanel.tsx +100 -12
- package/src/client/SideRails.tsx +106 -0
- package/src/client/diff-cells.tsx +147 -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 +12 -2
- 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 +372 -118
- package/src/path-lock.ts +56 -0
- package/src/repo-root.ts +66 -0
- package/src/types/dsh-shim.d.ts +12 -2
- package/src/worktree.ts +97 -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
|
-
"imgPane": "SD8qLW_imgPane",
|
|
473
|
-
"gutter": "SD8qLW_gutter",
|
|
474
|
-
"graphCell": "SD8qLW_graphCell",
|
|
475
|
-
"sidePane": "SD8qLW_sidePane",
|
|
476
|
-
"funnelTab": "SD8qLW_funnelTab",
|
|
477
|
-
"paneTitle": "SD8qLW_paneTitle",
|
|
478
|
-
"diffSpacer": "SD8qLW_diffSpacer",
|
|
479
|
-
"sideBlockHot": "SD8qLW_sideBlockHot",
|
|
480
|
-
"cssArea": "SD8qLW_cssArea",
|
|
481
|
-
"crMark": "SD8qLW_crMark",
|
|
482
|
-
"commitMessage": "SD8qLW_commitMessage",
|
|
483
|
-
"scopeBtn": "SD8qLW_scopeBtn",
|
|
484
|
-
"funnelList": "SD8qLW_funnelList",
|
|
485
|
-
"compareArrow": "SD8qLW_compareArrow",
|
|
486
|
-
"treeDir": "SD8qLW_treeDir",
|
|
487
|
-
"confirmBody": "SD8qLW_confirmBody",
|
|
488
|
-
"fileCountDel": "SD8qLW_fileCountDel",
|
|
489
|
-
"cardBehind": "SD8qLW_cardBehind",
|
|
490
|
-
"calMark": "SD8qLW_calMark",
|
|
491
|
-
"funnelPop": "SD8qLW_funnelPop",
|
|
492
|
-
"sideCodeAdd": "SD8qLW_sideCodeAdd",
|
|
493
|
-
"commitPop": "SD8qLW_commitPop",
|
|
494
|
-
"stDeleted": "SD8qLW_stDeleted",
|
|
495
|
-
"sideActions": "SD8qLW_sideActions",
|
|
496
472
|
"theme": "SD8qLW_theme",
|
|
497
|
-
"
|
|
498
|
-
"
|
|
499
|
-
"treeFilterInput": "SD8qLW_treeFilterInput",
|
|
500
|
-
"sideBlockHotFirst": "SD8qLW_sideBlockHotFirst",
|
|
501
|
-
"refSearch": "SD8qLW_refSearch",
|
|
502
|
-
"cardGlyph": "SD8qLW_cardGlyph",
|
|
503
|
-
"treeLabel": "SD8qLW_treeLabel",
|
|
504
|
-
"stModified": "SD8qLW_stModified",
|
|
505
|
-
"cardBranch": "SD8qLW_cardBranch",
|
|
473
|
+
"paletteRow": "SD8qLW_paletteRow",
|
|
474
|
+
"lineHunk": "SD8qLW_lineHunk",
|
|
506
475
|
"sideBlockHotLast": "SD8qLW_sideBlockHotLast",
|
|
507
|
-
"
|
|
508
|
-
"
|
|
509
|
-
"
|
|
510
|
-
"
|
|
511
|
-
"
|
|
512
|
-
"
|
|
513
|
-
"
|
|
514
|
-
"
|
|
515
|
-
"
|
|
516
|
-
"
|
|
517
|
-
"
|
|
518
|
-
"
|
|
519
|
-
"
|
|
520
|
-
"commitMeta": "SD8qLW_commitMeta",
|
|
521
|
-
"sideNavCount": "SD8qLW_sideNavCount",
|
|
522
|
-
"miniBtn": "SD8qLW_miniBtn",
|
|
523
|
-
"sideColGridBlame": "SD8qLW_sideColGridBlame",
|
|
524
|
-
"btnDanger": "SD8qLW_btnDanger",
|
|
525
|
-
"fileCounts": "SD8qLW_fileCounts",
|
|
526
|
-
"resizer": "SD8qLW_resizer",
|
|
527
|
-
"headerTotalsDel": "SD8qLW_headerTotalsDel",
|
|
528
|
-
"btnPrimary": "SD8qLW_btnPrimary",
|
|
529
|
-
"blameCell": "SD8qLW_blameCell",
|
|
530
|
-
"fileLi": "SD8qLW_fileLi",
|
|
476
|
+
"commitsPane": "SD8qLW_commitsPane",
|
|
477
|
+
"funnelBoundBtnActive": "SD8qLW_funnelBoundBtnActive",
|
|
478
|
+
"commitSubject": "SD8qLW_commitSubject",
|
|
479
|
+
"commitPopBody": "SD8qLW_commitPopBody",
|
|
480
|
+
"wordDel": "SD8qLW_wordDel",
|
|
481
|
+
"funnelTabActive": "SD8qLW_funnelTabActive",
|
|
482
|
+
"fbDirName": "SD8qLW_fbDirName",
|
|
483
|
+
"imgPane": "SD8qLW_imgPane",
|
|
484
|
+
"paneDivider": "SD8qLW_paneDivider",
|
|
485
|
+
"segmented": "SD8qLW_segmented",
|
|
486
|
+
"scopeRow": "SD8qLW_scopeRow",
|
|
487
|
+
"funnelTabs": "SD8qLW_funnelTabs",
|
|
488
|
+
"sideActions": "SD8qLW_sideActions",
|
|
531
489
|
"gsSlide": "SD8qLW_gsSlide",
|
|
532
|
-
"
|
|
533
|
-
"
|
|
534
|
-
"calGrid": "SD8qLW_calGrid",
|
|
535
|
-
"refRowSpacer": "SD8qLW_refRowSpacer",
|
|
536
|
-
"commitStaged": "SD8qLW_commitStaged",
|
|
537
|
-
"refLabel": "SD8qLW_refLabel",
|
|
538
|
-
"segmentActive": "SD8qLW_segmentActive",
|
|
539
|
-
"fbCommitHash": "SD8qLW_fbCommitHash",
|
|
540
|
-
"refRowName": "SD8qLW_refRowName",
|
|
541
|
-
"header": "SD8qLW_header",
|
|
542
|
-
"layoutGlyph": "SD8qLW_layoutGlyph",
|
|
543
|
-
"commitHash": "SD8qLW_commitHash",
|
|
544
|
-
"commitPopTop": "SD8qLW_commitPopTop",
|
|
545
|
-
"chevron": "SD8qLW_chevron",
|
|
546
|
-
"stUntracked": "SD8qLW_stUntracked",
|
|
547
|
-
"fileActive": "SD8qLW_fileActive",
|
|
548
|
-
"sideScroll": "SD8qLW_sideScroll",
|
|
549
|
-
"fileBinary": "SD8qLW_fileBinary",
|
|
550
|
-
"refValue": "SD8qLW_refValue",
|
|
551
|
-
"headerViewRef": "SD8qLW_headerViewRef",
|
|
552
|
-
"sideTabs": "SD8qLW_sideTabs",
|
|
553
|
-
"sideNav": "SD8qLW_sideNav",
|
|
554
|
-
"elideTail": "SD8qLW_elideTail",
|
|
555
|
-
"refPicker": "SD8qLW_refPicker",
|
|
556
|
-
"cardFiles": "SD8qLW_cardFiles",
|
|
557
|
-
"sideActionsAdjacent": "SD8qLW_sideActionsAdjacent",
|
|
558
|
-
"filterClear": "SD8qLW_filterClear",
|
|
559
|
-
"layoutButtonOn": "SD8qLW_layoutButtonOn",
|
|
490
|
+
"commitLine": "SD8qLW_commitLine",
|
|
491
|
+
"lineDel": "SD8qLW_lineDel",
|
|
560
492
|
"funnelBounds": "SD8qLW_funnelBounds",
|
|
561
|
-
"
|
|
562
|
-
"btnCount": "SD8qLW_btnCount",
|
|
563
|
-
"treeDirLi": "SD8qLW_treeDirLi",
|
|
564
|
-
"fbCommitLine": "SD8qLW_fbCommitLine",
|
|
565
|
-
"headerTotalsDim": "SD8qLW_headerTotalsDim",
|
|
566
|
-
"funnelFoot": "SD8qLW_funnelFoot",
|
|
567
|
-
"syncSpacer": "SD8qLW_syncSpacer",
|
|
568
|
-
"syncLevel": "SD8qLW_syncLevel",
|
|
569
|
-
"commitsPane": "SD8qLW_commitsPane",
|
|
570
|
-
"scopeHint": "SD8qLW_scopeHint",
|
|
493
|
+
"sideNumDel": "SD8qLW_sideNumDel",
|
|
571
494
|
"fbList": "SD8qLW_fbList",
|
|
572
|
-
"
|
|
573
|
-
"
|
|
574
|
-
"
|
|
495
|
+
"cardBranchName": "SD8qLW_cardBranchName",
|
|
496
|
+
"treeDirCount": "SD8qLW_treeDirCount",
|
|
497
|
+
"sideBlockHotFirst": "SD8qLW_sideBlockHotFirst",
|
|
498
|
+
"treeEmpty": "SD8qLW_treeEmpty",
|
|
499
|
+
"syncBar": "SD8qLW_syncBar",
|
|
500
|
+
"sliderValue": "SD8qLW_sliderValue",
|
|
501
|
+
"headerPicker": "SD8qLW_headerPicker",
|
|
502
|
+
"headerRight": "SD8qLW_headerRight",
|
|
503
|
+
"funnelBoundValSet": "SD8qLW_funnelBoundValSet",
|
|
504
|
+
"sideNav": "SD8qLW_sideNav",
|
|
505
|
+
"treeDirActive": "SD8qLW_treeDirActive",
|
|
506
|
+
"fileLi": "SD8qLW_fileLi",
|
|
507
|
+
"treeIconOn": "SD8qLW_treeIconOn",
|
|
575
508
|
"treeLead": "SD8qLW_treeLead",
|
|
576
|
-
"
|
|
509
|
+
"funnelList": "SD8qLW_funnelList",
|
|
577
510
|
"headerDetached": "SD8qLW_headerDetached",
|
|
578
|
-
"
|
|
579
|
-
"
|
|
580
|
-
"
|
|
581
|
-
"
|
|
582
|
-
"
|
|
583
|
-
"
|
|
584
|
-
"
|
|
585
|
-
"sliderValue": "SD8qLW_sliderValue",
|
|
511
|
+
"fbTree": "SD8qLW_fbTree",
|
|
512
|
+
"pathFileGlyph": "SD8qLW_pathFileGlyph",
|
|
513
|
+
"treeSub": "SD8qLW_treeSub",
|
|
514
|
+
"filterChips": "SD8qLW_filterChips",
|
|
515
|
+
"diffSpacer": "SD8qLW_diffSpacer",
|
|
516
|
+
"miniBtn": "SD8qLW_miniBtn",
|
|
517
|
+
"btnIcon": "SD8qLW_btnIcon",
|
|
586
518
|
"sideBannerTitle": "SD8qLW_sideBannerTitle",
|
|
587
|
-
"
|
|
588
|
-
"
|
|
589
|
-
"sideColGrid": "SD8qLW_sideColGrid",
|
|
590
|
-
"treeDirCounts": "SD8qLW_treeDirCounts",
|
|
591
|
-
"paletteRow": "SD8qLW_paletteRow",
|
|
592
|
-
"commitPopMeta": "SD8qLW_commitPopMeta",
|
|
593
|
-
"pathDirGlyph": "SD8qLW_pathDirGlyph",
|
|
594
|
-
"treeWrap": "SD8qLW_treeWrap",
|
|
595
|
-
"funnelPresets": "SD8qLW_funnelPresets",
|
|
596
|
-
"treeEmpty": "SD8qLW_treeEmpty",
|
|
597
|
-
"diffNav": "SD8qLW_diffNav",
|
|
598
|
-
"funnelPane": "SD8qLW_funnelPane",
|
|
599
|
-
"diffPre": "SD8qLW_diffPre",
|
|
600
|
-
"lineAdd": "SD8qLW_lineAdd",
|
|
601
|
-
"layoutSwitch": "SD8qLW_layoutSwitch",
|
|
602
|
-
"swatch": "SD8qLW_swatch",
|
|
603
|
-
"treeIconDown": "SD8qLW_treeIconDown",
|
|
604
|
-
"lineHunk": "SD8qLW_lineHunk",
|
|
605
|
-
"refPop": "SD8qLW_refPop",
|
|
606
|
-
"funnelChevron": "SD8qLW_funnelChevron",
|
|
607
|
-
"wordDel": "SD8qLW_wordDel",
|
|
608
|
-
"fbRow": "SD8qLW_fbRow",
|
|
609
|
-
"confirmActions": "SD8qLW_confirmActions",
|
|
610
|
-
"sliderRow": "SD8qLW_sliderRow",
|
|
611
|
-
"themeRowSplit": "SD8qLW_themeRowSplit",
|
|
612
|
-
"treeDirCount": "SD8qLW_treeDirCount",
|
|
613
|
-
"cmHost": "SD8qLW_cmHost",
|
|
519
|
+
"refLabel": "SD8qLW_refLabel",
|
|
520
|
+
"treeDirLi": "SD8qLW_treeDirLi",
|
|
614
521
|
"calNav": "SD8qLW_calNav",
|
|
615
|
-
"
|
|
616
|
-
"
|
|
522
|
+
"commitMessage": "SD8qLW_commitMessage",
|
|
523
|
+
"fbNote": "SD8qLW_fbNote",
|
|
524
|
+
"sideTab": "SD8qLW_sideTab",
|
|
617
525
|
"lineContext": "SD8qLW_lineContext",
|
|
618
|
-
"
|
|
619
|
-
"
|
|
526
|
+
"sidePane": "SD8qLW_sidePane",
|
|
527
|
+
"chipDark": "SD8qLW_chipDark",
|
|
528
|
+
"graphCell": "SD8qLW_graphCell",
|
|
529
|
+
"header": "SD8qLW_header",
|
|
530
|
+
"funnelTabCount": "SD8qLW_funnelTabCount",
|
|
531
|
+
"segmentChip": "SD8qLW_segmentChip",
|
|
532
|
+
"filterClear": "SD8qLW_filterClear",
|
|
533
|
+
"commitBox": "SD8qLW_commitBox",
|
|
534
|
+
"commitMeta": "SD8qLW_commitMeta",
|
|
535
|
+
"confirmBody": "SD8qLW_confirmBody",
|
|
536
|
+
"headerTotalsDel": "SD8qLW_headerTotalsDel",
|
|
537
|
+
"pathChildren": "SD8qLW_pathChildren",
|
|
538
|
+
"paneDividerActive": "SD8qLW_paneDividerActive",
|
|
539
|
+
"renameLine": "SD8qLW_renameLine",
|
|
540
|
+
"calToday": "SD8qLW_calToday",
|
|
541
|
+
"sideRail": "SD8qLW_sideRail",
|
|
542
|
+
"fbRowIgnored": "SD8qLW_fbRowIgnored",
|
|
543
|
+
"resizer": "SD8qLW_resizer",
|
|
544
|
+
"sideNum": "SD8qLW_sideNum",
|
|
545
|
+
"treeIconDown": "SD8qLW_treeIconDown",
|
|
546
|
+
"funnelPresetActive": "SD8qLW_funnelPresetActive",
|
|
547
|
+
"fbMain": "SD8qLW_fbMain",
|
|
548
|
+
"funnelFootCountOn": "SD8qLW_funnelFootCountOn",
|
|
549
|
+
"commitCopy": "SD8qLW_commitCopy",
|
|
550
|
+
"pathDirGlyph": "SD8qLW_pathDirGlyph",
|
|
551
|
+
"calMark": "SD8qLW_calMark",
|
|
552
|
+
"file": "SD8qLW_file",
|
|
553
|
+
"cardGlyph": "SD8qLW_cardGlyph",
|
|
554
|
+
"filterChipLabel": "SD8qLW_filterChipLabel",
|
|
620
555
|
"funnelBoundRow": "SD8qLW_funnelBoundRow",
|
|
621
|
-
"
|
|
622
|
-
"
|
|
623
|
-
"
|
|
624
|
-
"
|
|
556
|
+
"sideColWrap": "SD8qLW_sideColWrap",
|
|
557
|
+
"cardBehind": "SD8qLW_cardBehind",
|
|
558
|
+
"fileCountAdd": "SD8qLW_fileCountAdd",
|
|
559
|
+
"sideBlockHot": "SD8qLW_sideBlockHot",
|
|
560
|
+
"stModified": "SD8qLW_stModified",
|
|
561
|
+
"cardAhead": "SD8qLW_cardAhead",
|
|
562
|
+
"commitPop": "SD8qLW_commitPop",
|
|
563
|
+
"funnelName": "SD8qLW_funnelName",
|
|
564
|
+
"commitWhen": "SD8qLW_commitWhen",
|
|
625
565
|
"funnelBoundBtn": "SD8qLW_funnelBoundBtn",
|
|
626
|
-
"
|
|
627
|
-
"
|
|
628
|
-
"diffScroll": "SD8qLW_diffScroll",
|
|
629
|
-
"signAdd": "SD8qLW_signAdd",
|
|
630
|
-
"fbMain": "SD8qLW_fbMain",
|
|
631
|
-
"imgStage": "SD8qLW_imgStage",
|
|
632
|
-
"calHead": "SD8qLW_calHead",
|
|
633
|
-
"imgShot": "SD8qLW_imgShot",
|
|
634
|
-
"cardBranchName": "SD8qLW_cardBranchName",
|
|
635
|
-
"fileStatus": "SD8qLW_fileStatus",
|
|
636
|
-
"lineDel": "SD8qLW_lineDel",
|
|
637
|
-
"chipSystem": "SD8qLW_chipSystem",
|
|
638
|
-
"funnelButtonActive": "SD8qLW_funnelButtonActive",
|
|
566
|
+
"funnelBoundVal": "SD8qLW_funnelBoundVal",
|
|
567
|
+
"refCaret": "SD8qLW_refCaret",
|
|
639
568
|
"treeFilterClear": "SD8qLW_treeFilterClear",
|
|
640
|
-
"
|
|
569
|
+
"sideTabs": "SD8qLW_sideTabs",
|
|
570
|
+
"btnIconOn": "SD8qLW_btnIconOn",
|
|
571
|
+
"commitHash": "SD8qLW_commitHash",
|
|
572
|
+
"cardAdded": "SD8qLW_cardAdded",
|
|
573
|
+
"confirmTitle": "SD8qLW_confirmTitle",
|
|
574
|
+
"body": "SD8qLW_body",
|
|
575
|
+
"funnelPresets": "SD8qLW_funnelPresets",
|
|
576
|
+
"calTitle": "SD8qLW_calTitle",
|
|
577
|
+
"funnelCaption": "SD8qLW_funnelCaption",
|
|
578
|
+
"funnelRow": "SD8qLW_funnelRow",
|
|
579
|
+
"scopeBtnActive": "SD8qLW_scopeBtnActive",
|
|
580
|
+
"bgPreview": "SD8qLW_bgPreview",
|
|
581
|
+
"refButton": "SD8qLW_refButton",
|
|
582
|
+
"fileActive": "SD8qLW_fileActive",
|
|
583
|
+
"treeDirCounts": "SD8qLW_treeDirCounts",
|
|
584
|
+
"fileCounts": "SD8qLW_fileCounts",
|
|
585
|
+
"refGroup": "SD8qLW_refGroup",
|
|
641
586
|
"overlay": "SD8qLW_overlay",
|
|
642
|
-
"
|
|
643
|
-
"
|
|
644
|
-
"themeGroup": "SD8qLW_themeGroup",
|
|
645
|
-
"sideCode": "SD8qLW_sideCode",
|
|
646
|
-
"cal": "SD8qLW_cal",
|
|
647
|
-
"filterChipRemove": "SD8qLW_filterChipRemove",
|
|
648
|
-
"themeNote": "SD8qLW_themeNote",
|
|
649
|
-
"treeTools": "SD8qLW_treeTools",
|
|
650
|
-
"stRenamed": "SD8qLW_stRenamed",
|
|
651
|
-
"commitFilter": "SD8qLW_commitFilter",
|
|
652
|
-
"sideCol": "SD8qLW_sideCol",
|
|
653
|
-
"syncUpstream": "SD8qLW_syncUpstream",
|
|
654
|
-
"funnelFootCountOn": "SD8qLW_funnelFootCountOn",
|
|
655
|
-
"filePath": "SD8qLW_filePath",
|
|
587
|
+
"stDeleted": "SD8qLW_stDeleted",
|
|
588
|
+
"line": "SD8qLW_line",
|
|
656
589
|
"sideNumAdd": "SD8qLW_sideNumAdd",
|
|
657
|
-
"
|
|
658
|
-
"
|
|
659
|
-
"
|
|
660
|
-
"
|
|
661
|
-
"
|
|
662
|
-
"
|
|
663
|
-
"
|
|
664
|
-
"
|
|
665
|
-
"
|
|
666
|
-
"
|
|
667
|
-
"sideCodeDel": "SD8qLW_sideCodeDel",
|
|
668
|
-
"calIn": "SD8qLW_calIn",
|
|
669
|
-
"commitsFoot": "SD8qLW_commitsFoot",
|
|
670
|
-
"body": "SD8qLW_body",
|
|
671
|
-
"treeFilter": "SD8qLW_treeFilter",
|
|
672
|
-
"blockBtnDanger": "SD8qLW_blockBtnDanger",
|
|
673
|
-
"sideArmable": "SD8qLW_sideArmable",
|
|
674
|
-
"funnelFootCount": "SD8qLW_funnelFootCount",
|
|
675
|
-
"fbHeader": "SD8qLW_fbHeader",
|
|
676
|
-
"paneDivider": "SD8qLW_paneDivider",
|
|
677
|
-
"checkMarkOn": "SD8qLW_checkMarkOn",
|
|
590
|
+
"bodyRow": "SD8qLW_bodyRow",
|
|
591
|
+
"sideColGridWrap": "SD8qLW_sideColGridWrap",
|
|
592
|
+
"funnelPop": "SD8qLW_funnelPop",
|
|
593
|
+
"sideCodeSame": "SD8qLW_sideCodeSame",
|
|
594
|
+
"sideActionsAdjacent": "SD8qLW_sideActionsAdjacent",
|
|
595
|
+
"headerTotalsAdd": "SD8qLW_headerTotalsAdd",
|
|
596
|
+
"filePath": "SD8qLW_filePath",
|
|
597
|
+
"tree": "SD8qLW_tree",
|
|
598
|
+
"sideRailSpan": "SD8qLW_sideRailSpan",
|
|
599
|
+
"checkMark": "SD8qLW_checkMark",
|
|
678
600
|
"commitLead": "SD8qLW_commitLead",
|
|
679
601
|
"fbRowActive": "SD8qLW_fbRowActive",
|
|
680
|
-
"
|
|
681
|
-
"sideNum": "SD8qLW_sideNum",
|
|
682
|
-
"fbMore": "SD8qLW_fbMore",
|
|
683
|
-
"confirmScrim": "SD8qLW_confirmScrim",
|
|
684
|
-
"funnelMore": "SD8qLW_funnelMore",
|
|
685
|
-
"sideSaveReady": "SD8qLW_sideSaveReady",
|
|
686
|
-
"tree": "SD8qLW_tree",
|
|
687
|
-
"funnelCaption": "SD8qLW_funnelCaption",
|
|
688
|
-
"headerTotalsAdd": "SD8qLW_headerTotalsAdd",
|
|
689
|
-
"cardDetached": "SD8qLW_cardDetached",
|
|
690
|
-
"funnelBoundVal": "SD8qLW_funnelBoundVal",
|
|
691
|
-
"commitRefMore": "SD8qLW_commitRefMore",
|
|
692
|
-
"fbSearch": "SD8qLW_fbSearch",
|
|
693
|
-
"sideNumDel": "SD8qLW_sideNumDel",
|
|
694
|
-
"fbCommit": "SD8qLW_fbCommit",
|
|
695
|
-
"sideCols": "SD8qLW_sideCols",
|
|
696
|
-
"cardAdded": "SD8qLW_cardAdded",
|
|
697
|
-
"scopeRow": "SD8qLW_scopeRow",
|
|
698
|
-
"funnelTabs": "SD8qLW_funnelTabs",
|
|
699
|
-
"calWeek": "SD8qLW_calWeek",
|
|
700
|
-
"commitsSentinel": "SD8qLW_commitsSentinel",
|
|
701
|
-
"overlayMax": "SD8qLW_overlayMax",
|
|
702
|
-
"tab": "SD8qLW_tab",
|
|
703
|
-
"renameLine": "SD8qLW_renameLine",
|
|
704
|
-
"commits": "SD8qLW_commits",
|
|
602
|
+
"refPicker": "SD8qLW_refPicker",
|
|
705
603
|
"cardDeleted": "SD8qLW_cardDeleted",
|
|
706
|
-
"
|
|
707
|
-
"
|
|
708
|
-
"
|
|
709
|
-
"
|
|
710
|
-
"
|
|
711
|
-
"
|
|
712
|
-
"paneDividerActive": "SD8qLW_paneDividerActive",
|
|
713
|
-
"fbNote": "SD8qLW_fbNote",
|
|
604
|
+
"cmHost": "SD8qLW_cmHost",
|
|
605
|
+
"blockBtnDanger": "SD8qLW_blockBtnDanger",
|
|
606
|
+
"confirmActions": "SD8qLW_confirmActions",
|
|
607
|
+
"refSearch": "SD8qLW_refSearch",
|
|
608
|
+
"treeCol": "SD8qLW_treeCol",
|
|
609
|
+
"layoutGlyph": "SD8qLW_layoutGlyph",
|
|
714
610
|
"paneDividerY": "SD8qLW_paneDividerY",
|
|
715
|
-
"
|
|
611
|
+
"syncSpacer": "SD8qLW_syncSpacer",
|
|
612
|
+
"treeIcon": "SD8qLW_treeIcon",
|
|
716
613
|
"commitPopSubject": "SD8qLW_commitPopSubject",
|
|
717
|
-
"
|
|
718
|
-
"
|
|
719
|
-
"treeCol": "SD8qLW_treeCol",
|
|
720
|
-
"sideSpacer": "SD8qLW_sideSpacer",
|
|
721
|
-
"filterChipLabel": "SD8qLW_filterChipLabel",
|
|
722
|
-
"menuPop": "SD8qLW_menuPop",
|
|
723
|
-
"pullGroup": "SD8qLW_pullGroup",
|
|
724
|
-
"fbFileName": "SD8qLW_fbFileName",
|
|
614
|
+
"empty": "SD8qLW_empty",
|
|
615
|
+
"fbPath": "SD8qLW_fbPath",
|
|
725
616
|
"cardWt": "SD8qLW_cardWt",
|
|
726
|
-
"
|
|
727
|
-
"
|
|
617
|
+
"sideArmable": "SD8qLW_sideArmable",
|
|
618
|
+
"commitSubjectRow": "SD8qLW_commitSubjectRow",
|
|
728
619
|
"checkBox": "SD8qLW_checkBox",
|
|
729
|
-
"
|
|
730
|
-
"
|
|
731
|
-
"
|
|
732
|
-
"
|
|
733
|
-
"
|
|
734
|
-
"
|
|
620
|
+
"opBanner": "SD8qLW_opBanner",
|
|
621
|
+
"btnBehind": "SD8qLW_btnBehind",
|
|
622
|
+
"scopeHint": "SD8qLW_scopeHint",
|
|
623
|
+
"calGrid": "SD8qLW_calGrid",
|
|
624
|
+
"headerPathMain": "SD8qLW_headerPathMain",
|
|
625
|
+
"compareBar": "SD8qLW_compareBar",
|
|
626
|
+
"elideTail": "SD8qLW_elideTail",
|
|
627
|
+
"refFoot": "SD8qLW_refFoot",
|
|
628
|
+
"commitRef": "SD8qLW_commitRef",
|
|
629
|
+
"stUntracked": "SD8qLW_stUntracked",
|
|
630
|
+
"fileBinary": "SD8qLW_fileBinary",
|
|
631
|
+
"refEmpty": "SD8qLW_refEmpty",
|
|
632
|
+
"gutter": "SD8qLW_gutter",
|
|
735
633
|
"funnelPreset": "SD8qLW_funnelPreset",
|
|
634
|
+
"sideTabActive": "SD8qLW_sideTabActive",
|
|
635
|
+
"stRenamed": "SD8qLW_stRenamed",
|
|
636
|
+
"sideCode": "SD8qLW_sideCode",
|
|
736
637
|
"blockBar": "SD8qLW_blockBar",
|
|
737
|
-
"
|
|
738
|
-
"
|
|
739
|
-
"
|
|
740
|
-
"
|
|
741
|
-
"
|
|
742
|
-
"btn": "SD8qLW_btn",
|
|
743
|
-
"miniBtnPrimary": "SD8qLW_miniBtnPrimary",
|
|
744
|
-
"cardSep": "SD8qLW_cardSep",
|
|
745
|
-
"btnAhead": "SD8qLW_btnAhead",
|
|
746
|
-
"sideCurrentBlockActions": "SD8qLW_sideCurrentBlockActions",
|
|
747
|
-
"line": "SD8qLW_line",
|
|
748
|
-
"sideEditCell": "SD8qLW_sideEditCell",
|
|
749
|
-
"confirmTitle": "SD8qLW_confirmTitle",
|
|
750
|
-
"funnelName": "SD8qLW_funnelName",
|
|
751
|
-
"chevronOpen": "SD8qLW_chevronOpen",
|
|
638
|
+
"syncUpstream": "SD8qLW_syncUpstream",
|
|
639
|
+
"tabActive": "SD8qLW_tabActive",
|
|
640
|
+
"funnelBoundKey": "SD8qLW_funnelBoundKey",
|
|
641
|
+
"commitAmend": "SD8qLW_commitAmend",
|
|
642
|
+
"refList": "SD8qLW_refList",
|
|
752
643
|
"btnClose": "SD8qLW_btnClose",
|
|
644
|
+
"commitRefMore": "SD8qLW_commitRefMore",
|
|
645
|
+
"fbCommitLine": "SD8qLW_fbCommitLine",
|
|
646
|
+
"cardFiles": "SD8qLW_cardFiles",
|
|
647
|
+
"sideSaveReady": "SD8qLW_sideSaveReady",
|
|
648
|
+
"tab": "SD8qLW_tab",
|
|
649
|
+
"commitAuthor": "SD8qLW_commitAuthor",
|
|
650
|
+
"treeWrap": "SD8qLW_treeWrap",
|
|
651
|
+
"code": "SD8qLW_code",
|
|
652
|
+
"sideFlow": "SD8qLW_sideFlow",
|
|
753
653
|
"imgCaption": "SD8qLW_imgCaption",
|
|
654
|
+
"btnPrimary": "SD8qLW_btnPrimary",
|
|
655
|
+
"commitsSentinel": "SD8qLW_commitsSentinel",
|
|
656
|
+
"sideRailRight": "SD8qLW_sideRailRight",
|
|
657
|
+
"btnDanger": "SD8qLW_btnDanger",
|
|
658
|
+
"themeNote": "SD8qLW_themeNote",
|
|
659
|
+
"treeActions": "SD8qLW_treeActions",
|
|
660
|
+
"cardBranch": "SD8qLW_cardBranch",
|
|
661
|
+
"imgStage": "SD8qLW_imgStage",
|
|
662
|
+
"chevron": "SD8qLW_chevron",
|
|
754
663
|
"gsFade": "SD8qLW_gsFade",
|
|
755
|
-
"
|
|
756
|
-
"code": "SD8qLW_code",
|
|
757
|
-
"sideTabActive": "SD8qLW_sideTabActive",
|
|
664
|
+
"overlayMax": "SD8qLW_overlayMax",
|
|
758
665
|
"resizerActive": "SD8qLW_resizerActive",
|
|
759
|
-
"
|
|
760
|
-
"
|
|
761
|
-
"
|
|
762
|
-
"
|
|
763
|
-
"diffPane": "SD8qLW_diffPane",
|
|
666
|
+
"refRow": "SD8qLW_refRow",
|
|
667
|
+
"commitHasBody": "SD8qLW_commitHasBody",
|
|
668
|
+
"refRowName": "SD8qLW_refRowName",
|
|
669
|
+
"sideRailGap": "SD8qLW_sideRailGap",
|
|
764
670
|
"fbBody": "SD8qLW_fbBody",
|
|
765
|
-
"
|
|
766
|
-
"
|
|
767
|
-
"
|
|
768
|
-
"
|
|
769
|
-
"
|
|
770
|
-
"
|
|
771
|
-
"
|
|
772
|
-
"
|
|
671
|
+
"btn": "SD8qLW_btn",
|
|
672
|
+
"tabs": "SD8qLW_tabs",
|
|
673
|
+
"calHead": "SD8qLW_calHead",
|
|
674
|
+
"funnelCount": "SD8qLW_funnelCount",
|
|
675
|
+
"signDel": "SD8qLW_signDel",
|
|
676
|
+
"sideColGrid": "SD8qLW_sideColGrid",
|
|
677
|
+
"commitStaged": "SD8qLW_commitStaged",
|
|
678
|
+
"layoutButton": "SD8qLW_layoutButton",
|
|
679
|
+
"fbRow": "SD8qLW_fbRow",
|
|
680
|
+
"confirmScrim": "SD8qLW_confirmScrim",
|
|
681
|
+
"confirmBox": "SD8qLW_confirmBox",
|
|
682
|
+
"filterChipRemove": "SD8qLW_filterChipRemove",
|
|
683
|
+
"layoutButtonOn": "SD8qLW_layoutButtonOn",
|
|
684
|
+
"treeDirName": "SD8qLW_treeDirName",
|
|
685
|
+
"treeRow": "SD8qLW_treeRow",
|
|
686
|
+
"sliderRow": "SD8qLW_sliderRow",
|
|
687
|
+
"calIn": "SD8qLW_calIn",
|
|
773
688
|
"headerTotals": "SD8qLW_headerTotals",
|
|
689
|
+
"funnelBoundRows": "SD8qLW_funnelBoundRows",
|
|
690
|
+
"sideSpacer": "SD8qLW_sideSpacer",
|
|
691
|
+
"sideNavCount": "SD8qLW_sideNavCount",
|
|
692
|
+
"sideRailsOn": "SD8qLW_sideRailsOn",
|
|
693
|
+
"checkMarkOn": "SD8qLW_checkMarkOn",
|
|
694
|
+
"scopeBtn": "SD8qLW_scopeBtn",
|
|
695
|
+
"fbCommitHint": "SD8qLW_fbCommitHint",
|
|
696
|
+
"fileStatus": "SD8qLW_fileStatus",
|
|
697
|
+
"fileCountDel": "SD8qLW_fileCountDel",
|
|
698
|
+
"fbCommitWhen": "SD8qLW_fbCommitWhen",
|
|
699
|
+
"elideHead": "SD8qLW_elideHead",
|
|
700
|
+
"paneHead": "SD8qLW_paneHead",
|
|
701
|
+
"blameCell": "SD8qLW_blameCell",
|
|
702
|
+
"calWeek": "SD8qLW_calWeek",
|
|
703
|
+
"fbMore": "SD8qLW_fbMore",
|
|
774
704
|
"calOut": "SD8qLW_calOut",
|
|
775
|
-
"
|
|
776
|
-
"
|
|
777
|
-
"
|
|
778
|
-
"
|
|
705
|
+
"btnAhead": "SD8qLW_btnAhead",
|
|
706
|
+
"cssArea": "SD8qLW_cssArea",
|
|
707
|
+
"opBannerBad": "SD8qLW_opBannerBad",
|
|
708
|
+
"refValue": "SD8qLW_refValue",
|
|
709
|
+
"treeDir": "SD8qLW_treeDir",
|
|
710
|
+
"themeRowSplit": "SD8qLW_themeRowSplit",
|
|
711
|
+
"diffPane": "SD8qLW_diffPane",
|
|
712
|
+
"opBannerOk": "SD8qLW_opBannerOk",
|
|
713
|
+
"lnNew": "SD8qLW_lnNew",
|
|
779
714
|
"headerBranch": "SD8qLW_headerBranch",
|
|
780
|
-
"
|
|
715
|
+
"treeTools": "SD8qLW_treeTools",
|
|
716
|
+
"diffScroll": "SD8qLW_diffScroll",
|
|
717
|
+
"sideRails": "SD8qLW_sideRails",
|
|
718
|
+
"pathNode": "SD8qLW_pathNode",
|
|
719
|
+
"treeIconGlyph": "SD8qLW_treeIconGlyph",
|
|
720
|
+
"diffPre": "SD8qLW_diffPre",
|
|
721
|
+
"bgEmpty": "SD8qLW_bgEmpty",
|
|
722
|
+
"chevronOpen": "SD8qLW_chevronOpen",
|
|
723
|
+
"miniBtnPrimary": "SD8qLW_miniBtnPrimary",
|
|
724
|
+
"chipLight": "SD8qLW_chipLight",
|
|
725
|
+
"funnelFoot": "SD8qLW_funnelFoot",
|
|
726
|
+
"funnelPane": "SD8qLW_funnelPane",
|
|
727
|
+
"blockBtn": "SD8qLW_blockBtn",
|
|
728
|
+
"diffPreWrap": "SD8qLW_diffPreWrap",
|
|
729
|
+
"commits": "SD8qLW_commits",
|
|
781
730
|
"stAdded": "SD8qLW_stAdded",
|
|
782
|
-
"
|
|
783
|
-
"funnelRow": "SD8qLW_funnelRow",
|
|
731
|
+
"lineAdd": "SD8qLW_lineAdd",
|
|
784
732
|
"sideColRight": "SD8qLW_sideColRight",
|
|
785
|
-
"
|
|
786
|
-
"
|
|
787
|
-
"
|
|
733
|
+
"commitBtn": "SD8qLW_commitBtn",
|
|
734
|
+
"fbCommit": "SD8qLW_fbCommit",
|
|
735
|
+
"treeFilter": "SD8qLW_treeFilter",
|
|
736
|
+
"settingsPop": "SD8qLW_settingsPop",
|
|
737
|
+
"funnel": "SD8qLW_funnel",
|
|
738
|
+
"funnelTab": "SD8qLW_funnelTab",
|
|
739
|
+
"chipSystem": "SD8qLW_chipSystem",
|
|
740
|
+
"commitActive": "SD8qLW_commitActive",
|
|
741
|
+
"fileDiscard": "SD8qLW_fileDiscard",
|
|
742
|
+
"sideColGridBlame": "SD8qLW_sideColGridBlame",
|
|
743
|
+
"commitPopMeta": "SD8qLW_commitPopMeta",
|
|
744
|
+
"fbCommitWho": "SD8qLW_fbCommitWho",
|
|
745
|
+
"funnelFootClear": "SD8qLW_funnelFootClear",
|
|
788
746
|
"diffWrap": "SD8qLW_diffWrap",
|
|
789
|
-
"
|
|
790
|
-
"
|
|
791
|
-
"
|
|
792
|
-
"
|
|
747
|
+
"headerView": "SD8qLW_headerView",
|
|
748
|
+
"refPop": "SD8qLW_refPop",
|
|
749
|
+
"funnelChevron": "SD8qLW_funnelChevron",
|
|
750
|
+
"cardDetached": "SD8qLW_cardDetached",
|
|
751
|
+
"menuPop": "SD8qLW_menuPop",
|
|
752
|
+
"sideBanner": "SD8qLW_sideBanner",
|
|
753
|
+
"themeGroup": "SD8qLW_themeGroup",
|
|
754
|
+
"funnelButton": "SD8qLW_funnelButton",
|
|
755
|
+
"fbSearch": "SD8qLW_fbSearch",
|
|
756
|
+
"sideEditCell": "SD8qLW_sideEditCell",
|
|
757
|
+
"cardSep": "SD8qLW_cardSep",
|
|
758
|
+
"funnelButtonActive": "SD8qLW_funnelButtonActive",
|
|
759
|
+
"funnelFootCount": "SD8qLW_funnelFootCount",
|
|
760
|
+
"card": "SD8qLW_card",
|
|
761
|
+
"refRowSpacer": "SD8qLW_refRowSpacer",
|
|
762
|
+
"fbHeader": "SD8qLW_fbHeader",
|
|
763
|
+
"themeLabel": "SD8qLW_themeLabel",
|
|
764
|
+
"commitTop": "SD8qLW_commitTop",
|
|
765
|
+
"btnCount": "SD8qLW_btnCount",
|
|
793
766
|
"checkMarkPartial": "SD8qLW_checkMarkPartial",
|
|
767
|
+
"sideCodeDel": "SD8qLW_sideCodeDel",
|
|
768
|
+
"sideCols": "SD8qLW_sideCols",
|
|
769
|
+
"paletteRowActive": "SD8qLW_paletteRowActive",
|
|
770
|
+
"themeRail": "SD8qLW_themeRail",
|
|
771
|
+
"commitsFoot": "SD8qLW_commitsFoot",
|
|
772
|
+
"fbCommitHash": "SD8qLW_fbCommitHash",
|
|
773
|
+
"sideBannerActs": "SD8qLW_sideBannerActs",
|
|
774
|
+
"sideCol": "SD8qLW_sideCol",
|
|
775
|
+
"themeDirty": "SD8qLW_themeDirty",
|
|
776
|
+
"diffNav": "SD8qLW_diffNav",
|
|
777
|
+
"signAdd": "SD8qLW_signAdd",
|
|
778
|
+
"elide": "SD8qLW_elide",
|
|
779
|
+
"funnelSearch": "SD8qLW_funnelSearch",
|
|
780
|
+
"syncLevel": "SD8qLW_syncLevel",
|
|
781
|
+
"sideScroll": "SD8qLW_sideScroll",
|
|
794
782
|
"wtCurrent": "SD8qLW_wtCurrent",
|
|
795
|
-
"
|
|
796
|
-
"
|
|
797
|
-
"
|
|
798
|
-
"
|
|
799
|
-
"
|
|
783
|
+
"sideCellBlock": "SD8qLW_sideCellBlock",
|
|
784
|
+
"layoutSwitch": "SD8qLW_layoutSwitch",
|
|
785
|
+
"refRowActive": "SD8qLW_refRowActive",
|
|
786
|
+
"lnOld": "SD8qLW_lnOld",
|
|
787
|
+
"drawer": "SD8qLW_drawer",
|
|
788
|
+
"filterChip": "SD8qLW_filterChip",
|
|
789
|
+
"pullGroup": "SD8qLW_pullGroup",
|
|
790
|
+
"funnelBoundClear": "SD8qLW_funnelBoundClear",
|
|
791
|
+
"cal": "SD8qLW_cal",
|
|
792
|
+
"wordAdd": "SD8qLW_wordAdd",
|
|
793
|
+
"crMark": "SD8qLW_crMark",
|
|
794
|
+
"compareArrow": "SD8qLW_compareArrow",
|
|
795
|
+
"fbFileName": "SD8qLW_fbFileName",
|
|
796
|
+
"imgShot": "SD8qLW_imgShot",
|
|
797
|
+
"headerTotalsDim": "SD8qLW_headerTotalsDim",
|
|
798
|
+
"treeFilterInput": "SD8qLW_treeFilterInput",
|
|
799
|
+
"segmentActive": "SD8qLW_segmentActive",
|
|
800
|
+
"paneTitle": "SD8qLW_paneTitle",
|
|
801
|
+
"headerViewRef": "SD8qLW_headerViewRef",
|
|
802
|
+
"headerLeft": "SD8qLW_headerLeft",
|
|
803
|
+
"commitRow": "SD8qLW_commitRow",
|
|
804
|
+
"sideCurrentBlockActions": "SD8qLW_sideCurrentBlockActions",
|
|
805
|
+
"sideCodeAdd": "SD8qLW_sideCodeAdd",
|
|
806
|
+
"fbCommitWhat": "SD8qLW_fbCommitWhat",
|
|
807
|
+
"funnelMore": "SD8qLW_funnelMore",
|
|
808
|
+
"treeLabel": "SD8qLW_treeLabel",
|
|
809
|
+
"commitPopTop": "SD8qLW_commitPopTop",
|
|
810
|
+
"segment": "SD8qLW_segment",
|
|
811
|
+
"commitFilter": "SD8qLW_commitFilter",
|
|
800
812
|
"commit": "SD8qLW_commit",
|
|
801
|
-
"
|
|
802
|
-
"
|
|
813
|
+
"swatch": "SD8qLW_swatch",
|
|
814
|
+
"sideNotice": "SD8qLW_sideNotice"
|
|
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
|
] })
|
|
@@ -36294,7 +36675,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
36294
36675
|
* @param offset - px above the first row, e.g. the grid's top padding.
|
|
36295
36676
|
* @returns the first row of each block, in the order the blocks appear.
|
|
36296
36677
|
*/
|
|
36297
|
-
function blockTopsFromRows(blocks, rowH, offset = 0) {
|
|
36678
|
+
function blockTopsFromRows(blocks, rowH, offset = 0, topOf) {
|
|
36298
36679
|
const tops = [];
|
|
36299
36680
|
const seen = /* @__PURE__ */ new Set();
|
|
36300
36681
|
for (let i = 0; i < blocks.length; i += 1) {
|
|
@@ -36303,7 +36684,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
36303
36684
|
seen.add(block);
|
|
36304
36685
|
tops.push({
|
|
36305
36686
|
block,
|
|
36306
|
-
top: offset + i * rowH
|
|
36687
|
+
top: offset + (topOf === void 0 ? i * rowH : topOf(i))
|
|
36307
36688
|
});
|
|
36308
36689
|
}
|
|
36309
36690
|
return tops;
|
|
@@ -36349,7 +36730,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
36349
36730
|
* until the height is known would flash an empty pane; a screenful is both
|
|
36350
36731
|
* safe and close.
|
|
36351
36732
|
*/
|
|
36352
|
-
const ASSUMED_VIEWPORT_PX = 1200;
|
|
36733
|
+
const ASSUMED_VIEWPORT_PX$1 = 1200;
|
|
36353
36734
|
/** Whether two windows paint the same rows AND reserve the same total height.
|
|
36354
36735
|
* Comparing only start/end leaves a previous file's bottom spacer behind when
|
|
36355
36736
|
* two long files happen to expose the same viewport-sized row range. */
|
|
@@ -36365,7 +36746,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
36365
36746
|
* @param fallback - used when it is neither finite nor usable.
|
|
36366
36747
|
* @returns a finite, non-negative number.
|
|
36367
36748
|
*/
|
|
36368
|
-
function sane(value, fallback) {
|
|
36749
|
+
function sane$1(value, fallback) {
|
|
36369
36750
|
return Number.isFinite(value) && value > 0 ? value : fallback;
|
|
36370
36751
|
}
|
|
36371
36752
|
/**
|
|
@@ -36380,7 +36761,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
36380
36761
|
*/
|
|
36381
36762
|
function rowWindow(scrollTop, viewportH, rowCount, rowH = 20, overscan = 40) {
|
|
36382
36763
|
const rows = Math.max(0, Math.trunc(rowCount));
|
|
36383
|
-
const height = sane(rowH, 20);
|
|
36764
|
+
const height = sane$1(rowH, 20);
|
|
36384
36765
|
if (rows <= 400) return {
|
|
36385
36766
|
start: 0,
|
|
36386
36767
|
end: rows,
|
|
@@ -36388,7 +36769,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
36388
36769
|
padBottom: 0
|
|
36389
36770
|
};
|
|
36390
36771
|
const top = Number.isFinite(scrollTop) && scrollTop > 0 ? scrollTop : 0;
|
|
36391
|
-
const view = sane(viewportH, ASSUMED_VIEWPORT_PX);
|
|
36772
|
+
const view = sane$1(viewportH, ASSUMED_VIEWPORT_PX$1);
|
|
36392
36773
|
const pad = Math.max(0, Math.trunc(overscan));
|
|
36393
36774
|
const first = Math.max(0, Math.floor(top / height) - pad);
|
|
36394
36775
|
const last = Math.min(rows, Math.ceil((top + view) / height) + pad);
|
|
@@ -36540,6 +36921,154 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
36540
36921
|
});
|
|
36541
36922
|
}
|
|
36542
36923
|
//#endregion
|
|
36924
|
+
//#region src/client/h-rail.ts
|
|
36925
|
+
/** Before anything has been measured, and for a column that is not mounted. */
|
|
36926
|
+
const NO_RAIL = {
|
|
36927
|
+
view: 0,
|
|
36928
|
+
content: 0
|
|
36929
|
+
};
|
|
36930
|
+
/**
|
|
36931
|
+
* Whether a column overflows by enough to be worth a scrollbar.
|
|
36932
|
+
*
|
|
36933
|
+
* The one-pixel slack is not tidiness: a grid track rounds to a fraction, so a
|
|
36934
|
+
* column whose longest line exactly fits still reports a scroll width a third
|
|
36935
|
+
* of a pixel wider than its client width. Without the slack every file gets a
|
|
36936
|
+
* rail, and every one of those rails scrolls nowhere.
|
|
36937
|
+
*
|
|
36938
|
+
* @param metric - the column's measured widths.
|
|
36939
|
+
* @returns true when a rail should be shown for it.
|
|
36940
|
+
*/
|
|
36941
|
+
function railNeeded(metric) {
|
|
36942
|
+
const { view, content } = metric;
|
|
36943
|
+
if (!Number.isFinite(view) || !Number.isFinite(content)) return false;
|
|
36944
|
+
if (view <= 0) return false;
|
|
36945
|
+
return content > view + 1;
|
|
36946
|
+
}
|
|
36947
|
+
/** Whether the rail row is shown at all — either column overflowing is enough,
|
|
36948
|
+
* since the row is one sticky strip and a lone rail still needs its space. */
|
|
36949
|
+
function railsShown(left, right) {
|
|
36950
|
+
return railNeeded(left) || railNeeded(right);
|
|
36951
|
+
}
|
|
36952
|
+
/**
|
|
36953
|
+
* Whether two measurements are the same.
|
|
36954
|
+
*
|
|
36955
|
+
* The measuring effect runs on every render, so this is what keeps it from
|
|
36956
|
+
* setting state on every render and rendering again forever.
|
|
36957
|
+
*
|
|
36958
|
+
* @param a - the measurement held in state.
|
|
36959
|
+
* @param b - the one just read from the DOM.
|
|
36960
|
+
*/
|
|
36961
|
+
function sameMetric(a, b) {
|
|
36962
|
+
return a.view === b.view && a.content === b.content;
|
|
36963
|
+
}
|
|
36964
|
+
//#endregion
|
|
36965
|
+
//#region src/client/SideRails.tsx
|
|
36966
|
+
/**
|
|
36967
|
+
* Measure one column and keep its rail's scroll position tied to it.
|
|
36968
|
+
*
|
|
36969
|
+
* The measurement runs on EVERY render rather than on a dependency list: the
|
|
36970
|
+
* content width changes for reasons no list can name — a window scrolled to
|
|
36971
|
+
* longer rows, syntax spans replacing plain text, the editor mounting into the
|
|
36972
|
+
* right column, wrap turning on. Two integer reads is a cheap price for never
|
|
36973
|
+
* being stale, and {@link sameMetric} is what keeps setting state on every
|
|
36974
|
+
* render from becoming a render on every render.
|
|
36975
|
+
*
|
|
36976
|
+
* @param colRef - the column, which clips and scrolls its own content.
|
|
36977
|
+
* @param railRef - the strip at the bottom of the pane that stands in for it.
|
|
36978
|
+
* @returns the column's measured widths.
|
|
36979
|
+
*/
|
|
36980
|
+
function useRail(colRef, railRef) {
|
|
36981
|
+
const [metric, setMetric] = (0, react.useState)(NO_RAIL);
|
|
36982
|
+
const measure = (col) => {
|
|
36983
|
+
const next = {
|
|
36984
|
+
view: col.clientWidth,
|
|
36985
|
+
content: col.scrollWidth
|
|
36986
|
+
};
|
|
36987
|
+
setMetric((prev) => sameMetric(prev, next) ? prev : next);
|
|
36988
|
+
};
|
|
36989
|
+
(0, react.useLayoutEffect)(() => {
|
|
36990
|
+
const col = colRef.current;
|
|
36991
|
+
if (col !== null) measure(col);
|
|
36992
|
+
});
|
|
36993
|
+
(0, react.useEffect)(() => {
|
|
36994
|
+
const col = colRef.current;
|
|
36995
|
+
if (col === null) return;
|
|
36996
|
+
const observer = new ResizeObserver(() => {
|
|
36997
|
+
measure(col);
|
|
36998
|
+
});
|
|
36999
|
+
observer.observe(col);
|
|
37000
|
+
return () => {
|
|
37001
|
+
observer.disconnect();
|
|
37002
|
+
};
|
|
37003
|
+
}, [colRef]);
|
|
37004
|
+
(0, react.useEffect)(() => {
|
|
37005
|
+
const col = colRef.current;
|
|
37006
|
+
const rail = railRef.current;
|
|
37007
|
+
if (col === null || rail === null) return;
|
|
37008
|
+
const toRail = () => {
|
|
37009
|
+
if (rail.scrollLeft !== col.scrollLeft) rail.scrollLeft = col.scrollLeft;
|
|
37010
|
+
};
|
|
37011
|
+
const toCol = () => {
|
|
37012
|
+
if (col.scrollLeft !== rail.scrollLeft) col.scrollLeft = rail.scrollLeft;
|
|
37013
|
+
};
|
|
37014
|
+
col.addEventListener("scroll", toRail, { passive: true });
|
|
37015
|
+
rail.addEventListener("scroll", toCol, { passive: true });
|
|
37016
|
+
toRail();
|
|
37017
|
+
return () => {
|
|
37018
|
+
col.removeEventListener("scroll", toRail);
|
|
37019
|
+
rail.removeEventListener("scroll", toCol);
|
|
37020
|
+
};
|
|
37021
|
+
}, [colRef, railRef]);
|
|
37022
|
+
return metric;
|
|
37023
|
+
}
|
|
37024
|
+
/**
|
|
37025
|
+
* The side-by-side pane's horizontal scrollbars, stuck to the bottom of the
|
|
37026
|
+
* pane instead of the bottom of the file — see `h-rail.ts` for why they are
|
|
37027
|
+
* here at all.
|
|
37028
|
+
*
|
|
37029
|
+
* Always rendered, never conditionally: the strip collapses to nothing through
|
|
37030
|
+
* a class when neither column overflows, so both rails keep their elements and
|
|
37031
|
+
* the effects above keep stable dependencies. A rail that mounted and
|
|
37032
|
+
* unmounted with the measurement would re-attach its listeners on every file.
|
|
37033
|
+
*
|
|
37034
|
+
* @param leftRef - the left column.
|
|
37035
|
+
* @param rightRef - the right column.
|
|
37036
|
+
* @param split - the divider's position, as a fraction of the pane's width;
|
|
37037
|
+
* the rails carry the same flex sizing so each sits under the
|
|
37038
|
+
* column it scrolls.
|
|
37039
|
+
* @returns the sticky rail strip.
|
|
37040
|
+
*/
|
|
37041
|
+
function SideRails({ leftRef, rightRef, split }) {
|
|
37042
|
+
const leftRailRef = (0, react.useRef)(null);
|
|
37043
|
+
const rightRailRef = (0, react.useRef)(null);
|
|
37044
|
+
const left = useRail(leftRef, leftRailRef);
|
|
37045
|
+
const right = useRail(rightRef, rightRailRef);
|
|
37046
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
37047
|
+
className: railsShown(left, right) ? `${GitWorkbenchPanel_module_css_default.sideRails} ${GitWorkbenchPanel_module_css_default.sideRailsOn}` : GitWorkbenchPanel_module_css_default.sideRails,
|
|
37048
|
+
"aria-hidden": "true",
|
|
37049
|
+
children: [
|
|
37050
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
37051
|
+
ref: leftRailRef,
|
|
37052
|
+
className: GitWorkbenchPanel_module_css_default.sideRail,
|
|
37053
|
+
style: { flexBasis: `${split * 100}%` },
|
|
37054
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
37055
|
+
className: GitWorkbenchPanel_module_css_default.sideRailSpan,
|
|
37056
|
+
style: { width: left.content }
|
|
37057
|
+
})
|
|
37058
|
+
}),
|
|
37059
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: GitWorkbenchPanel_module_css_default.sideRailGap }),
|
|
37060
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
37061
|
+
ref: rightRailRef,
|
|
37062
|
+
className: `${GitWorkbenchPanel_module_css_default.sideRail} ${GitWorkbenchPanel_module_css_default.sideRailRight}`,
|
|
37063
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
37064
|
+
className: GitWorkbenchPanel_module_css_default.sideRailSpan,
|
|
37065
|
+
style: { width: right.content }
|
|
37066
|
+
})
|
|
37067
|
+
})
|
|
37068
|
+
]
|
|
37069
|
+
});
|
|
37070
|
+
}
|
|
37071
|
+
//#endregion
|
|
36543
37072
|
//#region src/client/use-row-window.ts
|
|
36544
37073
|
/**
|
|
36545
37074
|
* The rows a diff actually has to put in the DOM, tracked against its scroller.
|
|
@@ -36555,9 +37084,13 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
36555
37084
|
*
|
|
36556
37085
|
* @param scrollRef - the element that scrolls the rows.
|
|
36557
37086
|
* @param rowCount - how many rows the diff has.
|
|
37087
|
+
* @param enabled - false while soft wrap is on, when the rows are no longer a
|
|
37088
|
+
* fixed height and `use-variable-row-window.ts` answers
|
|
37089
|
+
* instead. Attaching both panes' listeners at once would put
|
|
37090
|
+
* two readers on the same scroll.
|
|
36558
37091
|
* @returns the rows to render and the spacer heights standing in for the rest.
|
|
36559
37092
|
*/
|
|
36560
|
-
function useRowWindow(scrollRef, rowCount, mountKey) {
|
|
37093
|
+
function useRowWindow(scrollRef, rowCount, mountKey, enabled = true) {
|
|
36561
37094
|
const count = Number.isFinite(rowCount) ? Math.max(0, Math.trunc(rowCount)) : 0;
|
|
36562
37095
|
const [held, setHeld] = (0, react.useState)(() => ({
|
|
36563
37096
|
mountKey,
|
|
@@ -36567,7 +37100,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
36567
37100
|
const visible = rowWindowForMount(held, count, mountKey);
|
|
36568
37101
|
(0, react.useEffect)(() => {
|
|
36569
37102
|
const el = scrollRef.current;
|
|
36570
|
-
if (el === null) return;
|
|
37103
|
+
if (el === null || !enabled) return;
|
|
36571
37104
|
const read = () => {
|
|
36572
37105
|
const next = rowWindow(el.scrollTop, el.clientHeight, count);
|
|
36573
37106
|
setHeld((prev) => prev.mountKey === mountKey && prev.rowCount === count && sameRowWindow(prev.win, next) ? prev : {
|
|
@@ -36587,11 +37120,475 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
36587
37120
|
}, [
|
|
36588
37121
|
scrollRef,
|
|
36589
37122
|
count,
|
|
36590
|
-
mountKey
|
|
37123
|
+
mountKey,
|
|
37124
|
+
enabled
|
|
36591
37125
|
]);
|
|
36592
37126
|
return visible;
|
|
36593
37127
|
}
|
|
36594
37128
|
//#endregion
|
|
37129
|
+
//#region src/client/row-heights.ts
|
|
37130
|
+
/**
|
|
37131
|
+
* Row offsets when the rows are NOT all the same height — what soft wrap makes
|
|
37132
|
+
* of a diff pane.
|
|
37133
|
+
*
|
|
37134
|
+
* `row-window.ts` places row `i` at `i * 20px` with no measuring at all, and
|
|
37135
|
+
* says so: the panes guarantee it by writing `white-space: pre`, so nothing
|
|
37136
|
+
* ever wraps. Turn wrapping on and that guarantee is gone — one row can be
|
|
37137
|
+
* five lines tall — and every number the window computes from it (which rows
|
|
37138
|
+
* are visible, how tall the spacers are, where a change sits) is wrong.
|
|
37139
|
+
*
|
|
37140
|
+
* The replacement keeps the same shape and the same rule: work proportional to
|
|
37141
|
+
* the VIEWPORT. Heights are MEASURED, but only for rows that are actually in
|
|
37142
|
+
* the DOM, which is the window plus its overscan; every other row carries an
|
|
37143
|
+
* estimate computed from its text. So a 20,000-row file costs one array and
|
|
37144
|
+
* some arithmetic, not 20,000 measurements.
|
|
37145
|
+
*
|
|
37146
|
+
* The prefix sums are a Fenwick tree rather than a running array, because both
|
|
37147
|
+
* things this is asked for happen on the scroll path and must not be linear:
|
|
37148
|
+
* "where does row i start" is a prefix query, "which row is at y" is a search
|
|
37149
|
+
* for a prefix, and a measurement that lands changes one row's height. All
|
|
37150
|
+
* three are O(log n) here; as a plain array of running totals, the third would
|
|
37151
|
+
* rewrite every entry after the row that moved.
|
|
37152
|
+
*
|
|
37153
|
+
* Pure: no React, no DOM. `tests/row-heights.test.ts` loads it directly.
|
|
37154
|
+
*
|
|
37155
|
+
* @module @young1lin/dsh-ui-gitworkbench/client/row-heights
|
|
37156
|
+
*/
|
|
37157
|
+
/** A viewport height to assume before the scroller has been measured, matching
|
|
37158
|
+
* `row-window.ts`: rendering nothing until the height is known flashes an
|
|
37159
|
+
* empty pane, and a screenful is both safe and close. */
|
|
37160
|
+
const ASSUMED_VIEWPORT_PX = 1200;
|
|
37161
|
+
/**
|
|
37162
|
+
* How many display columns a line occupies.
|
|
37163
|
+
*
|
|
37164
|
+
* Only for the ESTIMATE of rows nobody has measured, so it does not have to
|
|
37165
|
+
* agree with the browser to the character — it has to be close enough that
|
|
37166
|
+
* the scrollbar is the right length and a jump to the middle of the file lands
|
|
37167
|
+
* near where it should. Tabs advance to the next stop (`tab-size: 4` in the
|
|
37168
|
+
* panes' grid) and full-width characters take two columns, which are the two
|
|
37169
|
+
* ways a naive `text.length` is badly wrong rather than slightly wrong.
|
|
37170
|
+
*
|
|
37171
|
+
* @param text - one row's text.
|
|
37172
|
+
* @param tabSize - columns a tab advances to the next multiple of.
|
|
37173
|
+
*/
|
|
37174
|
+
function displayColumns(text, tabSize = 4) {
|
|
37175
|
+
let columns = 0;
|
|
37176
|
+
for (const char of text) {
|
|
37177
|
+
if (char === " ") {
|
|
37178
|
+
columns += tabSize - columns % tabSize;
|
|
37179
|
+
continue;
|
|
37180
|
+
}
|
|
37181
|
+
columns += isWide(char) ? 2 : 1;
|
|
37182
|
+
}
|
|
37183
|
+
return columns;
|
|
37184
|
+
}
|
|
37185
|
+
/**
|
|
37186
|
+
* Whether a character takes two columns in a monospace font: CJK, Hangul,
|
|
37187
|
+
* kana, the full-width forms, and the emoji blocks. The ranges rather than a
|
|
37188
|
+
* table because this runs over a file's worth of text and the answer only
|
|
37189
|
+
* feeds an estimate.
|
|
37190
|
+
*/
|
|
37191
|
+
function isWide(char) {
|
|
37192
|
+
const code = char.codePointAt(0) ?? 0;
|
|
37193
|
+
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;
|
|
37194
|
+
}
|
|
37195
|
+
/**
|
|
37196
|
+
* The height a row is guessed to have before it has been measured.
|
|
37197
|
+
*
|
|
37198
|
+
* @param text - the row's text.
|
|
37199
|
+
* @param columns - how many columns fit across the pane; 0 or less means the
|
|
37200
|
+
* pane has not been measured yet, and one line is assumed.
|
|
37201
|
+
* @param rowH - one line's height in px.
|
|
37202
|
+
*/
|
|
37203
|
+
function estimateRowHeight(text, columns, rowH) {
|
|
37204
|
+
if (!Number.isFinite(columns) || columns <= 0) return rowH;
|
|
37205
|
+
return Math.max(1, Math.ceil(displayColumns(text) / columns)) * rowH;
|
|
37206
|
+
}
|
|
37207
|
+
/**
|
|
37208
|
+
* Per-row heights with O(log n) offsets, backed by a Fenwick tree.
|
|
37209
|
+
*
|
|
37210
|
+
* Bounded by construction: two arrays of `rowCount`, which the panes already
|
|
37211
|
+
* cap. {@link measured} reports how much of it is real rather than guessed, so
|
|
37212
|
+
* a test can prove the measuring stays viewport-sized instead of trusting it.
|
|
37213
|
+
*/
|
|
37214
|
+
var RowHeights = class {
|
|
37215
|
+
/** Each row's height. */
|
|
37216
|
+
heights;
|
|
37217
|
+
/** Fenwick sums, 1-based; `tree[i]` covers a block ending at row `i - 1`. */
|
|
37218
|
+
tree;
|
|
37219
|
+
/** Rows whose height came from the DOM rather than from an estimate. */
|
|
37220
|
+
real;
|
|
37221
|
+
realCount = 0;
|
|
37222
|
+
/**
|
|
37223
|
+
* @param initial - each row's starting height, normally an estimate.
|
|
37224
|
+
*/
|
|
37225
|
+
constructor(initial) {
|
|
37226
|
+
const n = initial.length;
|
|
37227
|
+
this.heights = new Float64Array(n);
|
|
37228
|
+
this.tree = new Float64Array(n + 1);
|
|
37229
|
+
this.real = new Uint8Array(n);
|
|
37230
|
+
for (let i = 0; i < n; i += 1) this.heights[i] = sane(initial[i]);
|
|
37231
|
+
for (let i = 1; i <= n; i += 1) {
|
|
37232
|
+
this.tree[i] += this.heights[i - 1];
|
|
37233
|
+
const parent = i + (i & -i);
|
|
37234
|
+
if (parent <= n) this.tree[parent] += this.tree[i];
|
|
37235
|
+
}
|
|
37236
|
+
}
|
|
37237
|
+
/** How many rows there are. */
|
|
37238
|
+
get count() {
|
|
37239
|
+
return this.heights.length;
|
|
37240
|
+
}
|
|
37241
|
+
/** How many rows carry a measured height rather than an estimate. */
|
|
37242
|
+
measured() {
|
|
37243
|
+
return this.realCount;
|
|
37244
|
+
}
|
|
37245
|
+
/**
|
|
37246
|
+
* Record one row's real height.
|
|
37247
|
+
* @returns whether anything moved, so a caller can avoid a re-render.
|
|
37248
|
+
*/
|
|
37249
|
+
set(index, px) {
|
|
37250
|
+
if (!Number.isInteger(index) || index < 0 || index >= this.count) return false;
|
|
37251
|
+
const next = sane(px);
|
|
37252
|
+
if (this.real[index] === 0) {
|
|
37253
|
+
this.real[index] = 1;
|
|
37254
|
+
this.realCount += 1;
|
|
37255
|
+
}
|
|
37256
|
+
const delta = next - this.heights[index];
|
|
37257
|
+
if (delta === 0) return false;
|
|
37258
|
+
this.heights[index] = next;
|
|
37259
|
+
for (let i = index + 1; i <= this.count; i += i & -i) this.tree[i] += delta;
|
|
37260
|
+
return true;
|
|
37261
|
+
}
|
|
37262
|
+
/** One row's height. */
|
|
37263
|
+
heightAt(index) {
|
|
37264
|
+
if (index < 0 || index >= this.count) return 0;
|
|
37265
|
+
return this.heights[index];
|
|
37266
|
+
}
|
|
37267
|
+
/** Where a row starts, measured from the top of the scrolled content. */
|
|
37268
|
+
topAt(index) {
|
|
37269
|
+
let sum = 0;
|
|
37270
|
+
for (let i = Math.max(0, Math.min(index, this.count)); i > 0; i -= i & -i) sum += this.tree[i];
|
|
37271
|
+
return sum;
|
|
37272
|
+
}
|
|
37273
|
+
/** Every row's height together. */
|
|
37274
|
+
total() {
|
|
37275
|
+
return this.topAt(this.count);
|
|
37276
|
+
}
|
|
37277
|
+
/**
|
|
37278
|
+
* The row that contains `y`, by binary lifting over the tree — the same
|
|
37279
|
+
* search a running-totals array would do, without the array.
|
|
37280
|
+
*/
|
|
37281
|
+
rowAt(y) {
|
|
37282
|
+
if (this.count === 0) return 0;
|
|
37283
|
+
let remaining = Number.isFinite(y) && y > 0 ? y : 0;
|
|
37284
|
+
let index = 0;
|
|
37285
|
+
let step = 1;
|
|
37286
|
+
while (step * 2 <= this.count) step *= 2;
|
|
37287
|
+
for (; step > 0; step = Math.floor(step / 2)) {
|
|
37288
|
+
const probe = index + step;
|
|
37289
|
+
if (probe <= this.count && this.tree[probe] <= remaining) {
|
|
37290
|
+
remaining -= this.tree[probe];
|
|
37291
|
+
index = probe;
|
|
37292
|
+
}
|
|
37293
|
+
}
|
|
37294
|
+
return Math.min(index, this.count - 1);
|
|
37295
|
+
}
|
|
37296
|
+
};
|
|
37297
|
+
/** @param value - a number from the DOM, which can be NaN or negative. */
|
|
37298
|
+
function sane(value) {
|
|
37299
|
+
return Number.isFinite(value) && value > 0 ? value : 0;
|
|
37300
|
+
}
|
|
37301
|
+
/**
|
|
37302
|
+
* The window of rows to render when the rows are not all one height.
|
|
37303
|
+
*
|
|
37304
|
+
* Same answer shape as {@link rowWindow}, and the same short-circuit below
|
|
37305
|
+
* {@link WINDOW_WHOLE_BELOW}: windowing has costs of its own, and a file that
|
|
37306
|
+
* was never slow should render exactly as it did before.
|
|
37307
|
+
*
|
|
37308
|
+
* @param scrollTop - the scroller's current offset in px.
|
|
37309
|
+
* @param viewportH - the scroller's visible height in px; 0 before measuring.
|
|
37310
|
+
* @param heights - the rows' heights.
|
|
37311
|
+
* @param overscan - rows to keep beyond each edge.
|
|
37312
|
+
*/
|
|
37313
|
+
function variableRowWindow(scrollTop, viewportH, heights, overscan = 40) {
|
|
37314
|
+
const rows = heights.count;
|
|
37315
|
+
if (rows <= 400) return {
|
|
37316
|
+
start: 0,
|
|
37317
|
+
end: rows,
|
|
37318
|
+
padTop: 0,
|
|
37319
|
+
padBottom: 0
|
|
37320
|
+
};
|
|
37321
|
+
const top = Number.isFinite(scrollTop) && scrollTop > 0 ? scrollTop : 0;
|
|
37322
|
+
const view = Number.isFinite(viewportH) && viewportH > 0 ? viewportH : ASSUMED_VIEWPORT_PX;
|
|
37323
|
+
const pad = Math.max(0, Math.trunc(overscan));
|
|
37324
|
+
const start = Math.max(0, heights.rowAt(top) - pad);
|
|
37325
|
+
const end = Math.min(rows, heights.rowAt(top + view) + 1 + pad);
|
|
37326
|
+
const safeEnd = Math.max(start, end);
|
|
37327
|
+
return {
|
|
37328
|
+
start,
|
|
37329
|
+
end: safeEnd,
|
|
37330
|
+
padTop: heights.topAt(start),
|
|
37331
|
+
padBottom: Math.max(0, heights.total() - heights.topAt(safeEnd))
|
|
37332
|
+
};
|
|
37333
|
+
}
|
|
37334
|
+
//#endregion
|
|
37335
|
+
//#region src/client/use-variable-row-window.ts
|
|
37336
|
+
/**
|
|
37337
|
+
* The windowing hook for panes whose rows are not all one height — a diff
|
|
37338
|
+
* pane with soft wrap on.
|
|
37339
|
+
*
|
|
37340
|
+
* The fixed-height hook beside this one (`use-row-window.ts`) needs nothing
|
|
37341
|
+
* from the DOM but the scroll offset, because `i * 20px` is the answer. Once
|
|
37342
|
+
* lines wrap, only the DOM knows how tall a row came out, so this one measures
|
|
37343
|
+
* — and measures ONLY the rows it just rendered, which is the window plus its
|
|
37344
|
+
* overscan. Every other row carries an estimate computed from its text, so the
|
|
37345
|
+
* scrollbar is close from the first paint instead of growing as the reader
|
|
37346
|
+
* scrolls.
|
|
37347
|
+
*
|
|
37348
|
+
* A measurement that replaces an estimate for a row ABOVE the viewport moves
|
|
37349
|
+
* everything below it, including what the reader is looking at. The scroll
|
|
37350
|
+
* offset is corrected by the same delta in the same layout pass, so the rows
|
|
37351
|
+
* on screen stay under the eye rather than sliding.
|
|
37352
|
+
*
|
|
37353
|
+
* @module @young1lin/dsh-ui-gitworkbench/client/use-variable-row-window
|
|
37354
|
+
*/
|
|
37355
|
+
/** Attribute a pane puts on each measurable element, as `scope:index`. */
|
|
37356
|
+
const ROW_INDEX_ATTR = "data-gw-row";
|
|
37357
|
+
/**
|
|
37358
|
+
* What a pane writes on an element it wants measured.
|
|
37359
|
+
*
|
|
37360
|
+
* The scope is half the value rather than a second attribute because two
|
|
37361
|
+
* height models can be mounted inside one scroller — the aligned diff and the
|
|
37362
|
+
* dense index column beside the editor — and a bare index would let each read
|
|
37363
|
+
* the other's rows as its own.
|
|
37364
|
+
*
|
|
37365
|
+
* @param scope - which height model the element belongs to.
|
|
37366
|
+
* @param index - the row's index WITHIN that model.
|
|
37367
|
+
*/
|
|
37368
|
+
function rowMark(scope, index) {
|
|
37369
|
+
return { [ROW_INDEX_ATTR]: `${scope}:${index}` };
|
|
37370
|
+
}
|
|
37371
|
+
/**
|
|
37372
|
+
* Columns that fit across a pane, from its width and one character's advance.
|
|
37373
|
+
*
|
|
37374
|
+
* Measured off a probe rather than assumed: the panes' font size is a theme
|
|
37375
|
+
* variable a reader can change, so a hard-coded character width would put the
|
|
37376
|
+
* estimate out by a third on the smallest setting.
|
|
37377
|
+
*
|
|
37378
|
+
* @param grid - the element the rows are laid out in.
|
|
37379
|
+
* @returns columns across, or 0 when the element is not laid out yet.
|
|
37380
|
+
*/
|
|
37381
|
+
function columnsAcross(grid) {
|
|
37382
|
+
if (grid === null) return 0;
|
|
37383
|
+
const width = grid.clientWidth;
|
|
37384
|
+
if (!Number.isFinite(width) || width <= 0) return 0;
|
|
37385
|
+
const probe = document.createElement("span");
|
|
37386
|
+
probe.textContent = "0".repeat(100);
|
|
37387
|
+
probe.style.cssText = "position:absolute;visibility:hidden;white-space:pre;pointer-events:none";
|
|
37388
|
+
grid.appendChild(probe);
|
|
37389
|
+
const advance = probe.getBoundingClientRect().width / 100;
|
|
37390
|
+
probe.remove();
|
|
37391
|
+
if (!Number.isFinite(advance) || advance <= 0) return 0;
|
|
37392
|
+
return Math.max(1, Math.floor(width / advance));
|
|
37393
|
+
}
|
|
37394
|
+
function useVariableRowWindow({ scrollRef, rowsRef, widthRef, texts, mountKey, scope, enabled, rowH = 20 }) {
|
|
37395
|
+
/** Columns across the pane. State, because the estimate depends on it and a
|
|
37396
|
+
* dragged divider changes it. */
|
|
37397
|
+
const [columns, setColumns] = (0, react.useState)(0);
|
|
37398
|
+
/**
|
|
37399
|
+
* Bumped when a measurement moved a row.
|
|
37400
|
+
*
|
|
37401
|
+
* The heights live in a mutable structure, so changing one changes no
|
|
37402
|
+
* identity React watches — and the side-by-side pane reads them DURING
|
|
37403
|
+
* render, to impose each row's height on both of its cells. Without this
|
|
37404
|
+
* the first pass would measure correctly and then never re-render to apply
|
|
37405
|
+
* what it measured, which is a row that is one line taller on one side than
|
|
37406
|
+
* on the other. Bumped only when something actually moved, and imposing a
|
|
37407
|
+
* height does not change what is measured (the measured box is inside the
|
|
37408
|
+
* cell), so it settles in one extra pass.
|
|
37409
|
+
*/
|
|
37410
|
+
const [, bumpHeights] = (0, react.useState)(0);
|
|
37411
|
+
const [win, setWin] = (0, react.useState)(() => ({
|
|
37412
|
+
start: 0,
|
|
37413
|
+
end: texts.length,
|
|
37414
|
+
padTop: 0,
|
|
37415
|
+
padBottom: 0
|
|
37416
|
+
}));
|
|
37417
|
+
/** Rebuilt only when the diff or the width really changes — never on scroll. */
|
|
37418
|
+
const heights = (0, react.useMemo)(() => new RowHeights(enabled ? texts.map((text) => estimateRowHeight(text, columns, rowH)) : []), [
|
|
37419
|
+
texts,
|
|
37420
|
+
columns,
|
|
37421
|
+
rowH,
|
|
37422
|
+
mountKey,
|
|
37423
|
+
enabled
|
|
37424
|
+
]);
|
|
37425
|
+
const read = (0, react.useCallback)(() => {
|
|
37426
|
+
const el = scrollRef.current;
|
|
37427
|
+
if (el === null || heights.count === 0) return;
|
|
37428
|
+
const next = variableRowWindow(el.scrollTop, el.clientHeight, heights);
|
|
37429
|
+
setWin((prev) => sameRowWindow(prev, next) ? prev : next);
|
|
37430
|
+
}, [scrollRef, heights]);
|
|
37431
|
+
(0, react.useEffect)(() => {
|
|
37432
|
+
const el = scrollRef.current;
|
|
37433
|
+
if (el === null || !enabled) return;
|
|
37434
|
+
read();
|
|
37435
|
+
const observer = new ResizeObserver(() => {
|
|
37436
|
+
read();
|
|
37437
|
+
setColumns((prev) => {
|
|
37438
|
+
const measured = columnsAcross((widthRef ?? rowsRef).current);
|
|
37439
|
+
return measured === 0 || measured === prev ? prev : measured;
|
|
37440
|
+
});
|
|
37441
|
+
});
|
|
37442
|
+
el.addEventListener("scroll", read, { passive: true });
|
|
37443
|
+
observer.observe(el);
|
|
37444
|
+
return () => {
|
|
37445
|
+
el.removeEventListener("scroll", read);
|
|
37446
|
+
observer.disconnect();
|
|
37447
|
+
};
|
|
37448
|
+
}, [
|
|
37449
|
+
scrollRef,
|
|
37450
|
+
rowsRef,
|
|
37451
|
+
widthRef,
|
|
37452
|
+
read,
|
|
37453
|
+
enabled
|
|
37454
|
+
]);
|
|
37455
|
+
(0, react.useLayoutEffect)(() => {
|
|
37456
|
+
const root = rowsRef.current;
|
|
37457
|
+
const scroller = scrollRef.current;
|
|
37458
|
+
if (!enabled || root === null || scroller === null) return;
|
|
37459
|
+
const before = heights.topAt(win.start);
|
|
37460
|
+
const tallest = /* @__PURE__ */ new Map();
|
|
37461
|
+
for (const node of root.querySelectorAll(`[${ROW_INDEX_ATTR}^="${scope}:"]`)) {
|
|
37462
|
+
const index = Number(node.getAttribute(ROW_INDEX_ATTR)?.slice(scope.length + 1));
|
|
37463
|
+
if (!Number.isInteger(index)) continue;
|
|
37464
|
+
tallest.set(index, Math.max(tallest.get(index) ?? 0, node.getBoundingClientRect().height));
|
|
37465
|
+
}
|
|
37466
|
+
let moved = false;
|
|
37467
|
+
for (const [index, height] of tallest) if (heights.set(index, height)) moved = true;
|
|
37468
|
+
if (!moved) return;
|
|
37469
|
+
const after = heights.topAt(win.start);
|
|
37470
|
+
if (after !== before) scroller.scrollTop += after - before;
|
|
37471
|
+
bumpHeights((version) => version + 1);
|
|
37472
|
+
read();
|
|
37473
|
+
});
|
|
37474
|
+
return {
|
|
37475
|
+
win,
|
|
37476
|
+
rowTop: (0, react.useCallback)((index) => enabled ? heights.topAt(index) : Math.max(0, Math.trunc(index)) * rowH, [
|
|
37477
|
+
enabled,
|
|
37478
|
+
heights,
|
|
37479
|
+
rowH
|
|
37480
|
+
]),
|
|
37481
|
+
rowHeight: (0, react.useCallback)((index) => enabled ? heights.heightAt(index) : rowH, [
|
|
37482
|
+
enabled,
|
|
37483
|
+
heights,
|
|
37484
|
+
rowH
|
|
37485
|
+
])
|
|
37486
|
+
};
|
|
37487
|
+
}
|
|
37488
|
+
//#endregion
|
|
37489
|
+
//#region src/client/diff-cells.tsx
|
|
37490
|
+
/** Classes that paint only a block's OUTER perimeter. Internal rows carry the
|
|
37491
|
+
* vertical edges but no top/bottom line, avoiding the blue ladder a large
|
|
37492
|
+
* addition block used to draw. Absent side-cells return no class at all. */
|
|
37493
|
+
function blockHotClass(rows, index, side, hot) {
|
|
37494
|
+
if (!hot) return "";
|
|
37495
|
+
const edge = blockEdge(rows, index, side);
|
|
37496
|
+
if (edge === null) return "";
|
|
37497
|
+
const first = edge === "first" || edge === "single" ? ` ${GitWorkbenchPanel_module_css_default.sideBlockHotFirst}` : "";
|
|
37498
|
+
const last = edge === "last" || edge === "single" ? ` ${GitWorkbenchPanel_module_css_default.sideBlockHotLast}` : "";
|
|
37499
|
+
return ` ${GitWorkbenchPanel_module_css_default.sideBlockHot}${first}${last}`;
|
|
37500
|
+
}
|
|
37501
|
+
/** Line-number cell class: a PRESENT cell of a changed row carries its side's
|
|
37502
|
+
* tint into the gutter; an absent one stays blank, the way a split diff shows
|
|
37503
|
+
* a one-sided change with an empty opposite pane rather than a tinted void. */
|
|
37504
|
+
function sideNumClass(row, side) {
|
|
37505
|
+
if ((side === "left" ? row.left : row.right) === null || row.kind === "same") return GitWorkbenchPanel_module_css_default.sideNum;
|
|
37506
|
+
return `${GitWorkbenchPanel_module_css_default.sideNum} ${side === "left" ? GitWorkbenchPanel_module_css_default.sideNumDel : GitWorkbenchPanel_module_css_default.sideNumAdd}`;
|
|
37507
|
+
}
|
|
37508
|
+
/** Code cell class: deletions tint left, additions right, context stays quiet. */
|
|
37509
|
+
function sideCodeClass(row, side) {
|
|
37510
|
+
if ((side === "left" ? row.left : row.right) === null || row.kind === "same") return GitWorkbenchPanel_module_css_default.sideCodeSame;
|
|
37511
|
+
return `${side === "left" ? GitWorkbenchPanel_module_css_default.sideCodeDel : GitWorkbenchPanel_module_css_default.sideCodeAdd} ${GitWorkbenchPanel_module_css_default.sideCellBlock}`;
|
|
37512
|
+
}
|
|
37513
|
+
/** One text with every carriage return drawn as the CR glyph. No CR means
|
|
37514
|
+
* the text comes back untouched — the common line, on both sides, costs one
|
|
37515
|
+
* `includes`. The glyph spans are aria-hidden and unselectable, so copying a
|
|
37516
|
+
* line copies code, not markers. */
|
|
37517
|
+
function renderWithCrMarks(text) {
|
|
37518
|
+
const parts = splitOnCr(text);
|
|
37519
|
+
if (parts.length === 1) return text;
|
|
37520
|
+
const out = [parts[0]];
|
|
37521
|
+
for (let i = 1; i < parts.length; i += 1) {
|
|
37522
|
+
out.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
37523
|
+
className: GitWorkbenchPanel_module_css_default.crMark,
|
|
37524
|
+
"aria-hidden": "true",
|
|
37525
|
+
children: "␍"
|
|
37526
|
+
}, `cr${i}`));
|
|
37527
|
+
out.push(parts[i]);
|
|
37528
|
+
}
|
|
37529
|
+
return out;
|
|
37530
|
+
}
|
|
37531
|
+
/** One cell's Shiki runs, or its plain text when no tokens exist; either way
|
|
37532
|
+
* each carriage return in the cell is drawn, so a line whose only change is
|
|
37533
|
+
* its ending shows the difference instead of two identical-looking cells. */
|
|
37534
|
+
function renderSideCode(cell, tokens) {
|
|
37535
|
+
if (cell === null) return "";
|
|
37536
|
+
if (tokens === void 0 || tokens.length === 0) return renderWithCrMarks(cell.text);
|
|
37537
|
+
if (tokens.length === 1 && tokens[0].color === void 0 && !tokens[0].italic) return renderWithCrMarks(cell.text);
|
|
37538
|
+
return tokens.map((tok, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
37539
|
+
style: tok.color === void 0 && !tok.italic ? void 0 : {
|
|
37540
|
+
color: tok.color,
|
|
37541
|
+
fontStyle: tok.italic ? "italic" : void 0
|
|
37542
|
+
},
|
|
37543
|
+
children: renderWithCrMarks(tok.text)
|
|
37544
|
+
}, i));
|
|
37545
|
+
}
|
|
37546
|
+
/**
|
|
37547
|
+
* The spacer standing in for the rows above or below the window.
|
|
37548
|
+
*
|
|
37549
|
+
* It spans every column of the grid, so a blame gutter does not change it.
|
|
37550
|
+
* @param height - px of rows it stands in for; nothing is rendered for 0.
|
|
37551
|
+
*/
|
|
37552
|
+
function RowSpacer({ height }) {
|
|
37553
|
+
if (height <= 0) return null;
|
|
37554
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
37555
|
+
className: GitWorkbenchPanel_module_css_default.sideSpacer,
|
|
37556
|
+
style: { height: `${height}px` },
|
|
37557
|
+
"aria-hidden": "true"
|
|
37558
|
+
});
|
|
37559
|
+
}
|
|
37560
|
+
/**
|
|
37561
|
+
* One side of one aligned row: its line-number cell and its code cell.
|
|
37562
|
+
*
|
|
37563
|
+
* Written once and used by all three columns the pane draws — the left side of
|
|
37564
|
+
* a diff, the right side, and the dense index column beside the editor —
|
|
37565
|
+
* because the three differ only in which cell they read, what hangs the block
|
|
37566
|
+
* bar and whether a click arms the editor. Everything else about them, from
|
|
37567
|
+
* the block outline to the CR markers, is the same in all three and was
|
|
37568
|
+
* previously the same three times.
|
|
37569
|
+
*/
|
|
37570
|
+
function SideCells({ row, side, index, rows, current, tokens, mark, minHeight, bar, armable, onArm }) {
|
|
37571
|
+
const hot = blockHotClass(rows, index, side, current);
|
|
37572
|
+
const cell = side === "left" ? row.left : row.right;
|
|
37573
|
+
const code = renderSideCode(cell, tokens);
|
|
37574
|
+
const box = minHeight !== void 0 && minHeight > 0 ? { minHeight: `${minHeight}px` } : void 0;
|
|
37575
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
37576
|
+
className: `${sideNumClass(row, side)}${hot}`,
|
|
37577
|
+
style: box,
|
|
37578
|
+
children: cell === null ? "" : cell.line
|
|
37579
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
37580
|
+
className: `${GitWorkbenchPanel_module_css_default.sideCode} ${sideCodeClass(row, side)}${hot}${armable === true ? ` ${GitWorkbenchPanel_module_css_default.sideArmable}` : ""}`,
|
|
37581
|
+
style: box,
|
|
37582
|
+
"data-block": cell !== null && row.block >= 0 ? row.block : void 0,
|
|
37583
|
+
onClick: onArm,
|
|
37584
|
+
children: [mark === void 0 ? code : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
37585
|
+
className: GitWorkbenchPanel_module_css_default.sideFlow,
|
|
37586
|
+
...mark,
|
|
37587
|
+
children: code
|
|
37588
|
+
}), bar]
|
|
37589
|
+
})] });
|
|
37590
|
+
}
|
|
37591
|
+
//#endregion
|
|
36595
37592
|
//#region src/client/DiffViews.tsx
|
|
36596
37593
|
const SPLIT_MIN = .15;
|
|
36597
37594
|
const SPLIT_MAX = .85;
|
|
@@ -36632,14 +37629,24 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
36632
37629
|
* a block child of a scroller is only ever as wide as the scrollport. A header
|
|
36633
37630
|
* outside the scrolled box has neither problem.
|
|
36634
37631
|
*/
|
|
36635
|
-
function DiffView({ segment, path, palette, t }) {
|
|
37632
|
+
function DiffView({ segment, path, palette, t, wrap }) {
|
|
36636
37633
|
const lang = shikiLangOf(path);
|
|
36637
37634
|
const shikiTheme = shikiThemeOf(palette);
|
|
36638
37635
|
const grammarGen = (0, react.useSyncExternalStore)(subscribeGrammarLoaded, grammarLoadCount);
|
|
36639
37636
|
const rowsWithWords = (0, react.useMemo)(() => attachWordRanges(parseRows(segment)), [segment]);
|
|
36640
37637
|
const sides = (0, react.useMemo)(() => gutterSides(rowsWithWords), [rowsWithWords]);
|
|
36641
37638
|
const scrollRef = (0, react.useRef)(null);
|
|
36642
|
-
const
|
|
37639
|
+
const preRef = (0, react.useRef)(null);
|
|
37640
|
+
const fixed = useRowWindow(scrollRef, rowsWithWords.length, path, !wrap);
|
|
37641
|
+
const flow = useVariableRowWindow({
|
|
37642
|
+
scrollRef,
|
|
37643
|
+
rowsRef: preRef,
|
|
37644
|
+
texts: (0, react.useMemo)(() => rowsWithWords.map((row) => row.text), [rowsWithWords]),
|
|
37645
|
+
mountKey: path,
|
|
37646
|
+
scope: "u",
|
|
37647
|
+
enabled: wrap
|
|
37648
|
+
});
|
|
37649
|
+
const win = wrap ? flow.win : fixed;
|
|
36643
37650
|
const syntax = (0, react.useMemo)(() => highlightForRowsWindow(rowsWithWords, lang, shikiTheme, win.start, win.end), [
|
|
36644
37651
|
rowsWithWords,
|
|
36645
37652
|
lang,
|
|
@@ -36652,7 +37659,9 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
36652
37659
|
const changes = (0, react.useMemo)(() => countBlocks(blocks), [blocks]);
|
|
36653
37660
|
const blocksForNav = (0, react.useRef)(blocks);
|
|
36654
37661
|
blocksForNav.current = blocks;
|
|
36655
|
-
const
|
|
37662
|
+
const placeRow = (0, react.useRef)(void 0);
|
|
37663
|
+
placeRow.current = wrap ? flow.rowTop : void 0;
|
|
37664
|
+
const { goToChange } = useChangeNav(scrollRef, (0, react.useCallback)(() => blockTopsFromRows(blocksForNav.current, 20, 8, placeRow.current), []));
|
|
36656
37665
|
const walk = (0, react.useRef)(goToChange);
|
|
36657
37666
|
walk.current = goToChange;
|
|
36658
37667
|
(0, react.useEffect)(() => {
|
|
@@ -36703,7 +37712,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
36703
37712
|
className: GitWorkbenchPanel_module_css_default.diffScroll,
|
|
36704
37713
|
tabIndex: -1,
|
|
36705
37714
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("pre", {
|
|
36706
|
-
|
|
37715
|
+
ref: preRef,
|
|
37716
|
+
className: wrap ? `${GitWorkbenchPanel_module_css_default.diffPre} ${GitWorkbenchPanel_module_css_default.diffPreWrap}` : GitWorkbenchPanel_module_css_default.diffPre,
|
|
36707
37717
|
children: [
|
|
36708
37718
|
win.padTop > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
36709
37719
|
className: GitWorkbenchPanel_module_css_default.diffSpacer,
|
|
@@ -36715,6 +37725,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
36715
37725
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
36716
37726
|
className: `${GitWorkbenchPanel_module_css_default.line} ${rowClass(row.kind)}`,
|
|
36717
37727
|
"data-block": blocks[i] >= 0 ? blocks[i] : void 0,
|
|
37728
|
+
...rowMark("u", i),
|
|
36718
37729
|
children: [
|
|
36719
37730
|
sides.old ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
36720
37731
|
className: GitWorkbenchPanel_module_css_default.lnOld,
|
|
@@ -36799,7 +37810,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
36799
37810
|
* (history and compare keep it unconditionally), with a notice — a silently
|
|
36800
37811
|
* different view reads as a broken one, not a guarded one.
|
|
36801
37812
|
*/
|
|
36802
|
-
function SideBySideView({ t, path, palette, statsPath, fetchSides, writeChecked, scopeKey, gen, fallbackSegment, fallbackLoading, onBlockAction, onSaved, onDirtyChange }) {
|
|
37813
|
+
function SideBySideView({ t, path, palette, wrap, statsPath, fetchSides, writeChecked, scopeKey, gen, fallbackSegment, fallbackLoading, onBlockAction, onSaved, onDirtyChange }) {
|
|
36803
37814
|
const [layer, setLayer] = (0, react.useState)("unstaged");
|
|
36804
37815
|
const [split, setSplit] = (0, react.useState)(.5);
|
|
36805
37816
|
const colsRef = (0, react.useRef)(null);
|
|
@@ -36898,7 +37909,25 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
36898
37909
|
const alignedBlockTops = (0, react.useMemo)(() => blockTopsFromRows(rows.map((row) => row.block), 20, navOffset), [rows, navOffset]);
|
|
36899
37910
|
const editorBlockTops = (0, react.useMemo)(() => blockTopsFromSideRows(rows, "right", 20, navOffset), [rows, navOffset]);
|
|
36900
37911
|
const rowWindowKey = `${scopeKey}\x1f${path}\x1f${layer}\x1f${sides?.diffSha ?? ""}`;
|
|
36901
|
-
const
|
|
37912
|
+
const alignedGridRef = (0, react.useRef)(null);
|
|
37913
|
+
const denseGridRef = (0, react.useRef)(null);
|
|
37914
|
+
const leftColRef = (0, react.useRef)(null);
|
|
37915
|
+
const rightColRef = (0, react.useRef)(null);
|
|
37916
|
+
const fixedWin = useRowWindow(scrollRef, rows.length, rowWindowKey, !wrap);
|
|
37917
|
+
const flow = useVariableRowWindow({
|
|
37918
|
+
scrollRef,
|
|
37919
|
+
rowsRef: colsRef,
|
|
37920
|
+
widthRef: alignedGridRef,
|
|
37921
|
+
texts: (0, react.useMemo)(() => rows.map((row) => {
|
|
37922
|
+
const left = row.left?.text ?? "";
|
|
37923
|
+
const right = row.right?.text ?? "";
|
|
37924
|
+
return left.length >= right.length ? left : right;
|
|
37925
|
+
}), [rows]),
|
|
37926
|
+
mountKey: rowWindowKey,
|
|
37927
|
+
scope: "a",
|
|
37928
|
+
enabled: wrap
|
|
37929
|
+
});
|
|
37930
|
+
const win = wrap ? flow.win : fixedWin;
|
|
36902
37931
|
const leftLines = (0, react.useMemo)(() => rows.map((row) => row.left === null ? "" : row.left.text), [rows]);
|
|
36903
37932
|
const rightLines = (0, react.useMemo)(() => rows.map((row) => row.right === null ? "" : row.right.text), [rows]);
|
|
36904
37933
|
const leftSyntax = (0, react.useMemo)(() => highlightWindow(leftLines, lang, shikiTheme, win.start, win.end), [
|
|
@@ -36949,7 +37978,16 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
36949
37978
|
row,
|
|
36950
37979
|
i
|
|
36951
37980
|
})).filter((entry) => entry.row.left !== null), [rows]);
|
|
36952
|
-
const
|
|
37981
|
+
const fixedLeftWin = useRowWindow(scrollRef, leftRows.length, rowWindowKey, !wrap);
|
|
37982
|
+
const leftFlow = useVariableRowWindow({
|
|
37983
|
+
scrollRef,
|
|
37984
|
+
rowsRef: denseGridRef,
|
|
37985
|
+
texts: (0, react.useMemo)(() => leftRows.map((entry) => entry.row.left?.text ?? ""), [leftRows]),
|
|
37986
|
+
mountKey: rowWindowKey,
|
|
37987
|
+
scope: "d",
|
|
37988
|
+
enabled: wrap
|
|
37989
|
+
});
|
|
37990
|
+
const leftWin = wrap ? leftFlow.win : fixedLeftWin;
|
|
36953
37991
|
/** Arm the editor from the payload on screen; the unstaged tab, and only
|
|
36954
37992
|
* for a payload `editableSides` accepts — armEdit itself refuses the rest,
|
|
36955
37993
|
* so even a stray call cannot put CRLF text into the buffer. */
|
|
@@ -37144,7 +38182,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
37144
38182
|
segment: fallbackSegment,
|
|
37145
38183
|
path,
|
|
37146
38184
|
palette,
|
|
37147
|
-
t
|
|
38185
|
+
t,
|
|
38186
|
+
wrap
|
|
37148
38187
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
37149
38188
|
className: GitWorkbenchPanel_module_css_default.empty,
|
|
37150
38189
|
children: fallbackLoading ? t("loadingDiff") : t("noTextDiff")
|
|
@@ -37370,7 +38409,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
37370
38409
|
children: bodyState.kind === "empty" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
37371
38410
|
className: GitWorkbenchPanel_module_css_default.empty,
|
|
37372
38411
|
children: t("noTextDiff")
|
|
37373
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
38412
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
37374
38413
|
ref: colsRef,
|
|
37375
38414
|
className: GitWorkbenchPanel_module_css_default.sideCols,
|
|
37376
38415
|
onMouseOver: onBodyHover,
|
|
@@ -37380,29 +38419,31 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
37380
38419
|
},
|
|
37381
38420
|
children: [
|
|
37382
38421
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
37383
|
-
|
|
38422
|
+
ref: leftColRef,
|
|
38423
|
+
className: wrap ? `${GitWorkbenchPanel_module_css_default.sideCol} ${GitWorkbenchPanel_module_css_default.sideColWrap}` : GitWorkbenchPanel_module_css_default.sideCol,
|
|
37384
38424
|
style: {
|
|
37385
38425
|
flexBasis: `${split * 100}%`,
|
|
37386
38426
|
paddingTop: blockBarClearance
|
|
37387
38427
|
},
|
|
37388
38428
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
37389
|
-
|
|
38429
|
+
ref: bodyState.kind === "editor" ? denseGridRef : alignedGridRef,
|
|
38430
|
+
className: wrap ? `${GitWorkbenchPanel_module_css_default.sideColGrid} ${GitWorkbenchPanel_module_css_default.sideColGridWrap}` : GitWorkbenchPanel_module_css_default.sideColGrid,
|
|
37390
38431
|
children: bodyState.kind === "editor" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
37391
38432
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowSpacer, { height: leftWin.padTop }),
|
|
37392
38433
|
leftRows.slice(leftWin.start, leftWin.end).map((entry, kk) => {
|
|
37393
38434
|
const k = leftWin.start + kk;
|
|
37394
38435
|
const { row, i } = entry;
|
|
37395
38436
|
const hot = hotBlock !== null && row.block === hotBlock;
|
|
37396
|
-
|
|
37397
|
-
|
|
37398
|
-
|
|
37399
|
-
|
|
37400
|
-
|
|
37401
|
-
|
|
37402
|
-
|
|
37403
|
-
|
|
37404
|
-
|
|
37405
|
-
}
|
|
38437
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SideCells, {
|
|
38438
|
+
row,
|
|
38439
|
+
side: "left",
|
|
38440
|
+
index: i,
|
|
38441
|
+
rows,
|
|
38442
|
+
current: row.block >= 0 && row.block === currentBlock,
|
|
38443
|
+
tokens: leftSyntax?.[i],
|
|
38444
|
+
mark: wrap ? rowMark("d", k) : void 0,
|
|
38445
|
+
bar: hot && k === hotFirstLeft ? blockBar(row.block) : null
|
|
38446
|
+
}, `l${i}`);
|
|
37406
38447
|
}),
|
|
37407
38448
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowSpacer, { height: leftWin.padBottom })
|
|
37408
38449
|
] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
@@ -37410,17 +38451,17 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
37410
38451
|
rows.slice(win.start, win.end).map((row, k) => {
|
|
37411
38452
|
const i = win.start + k;
|
|
37412
38453
|
const hot = hotBlock !== null && row.block === hotBlock;
|
|
37413
|
-
|
|
37414
|
-
|
|
37415
|
-
|
|
37416
|
-
|
|
37417
|
-
|
|
37418
|
-
|
|
37419
|
-
|
|
37420
|
-
|
|
37421
|
-
|
|
37422
|
-
|
|
37423
|
-
}
|
|
38454
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SideCells, {
|
|
38455
|
+
row,
|
|
38456
|
+
side: "left",
|
|
38457
|
+
index: i,
|
|
38458
|
+
rows,
|
|
38459
|
+
current: row.block >= 0 && row.block === currentBlock,
|
|
38460
|
+
tokens: leftSyntax?.[i],
|
|
38461
|
+
mark: wrap ? rowMark("a", i) : void 0,
|
|
38462
|
+
minHeight: wrap ? flow.rowHeight(i) : void 0,
|
|
38463
|
+
bar: hot && i === hotFirst && row.right === null ? blockBar(row.block) : null
|
|
38464
|
+
}, i);
|
|
37424
38465
|
}),
|
|
37425
38466
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowSpacer, { height: win.padBottom })
|
|
37426
38467
|
] })
|
|
@@ -37431,7 +38472,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
37431
38472
|
onDrag: onSplitDrag
|
|
37432
38473
|
}),
|
|
37433
38474
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
37434
|
-
|
|
38475
|
+
ref: rightColRef,
|
|
38476
|
+
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
38477
|
style: { paddingTop: blockBarClearance },
|
|
37436
38478
|
children: bodyState.kind === "editor" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CodeEditor, {
|
|
37437
38479
|
value: edit.buffer,
|
|
@@ -37447,33 +38489,39 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
37447
38489
|
ariaLabel: path,
|
|
37448
38490
|
onSave: () => {
|
|
37449
38491
|
if (dirty && !saving) runSave(edit.baseSha);
|
|
37450
|
-
}
|
|
38492
|
+
},
|
|
38493
|
+
wrap
|
|
37451
38494
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
37452
|
-
className: GitWorkbenchPanel_module_css_default.sideColGrid,
|
|
38495
|
+
className: wrap ? `${GitWorkbenchPanel_module_css_default.sideColGrid} ${GitWorkbenchPanel_module_css_default.sideColGridWrap}` : GitWorkbenchPanel_module_css_default.sideColGrid,
|
|
37453
38496
|
children: [
|
|
37454
38497
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowSpacer, { height: win.padTop }),
|
|
37455
38498
|
rows.slice(win.start, win.end).map((row, k) => {
|
|
37456
38499
|
const i = win.start + k;
|
|
37457
38500
|
const hot = hotBlock !== null && row.block === hotBlock;
|
|
37458
|
-
|
|
37459
|
-
|
|
37460
|
-
|
|
37461
|
-
|
|
37462
|
-
|
|
37463
|
-
|
|
37464
|
-
|
|
37465
|
-
|
|
37466
|
-
|
|
37467
|
-
|
|
37468
|
-
|
|
37469
|
-
|
|
38501
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SideCells, {
|
|
38502
|
+
row,
|
|
38503
|
+
side: "right",
|
|
38504
|
+
index: i,
|
|
38505
|
+
rows,
|
|
38506
|
+
current: row.block >= 0 && row.block === currentBlock,
|
|
38507
|
+
tokens: rightSyntax?.[i],
|
|
38508
|
+
mark: wrap ? rowMark("a", i) : void 0,
|
|
38509
|
+
minHeight: wrap ? flow.rowHeight(i) : void 0,
|
|
38510
|
+
bar: hot && i === hotFirst && row.right !== null ? blockBar(row.block) : null,
|
|
38511
|
+
armable: layer === "unstaged" && armable,
|
|
38512
|
+
onArm: layer === "unstaged" && armable ? armFromCell : void 0
|
|
38513
|
+
}, i);
|
|
37470
38514
|
}),
|
|
37471
38515
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(RowSpacer, { height: win.padBottom })
|
|
37472
38516
|
]
|
|
37473
38517
|
})
|
|
37474
38518
|
})
|
|
37475
38519
|
]
|
|
37476
|
-
})
|
|
38520
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SideRails, {
|
|
38521
|
+
leftRef: leftColRef,
|
|
38522
|
+
rightRef: rightColRef,
|
|
38523
|
+
split
|
|
38524
|
+
})] })
|
|
37477
38525
|
}),
|
|
37478
38526
|
pendingLayer !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LeaveEditsConfirm, {
|
|
37479
38527
|
t,
|
|
@@ -37547,76 +38595,6 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
37547
38595
|
})
|
|
37548
38596
|
});
|
|
37549
38597
|
}
|
|
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
38598
|
//#endregion
|
|
37621
38599
|
//#region src/client/ChromeGlyph.tsx
|
|
37622
38600
|
/**
|
|
@@ -37632,7 +38610,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
37632
38610
|
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
38611
|
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
38612
|
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"
|
|
38613
|
+
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",
|
|
38614
|
+
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
38615
|
};
|
|
37637
38616
|
function ChromeGlyph({ of }) {
|
|
37638
38617
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
|
|
@@ -39251,6 +40230,10 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
39251
40230
|
* field of the appearance object: that one is about colour, and this choice
|
|
39252
40231
|
* has to survive a build that adds a palette. */
|
|
39253
40232
|
const STORE_HISTORY_LAYOUT = "dsh-ui-gitworkbench:history-layout";
|
|
40233
|
+
/** Soft wrap, on or off. A reading preference rather than a project setting:
|
|
40234
|
+
* it says how THIS person wants long lines shown, so it lives beside the
|
|
40235
|
+
* pane sizes in localStorage rather than in the shared style store. */
|
|
40236
|
+
const STORE_WRAP = "dsh-ui-gitworkbench:wrap";
|
|
39254
40237
|
const DEFAULT_PANES = {
|
|
39255
40238
|
commits: null,
|
|
39256
40239
|
tree: null,
|
|
@@ -39320,7 +40303,10 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
39320
40303
|
* unvisited worktree does not re-render the browser on every pass. */
|
|
39321
40304
|
const EMPTY_TREE = {
|
|
39322
40305
|
paths: [],
|
|
39323
|
-
truncated: false
|
|
40306
|
+
truncated: false,
|
|
40307
|
+
ignored: [],
|
|
40308
|
+
ignoredTruncated: false,
|
|
40309
|
+
children: NO_IGNORED_READS
|
|
39324
40310
|
};
|
|
39325
40311
|
/** The overlay with nothing on it — one instance, so an empty overlay never
|
|
39326
40312
|
* re-renders the tree that receives it. */
|
|
@@ -39346,7 +40332,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
39346
40332
|
for (const preferred of ["main", "master"]) if (branches.includes(preferred) && preferred !== head) return preferred;
|
|
39347
40333
|
return branches.find((branch) => branch !== head) ?? "";
|
|
39348
40334
|
}
|
|
39349
|
-
function GitWorkbenchPanel({ sessionId, useSessions, t, fetchStats, fetchFileDiff, fetchFileSides, writeChecked, fetchBlame, fetchFileImage, fetchWorktreeStatus, fetchSessionBinding, fetchCommitStats, fetchCommits, fetchAuthors, fetchRepoTree, fetchCompare, fetchStyle, saveStyle, fetchSync, runGitOp, fetchDiscardPlan }) {
|
|
40335
|
+
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
40336
|
const worktreePath = useSessions((state) => state?.byId?.[sessionId]?.cwd);
|
|
39351
40337
|
/** Whether the session's agent has a turn in flight — the store mirrors it
|
|
39352
40338
|
* live, so it is the signal for polling faster while there is something to
|
|
@@ -39367,10 +40353,10 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
39367
40353
|
const rememberPlace = (0, react.useCallback)((key, next) => {
|
|
39368
40354
|
setFilesPlaces((prev) => withPlace(prev, key, next));
|
|
39369
40355
|
}, []);
|
|
39370
|
-
const rememberTree = (0, react.useCallback)((key,
|
|
40356
|
+
const rememberTree = (0, react.useCallback)((key, update) => {
|
|
39371
40357
|
setFilesTrees((prev) => {
|
|
39372
40358
|
const map = new Map(prev);
|
|
39373
|
-
map.set(key,
|
|
40359
|
+
map.set(key, update(prev.get(key) ?? EMPTY_TREE));
|
|
39374
40360
|
return map;
|
|
39375
40361
|
});
|
|
39376
40362
|
}, []);
|
|
@@ -39443,6 +40429,10 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
39443
40429
|
* the row height it implies is published from.
|
|
39444
40430
|
*/
|
|
39445
40431
|
const [historyLayout, setHistoryLayout] = (0, react.useState)(() => readStored(STORE_HISTORY_LAYOUT, isHistoryLayout, DEFAULT_HISTORY_LAYOUT));
|
|
40432
|
+
/** Soft wrap. Default OFF, which is what the panes have always done: code is
|
|
40433
|
+
* written in columns, and wrapping it is a choice about one long file, not
|
|
40434
|
+
* a better default for every file. */
|
|
40435
|
+
const [wrap, setWrap] = (0, react.useState)(() => readStored(STORE_WRAP, (value) => typeof value === "boolean", false));
|
|
39446
40436
|
/** Per-project and global styling; both scopes, unresolved. */
|
|
39447
40437
|
const [style, setStyle] = (0, react.useState)(EMPTY_SETTINGS);
|
|
39448
40438
|
/** Whether dsh's resolved palette is currently dark. */
|
|
@@ -40113,6 +41103,21 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
40113
41103
|
setHistoryLayout(next);
|
|
40114
41104
|
writeStored(STORE_HISTORY_LAYOUT, next);
|
|
40115
41105
|
};
|
|
41106
|
+
/**
|
|
41107
|
+
* Turn soft wrap on or off, and remember it.
|
|
41108
|
+
*
|
|
41109
|
+
* A plain function, like every other handler below the two guards above:
|
|
41110
|
+
* those `return null`s are the reason nothing past this point may be a HOOK.
|
|
41111
|
+
* A `useCallback` here rendered fewer hooks than the previous pass on the
|
|
41112
|
+
* frame the first stats arrived, which React reports as error #310 and the
|
|
41113
|
+
* shell reports as "slot entry crashed" — the chip simply vanishes.
|
|
41114
|
+
*/
|
|
41115
|
+
const toggleWrap = () => {
|
|
41116
|
+
setWrap((prev) => {
|
|
41117
|
+
writeStored(STORE_WRAP, !prev);
|
|
41118
|
+
return !prev;
|
|
41119
|
+
});
|
|
41120
|
+
};
|
|
40116
41121
|
/** Tab switch. No direction refetches the working tree: `viewKey` already
|
|
40117
41122
|
* separates the tabs' per-file diff caches, so bumping `gen` here only cost a
|
|
40118
41123
|
* redundant round trip. */
|
|
@@ -40212,6 +41217,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
40212
41217
|
onHistoryLayout: applyHistoryLayout,
|
|
40213
41218
|
onClose: () => setOpen(false),
|
|
40214
41219
|
onRefresh: refresh,
|
|
41220
|
+
wrap,
|
|
41221
|
+
onToggleWrap: toggleWrap,
|
|
40215
41222
|
commitDraft,
|
|
40216
41223
|
onCommitDraft: setCommitDraft,
|
|
40217
41224
|
commitAmend,
|
|
@@ -40229,6 +41236,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
40229
41236
|
writeChecked,
|
|
40230
41237
|
fetchBlame,
|
|
40231
41238
|
fetchFileImage,
|
|
41239
|
+
fetchIgnoredDir,
|
|
40232
41240
|
viewKey,
|
|
40233
41241
|
gen,
|
|
40234
41242
|
collapsed,
|
|
@@ -40290,7 +41298,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
40290
41298
|
]
|
|
40291
41299
|
});
|
|
40292
41300
|
}
|
|
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 }) {
|
|
41301
|
+
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
41302
|
const body = shown ?? EMPTY_STATS;
|
|
40295
41303
|
/** The file list with ticks still awaiting git laid over them. The tree and
|
|
40296
41304
|
* the commit box read this, so a click moves its box and the "N ticked"
|
|
@@ -40315,8 +41323,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
40315
41323
|
const rememberPlaceHere = (0, react.useCallback)((next) => {
|
|
40316
41324
|
onFilesPlace(filesKey, next);
|
|
40317
41325
|
}, [onFilesPlace, filesKey]);
|
|
40318
|
-
const rememberTreeHere = (0, react.useCallback)((
|
|
40319
|
-
onFilesTree(filesKey,
|
|
41326
|
+
const rememberTreeHere = (0, react.useCallback)((update) => {
|
|
41327
|
+
onFilesTree(filesKey, update);
|
|
40320
41328
|
}, [onFilesTree, filesKey]);
|
|
40321
41329
|
const browsablePaths = (0, react.useMemo)(() => stats.files.filter((file) => file.status !== "deleted").map((file) => file.path), [stats.files]);
|
|
40322
41330
|
const active = preferredFile(body.files, activeFilterPaths, selected);
|
|
@@ -40683,6 +41691,15 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
40683
41691
|
onClick: onToggleMaximized,
|
|
40684
41692
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChromeGlyph, { of: maximized ? "restore" : "maximize" })
|
|
40685
41693
|
}),
|
|
41694
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
41695
|
+
type: "button",
|
|
41696
|
+
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}`,
|
|
41697
|
+
"aria-pressed": wrap,
|
|
41698
|
+
"aria-label": wrap ? t("wrapLinesOff") : t("wrapLines"),
|
|
41699
|
+
title: wrap ? t("wrapLinesOff") : t("wrapLines"),
|
|
41700
|
+
onClick: onToggleWrap,
|
|
41701
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChromeGlyph, { of: "wrap" })
|
|
41702
|
+
}),
|
|
40686
41703
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
40687
41704
|
type: "button",
|
|
40688
41705
|
className: `${GitWorkbenchPanel_module_css_default.btn} ${GitWorkbenchPanel_module_css_default.btnIcon}`,
|
|
@@ -40841,7 +41858,9 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
40841
41858
|
onPlace: rememberPlaceHere,
|
|
40842
41859
|
cached: filesTrees.get(filesKey) ?? EMPTY_TREE,
|
|
40843
41860
|
onTree: rememberTreeHere,
|
|
41861
|
+
wrap,
|
|
40844
41862
|
fetchRepoTree,
|
|
41863
|
+
fetchIgnoredDir,
|
|
40845
41864
|
fetchFileSides,
|
|
40846
41865
|
writeChecked,
|
|
40847
41866
|
fetchBlame,
|
|
@@ -40913,6 +41932,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
40913
41932
|
t,
|
|
40914
41933
|
path: active,
|
|
40915
41934
|
palette: theme,
|
|
41935
|
+
wrap,
|
|
40916
41936
|
statsPath,
|
|
40917
41937
|
fetchSides: fetchFileSides,
|
|
40918
41938
|
writeChecked,
|
|
@@ -40930,7 +41950,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
40930
41950
|
segment,
|
|
40931
41951
|
path: active ?? "",
|
|
40932
41952
|
palette: theme,
|
|
40933
|
-
t
|
|
41953
|
+
t,
|
|
41954
|
+
wrap
|
|
40934
41955
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
40935
41956
|
className: GitWorkbenchPanel_module_css_default.empty,
|
|
40936
41957
|
children: t("noTextDiff")
|
|
@@ -40998,6 +42019,11 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
40998
42019
|
tabFiles: "文件",
|
|
40999
42020
|
fileSearchPlaceholder: "搜索文件…",
|
|
41000
42021
|
filesTruncated: "文件太多,列表已截断;用搜索找剩下的。",
|
|
42022
|
+
filesIgnored: "已被 gitignore",
|
|
42023
|
+
wrapLines: "自动换行",
|
|
42024
|
+
wrapLinesOff: "取消自动换行",
|
|
42025
|
+
filesIgnoredCut: "这个目录条目太多,已截断;搜索找不到没列出的部分。",
|
|
42026
|
+
filesIgnoredFailed: "无法列出被忽略的文件。",
|
|
41001
42027
|
filesEmpty: "这个仓库还没有文件",
|
|
41002
42028
|
filesNoMatch: "没有匹配的文件",
|
|
41003
42029
|
filesMore: "还有 {count} 个,用上面的搜索找",
|
|
@@ -41212,6 +42238,11 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
41212
42238
|
tabFiles: "Files",
|
|
41213
42239
|
fileSearchPlaceholder: "Search files…",
|
|
41214
42240
|
filesTruncated: "Too many files to list; use the search for the rest.",
|
|
42241
|
+
filesIgnored: "Ignored (gitignore)",
|
|
42242
|
+
wrapLines: "Wrap long lines",
|
|
42243
|
+
wrapLinesOff: "Stop wrapping lines",
|
|
42244
|
+
filesIgnoredCut: "This directory has too many entries; the list is cut, and the search cannot reach the rest.",
|
|
42245
|
+
filesIgnoredFailed: "Could not list the ignored files.",
|
|
41215
42246
|
filesEmpty: "This repository has no files yet",
|
|
41216
42247
|
filesNoMatch: "No matching files",
|
|
41217
42248
|
filesMore: "and {count} more — use the search above",
|
|
@@ -41516,6 +42547,17 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
41516
42547
|
const result = await connection.rpc.call("/api", "gitWorkbench/repoTree", { args: { worktreePath: worktreePath ?? "" } }, signal);
|
|
41517
42548
|
return result.ok ? result.value : null;
|
|
41518
42549
|
},
|
|
42550
|
+
fetchIgnoredDir: async (worktreePath, dir, signal) => {
|
|
42551
|
+
try {
|
|
42552
|
+
const result = await connection.rpc.call("/api", "gitWorkbench/ignoredDir", { args: {
|
|
42553
|
+
worktreePath: worktreePath ?? "",
|
|
42554
|
+
dir
|
|
42555
|
+
} }, signal);
|
|
42556
|
+
return result.ok ? result.value : null;
|
|
42557
|
+
} catch {
|
|
42558
|
+
return null;
|
|
42559
|
+
}
|
|
42560
|
+
},
|
|
41519
42561
|
fetchCompare: async (worktreePath, base, head, signal) => {
|
|
41520
42562
|
const result = await connection.rpc.call("/api", "gitWorkbench/compareRefs", { args: {
|
|
41521
42563
|
worktreePath: worktreePath ?? "",
|