dsh-diff-approval 0.11.0 → 0.12.0

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/lib/client.js CHANGED
@@ -712,6 +712,111 @@ window.__ModuleLoader__.load({
712
712
  return (text.endsWith("\n") ? text.slice(0, -1) : text).split("\n");
713
713
  }
714
714
  //#endregion
715
+ //#region lib/types/client/split-diff.js
716
+ /**
717
+ * Side-by-side (split) diff model: the unified whole-file diff rows are
718
+ * regrouped into line-aligned pairs for a two-column "before | current" view.
719
+ * Pure derivation; the view owns rendering. A context row becomes a pair with
720
+ * both sides, a deletion a left-only pair, an addition a right-only pair, and
721
+ * an adjacent deletion/addition run is paired line-by-line into a single
722
+ * replacement pair so the two columns line up.
723
+ * @module dsh-diff-approval/client/split-diff
724
+ */
725
+ /** One whole-file diff row → its visible left side text. */
726
+ function leftSideOf(row) {
727
+ if (row.kind === "add") return void 0;
728
+ return {
729
+ text: row.text,
730
+ line: row.oldLine
731
+ };
732
+ }
733
+ /** One whole-file diff row → its visible right side text. */
734
+ function rightSideOf(row) {
735
+ if (row.kind === "del") return void 0;
736
+ return {
737
+ text: row.text,
738
+ line: row.newLine
739
+ };
740
+ }
741
+ /**
742
+ * Regroup the whole-file rows into aligned split pairs, pairing a deletion run
743
+ * with a following addition run line-by-line (so a replaced line is one pair),
744
+ * and leaving a stray deletion or addition as a one-sided pair.
745
+ * @param rows - the whole-file diff rows.
746
+ * @returns the split pairs plus the row→pair index map.
747
+ */
748
+ function computeSideBySideDiff(rows) {
749
+ const pairs = [];
750
+ const pairOfRow = /* @__PURE__ */ new Map();
751
+ const pendingDel = [];
752
+ const push = (pair, rows) => {
753
+ const index = pairs.length;
754
+ pairs.push(pair);
755
+ for (const r of rows) pairOfRow.set(r, index);
756
+ };
757
+ const flushPending = () => {
758
+ for (const { index, row } of pendingDel) push({
759
+ kind: "del",
760
+ left: leftSideOf(row),
761
+ right: void 0
762
+ }, [index]);
763
+ pendingDel.length = 0;
764
+ };
765
+ for (let i = 0; i < rows.length; i++) {
766
+ const row = rows[i];
767
+ if (row.kind === "context") {
768
+ flushPending();
769
+ push({
770
+ kind: "context",
771
+ left: leftSideOf(row),
772
+ right: rightSideOf(row)
773
+ }, [i]);
774
+ } else if (row.kind === "del") pendingDel.push({
775
+ index: i,
776
+ row
777
+ });
778
+ else {
779
+ const del = pendingDel.shift();
780
+ if (del !== void 0) push({
781
+ kind: "replace",
782
+ left: leftSideOf(del.row),
783
+ right: rightSideOf(row)
784
+ }, [del.index, i]);
785
+ else push({
786
+ kind: "add",
787
+ left: void 0,
788
+ right: rightSideOf(row)
789
+ }, [i]);
790
+ }
791
+ }
792
+ flushPending();
793
+ return {
794
+ pairs,
795
+ pairOfRow
796
+ };
797
+ }
798
+ /**
799
+ * Pair indices whose left or right text contains the query (case-insensitive).
800
+ * A pair counts once however many times the query appears, so split search
801
+ * highlights the whole pair on both columns and a single "current" pair is
802
+ * stepped through — not each individual left/right occurrence.
803
+ * @param pairs - the split pairs.
804
+ * @param query - the query text; an empty query matches nothing.
805
+ * @returns matching pair indices, in file order.
806
+ */
807
+ function searchPairs(pairs, query) {
808
+ if (query === "") return [];
809
+ const lower = query.toLowerCase();
810
+ const matches = [];
811
+ for (let index = 0; index < pairs.length; index++) {
812
+ const p = pairs[index];
813
+ if (p === void 0) continue;
814
+ if (p.left !== void 0 && p.left.text.toLowerCase().includes(lower)) matches.push(index);
815
+ else if (p.right !== void 0 && p.right.text.toLowerCase().includes(lower)) matches.push(index);
816
+ }
817
+ return matches;
818
+ }
819
+ //#endregion
715
820
  //#region node_modules/.pnpm/@shikijs+types@4.4.3/node_modules/@shikijs/types/dist/index.mjs
716
821
  var ShikiError = class extends Error {
717
822
  constructor(message) {
@@ -11631,6 +11736,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
11631
11736
  const PASTE_ON_COPY_KEY = "diff-approval:paste-on-copy";
11632
11737
  const IMPORT_UNTRACKED_KEY = "diff-approval:import-untracked";
11633
11738
  const TAB_WIDTH_KEY = "diff-approval:tab-size";
11739
+ const SPLIT_MODE_KEY = "diff-approval:split-mode";
11634
11740
  const WRAP_PREFIX = "diff-approval:wrap:";
11635
11741
  /**
11636
11742
  * Whether copying a reference should also paste it into the chat input and
@@ -11686,9 +11792,22 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
11686
11792
  function setTabWidth(value) {
11687
11793
  localStorage.setItem(TAB_WIDTH_KEY, String(value));
11688
11794
  }
11795
+ /**
11796
+ * Whether the whole-file diff view uses the two-column (side-by-side) layout.
11797
+ * Default off (single column): the unified diff. Only an explicit `'1'` enables
11798
+ * split mode.
11799
+ * @returns whether the split (two-column) diff view is used.
11800
+ */
11801
+ function splitMode() {
11802
+ return localStorage.getItem(SPLIT_MODE_KEY) === "1";
11803
+ }
11804
+ /** Persist the split-view preference. */
11805
+ function setSplitMode(value) {
11806
+ localStorage.setItem(SPLIT_MODE_KEY, value ? "1" : "0");
11807
+ }
11689
11808
  //#endregion
11690
11809
  //#region \0dsh-css:/home/runner/work/dsh-diff-approval/dsh-diff-approval/src/client/PendingPanel.module.css.mjs
11691
- const css = ".F1KBNa_layer{box-sizing:border-box;flex:none;align-items:center;width:calc(100% + 4px);height:42px;margin:4px -2px;display:flex;position:relative}.F1KBNa_footerButtons{align-items:center;width:100%;display:flex}.F1KBNa_badge{box-sizing:border-box;width:100%;height:42px;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border:none;border-radius:12px;align-items:center;gap:8px;padding:0 10px 0 8px;font-family:inherit;font-size:14px;line-height:22px;display:flex;overflow:hidden}.F1KBNa_badge:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_badge[data-active]{background:var(--dsw-alias-interactive-bg-hover-solid)}.F1KBNa_badge:disabled{color:var(--dsw-alias-label-tertiary);cursor:default;background:0 0}.F1KBNa_badgeLabel{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.F1KBNa_badgeCount{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;flex:none;margin-left:auto;font-size:12px;line-height:16px}.F1KBNa_layer.F1KBNa_rail{width:36px;height:36px;margin:8px 0 10px}.F1KBNa_rail .F1KBNa_badge{border-radius:50%;justify-content:center;gap:0;width:36px;height:36px;padding:0}.F1KBNa_rail .F1KBNa_badgeLabel{display:none}.F1KBNa_rail .F1KBNa_badgeCount{box-sizing:border-box;background:var(--dsw-alias-state-business-primary);min-width:18px;height:18px;color:var(--dsw-alias-label-primary-foreground);font-variant-numeric:tabular-nums;border-radius:9px;justify-content:center;align-items:center;padding:0 4px;font-size:11px;line-height:18px;display:flex;position:absolute;top:-3px;right:-7px}.F1KBNa_fullscreenBackdrop{z-index:29;background:var(--dsw-specific-sidebar-fill);position:fixed;inset:0}.F1KBNa_panel{z-index:30;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);width:auto;max-width:none;box-shadow:var(--dsw-shadow-lv2);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);border-radius:12px;flex-direction:column;display:flex;position:fixed;inset:8px 8px 128px;overflow:hidden}.F1KBNa_header{box-sizing:border-box;border-bottom:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);flex:none;justify-content:space-between;align-items:center;min-height:44px;padding:10px 12px;display:flex}.F1KBNa_headerActions{align-items:center;gap:2px;display:flex}.F1KBNa_settingsPage{padding:8px 12px}.F1KBNa_settingsRow{border-bottom:1px solid var(--dsw-alias-border-l2);align-items:center;gap:8px;padding:16px 0;display:flex}.F1KBNa_settingsRowText{flex-direction:column;flex:1;gap:4px;min-width:0;padding-right:48px;display:flex}.F1KBNa_settingsRowTitle{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:400;line-height:22px}.F1KBNa_settingsRowDesc{color:var(--dsw-alias-label-tertiary);font-size:12px;font-weight:400;line-height:18px}.F1KBNa_settingsSelector{background:var(--dsw-alias-bg-module-platform);height:36px;font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;border:none;border-radius:18px;align-items:center;gap:12px;padding:0 14px;font-size:14px;line-height:22px;display:inline-flex}.F1KBNa_settingsSelector:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_settingsSelectorChevron{flex:none}.F1KBNa_states{flex-direction:column;flex:1;min-height:0;padding:4px 12px 12px;display:flex;overflow-y:auto}.F1KBNa_split{flex:1;align-items:stretch;min-height:0;display:flex;position:relative}.F1KBNa_fileListFloat{z-index:40;box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);box-shadow:var(--dsw-shadow-lv2);border-radius:12px;flex-direction:column;padding:6px 8px 10px;display:flex;position:absolute;overflow:hidden}.F1KBNa_fileList{box-sizing:border-box;border-right:1px solid var(--dsw-alias-border-l2);flex-direction:column;flex:none;width:240px;min-height:0;padding:4px 8px 12px;display:flex}.F1KBNa_listScroll{flex:1;min-height:0;overflow-y:auto}.F1KBNa_bulkActions{flex:none;gap:6px;padding-top:8px;display:flex}.F1KBNa_bulkActions .F1KBNa_action{text-align:center;flex:1}.F1KBNa_resizeHandle{cursor:col-resize;background:0 0;flex:none;width:5px;margin:0 -2px}.F1KBNa_resizeHandle:hover{background:var(--dsw-alias-border-l2)}.F1KBNa_detail{flex-direction:column;flex:1;min-width:0;min-height:0;display:flex}.F1KBNa_detailEmpty{color:var(--dsw-alias-label-tertiary);text-align:center;flex:1;justify-content:center;align-items:center;margin:0;padding:24px;font-size:12px;line-height:18px;display:flex}.F1KBNa_title{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:500;line-height:20px}.F1KBNa_note,.F1KBNa_readError,.F1KBNa_hint{color:var(--dsw-alias-label-tertiary);margin:4px 0;font-size:12px;line-height:18px}.F1KBNa_noteCentered{text-align:center;margin:auto}.F1KBNa_emptyState{flex-direction:column;align-items:center;gap:10px;margin:auto;display:flex}.F1KBNa_importButton{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:8px;padding:5px 14px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_importButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_importButton:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.F1KBNa_importNote{color:var(--dsw-alias-label-tertiary);text-align:center;margin:0;font-size:12px;line-height:18px}.F1KBNa_readError{color:var(--dsw-alias-state-error-primary)}.F1KBNa_group{color:var(--dsw-alias-label-tertiary);margin:8px 0 4px;font-size:12px;font-weight:500;line-height:16px}.F1KBNa_rows{margin:0;padding:0;list-style:none}.F1KBNa_row{border:1px solid #0000;border-radius:10px;margin:2px 0}.F1KBNa_rowHead{width:100%;color:var(--dsw-alias-label-primary);font:inherit;text-align:left;cursor:pointer;background:0 0;border:none;border-radius:10px;align-items:baseline;gap:8px;padding:6px 8px;display:flex}.F1KBNa_rowHead:hover{background:var(--dsw-alias-interactive-bg-hover-solid)}.F1KBNa_rowHead[data-selected]{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_rowPath{text-overflow:ellipsis;white-space:nowrap;min-width:0;font:var(--dsw-font-markdown-code-block);overflow:hidden}.F1KBNa_kindTag{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-tertiary);white-space:nowrap;border-radius:6px;flex:none;padding:1px 6px;font-size:11px;line-height:14px}.F1KBNa_kindHint{color:var(--dsw-alias-label-tertiary);flex:none;font-size:12px;line-height:16px}.F1KBNa_divergedHint,.F1KBNa_missingHint{border-bottom:1px solid var(--dsw-alias-border-l2);margin:0;padding:6px 8px;font-size:12px;line-height:18px}.F1KBNa_missing{border:1px solid var(--dsw-alias-state-warn-primary);color:var(--dsw-alias-state-warn-label,var(--dsw-alias-state-warn-primary));white-space:nowrap;border-radius:6px;flex:none;padding:1px 6px;font-size:11px;line-height:14px}.F1KBNa_rowFailed{border:1px solid var(--dsw-alias-state-error-primary);color:var(--dsw-alias-state-error-primary);white-space:nowrap;border-radius:6px;flex:none;padding:1px 6px;font-size:11px;line-height:14px}.F1KBNa_actionError{border-bottom:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-state-error-primary);overflow-wrap:anywhere;margin:0;padding:6px 8px;font-size:12px;line-height:18px}.F1KBNa_missingHint{color:var(--dsw-alias-state-warn-label,var(--dsw-alias-state-warn-primary))}.F1KBNa_rowMeta{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;flex:none;gap:6px;margin-left:auto;font-size:12px;line-height:16px;display:inline-flex}.F1KBNa_addCount{color:color-mix(in srgb, var(--dsw-alias-state-success-primary) 60%, var(--dsw-alias-label-primary))}.F1KBNa_delCount{color:color-mix(in srgb, var(--dsw-alias-state-error-primary) 60%, var(--dsw-alias-label-primary))}.F1KBNa_diff{background:var(--dsw-alias-markdown-code-block);flex-direction:column;flex:1;min-height:0;display:flex;position:relative;overflow:hidden}.F1KBNa_diffHeader{border-bottom:1px solid var(--dsw-alias-border-l2);align-items:center;gap:8px;padding:6px 8px;display:flex}.F1KBNa_diffPath{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-primary);font:var(--dsw-font-markdown-code-block);flex:1;font-size:12px;line-height:18px;overflow:hidden}.F1KBNa_diffActions{border-bottom:1px solid var(--dsw-alias-border-l2);align-items:center;gap:8px;padding:6px 8px;display:flex}.F1KBNa_diffStats{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;font-size:12px;line-height:16px}.F1KBNa_flexSpacer{flex:1}.F1KBNa_action{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:8px;padding:3px 12px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_action:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_action:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.F1KBNa_actionPrimary{background:var(--dsw-alias-state-business-primary);border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50)}.F1KBNa_actionPrimary:hover:not(:disabled){background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 85%, var(--dsw-static-neutral-bluish-1000))}.F1KBNa_actionPrimary:disabled{background:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50);opacity:.55}.F1KBNa_actionQuietDisabled:disabled{cursor:pointer;color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-border-l1);background:0 0}.F1KBNa_actionPrimary.F1KBNa_actionQuietDisabled:disabled{background:var(--dsw-alias-state-business-primary);border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50);opacity:1}.F1KBNa_iconAction{justify-content:center;align-items:center;min-height:25px;padding:4px 6px;display:inline-flex}.F1KBNa_close{cursor:pointer;width:28px;height:28px;color:var(--dsw-alias-label-tertiary);background:0 0;border:none;border-radius:28px;justify-content:center;align-items:center;padding:0;display:inline-flex}.F1KBNa_close:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_expand{cursor:pointer;width:28px;height:28px;color:var(--dsw-alias-label-tertiary);background:0 0;border:none;border-radius:28px;justify-content:center;align-items:center;padding:0;display:inline-flex}.F1KBNa_expand:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_expandExpanded svg{transform:rotate(180deg)}.F1KBNa_diffBodyWrap{flex:1;min-height:0;display:flex;position:relative}.F1KBNa_diffBody{min-width:0;font:var(--dsw-font-markdown-code-block);cursor:text;outline:none;flex:1;padding:0;position:relative;overflow:auto}.F1KBNa_diffBody::-webkit-scrollbar,.F1KBNa_diffBody::-webkit-scrollbar-track,.F1KBNa_diffBody::-webkit-scrollbar-thumb{cursor:default}.F1KBNa_blockActions{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-markdown-code-block);box-shadow:var(--dsw-shadow-lv1);z-index:2;border-radius:10px;align-items:center;gap:9px;padding:5px;display:flex;position:absolute;right:8px}.F1KBNa_blockPosition{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;white-space:nowrap;margin-top:1px;margin-left:7px;font-size:12px;line-height:16px}.F1KBNa_searchBar{z-index:3;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-markdown-code-block);box-shadow:var(--dsw-shadow-lv1);border-radius:10px;align-items:center;gap:4px;padding:4px;display:flex;position:absolute;top:8px;right:8px}.F1KBNa_searchInput{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);width:150px;color:var(--dsw-alias-label-primary);border-radius:6px;outline:none;padding:3px 8px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_searchInput:focus{border-color:var(--dsw-alias-state-business-primary)}.F1KBNa_searchCount{text-align:center;min-width:34px;color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;white-space:nowrap;font-size:12px;line-height:16px}.F1KBNa_diffBody [data-diff-search=hit]{background-image:linear-gradient(#facc1529,#facc1529)}.F1KBNa_diffBody [data-diff-search=current]{background-image:linear-gradient(#facc1552,#facc1552)}.F1KBNa_blockFlash{z-index:1;box-sizing:border-box;border:2px solid var(--dsw-alias-state-business-primary);pointer-events:none;border-radius:4px;animation:1s ease-out forwards F1KBNa_diffFlash;position:absolute;left:0;right:0}@keyframes F1KBNa_diffFlash{0%{opacity:1}to{opacity:0}}.F1KBNa_overviewRuler{pointer-events:none;opacity:.5;width:4px;position:absolute;top:0;bottom:0;right:0}.F1KBNa_overviewMarker{border-radius:2px;width:100%;min-height:2px;position:absolute;right:0}.F1KBNa_markerDel{background-color:var(--dsw-alias-state-error-primary)}.F1KBNa_markerAdd{background-color:var(--dsw-alias-state-success-primary)}.F1KBNa_lines{border-spacing:0;width:max-content;min-width:100%;display:table}.F1KBNa_line{height:22px;line-height:22px;display:table-row}.F1KBNa_vSpacer{display:table-row}.F1KBNa_gutter{box-sizing:border-box;text-align:right;width:44px;color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;user-select:none;cursor:default;padding-right:10px;display:table-cell}.F1KBNa_code{white-space:pre;display:table-cell}.F1KBNa_context{color:var(--dsw-alias-label-primary)}.F1KBNa_del{background-color:color-mix(in srgb, var(--dsw-alias-state-error-primary) 12%, transparent)}.F1KBNa_add{background-color:color-mix(in srgb, var(--dsw-alias-state-success-primary) 10%, transparent)}.F1KBNa_statusBar{box-sizing:border-box;border-top:1px solid var(--dsw-alias-border-l2);height:34px;color:var(--dsw-alias-label-tertiary);font-family:var(--dsw-font-markdown-code-block);font-variant-numeric:tabular-nums;flex:none;align-items:center;gap:8px;padding:0 8px;font-size:12px;line-height:18px;display:flex}.F1KBNa_statusAction{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);white-space:nowrap;cursor:pointer;background:0 0;border-radius:8px;padding:3px 12px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_statusAction:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_langSelect{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:8px;flex:none;align-items:center;gap:4px;padding:3px 12px;font-family:inherit;font-size:12px;line-height:18px;display:inline-flex}.F1KBNa_langSelect:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_langLabel{text-overflow:ellipsis;white-space:nowrap;max-width:140px;overflow:hidden}.F1KBNa_notice{z-index:60;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);max-width:360px;box-shadow:var(--dsw-shadow-lv3);border-radius:10px;align-items:flex-start;gap:12px;padding:12px 14px;display:flex;position:fixed;bottom:24px;right:24px}.F1KBNa_noticeText{font:var(--dsw-font-caption);color:var(--dsw-alias-label-primary);flex:1;margin:0;line-height:1.45}.F1KBNa_noticeButton{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);font:var(--dsw-font-caption);cursor:pointer;border-radius:6px;flex:none;padding:4px 10px}.F1KBNa_noticeButton:hover{background:var(--dsw-alias-interactive-bg-hover-solid)}.F1KBNa_wrap .F1KBNa_line{height:auto;min-height:22px}.F1KBNa_subline{white-space:pre;height:22px;line-height:22px;display:block;overflow:hidden}.F1KBNa_wrapActive{background:var(--dsw-alias-state-business-primary);border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50)}.F1KBNa_wrapActive:hover{background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 85%, var(--dsw-static-neutral-bluish-1000))}";
11810
+ const css = ".F1KBNa_layer{box-sizing:border-box;flex:none;align-items:center;width:calc(100% + 4px);height:42px;margin:4px -2px;display:flex;position:relative}.F1KBNa_footerButtons{align-items:center;width:100%;display:flex}.F1KBNa_badge{box-sizing:border-box;width:100%;height:42px;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border:none;border-radius:12px;align-items:center;gap:8px;padding:0 10px 0 8px;font-family:inherit;font-size:14px;line-height:22px;display:flex;overflow:hidden}.F1KBNa_badge:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_badge[data-active]{background:var(--dsw-alias-interactive-bg-hover-solid)}.F1KBNa_badge:disabled{color:var(--dsw-alias-label-tertiary);cursor:default;background:0 0}.F1KBNa_badgeLabel{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.F1KBNa_badgeCount{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;flex:none;margin-left:auto;font-size:12px;line-height:16px}.F1KBNa_layer.F1KBNa_rail{width:36px;height:36px;margin:8px 0 10px}.F1KBNa_rail .F1KBNa_badge{border-radius:50%;justify-content:center;gap:0;width:36px;height:36px;padding:0}.F1KBNa_rail .F1KBNa_badgeLabel{display:none}.F1KBNa_rail .F1KBNa_badgeCount{box-sizing:border-box;background:var(--dsw-alias-state-business-primary);min-width:18px;height:18px;color:var(--dsw-alias-label-primary-foreground);font-variant-numeric:tabular-nums;border-radius:9px;justify-content:center;align-items:center;padding:0 4px;font-size:11px;line-height:18px;display:flex;position:absolute;top:-3px;right:-7px}.F1KBNa_fullscreenBackdrop{z-index:29;background:var(--dsw-specific-sidebar-fill);position:fixed;inset:0}.F1KBNa_panel{z-index:30;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);width:auto;max-width:none;box-shadow:var(--dsw-shadow-lv2);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);border-radius:12px;flex-direction:column;display:flex;position:fixed;inset:8px 8px 128px;overflow:hidden}.F1KBNa_header{box-sizing:border-box;border-bottom:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);flex:none;justify-content:space-between;align-items:center;min-height:44px;padding:10px 12px;display:flex}.F1KBNa_headerActions{align-items:center;gap:2px;display:flex}.F1KBNa_settingsPage{padding:8px 12px}.F1KBNa_settingsRow{border-bottom:1px solid var(--dsw-alias-border-l2);align-items:center;gap:8px;padding:16px 0;display:flex}.F1KBNa_settingsRowText{flex-direction:column;flex:1;gap:4px;min-width:0;padding-right:48px;display:flex}.F1KBNa_settingsRowTitle{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:400;line-height:22px}.F1KBNa_settingsRowDesc{color:var(--dsw-alias-label-tertiary);font-size:12px;font-weight:400;line-height:18px}.F1KBNa_settingsSelector{background:var(--dsw-alias-bg-module-platform);height:36px;font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;border:none;border-radius:18px;align-items:center;gap:12px;padding:0 14px;font-size:14px;line-height:22px;display:inline-flex}.F1KBNa_settingsSelector:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_settingsSelectorChevron{flex:none}.F1KBNa_states{flex-direction:column;flex:1;min-height:0;padding:4px 12px 12px;display:flex;overflow-y:auto}.F1KBNa_split{flex:1;align-items:stretch;min-height:0;display:flex;position:relative}.F1KBNa_fileListFloat{z-index:40;box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);box-shadow:var(--dsw-shadow-lv2);border-radius:12px;flex-direction:column;padding:6px 8px 10px;display:flex;position:absolute;overflow:hidden}.F1KBNa_fileList{box-sizing:border-box;border-right:1px solid var(--dsw-alias-border-l2);flex-direction:column;flex:none;width:240px;min-height:0;padding:4px 8px 12px;display:flex}.F1KBNa_listScroll{flex:1;min-height:0;overflow-y:auto}.F1KBNa_bulkActions{flex:none;gap:6px;padding-top:8px;display:flex}.F1KBNa_bulkActions .F1KBNa_action{text-align:center;flex:1}.F1KBNa_resizeHandle{cursor:col-resize;background:0 0;flex:none;width:5px;margin:0 -2px}.F1KBNa_resizeHandle:hover{background:var(--dsw-alias-border-l2)}.F1KBNa_detail{flex-direction:column;flex:1;min-width:0;min-height:0;display:flex}.F1KBNa_detailEmpty{color:var(--dsw-alias-label-tertiary);text-align:center;flex:1;justify-content:center;align-items:center;margin:0;padding:24px;font-size:12px;line-height:18px;display:flex}.F1KBNa_title{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:500;line-height:20px}.F1KBNa_note,.F1KBNa_readError,.F1KBNa_hint{color:var(--dsw-alias-label-tertiary);margin:4px 0;font-size:12px;line-height:18px}.F1KBNa_noteCentered{text-align:center;margin:auto}.F1KBNa_emptyState{flex-direction:column;align-items:center;gap:10px;margin:auto;display:flex}.F1KBNa_importButton{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:8px;padding:5px 14px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_importButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_importButton:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.F1KBNa_importNote{color:var(--dsw-alias-label-tertiary);text-align:center;margin:0;font-size:12px;line-height:18px}.F1KBNa_readError{color:var(--dsw-alias-state-error-primary)}.F1KBNa_group{color:var(--dsw-alias-label-tertiary);margin:8px 0 4px;font-size:12px;font-weight:500;line-height:16px}.F1KBNa_rows{margin:0;padding:0;list-style:none}.F1KBNa_row{border:1px solid #0000;border-radius:10px;margin:2px 0}.F1KBNa_rowHead{width:100%;color:var(--dsw-alias-label-primary);font:inherit;text-align:left;cursor:pointer;background:0 0;border:none;border-radius:10px;align-items:baseline;gap:8px;padding:6px 8px;display:flex}.F1KBNa_rowHead:hover{background:var(--dsw-alias-interactive-bg-hover-solid)}.F1KBNa_rowHead[data-selected]{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_rowPath{text-overflow:ellipsis;white-space:nowrap;min-width:0;font:var(--dsw-font-markdown-code-block);overflow:hidden}.F1KBNa_kindTag{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-tertiary);white-space:nowrap;border-radius:6px;flex:none;padding:1px 6px;font-size:11px;line-height:14px}.F1KBNa_kindHint{color:var(--dsw-alias-label-tertiary);flex:none;font-size:12px;line-height:16px}.F1KBNa_divergedHint,.F1KBNa_missingHint{border-bottom:1px solid var(--dsw-alias-border-l2);margin:0;padding:6px 8px;font-size:12px;line-height:18px}.F1KBNa_missing{border:1px solid var(--dsw-alias-state-warn-primary);color:var(--dsw-alias-state-warn-label,var(--dsw-alias-state-warn-primary));white-space:nowrap;border-radius:6px;flex:none;padding:1px 6px;font-size:11px;line-height:14px}.F1KBNa_rowFailed{border:1px solid var(--dsw-alias-state-error-primary);color:var(--dsw-alias-state-error-primary);white-space:nowrap;border-radius:6px;flex:none;padding:1px 6px;font-size:11px;line-height:14px}.F1KBNa_actionError{border-bottom:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-state-error-primary);overflow-wrap:anywhere;margin:0;padding:6px 8px;font-size:12px;line-height:18px}.F1KBNa_missingHint{color:var(--dsw-alias-state-warn-label,var(--dsw-alias-state-warn-primary))}.F1KBNa_rowMeta{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;flex:none;gap:6px;margin-left:auto;font-size:12px;line-height:16px;display:inline-flex}.F1KBNa_addCount{color:color-mix(in srgb, var(--dsw-alias-state-success-primary) 60%, var(--dsw-alias-label-primary))}.F1KBNa_delCount{color:color-mix(in srgb, var(--dsw-alias-state-error-primary) 60%, var(--dsw-alias-label-primary))}.F1KBNa_diff{background:var(--dsw-alias-markdown-code-block);flex-direction:column;flex:1;min-height:0;display:flex;position:relative;overflow:hidden}.F1KBNa_diffHeader{border-bottom:1px solid var(--dsw-alias-border-l2);align-items:center;gap:8px;padding:6px 8px;display:flex}.F1KBNa_diffPath{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-primary);font:var(--dsw-font-markdown-code-block);flex:1;font-size:12px;line-height:18px;overflow:hidden}.F1KBNa_diffActions{border-bottom:1px solid var(--dsw-alias-border-l2);align-items:center;gap:8px;padding:6px 8px;display:flex}.F1KBNa_diffStats{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;font-size:12px;line-height:16px}.F1KBNa_flexSpacer{flex:1}.F1KBNa_action{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:8px;padding:3px 12px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_action:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_action:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.F1KBNa_actionPrimary{background:var(--dsw-alias-state-business-primary);border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50)}.F1KBNa_actionPrimary:hover:not(:disabled){background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 85%, var(--dsw-static-neutral-bluish-1000))}.F1KBNa_actionPrimary:disabled{background:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50);opacity:.55}.F1KBNa_actionQuietDisabled:disabled{cursor:pointer;color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-border-l1);background:0 0}.F1KBNa_actionPrimary.F1KBNa_actionQuietDisabled:disabled{background:var(--dsw-alias-state-business-primary);border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50);opacity:1}.F1KBNa_iconAction{justify-content:center;align-items:center;min-height:25px;padding:4px 6px;display:inline-flex}.F1KBNa_close{cursor:pointer;width:28px;height:28px;color:var(--dsw-alias-label-tertiary);background:0 0;border:none;border-radius:28px;justify-content:center;align-items:center;padding:0;display:inline-flex}.F1KBNa_close:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_expand{cursor:pointer;width:28px;height:28px;color:var(--dsw-alias-label-tertiary);background:0 0;border:none;border-radius:28px;justify-content:center;align-items:center;padding:0;display:inline-flex}.F1KBNa_expand:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_expandExpanded svg{transform:rotate(180deg)}.F1KBNa_diffBodyWrap{flex:1;min-height:0;display:flex;position:relative}.F1KBNa_diffBody{min-width:0;font:var(--dsw-font-markdown-code-block);cursor:text;outline:none;flex:1;padding:0;position:relative;overflow:auto}.F1KBNa_diffBody::-webkit-scrollbar,.F1KBNa_diffBody::-webkit-scrollbar-track,.F1KBNa_diffBody::-webkit-scrollbar-thumb{cursor:default}.F1KBNa_blockActions{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-markdown-code-block);box-shadow:var(--dsw-shadow-lv1);z-index:2;border-radius:10px;align-items:center;gap:9px;padding:5px;display:flex;position:absolute;right:8px}.F1KBNa_blockPosition{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;white-space:nowrap;margin-top:1px;margin-left:7px;font-size:12px;line-height:16px}.F1KBNa_searchBar{z-index:3;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-markdown-code-block);box-shadow:var(--dsw-shadow-lv1);border-radius:10px;align-items:center;gap:4px;padding:4px;display:flex;position:absolute;top:8px;right:8px}.F1KBNa_searchInput{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);width:150px;color:var(--dsw-alias-label-primary);border-radius:6px;outline:none;padding:3px 8px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_searchInput:focus{border-color:var(--dsw-alias-state-business-primary)}.F1KBNa_searchCount{text-align:center;min-width:34px;color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;white-space:nowrap;font-size:12px;line-height:16px}.F1KBNa_diffBody [data-diff-search=hit]{background-image:linear-gradient(#facc1529,#facc1529)}.F1KBNa_diffBody [data-diff-search=current]{background-image:linear-gradient(#facc1552,#facc1552)}.F1KBNa_blockFlash{z-index:1;box-sizing:border-box;border:2px solid var(--dsw-alias-state-business-primary);pointer-events:none;border-radius:4px;animation:1s ease-out forwards F1KBNa_diffFlash;position:absolute;left:0;right:0}@keyframes F1KBNa_diffFlash{0%{opacity:1}to{opacity:0}}.F1KBNa_overviewRuler{pointer-events:none;opacity:.5;width:4px;position:absolute;top:0;bottom:0;right:0}.F1KBNa_overviewMarker{border-radius:2px;width:100%;min-height:2px;position:absolute;right:0}.F1KBNa_markerDel{background-color:var(--dsw-alias-state-error-primary)}.F1KBNa_markerAdd{background-color:var(--dsw-alias-state-success-primary)}.F1KBNa_lines{border-spacing:0;width:max-content;min-width:100%;display:table}.F1KBNa_line{height:22px;line-height:22px;display:table-row}.F1KBNa_vSpacer{display:table-row}.F1KBNa_gutter{box-sizing:border-box;text-align:right;width:44px;color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;user-select:none;cursor:default;padding-right:10px;display:table-cell}.F1KBNa_code{white-space:pre;display:table-cell}.F1KBNa_context{color:var(--dsw-alias-label-primary)}.F1KBNa_del{background-color:color-mix(in srgb, var(--dsw-alias-state-error-primary) 12%, transparent)}.F1KBNa_add{background-color:color-mix(in srgb, var(--dsw-alias-state-success-primary) 10%, transparent)}.F1KBNa_statusBar{box-sizing:border-box;border-top:1px solid var(--dsw-alias-border-l2);height:34px;color:var(--dsw-alias-label-tertiary);font-family:var(--dsw-font-markdown-code-block);font-variant-numeric:tabular-nums;flex:none;align-items:center;gap:8px;padding:0 8px;font-size:12px;line-height:18px;display:flex}.F1KBNa_statusAction{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);white-space:nowrap;cursor:pointer;background:0 0;border-radius:8px;padding:3px 12px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_statusAction:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_langSelect{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:8px;flex:none;align-items:center;gap:4px;padding:3px 12px;font-family:inherit;font-size:12px;line-height:18px;display:inline-flex}.F1KBNa_langSelect:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_langLabel{text-overflow:ellipsis;white-space:nowrap;max-width:140px;overflow:hidden}.F1KBNa_notice{z-index:60;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);max-width:360px;box-shadow:var(--dsw-shadow-lv3);border-radius:10px;align-items:flex-start;gap:12px;padding:12px 14px;display:flex;position:fixed;bottom:24px;right:24px}.F1KBNa_noticeText{font:var(--dsw-font-caption);color:var(--dsw-alias-label-primary);flex:1;margin:0;line-height:1.45}.F1KBNa_noticeButton{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);font:var(--dsw-font-caption);cursor:pointer;border-radius:6px;flex:none;padding:4px 10px}.F1KBNa_noticeButton:hover{background:var(--dsw-alias-interactive-bg-hover-solid)}.F1KBNa_wrap .F1KBNa_line{height:auto;min-height:22px}.F1KBNa_subline{white-space:pre;height:22px;line-height:22px;display:block;overflow:hidden}.F1KBNa_wrapActive{background:var(--dsw-alias-state-business-primary);border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50)}.F1KBNa_wrapActive:hover{background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 85%, var(--dsw-static-neutral-bluish-1000))}.F1KBNa_splitRoot{flex-direction:column;flex:1;min-height:0;display:flex;position:relative}.F1KBNa_diffBodySplit{flex:1;min-height:0;overflow-x:hidden}.F1KBNa_splitCols{width:100%;min-width:0;display:flex}.F1KBNa_splitCol{box-sizing:border-box;flex:1 1 0;min-width:0;overflow:hidden}.F1KBNa_splitDivider{background:var(--dsw-alias-border-l2);flex:0 0 1px}.F1KBNa_splitCol .F1KBNa_gutter,.F1KBNa_splitCol .F1KBNa_code{vertical-align:top}.F1KBNa_splitHScrollRow{border-top:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);flex:none;width:100%;min-width:0;display:flex}.F1KBNa_splitHScroll{flex:1 1 0;min-width:0;height:15px;overflow:auto hidden}.F1KBNa_splitHScroll::-webkit-scrollbar{height:15px}.F1KBNa_splitHScroll::-webkit-scrollbar-track{cursor:default}.F1KBNa_splitHScroll::-webkit-scrollbar-thumb{cursor:default}.F1KBNa_splitHScrollFill{height:1px}.F1KBNa_splitLdel{background-color:color-mix(in srgb, var(--dsw-alias-state-error-primary) 12%, transparent)}.F1KBNa_splitLadd{background-color:color-mix(in srgb, var(--dsw-alias-state-success-primary) 10%, transparent)}.F1KBNa_splitRdel{background-color:color-mix(in srgb, var(--dsw-alias-state-error-primary) 12%, transparent)}.F1KBNa_splitRadd{background-color:color-mix(in srgb, var(--dsw-alias-state-success-primary) 10%, transparent)}";
11692
11811
  const tagId = "dsh-diff-approval/PendingPanel.module.css";
11693
11812
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
11694
11813
  const tag = document.createElement("style");
@@ -11698,99 +11817,111 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
11698
11817
  document.head.appendChild(tag);
11699
11818
  }
11700
11819
  var PendingPanel_module_css_default = {
11701
- "divergedHint": "F1KBNa_divergedHint",
11702
- "detail": "F1KBNa_detail",
11703
- "fullscreenBackdrop": "F1KBNa_fullscreenBackdrop",
11704
- "diffBody": "F1KBNa_diffBody",
11705
- "langSelect": "F1KBNa_langSelect",
11820
+ "layer": "F1KBNa_layer",
11821
+ "rowHead": "F1KBNa_rowHead",
11822
+ "header": "F1KBNa_header",
11823
+ "searchCount": "F1KBNa_searchCount",
11824
+ "splitRdel": "F1KBNa_splitRdel",
11825
+ "blockActions": "F1KBNa_blockActions",
11826
+ "badge": "F1KBNa_badge",
11827
+ "fileList": "F1KBNa_fileList",
11828
+ "badgeLabel": "F1KBNa_badgeLabel",
11829
+ "rows": "F1KBNa_rows",
11830
+ "settingsRowTitle": "F1KBNa_settingsRowTitle",
11831
+ "rail": "F1KBNa_rail",
11832
+ "settingsPage": "F1KBNa_settingsPage",
11833
+ "add": "F1KBNa_add",
11834
+ "splitCols": "F1KBNa_splitCols",
11835
+ "splitHScrollRow": "F1KBNa_splitHScrollRow",
11836
+ "splitHScroll": "F1KBNa_splitHScroll",
11837
+ "diffPath": "F1KBNa_diffPath",
11838
+ "settingsRowText": "F1KBNa_settingsRowText",
11839
+ "detailEmpty": "F1KBNa_detailEmpty",
11840
+ "action": "F1KBNa_action",
11841
+ "notice": "F1KBNa_notice",
11842
+ "splitHScrollFill": "F1KBNa_splitHScrollFill",
11843
+ "splitLdel": "F1KBNa_splitLdel",
11844
+ "diffBodySplit": "F1KBNa_diffBodySplit",
11845
+ "wrap": "F1KBNa_wrap",
11846
+ "row": "F1KBNa_row",
11847
+ "expand": "F1KBNa_expand",
11848
+ "blockFlash": "F1KBNa_blockFlash",
11849
+ "importButton": "F1KBNa_importButton",
11850
+ "del": "F1KBNa_del",
11851
+ "splitRoot": "F1KBNa_splitRoot",
11852
+ "states": "F1KBNa_states",
11706
11853
  "note": "F1KBNa_note",
11707
- "code": "F1KBNa_code",
11708
- "diffHeader": "F1KBNa_diffHeader",
11709
- "overviewRuler": "F1KBNa_overviewRuler",
11854
+ "panel": "F1KBNa_panel",
11855
+ "title": "F1KBNa_title",
11856
+ "settingsSelector": "F1KBNa_settingsSelector",
11857
+ "diffBodyWrap": "F1KBNa_diffBodyWrap",
11858
+ "diffBody": "F1KBNa_diffBody",
11710
11859
  "readError": "F1KBNa_readError",
11711
- "gutter": "F1KBNa_gutter",
11712
- "markerAdd": "F1KBNa_markerAdd",
11713
- "del": "F1KBNa_del",
11714
- "fileList": "F1KBNa_fileList",
11860
+ "bulkActions": "F1KBNa_bulkActions",
11715
11861
  "delCount": "F1KBNa_delCount",
11716
- "diffBodyWrap": "F1KBNa_diffBodyWrap",
11717
- "blockFlash": "F1KBNa_blockFlash",
11862
+ "addCount": "F1KBNa_addCount",
11863
+ "diffStats": "F1KBNa_diffStats",
11864
+ "close": "F1KBNa_close",
11865
+ "kindHint": "F1KBNa_kindHint",
11866
+ "blockPosition": "F1KBNa_blockPosition",
11867
+ "searchInput": "F1KBNa_searchInput",
11868
+ "overviewRuler": "F1KBNa_overviewRuler",
11869
+ "vSpacer": "F1KBNa_vSpacer",
11718
11870
  "context": "F1KBNa_context",
11719
- "fileListFloat": "F1KBNa_fileListFloat",
11720
- "diff": "F1KBNa_diff",
11871
+ "fullscreenBackdrop": "F1KBNa_fullscreenBackdrop",
11872
+ "gutter": "F1KBNa_gutter",
11873
+ "iconAction": "F1KBNa_iconAction",
11874
+ "statusBar": "F1KBNa_statusBar",
11875
+ "noticeText": "F1KBNa_noticeText",
11876
+ "wrapActive": "F1KBNa_wrapActive",
11877
+ "splitRadd": "F1KBNa_splitRadd",
11721
11878
  "rowMeta": "F1KBNa_rowMeta",
11722
- "panel": "F1KBNa_panel",
11723
- "title": "F1KBNa_title",
11724
- "expand": "F1KBNa_expand",
11725
- "lines": "F1KBNa_lines",
11726
- "missingHint": "F1KBNa_missingHint",
11879
+ "diffHeader": "F1KBNa_diffHeader",
11880
+ "footerButtons": "F1KBNa_footerButtons",
11727
11881
  "headerActions": "F1KBNa_headerActions",
11882
+ "actionQuietDisabled": "F1KBNa_actionQuietDisabled",
11883
+ "detail": "F1KBNa_detail",
11884
+ "missing": "F1KBNa_missing",
11885
+ "markerDel": "F1KBNa_markerDel",
11728
11886
  "settingsRowDesc": "F1KBNa_settingsRowDesc",
11729
- "close": "F1KBNa_close",
11730
- "iconAction": "F1KBNa_iconAction",
11731
- "rail": "F1KBNa_rail",
11732
- "wrap": "F1KBNa_wrap",
11733
- "diffPath": "F1KBNa_diffPath",
11887
+ "langSelect": "F1KBNa_langSelect",
11734
11888
  "importNote": "F1KBNa_importNote",
11735
- "missing": "F1KBNa_missing",
11736
- "footerButtons": "F1KBNa_footerButtons",
11889
+ "listScroll": "F1KBNa_listScroll",
11890
+ "group": "F1KBNa_group",
11891
+ "divergedHint": "F1KBNa_divergedHint",
11892
+ "splitCol": "F1KBNa_splitCol",
11737
11893
  "resizeHandle": "F1KBNa_resizeHandle",
11738
- "line": "F1KBNa_line",
11739
- "kindTag": "F1KBNa_kindTag",
11740
- "bulkActions": "F1KBNa_bulkActions",
11741
- "vSpacer": "F1KBNa_vSpacer",
11742
- "emptyState": "F1KBNa_emptyState",
11743
- "badgeLabel": "F1KBNa_badgeLabel",
11744
- "rowFailed": "F1KBNa_rowFailed",
11745
- "layer": "F1KBNa_layer",
11746
- "badgeCount": "F1KBNa_badgeCount",
11894
+ "actionPrimary": "F1KBNa_actionPrimary",
11895
+ "diffFlash": "F1KBNa_diffFlash",
11896
+ "subline": "F1KBNa_subline",
11897
+ "statusAction": "F1KBNa_statusAction",
11747
11898
  "noteCentered": "F1KBNa_noteCentered",
11748
- "settingsSelectorChevron": "F1KBNa_settingsSelectorChevron",
11749
- "importButton": "F1KBNa_importButton",
11750
- "header": "F1KBNa_header",
11751
- "action": "F1KBNa_action",
11752
11899
  "actionError": "F1KBNa_actionError",
11753
- "flexSpacer": "F1KBNa_flexSpacer",
11754
- "settingsRowText": "F1KBNa_settingsRowText",
11755
- "actionQuietDisabled": "F1KBNa_actionQuietDisabled",
11756
- "blockActions": "F1KBNa_blockActions",
11757
- "listScroll": "F1KBNa_listScroll",
11900
+ "lines": "F1KBNa_lines",
11758
11901
  "hint": "F1KBNa_hint",
11759
- "kindHint": "F1KBNa_kindHint",
11760
- "diffActions": "F1KBNa_diffActions",
11902
+ "diff": "F1KBNa_diff",
11903
+ "markerAdd": "F1KBNa_markerAdd",
11904
+ "code": "F1KBNa_code",
11905
+ "emptyState": "F1KBNa_emptyState",
11761
11906
  "expandExpanded": "F1KBNa_expandExpanded",
11762
- "settingsRow": "F1KBNa_settingsRow",
11763
- "blockPosition": "F1KBNa_blockPosition",
11764
- "statusAction": "F1KBNa_statusAction",
11765
- "searchBar": "F1KBNa_searchBar",
11766
- "searchInput": "F1KBNa_searchInput",
11767
- "rows": "F1KBNa_rows",
11768
- "statusBar": "F1KBNa_statusBar",
11769
- "settingsPage": "F1KBNa_settingsPage",
11770
- "overviewMarker": "F1KBNa_overviewMarker",
11771
- "add": "F1KBNa_add",
11772
11907
  "langLabel": "F1KBNa_langLabel",
11773
- "notice": "F1KBNa_notice",
11774
- "states": "F1KBNa_states",
11908
+ "searchBar": "F1KBNa_searchBar",
11909
+ "badgeCount": "F1KBNa_badgeCount",
11910
+ "diffActions": "F1KBNa_diffActions",
11911
+ "splitDivider": "F1KBNa_splitDivider",
11912
+ "settingsRow": "F1KBNa_settingsRow",
11913
+ "noticeButton": "F1KBNa_noticeButton",
11914
+ "splitLadd": "F1KBNa_splitLadd",
11915
+ "settingsSelectorChevron": "F1KBNa_settingsSelectorChevron",
11775
11916
  "rowPath": "F1KBNa_rowPath",
11776
- "searchCount": "F1KBNa_searchCount",
11777
- "diffStats": "F1KBNa_diffStats",
11778
- "badge": "F1KBNa_badge",
11779
- "markerDel": "F1KBNa_markerDel",
11780
- "addCount": "F1KBNa_addCount",
11781
- "settingsSelector": "F1KBNa_settingsSelector",
11782
- "diffFlash": "F1KBNa_diffFlash",
11783
- "subline": "F1KBNa_subline",
11917
+ "fileListFloat": "F1KBNa_fileListFloat",
11918
+ "missingHint": "F1KBNa_missingHint",
11919
+ "rowFailed": "F1KBNa_rowFailed",
11920
+ "overviewMarker": "F1KBNa_overviewMarker",
11921
+ "kindTag": "F1KBNa_kindTag",
11922
+ "flexSpacer": "F1KBNa_flexSpacer",
11784
11923
  "split": "F1KBNa_split",
11785
- "detailEmpty": "F1KBNa_detailEmpty",
11786
- "noticeButton": "F1KBNa_noticeButton",
11787
- "row": "F1KBNa_row",
11788
- "wrapActive": "F1KBNa_wrapActive",
11789
- "settingsRowTitle": "F1KBNa_settingsRowTitle",
11790
- "group": "F1KBNa_group",
11791
- "rowHead": "F1KBNa_rowHead",
11792
- "actionPrimary": "F1KBNa_actionPrimary",
11793
- "noticeText": "F1KBNa_noticeText"
11924
+ "line": "F1KBNa_line"
11794
11925
  };
11795
11926
  //#endregion
11796
11927
  //#region lib/types/client/PendingPanel.js
@@ -12155,6 +12286,541 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12155
12286
  });
12156
12287
  return blocks;
12157
12288
  }
12289
+ /** One side's line-content for the split view: the highlighted runs or plain text. */
12290
+ function splitSideContent(side, wrapped, runs) {
12291
+ if (side === void 0) return "";
12292
+ const highlighted = runs !== void 0 && runs.length > 0;
12293
+ if (wrapped === void 0) return highlighted ? runs.map((span, i) => (0, react_jsx_runtime.jsx)("span", {
12294
+ style: span.style,
12295
+ children: span.text
12296
+ }, i)) : side.text === "" ? "\xA0" : side.text;
12297
+ let offset = 0;
12298
+ return wrapped.map((line, i) => {
12299
+ const start = offset;
12300
+ offset += line.length;
12301
+ const content = highlighted ? clipRuns(runs, start, offset) : line === "" ? "\xA0" : line;
12302
+ return (0, react_jsx_runtime.jsx)("div", {
12303
+ className: PendingPanel_module_css_default.subline,
12304
+ children: content
12305
+ }, i);
12306
+ });
12307
+ }
12308
+ /**
12309
+ * One side of a split pair row, rendered inside its own column. The two columns
12310
+ * are drawn by two independent `.splitCol` scrollers (each with its own
12311
+ * horizontal scrollbar) that share one vertical scroller, and each row gets the
12312
+ * same fixed `height` (the pair's max of the two sides' wrapped sub-line
12313
+ * counts) so the left/right halves always align on the same Y — no jump when
12314
+ * one side is longer. The gutter and code are top-aligned so sub-lines line up
12315
+ * across the divider.
12316
+ */
12317
+ function SplitSideRow({ index, side, wrapped, runs, kind, isLeft, height, focused, searchHit, searchCurrent, onHover }) {
12318
+ const tint = isLeft ? kind === "del" || kind === "replace" ? PendingPanel_module_css_default.splitLdel : "" : kind === "add" || kind === "replace" ? PendingPanel_module_css_default.splitRadd : "";
12319
+ return (0, react_jsx_runtime.jsxs)("div", {
12320
+ className: PendingPanel_module_css_default.line,
12321
+ style: { height },
12322
+ "data-diff-split-row": true,
12323
+ "data-diff-split-index": index,
12324
+ "data-diff-split-side": isLeft ? "left" : "right",
12325
+ "data-diff-focused": focused ? "" : void 0,
12326
+ "data-diff-search": searchHit ? searchCurrent ? "current" : "hit" : void 0,
12327
+ onMouseEnter: onHover,
12328
+ children: [(0, react_jsx_runtime.jsx)("span", {
12329
+ className: PendingPanel_module_css_default.gutter,
12330
+ children: side?.line ?? ""
12331
+ }), (0, react_jsx_runtime.jsx)("span", {
12332
+ className: `${PendingPanel_module_css_default.code} ${tint}`,
12333
+ "data-diff-code": true,
12334
+ children: splitSideContent(side, wrapped, runs)
12335
+ })]
12336
+ });
12337
+ }
12338
+ /** The two-column (side-by-side) whole-file diff view. */
12339
+ const SplitDiff = (0, react.forwardRef)(function SplitDiff({ file, model, runs, langWrap, tabWidthSpaces, busy, t, onBlockKeep, onBlockRevert }, ref) {
12340
+ const { pairs, pairOfRow } = (0, react.useMemo)(() => computeSideBySideDiff(model.diff.rows), [model]);
12341
+ const pairCount = pairs.length;
12342
+ const bodyRef = (0, react.useRef)(null);
12343
+ const [scrollTop, setScrollTop] = (0, react.useState)(0);
12344
+ const [viewportH, setViewportH] = (0, react.useState)(0);
12345
+ const [bodyWidth, setBodyWidth] = (0, react.useState)(0);
12346
+ const [hoveredBlock, setHoveredBlock] = (0, react.useState)(void 0);
12347
+ const [focus, setFocus] = (0, react.useState)(0);
12348
+ const [flashKey, setFlashKey] = (0, react.useState)(0);
12349
+ const hoveredBlockRef = (0, react.useRef)(void 0);
12350
+ const leftColRef = (0, react.useRef)(null);
12351
+ const rightColRef = (0, react.useRef)(null);
12352
+ const leftHScrollRef = (0, react.useRef)(null);
12353
+ const rightHScrollRef = (0, react.useRef)(null);
12354
+ const [fillWidth, setFillWidth] = (0, react.useState)({
12355
+ left: 0,
12356
+ right: 0
12357
+ });
12358
+ const [searchOpen, setSearchOpen] = (0, react.useState)(false);
12359
+ const [searchQuery, setSearchQuery] = (0, react.useState)("");
12360
+ const [searchIndex, setSearchIndex] = (0, react.useState)(0);
12361
+ const searchInputRef = (0, react.useRef)(null);
12362
+ (0, react.useEffect)(() => {
12363
+ setFocus(0);
12364
+ bodyRef.current?.focus();
12365
+ setFlashKey((k) => k + 1);
12366
+ setHoveredBlock(void 0);
12367
+ setSearchOpen(false);
12368
+ setSearchQuery("");
12369
+ setSearchIndex(0);
12370
+ }, [file.id]);
12371
+ (0, react.useEffect)(() => {
12372
+ const body = bodyRef.current;
12373
+ if (body === null) return;
12374
+ const measure = () => {
12375
+ setViewportH(body.clientHeight);
12376
+ setBodyWidth(body.clientWidth);
12377
+ };
12378
+ measure();
12379
+ const observer = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(measure);
12380
+ observer?.observe(body);
12381
+ return () => {
12382
+ observer?.disconnect();
12383
+ };
12384
+ }, [file.id]);
12385
+ const blockOfPair = (0, react.useMemo)(() => model.blocks.map((block) => ({
12386
+ start: pairOfRow.get(block.start) ?? 0,
12387
+ end: pairOfRow.get(block.end) ?? 0
12388
+ })), [model, pairOfRow]);
12389
+ const blockIndexByPair = (0, react.useMemo)(() => {
12390
+ const map = /* @__PURE__ */ new Map();
12391
+ blockOfPair.forEach((block, bi) => {
12392
+ for (let k = block.start; k <= block.end; k++) map.set(k, bi);
12393
+ });
12394
+ return map;
12395
+ }, [blockOfPair]);
12396
+ const onPairHover = (0, react.useCallback)((k) => {
12397
+ const bi = blockIndexByPair.get(k);
12398
+ setHoveredBlock(bi);
12399
+ if (bi !== void 0) hoveredBlockRef.current = bi;
12400
+ }, [blockIndexByPair]);
12401
+ const colWidth = Math.max(0, (bodyWidth - 1) / 2);
12402
+ const pairWrapped = (0, react.useMemo)(() => {
12403
+ if (!langWrap || bodyWidth === 0) return null;
12404
+ const measure = makeMeasurer(codeFontOf());
12405
+ if (measure === void 0) return null;
12406
+ const charWidth = measure("0");
12407
+ const wrapW = colWidth - WRAP_GUTTERS_PX / 2 - charWidth;
12408
+ const tabPx = tabWidthSpaces * measure(" ");
12409
+ return pairs.map((p) => ({
12410
+ left: p.left === void 0 ? void 0 : wrapInto(p.left.text, wrapW, measure, tabPx),
12411
+ right: p.right === void 0 ? void 0 : wrapInto(p.right.text, wrapW, measure, tabPx)
12412
+ }));
12413
+ }, [
12414
+ pairs,
12415
+ langWrap,
12416
+ bodyWidth,
12417
+ colWidth,
12418
+ tabWidthSpaces
12419
+ ]);
12420
+ const pairHeights = (0, react.useMemo)(() => {
12421
+ if (pairWrapped === null) return null;
12422
+ return pairWrapped.map((w) => Math.max(w.left?.length ?? 1, w.right?.length ?? 1) * ROW_HEIGHT_PX);
12423
+ }, [pairWrapped]);
12424
+ const pairOffsets = (0, react.useMemo)(() => {
12425
+ if (pairHeights === null) return null;
12426
+ const offs = new Array(pairHeights.length + 1);
12427
+ offs[0] = 0;
12428
+ for (let i = 0; i < pairHeights.length; i++) offs[i + 1] = offs[i] + pairHeights[i];
12429
+ return offs;
12430
+ }, [pairHeights]);
12431
+ const totalHeight = pairOffsets === null ? pairCount * ROW_HEIGHT_PX : pairOffsets[pairCount] ?? 0;
12432
+ const off = (k) => pairOffsets === null ? k * ROW_HEIGHT_PX : pairOffsets[Math.max(0, Math.min(k, pairCount))] ?? 0;
12433
+ const pairHeightAt = (k) => pairHeights === null ? ROW_HEIGHT_PX : pairHeights[k] ?? ROW_HEIGHT_PX;
12434
+ const widestSide = (0, react.useMemo)(() => {
12435
+ let left = 0;
12436
+ let right = 0;
12437
+ for (const p of pairs) {
12438
+ if (p.left !== void 0) left = Math.max(left, p.left.text.length);
12439
+ if (p.right !== void 0) right = Math.max(right, p.right.text.length);
12440
+ }
12441
+ return {
12442
+ left,
12443
+ right
12444
+ };
12445
+ }, [pairs]);
12446
+ (0, react.useLayoutEffect)(() => {
12447
+ const sync = (side) => {
12448
+ const col = side === "left" ? leftColRef.current : rightColRef.current;
12449
+ const strip = side === "left" ? leftHScrollRef.current : rightHScrollRef.current;
12450
+ if (col === null || strip === null) return;
12451
+ const width = col.scrollWidth;
12452
+ setFillWidth((prev) => prev[side] === width ? prev : {
12453
+ ...prev,
12454
+ [side]: width
12455
+ });
12456
+ strip.scrollLeft = col.scrollLeft;
12457
+ };
12458
+ sync("left");
12459
+ sync("right");
12460
+ }, [
12461
+ pairs,
12462
+ langWrap,
12463
+ tabWidthSpaces,
12464
+ bodyWidth
12465
+ ]);
12466
+ const onHScroll = (0, react.useCallback)((side) => {
12467
+ const strip = side === "left" ? leftHScrollRef.current : rightHScrollRef.current;
12468
+ const col = side === "left" ? leftColRef.current : rightColRef.current;
12469
+ if (strip === null || col === null) return;
12470
+ col.scrollLeft = strip.scrollLeft;
12471
+ }, []);
12472
+ const searchMatches = (0, react.useMemo)(() => searchPairs(pairs, searchQuery), [pairs, searchQuery]);
12473
+ const searchHitSet = (0, react.useMemo)(() => new Set(searchMatches), [searchMatches]);
12474
+ const currentSearchPair = searchMatches.length === 0 ? void 0 : searchMatches[searchIndex % searchMatches.length];
12475
+ const closeSearch = () => {
12476
+ setSearchOpen(false);
12477
+ setSearchQuery("");
12478
+ setSearchIndex(0);
12479
+ bodyRef.current?.focus();
12480
+ };
12481
+ const openSearch = () => {
12482
+ setSearchOpen(true);
12483
+ requestAnimationFrame(() => {
12484
+ searchInputRef.current?.focus();
12485
+ searchInputRef.current?.select();
12486
+ });
12487
+ };
12488
+ const goSearch = (direction) => {
12489
+ const len = searchMatches.length;
12490
+ if (len === 0) return;
12491
+ const next = (searchIndex + direction + len) % len;
12492
+ setSearchIndex(next);
12493
+ const pairIndex = searchMatches[next];
12494
+ if (pairIndex === void 0) return;
12495
+ const body = bodyRef.current;
12496
+ if (body === null) return;
12497
+ const target = Math.max(0, off(pairIndex) - 44);
12498
+ const clamped = Math.max(0, Math.min(target, body.scrollHeight - body.clientHeight));
12499
+ if (body.scrollTop !== clamped) body.scrollTop = clamped;
12500
+ setScrollTop(clamped);
12501
+ };
12502
+ const handleBlockAction = async (action) => {
12503
+ const operated = hoveredBlock ?? hoveredBlockRef.current;
12504
+ if (operated === void 0) return;
12505
+ const range = blockRanges[operated];
12506
+ if (range === void 0) return;
12507
+ await (action === "keep" ? onBlockKeep(file.sessionId, file.id, range) : onBlockRevert(file.sessionId, file.id, range));
12508
+ const count = model.blocks.length;
12509
+ if (count === 0) return;
12510
+ const next = Math.max(0, Math.min(operated, count - 1));
12511
+ setFocus(next);
12512
+ setHoveredBlock(void 0);
12513
+ setFlashKey((key) => key + 1);
12514
+ };
12515
+ const pairAtY = (y) => {
12516
+ if (pairOffsets === null) return Math.floor(y / ROW_HEIGHT_PX);
12517
+ if (y <= 0) return 0;
12518
+ let lo = 0, hi = pairCount;
12519
+ while (lo < hi) {
12520
+ const mid = lo + hi + 1 >> 1;
12521
+ if ((pairOffsets[mid] ?? 0) <= y) lo = mid;
12522
+ else hi = mid - 1;
12523
+ }
12524
+ return lo;
12525
+ };
12526
+ const viewport = viewportH > 0 ? viewportH : totalHeight;
12527
+ const start = Math.max(0, pairAtY(scrollTop) - OVERSCAN_ROWS);
12528
+ const end = Math.min(pairCount, pairAtY(scrollTop + viewport) + OVERSCAN_ROWS);
12529
+ const visiblePairs = pairs.slice(start, end);
12530
+ const jump = (direction) => {
12531
+ if (blockOfPair.length === 0) return;
12532
+ setFocus((current) => {
12533
+ if (direction === -1) return (current - 1 + blockOfPair.length) % blockOfPair.length;
12534
+ const top = bodyRef.current?.scrollTop ?? 0;
12535
+ for (let index = current + 1; index < blockOfPair.length; index++) if (off(blockOfPair[index].start) >= top) return index;
12536
+ return 0;
12537
+ });
12538
+ setFlashKey((k) => k + 1);
12539
+ };
12540
+ (0, react.useImperativeHandle)(ref, () => ({
12541
+ jump,
12542
+ openSearch
12543
+ }), [jump, openSearch]);
12544
+ (0, react.useLayoutEffect)(() => {
12545
+ if (pairCount === 0) return;
12546
+ const block = blockOfPair[focus];
12547
+ if (block === void 0) return;
12548
+ const body = bodyRef.current;
12549
+ if (body === null) return;
12550
+ const target = off(block.start) - 44;
12551
+ const clamped = Math.max(0, Math.min(target, body.scrollHeight - body.clientHeight));
12552
+ if (body.scrollTop !== clamped) body.scrollTop = clamped;
12553
+ setScrollTop(clamped);
12554
+ }, [
12555
+ model,
12556
+ focus,
12557
+ flashKey,
12558
+ pairCount
12559
+ ]);
12560
+ const onScroll = () => {
12561
+ setScrollTop(bodyRef.current?.scrollTop ?? 0);
12562
+ };
12563
+ const inFocused = (k) => {
12564
+ const block = blockOfPair[focus];
12565
+ return block !== void 0 && k >= block.start && k <= block.end;
12566
+ };
12567
+ const blockRanges = (0, react.useMemo)(() => model.blocks.map((block) => blockRangesOf(model.diff.rows, block)), [model]);
12568
+ const focusedBlock = blockOfPair[focus];
12569
+ const flashTop = focusedBlock === void 0 ? 0 : Math.max(0, off(focusedBlock.start) - scrollTop);
12570
+ const flashBottom = focusedBlock === void 0 ? 0 : Math.min(viewportH > 0 ? viewportH : Number.POSITIVE_INFINITY, off(focusedBlock.end + 1) - scrollTop);
12571
+ const flashHeight = Math.max(0, flashBottom - flashTop);
12572
+ const blockActionsTop = hoveredBlock === void 0 || blockOfPair[hoveredBlock] === void 0 ? 0 : Math.max(0, Math.min(off(blockOfPair[hoveredBlock].end + 1) - scrollTop, Math.max(0, viewportH - BLOCK_ACTIONS_FRAME_PX)));
12573
+ return (0, react_jsx_runtime.jsxs)("div", {
12574
+ className: PendingPanel_module_css_default.splitRoot,
12575
+ onMouseLeave: () => setHoveredBlock(void 0),
12576
+ children: [
12577
+ (0, react_jsx_runtime.jsx)("div", {
12578
+ className: `${PendingPanel_module_css_default.diffBody} ${PendingPanel_module_css_default.diffBodySplit}`,
12579
+ ref: bodyRef,
12580
+ tabIndex: 0,
12581
+ onScroll,
12582
+ style: { tabSize: tabWidthSpaces },
12583
+ "data-diff-body": true,
12584
+ children: (0, react_jsx_runtime.jsxs)("div", {
12585
+ className: PendingPanel_module_css_default.splitCols,
12586
+ children: [
12587
+ (0, react_jsx_runtime.jsx)("div", {
12588
+ className: PendingPanel_module_css_default.splitCol,
12589
+ ref: leftColRef,
12590
+ "data-diff-split-side": "left",
12591
+ children: (0, react_jsx_runtime.jsxs)("div", {
12592
+ className: `${PendingPanel_module_css_default.lines}${langWrap ? " " + PendingPanel_module_css_default.wrap : ""}`,
12593
+ style: langWrap ? void 0 : { minWidth: `max(100%, ${widestSide.left}ch)` },
12594
+ children: [
12595
+ start > 0 && (0, react_jsx_runtime.jsx)("div", {
12596
+ className: PendingPanel_module_css_default.vSpacer,
12597
+ style: { height: off(start) },
12598
+ "aria-hidden": "true"
12599
+ }),
12600
+ visiblePairs.map((pair, offset) => {
12601
+ const index = start + offset;
12602
+ const leftRuns = pair.left === void 0 ? void 0 : runs?.oldRuns?.[(pair.left.line ?? 0) - 1];
12603
+ return (0, react_jsx_runtime.jsx)(SplitSideRow, {
12604
+ index,
12605
+ side: pair.left,
12606
+ wrapped: pairWrapped?.[index]?.left,
12607
+ runs: leftRuns,
12608
+ kind: pair.kind,
12609
+ isLeft: true,
12610
+ height: pairHeightAt(index),
12611
+ focused: inFocused(index),
12612
+ searchHit: searchHitSet.has(index),
12613
+ searchCurrent: index === currentSearchPair,
12614
+ onHover: () => onPairHover(index)
12615
+ }, index);
12616
+ }),
12617
+ end < pairCount && (0, react_jsx_runtime.jsx)("div", {
12618
+ className: PendingPanel_module_css_default.vSpacer,
12619
+ style: { height: totalHeight - off(end) },
12620
+ "aria-hidden": "true"
12621
+ })
12622
+ ]
12623
+ })
12624
+ }),
12625
+ (0, react_jsx_runtime.jsx)("div", { className: PendingPanel_module_css_default.splitDivider }),
12626
+ (0, react_jsx_runtime.jsx)("div", {
12627
+ className: PendingPanel_module_css_default.splitCol,
12628
+ ref: rightColRef,
12629
+ "data-diff-split-side": "right",
12630
+ children: (0, react_jsx_runtime.jsxs)("div", {
12631
+ className: `${PendingPanel_module_css_default.lines}${langWrap ? " " + PendingPanel_module_css_default.wrap : ""}`,
12632
+ style: langWrap ? void 0 : { minWidth: `max(100%, ${widestSide.right}ch)` },
12633
+ children: [
12634
+ start > 0 && (0, react_jsx_runtime.jsx)("div", {
12635
+ className: PendingPanel_module_css_default.vSpacer,
12636
+ style: { height: off(start) },
12637
+ "aria-hidden": "true"
12638
+ }),
12639
+ visiblePairs.map((pair, offset) => {
12640
+ const index = start + offset;
12641
+ const rightRuns = pair.right === void 0 ? void 0 : runs?.newRuns?.[(pair.right.line ?? 0) - 1];
12642
+ return (0, react_jsx_runtime.jsx)(SplitSideRow, {
12643
+ index,
12644
+ side: pair.right,
12645
+ wrapped: pairWrapped?.[index]?.right,
12646
+ runs: rightRuns,
12647
+ kind: pair.kind,
12648
+ isLeft: false,
12649
+ height: pairHeightAt(index),
12650
+ focused: inFocused(index),
12651
+ searchHit: searchHitSet.has(index),
12652
+ searchCurrent: index === currentSearchPair,
12653
+ onHover: () => onPairHover(index)
12654
+ }, index);
12655
+ }),
12656
+ end < pairCount && (0, react_jsx_runtime.jsx)("div", {
12657
+ className: PendingPanel_module_css_default.vSpacer,
12658
+ style: { height: totalHeight - off(end) },
12659
+ "aria-hidden": "true"
12660
+ })
12661
+ ]
12662
+ })
12663
+ })
12664
+ ]
12665
+ })
12666
+ }),
12667
+ (0, react_jsx_runtime.jsxs)("div", {
12668
+ className: PendingPanel_module_css_default.splitHScrollRow,
12669
+ "data-diff-hscroll-row": true,
12670
+ children: [
12671
+ (0, react_jsx_runtime.jsx)("div", {
12672
+ className: PendingPanel_module_css_default.splitHScroll,
12673
+ ref: leftHScrollRef,
12674
+ "data-diff-hscroll": "left",
12675
+ style: {
12676
+ width: colWidth,
12677
+ flex: "none"
12678
+ },
12679
+ onScroll: () => onHScroll("left"),
12680
+ children: (0, react_jsx_runtime.jsx)("div", {
12681
+ className: PendingPanel_module_css_default.splitHScrollFill,
12682
+ style: { width: fillWidth.left || void 0 }
12683
+ })
12684
+ }),
12685
+ (0, react_jsx_runtime.jsx)("div", { className: PendingPanel_module_css_default.splitDivider }),
12686
+ (0, react_jsx_runtime.jsx)("div", {
12687
+ className: PendingPanel_module_css_default.splitHScroll,
12688
+ ref: rightHScrollRef,
12689
+ "data-diff-hscroll": "right",
12690
+ style: {
12691
+ width: colWidth,
12692
+ flex: "none"
12693
+ },
12694
+ onScroll: () => onHScroll("right"),
12695
+ children: (0, react_jsx_runtime.jsx)("div", {
12696
+ className: PendingPanel_module_css_default.splitHScrollFill,
12697
+ style: { width: fillWidth.right || void 0 }
12698
+ })
12699
+ })
12700
+ ]
12701
+ }),
12702
+ searchOpen && (0, react_jsx_runtime.jsxs)("div", {
12703
+ className: PendingPanel_module_css_default.searchBar,
12704
+ "data-diff-searchbar": true,
12705
+ children: [
12706
+ (0, react_jsx_runtime.jsx)("input", {
12707
+ ref: searchInputRef,
12708
+ className: PendingPanel_module_css_default.searchInput,
12709
+ "data-diff-search-input": true,
12710
+ value: searchQuery,
12711
+ placeholder: t("panel.searchPlaceholder"),
12712
+ onChange: (event) => {
12713
+ setSearchQuery(event.target.value);
12714
+ setSearchIndex(0);
12715
+ },
12716
+ onKeyDown: (event) => {
12717
+ if (event.key === "Enter") {
12718
+ event.preventDefault();
12719
+ goSearch(event.shiftKey ? -1 : 1);
12720
+ } else if (event.key === "Escape") closeSearch();
12721
+ }
12722
+ }),
12723
+ (0, react_jsx_runtime.jsx)("span", {
12724
+ className: PendingPanel_module_css_default.searchCount,
12725
+ "data-diff-search-count": true,
12726
+ children: searchMatches.length === 0 ? "0/0" : `${searchIndex % searchMatches.length + 1}/${searchMatches.length}`
12727
+ }),
12728
+ (0, react_jsx_runtime.jsx)("button", {
12729
+ type: "button",
12730
+ className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.iconAction}`,
12731
+ "data-diff-search-prev": true,
12732
+ "aria-label": t("action.prevDiff"),
12733
+ disabled: searchMatches.length === 0,
12734
+ onClick: () => {
12735
+ goSearch(-1);
12736
+ },
12737
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronUpOutline14, { size: 14 })
12738
+ }),
12739
+ (0, react_jsx_runtime.jsx)("button", {
12740
+ type: "button",
12741
+ className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.iconAction}`,
12742
+ "data-diff-search-next": true,
12743
+ "aria-label": t("action.nextDiff"),
12744
+ disabled: searchMatches.length === 0,
12745
+ onClick: () => {
12746
+ goSearch(1);
12747
+ },
12748
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { size: 14 })
12749
+ }),
12750
+ (0, react_jsx_runtime.jsx)("button", {
12751
+ type: "button",
12752
+ className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.iconAction}`,
12753
+ "data-diff-search-close": true,
12754
+ "aria-label": t("action.close"),
12755
+ onClick: closeSearch,
12756
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCloseOutline16, { size: 14 })
12757
+ })
12758
+ ]
12759
+ }),
12760
+ focusedBlock !== void 0 && flashKey > 0 && (0, react_jsx_runtime.jsx)("div", {
12761
+ className: PendingPanel_module_css_default.blockFlash,
12762
+ "data-diff-block-flash": true,
12763
+ style: {
12764
+ top: flashTop,
12765
+ height: flashHeight
12766
+ }
12767
+ }, flashKey),
12768
+ hoveredBlock !== void 0 && blockOfPair[hoveredBlock] !== void 0 && (0, react_jsx_runtime.jsxs)("div", {
12769
+ className: PendingPanel_module_css_default.blockActions,
12770
+ "data-diff-block-actions": true,
12771
+ style: { top: blockActionsTop },
12772
+ children: [
12773
+ (0, react_jsx_runtime.jsx)("span", {
12774
+ className: PendingPanel_module_css_default.blockPosition,
12775
+ "data-diff-block-position": true,
12776
+ children: t("panel.blockPosition", {
12777
+ current: hoveredBlock + 1,
12778
+ total: blockOfPair.length
12779
+ })
12780
+ }),
12781
+ (0, react_jsx_runtime.jsx)("button", {
12782
+ type: "button",
12783
+ className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.iconAction}`,
12784
+ "data-diff-block-prev": true,
12785
+ "aria-label": t("action.prevDiff"),
12786
+ disabled: busy,
12787
+ onClick: () => jump(-1),
12788
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronUpOutline14, { size: 14 })
12789
+ }),
12790
+ (0, react_jsx_runtime.jsx)("button", {
12791
+ type: "button",
12792
+ className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.iconAction}`,
12793
+ "data-diff-block-next": true,
12794
+ "aria-label": t("action.nextDiff"),
12795
+ disabled: busy,
12796
+ onClick: () => jump(1),
12797
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { size: 14 })
12798
+ }),
12799
+ (0, react_jsx_runtime.jsx)("button", {
12800
+ type: "button",
12801
+ className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.actionPrimary}`,
12802
+ "data-diff-block-keep": true,
12803
+ disabled: busy,
12804
+ onClick: () => {
12805
+ handleBlockAction("keep");
12806
+ },
12807
+ children: t("action.keep")
12808
+ }),
12809
+ (0, react_jsx_runtime.jsx)("button", {
12810
+ type: "button",
12811
+ className: `${PendingPanel_module_css_default.action}`,
12812
+ "data-diff-block-revert": true,
12813
+ disabled: busy,
12814
+ onClick: () => {
12815
+ handleBlockAction("revert");
12816
+ },
12817
+ children: t("action.revert")
12818
+ })
12819
+ ]
12820
+ })
12821
+ ]
12822
+ });
12823
+ });
12158
12824
  /** The diff-row index containing a node, or undefined. */
12159
12825
  function rowIndexAt(node) {
12160
12826
  if (node === null) return void 0;
@@ -12163,6 +12829,43 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12163
12829
  const index = Number(row.dataset.diffRow);
12164
12830
  return Number.isFinite(index) ? index : void 0;
12165
12831
  }
12832
+ /** The split pair index and which side (left=old, right=new) a node sits in, or undefined. */
12833
+ function splitRowInfoAt(node) {
12834
+ if (node === null) return void 0;
12835
+ const row = (node instanceof Element ? node : node.parentElement)?.closest("[data-diff-split-row]");
12836
+ if (row === null || row === void 0) return void 0;
12837
+ const side = row.dataset.diffSplitSide;
12838
+ if (side !== "left" && side !== "right") return void 0;
12839
+ const index = Number(row.dataset.diffSplitIndex);
12840
+ if (!Number.isFinite(index)) return void 0;
12841
+ return {
12842
+ pairIndex: index,
12843
+ side: side === "left" ? "old" : "new"
12844
+ };
12845
+ }
12846
+ /**
12847
+ * Derive the selected split pair range per side (a left-column selection
12848
+ * references the old file, a right-column selection the new file). A selection
12849
+ * spanning the divider (both sides) references two files, so it is rejected.
12850
+ */
12851
+ function splitRowRangeOf(selection) {
12852
+ if (selection === null || selection.isCollapsed || selection.rangeCount === 0) return void 0;
12853
+ const range = selection.getRangeAt(0);
12854
+ const startInfo = splitRowInfoAt(range.startContainer);
12855
+ const endInfo = splitRowInfoAt(range.endContainer);
12856
+ if (startInfo === void 0 || endInfo === void 0) return void 0;
12857
+ if (startInfo.side !== endInfo.side) return void 0;
12858
+ let start = startInfo.pairIndex;
12859
+ let end = endInfo.pairIndex;
12860
+ if (lineOffsetAt(range.startContainer, range.startOffset) >= lineLengthAt(range.startContainer)) start += 1;
12861
+ if (lineOffsetAt(range.endContainer, range.endOffset) === 0) end -= 1;
12862
+ if (start > end) return void 0;
12863
+ return {
12864
+ start,
12865
+ end,
12866
+ side: startInfo.side
12867
+ };
12868
+ }
12166
12869
  /** Character offset of a selection boundary within its line's code text. */
12167
12870
  function lineOffsetAt(node, offset) {
12168
12871
  const code = (node instanceof Element ? node : node.parentElement)?.closest("[data-diff-code]");
@@ -12288,6 +12991,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12288
12991
  setWrapEnabled(wrapKey, next);
12289
12992
  };
12290
12993
  const [tabWidthSpaces] = (0, react.useState)(() => tabWidth());
12994
+ const splitView = splitMode();
12995
+ const splitDiffRef = (0, react.useRef)(null);
12291
12996
  const model = (0, react.useMemo)(() => {
12292
12997
  const diff = computeWholeFileDiff(file.oldText, file.newText);
12293
12998
  return {
@@ -12295,6 +13000,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12295
13000
  blocks: changeBlocksOf(diff)
12296
13001
  };
12297
13002
  }, [file.oldText, file.newText]);
13003
+ const splitPairs = (0, react.useMemo)(() => splitView ? computeSideBySideDiff(model.diff.rows).pairs : null, [splitView, model]);
12298
13004
  const rulerMarkers = (0, react.useMemo)(() => {
12299
13005
  const rows = model.diff.rows;
12300
13006
  const total = rows.length;
@@ -12554,6 +13260,15 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12554
13260
  setScrollTick((tick) => tick + 1);
12555
13261
  setFlashKey((key) => key + 1);
12556
13262
  };
13263
+ const jumpBlock = (direction) => {
13264
+ if (splitView) {
13265
+ splitDiffRef.current?.jump(direction);
13266
+ return;
13267
+ }
13268
+ jump(direction);
13269
+ };
13270
+ const jumpBlockRef = (0, react.useRef)(jumpBlock);
13271
+ jumpBlockRef.current = jumpBlock;
12557
13272
  const stepBlock = (direction) => {
12558
13273
  const count = model.blocks.length;
12559
13274
  if (count === 0) return;
@@ -12563,9 +13278,22 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12563
13278
  setScrollTick((tick) => tick + 1);
12564
13279
  setFlashKey((key) => key + 1);
12565
13280
  };
13281
+ const handleBlockAction = async (action) => {
13282
+ if (busy || hoveredBlock === void 0) return;
13283
+ const operated = hoveredBlock;
13284
+ const range = blockRanges[operated];
13285
+ await (action === "keep" ? onBlockKeep(file.sessionId, file.id, range) : onBlockRevert(file.sessionId, file.id, range));
13286
+ const count = model.blocks.length;
13287
+ if (count === 0) return;
13288
+ const next = Math.max(0, Math.min(operated, count - 1));
13289
+ setFocus(next);
13290
+ setHoveredBlock(void 0);
13291
+ setScrollTick((tick) => tick + 1);
13292
+ setFlashKey((key) => key + 1);
13293
+ };
12566
13294
  (0, react.useEffect)(() => {
12567
13295
  if (jumpSignal === 0) return;
12568
- jump(1);
13296
+ jumpBlock(1);
12569
13297
  }, [jumpSignal]);
12570
13298
  const onScroll = () => {
12571
13299
  const body = bodyRef.current;
@@ -12574,15 +13302,27 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12574
13302
  setViewportHeight(body.clientHeight);
12575
13303
  };
12576
13304
  (0, react.useEffect)(() => {
12577
- const update = () => setSelection(rowRangeOf(window.getSelection()));
13305
+ const update = () => setSelection(splitView ? splitRowRangeOf(window.getSelection()) : rowRangeOf(window.getSelection()));
12578
13306
  document.addEventListener("selectionchange", update);
12579
13307
  update();
12580
13308
  return () => {
12581
13309
  document.removeEventListener("selectionchange", update);
12582
13310
  };
12583
- }, [file.id]);
13311
+ }, [file.id, splitView]);
12584
13312
  const selectionReference = (() => {
12585
13313
  if (selection === void 0) return void 0;
13314
+ if (splitView) {
13315
+ if (selection.side === void 0 || splitPairs === null) return void 0;
13316
+ const lineNumbers = [];
13317
+ for (let index = selection.start; index <= selection.end; index++) {
13318
+ const pair = splitPairs[index];
13319
+ if (pair === void 0) continue;
13320
+ const line = selection.side === "old" ? pair.left?.line : pair.right?.line;
13321
+ if (line !== void 0) lineNumbers.push(line);
13322
+ }
13323
+ if (lineNumbers.length === 0) return void 0;
13324
+ return referenceOf(file.path, workspacePath, Math.min(...lineNumbers), Math.max(...lineNumbers));
13325
+ }
12586
13326
  const lineNumbers = model.diff.rows.slice(selection.start, selection.end + 1).map((row) => row.newLine).filter((number) => number !== void 0);
12587
13327
  if (lineNumbers.length === 0) return void 0;
12588
13328
  return referenceOf(file.path, workspacePath, Math.min(...lineNumbers), Math.max(...lineNumbers));
@@ -12618,6 +13358,10 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12618
13358
  if (!(event.ctrlKey || event.metaKey) || event.altKey || event.shiftKey) return;
12619
13359
  if (event.key.toLowerCase() !== "f") return;
12620
13360
  event.preventDefault();
13361
+ if (splitView) {
13362
+ splitDiffRef.current?.openSearch();
13363
+ return;
13364
+ }
12621
13365
  setSearchOpen(true);
12622
13366
  searchInputRef.current?.focus();
12623
13367
  searchInputRef.current?.select();
@@ -12627,8 +13371,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12627
13371
  window.removeEventListener("keydown", onKeyDown, true);
12628
13372
  };
12629
13373
  }, []);
12630
- const jumpRef = (0, react.useRef)(jump);
12631
- jumpRef.current = jump;
13374
+ const jumpRef = (0, react.useRef)(jumpBlock);
13375
+ jumpRef.current = jumpBlock;
12632
13376
  (0, react.useEffect)(() => {
12633
13377
  const onKeyDown = (event) => {
12634
13378
  if (!(event.ctrlKey || event.metaKey) || event.altKey || event.shiftKey) return;
@@ -12736,7 +13480,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12736
13480
  "aria-label": t("action.prevDiff"),
12737
13481
  disabled: busy,
12738
13482
  onClick: () => {
12739
- jump(-1);
13483
+ jumpBlock(-1);
12740
13484
  },
12741
13485
  children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronUpOutline14, { size: 14 })
12742
13486
  })
@@ -12751,7 +13495,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12751
13495
  "aria-label": t("action.nextDiff"),
12752
13496
  disabled: busy,
12753
13497
  onClick: () => {
12754
- jump(1);
13498
+ jumpBlock(1);
12755
13499
  },
12756
13500
  children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { size: 14 })
12757
13501
  })
@@ -12801,7 +13545,18 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12801
13545
  className: PendingPanel_module_css_default.missingHint,
12802
13546
  children: t("panel.missingHint")
12803
13547
  }),
12804
- (0, react_jsx_runtime.jsxs)("div", {
13548
+ splitView ? (0, react_jsx_runtime.jsx)(SplitDiff, {
13549
+ ref: splitDiffRef,
13550
+ file,
13551
+ model,
13552
+ runs,
13553
+ langWrap,
13554
+ tabWidthSpaces,
13555
+ busy,
13556
+ t,
13557
+ onBlockKeep,
13558
+ onBlockRevert
13559
+ }) : (0, react_jsx_runtime.jsxs)("div", {
12805
13560
  className: PendingPanel_module_css_default.diffBodyWrap,
12806
13561
  children: [
12807
13562
  (0, react_jsx_runtime.jsxs)("div", {
@@ -12886,7 +13641,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12886
13641
  "data-diff-block-keep": true,
12887
13642
  disabled: busy,
12888
13643
  onClick: () => {
12889
- onBlockKeep(file.sessionId, file.id, blockRanges[hoveredBlock]);
13644
+ handleBlockAction("keep");
12890
13645
  },
12891
13646
  children: t("action.keep")
12892
13647
  }),
@@ -12896,7 +13651,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12896
13651
  "data-diff-block-revert": true,
12897
13652
  disabled: busy,
12898
13653
  onClick: () => {
12899
- onBlockRevert(file.sessionId, file.id, blockRanges[hoveredBlock]);
13654
+ handleBlockAction("revert");
12900
13655
  },
12901
13656
  children: t("action.revert")
12902
13657
  })
@@ -13733,6 +14488,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13733
14488
  const [includeUntrackedOpen, setIncludeUntrackedOpen] = (0, react.useState)(false);
13734
14489
  const [tab, setTabState] = (0, react.useState)(tabWidth);
13735
14490
  const [tabOpen, setTabOpen] = (0, react.useState)(false);
14491
+ const [split, setSplitState] = (0, react.useState)(splitMode);
14492
+ const [splitOpen, setSplitOpen] = (0, react.useState)(false);
13736
14493
  const setPasteOnCopy = (value) => {
13737
14494
  setPasteOnCopyState(value);
13738
14495
  setPasteOnCopyEnabled(value);
@@ -13745,6 +14502,10 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13745
14502
  setTabState(value);
13746
14503
  setTabWidth(value);
13747
14504
  };
14505
+ const setSplit = (value) => {
14506
+ setSplitState(value);
14507
+ setSplitMode(value);
14508
+ };
13748
14509
  return (0, react_jsx_runtime.jsxs)("div", {
13749
14510
  className: PendingPanel_module_css_default.settingsPage,
13750
14511
  "data-diff-settings": true,
@@ -13777,6 +14538,16 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13777
14538
  onOpenChange: setTabOpen,
13778
14539
  onSelect: setTab,
13779
14540
  dataAttribute: "data-diff-tab-width-select"
14541
+ }),
14542
+ (0, react_jsx_runtime.jsx)(PreferenceRow, {
14543
+ title: t("panel.splitMode"),
14544
+ description: t("panel.splitModeDesc"),
14545
+ value: split,
14546
+ open: splitOpen,
14547
+ onOpenChange: setSplitOpen,
14548
+ onSelect: setSplit,
14549
+ dataAttribute: "data-diff-split-mode-select",
14550
+ t
13780
14551
  })
13781
14552
  ]
13782
14553
  });
@@ -14175,8 +14946,10 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
14175
14946
  "panel.pasteOnCopyDesc": "开启后,复制的引用会自动填入消息输入框,输入框会获得焦点。",
14176
14947
  "panel.importUntracked": "导入未跟踪的文件改动",
14177
14948
  "panel.importUntrackedDesc": "开启后,导入工作区改动会包含未跟踪/未版本化的新增文件(Git 未跟踪、SVN 未版本化、Perforce 未版本化)。收集改动需要扫描整个工作区,文件数量大时可能较慢。",
14178
- "panel.tabWidth": "Tab 宽度",
14179
- "panel.tabWidthDesc": "diff 中制表符(Tab)的缩进宽度,可选 2 / 4 / 8 个空格(默认 4),同时作用于行宽折行测量。",
14949
+ "panel.tabWidth": "制表符宽度",
14950
+ "panel.tabWidthDesc": "差异中制表符的缩进宽度,可选 2 / 4 / 8 个空格(默认 4),同时作用于行宽折行测量。",
14951
+ "panel.splitMode": "双栏对比",
14952
+ "panel.splitModeDesc": "开启后整文件差异用左「改前」|右「当前」双栏、逐行对齐的视图展示,默认关闭使用单栏(合并)视图。",
14180
14953
  "settings.tabLabel": "改动审批",
14181
14954
  "row.create": "新增文件",
14182
14955
  "row.failed": "失败",
@@ -14239,7 +15012,9 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
14239
15012
  "panel.importUntracked": "Import changes to untracked files",
14240
15013
  "panel.importUntrackedDesc": "When enabled, importing workspace changes includes new/untracked files (Git-untracked, SVN-unversioned, Perforce-unversioned). Collecting changes scans the whole workspace, which can be slow on large trees.",
14241
15014
  "panel.tabWidth": "Tab width",
14242
- "panel.tabWidthDesc": "The indent width of a tab character in the diff, as 2 / 4 / 8 spaces (default 4). Also drives the wrapped-line measurement.",
15015
+ "panel.tabWidthDesc": "The indent width of a tab character in the differences, as 2 / 4 / 8 spaces (default 4). Also drives the wrapped-line measurement.",
15016
+ "panel.splitMode": "Side-by-side view",
15017
+ "panel.splitModeDesc": "When on, the whole-file differences render as a side-by-side (left \"before\" | right \"current\") line-aligned view. Off (default) uses the single-column unified view.",
14243
15018
  "settings.tabLabel": "Diff Approval",
14244
15019
  "row.create": "New file",
14245
15020
  "row.failed": "Failed",