dsh-diff-approval 0.16.0 → 0.18.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/README.md +15 -11
- package/README.zh.md +15 -11
- package/docs/images/file-list-collapsed.png +0 -0
- package/docs/images/file-list-collapsed.zh.png +0 -0
- package/docs/images/fullscreen.png +0 -0
- package/docs/images/fullscreen.zh.png +0 -0
- package/docs/images/pending-panel.png +0 -0
- package/docs/images/pending-panel.zh.png +0 -0
- package/lib/client.js +1760 -399
- package/lib/index.js +37 -3
- package/lib/types/client/ColorPicker.d.ts +23 -0
- package/lib/types/client/PendingPanel.d.ts +14 -2
- package/lib/types/client/conversation-access.d.ts +9 -0
- package/lib/types/client/locales.d.ts +58 -0
- package/lib/types/client/port.d.ts +2 -2
- package/lib/types/client/produced-diff.d.ts +27 -0
- package/lib/types/client/reference.d.ts +11 -0
- package/lib/types/client/settings.d.ts +45 -0
- package/lib/types/client/slots.d.ts +2 -7
- package/lib/types/client/store.d.ts +2 -4
- package/lib/types/client/whole-file-diff.d.ts +9 -0
- package/lib/types/types.d.ts +5 -0
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -667,6 +667,143 @@ window.__ModuleLoader__.load({
|
|
|
667
667
|
const normalized = text.replace(/\r\n?/g, "\n");
|
|
668
668
|
return normalized.endsWith("\n") ? normalized.slice(0, -1) : normalized;
|
|
669
669
|
}
|
|
670
|
+
/** A changed middle larger than this many old×new line cells falls back to the
|
|
671
|
+
* greedy anchor alignment: the `diff` package's O((N+M)·D) Myers scan (and its
|
|
672
|
+
* high constant) would otherwise stall on a big, heavily-edited region for no
|
|
673
|
+
* benefit. */
|
|
674
|
+
const MIDDLE_CELL_CAP = 1e6;
|
|
675
|
+
/** A fast, greedy line alignment for a large changed middle. Lines present on
|
|
676
|
+
* both sides (in order) become context; a line only on one side is del/add;
|
|
677
|
+
* two unmatched side-by-side lines are a replacement. It is O(N+M) (amortized,
|
|
678
|
+
* with per-line index queues) and recognises unchanged lines as context, so a
|
|
679
|
+
* big scattered file does not get marked as all-changed — it only gives up the
|
|
680
|
+
* minimal-edit property Myers would provide. */
|
|
681
|
+
function alignLargeMiddle(midOld, midNew, start) {
|
|
682
|
+
const rows = [];
|
|
683
|
+
let removed = 0;
|
|
684
|
+
let added = 0;
|
|
685
|
+
const newPos = /* @__PURE__ */ new Map();
|
|
686
|
+
const oldPos = /* @__PURE__ */ new Map();
|
|
687
|
+
midNew.forEach((line, index) => {
|
|
688
|
+
const q = newPos.get(line);
|
|
689
|
+
if (q) q.push(index);
|
|
690
|
+
else newPos.set(line, [index]);
|
|
691
|
+
});
|
|
692
|
+
midOld.forEach((line, index) => {
|
|
693
|
+
const q = oldPos.get(line);
|
|
694
|
+
if (q) q.push(index);
|
|
695
|
+
else oldPos.set(line, [index]);
|
|
696
|
+
});
|
|
697
|
+
let oldLine = start;
|
|
698
|
+
let newLine = start;
|
|
699
|
+
let i = 0;
|
|
700
|
+
let j = 0;
|
|
701
|
+
while (i < midOld.length && j < midNew.length) {
|
|
702
|
+
if (midOld[i] === midNew[j]) {
|
|
703
|
+
rows.push({
|
|
704
|
+
kind: "context",
|
|
705
|
+
text: midOld[i],
|
|
706
|
+
oldLine: ++oldLine,
|
|
707
|
+
newLine: ++newLine
|
|
708
|
+
});
|
|
709
|
+
i++;
|
|
710
|
+
j++;
|
|
711
|
+
continue;
|
|
712
|
+
}
|
|
713
|
+
const nxtNew = newPos.get(midOld[i])?.find((index) => index >= j);
|
|
714
|
+
const nxtOld = oldPos.get(midNew[j])?.find((index) => index >= i);
|
|
715
|
+
if (nxtNew !== void 0 && (nxtOld === void 0 || nxtNew - j <= nxtOld - i)) {
|
|
716
|
+
for (let k = j; k < nxtNew; k++) {
|
|
717
|
+
rows.push({
|
|
718
|
+
kind: "add",
|
|
719
|
+
text: midNew[k],
|
|
720
|
+
oldLine: void 0,
|
|
721
|
+
newLine: ++newLine
|
|
722
|
+
});
|
|
723
|
+
added++;
|
|
724
|
+
}
|
|
725
|
+
j = nxtNew;
|
|
726
|
+
} else if (nxtOld !== void 0) {
|
|
727
|
+
for (let k = i; k < nxtOld; k++) {
|
|
728
|
+
rows.push({
|
|
729
|
+
kind: "del",
|
|
730
|
+
text: midOld[k],
|
|
731
|
+
oldLine: ++oldLine,
|
|
732
|
+
newLine: void 0
|
|
733
|
+
});
|
|
734
|
+
removed++;
|
|
735
|
+
}
|
|
736
|
+
i = nxtOld;
|
|
737
|
+
} else {
|
|
738
|
+
rows.push({
|
|
739
|
+
kind: "del",
|
|
740
|
+
text: midOld[i],
|
|
741
|
+
oldLine: ++oldLine,
|
|
742
|
+
newLine: void 0
|
|
743
|
+
});
|
|
744
|
+
removed++;
|
|
745
|
+
i++;
|
|
746
|
+
rows.push({
|
|
747
|
+
kind: "add",
|
|
748
|
+
text: midNew[j],
|
|
749
|
+
oldLine: void 0,
|
|
750
|
+
newLine: ++newLine
|
|
751
|
+
});
|
|
752
|
+
added++;
|
|
753
|
+
j++;
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
while (i < midOld.length) {
|
|
757
|
+
rows.push({
|
|
758
|
+
kind: "del",
|
|
759
|
+
text: midOld[i],
|
|
760
|
+
oldLine: ++oldLine,
|
|
761
|
+
newLine: void 0
|
|
762
|
+
});
|
|
763
|
+
removed++;
|
|
764
|
+
i++;
|
|
765
|
+
}
|
|
766
|
+
while (j < midNew.length) {
|
|
767
|
+
rows.push({
|
|
768
|
+
kind: "add",
|
|
769
|
+
text: midNew[j],
|
|
770
|
+
oldLine: void 0,
|
|
771
|
+
newLine: ++newLine
|
|
772
|
+
});
|
|
773
|
+
added++;
|
|
774
|
+
j++;
|
|
775
|
+
}
|
|
776
|
+
return {
|
|
777
|
+
rows,
|
|
778
|
+
removed,
|
|
779
|
+
added
|
|
780
|
+
};
|
|
781
|
+
}
|
|
782
|
+
/** Reorder each contiguous change run (a maximal run of non-context rows) into
|
|
783
|
+
* the standard unified-diff shape — all `del` rows first, then all `add` rows.
|
|
784
|
+
* The diff package's Myers scan can emit per-line replacements (`del add del
|
|
785
|
+
* add`) for some content, which reads as interleaved in the viewer and makes
|
|
786
|
+
* the split view pair each line separately. Reordering a run to del-block→add-
|
|
787
|
+
* block keeps each row's own line numbers and never changes the run's row
|
|
788
|
+
* boundaries, so change blocks, split alignment, and keep/revert ranges stay
|
|
789
|
+
* correct — it only tidies the display order. */
|
|
790
|
+
function normalizeChangeRuns(rows) {
|
|
791
|
+
for (let i = 0; i < rows.length;) {
|
|
792
|
+
if (rows[i].kind === "context") {
|
|
793
|
+
i++;
|
|
794
|
+
continue;
|
|
795
|
+
}
|
|
796
|
+
const start = i;
|
|
797
|
+
while (i < rows.length && rows[i].kind !== "context") i++;
|
|
798
|
+
const run = rows.slice(start, i);
|
|
799
|
+
const dels = run.filter((row) => row.kind === "del");
|
|
800
|
+
const adds = run.filter((row) => row.kind === "add");
|
|
801
|
+
if (dels.length !== 0 && adds.length !== 0) {
|
|
802
|
+
rows.splice(start, run.length);
|
|
803
|
+
rows.splice(start, 0, ...dels, ...adds);
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
}
|
|
670
807
|
function computeWholeFileDiff(oldText, newText) {
|
|
671
808
|
const oldNorm = oldText.replace(/\r\n?/g, "\n");
|
|
672
809
|
const newNorm = newText.replace(/\r\n?/g, "\n");
|
|
@@ -682,43 +819,94 @@ window.__ModuleLoader__.load({
|
|
|
682
819
|
};
|
|
683
820
|
const oldLines = contentLines(oldNorm);
|
|
684
821
|
const newLines = contentLines(newNorm);
|
|
685
|
-
|
|
822
|
+
let start = 0;
|
|
823
|
+
const minLen = Math.min(oldLines.length, newLines.length);
|
|
824
|
+
while (start < minLen && oldLines[start] === newLines[start]) start++;
|
|
825
|
+
let endOld = oldLines.length;
|
|
826
|
+
let endNew = newLines.length;
|
|
827
|
+
while (start < endOld && start < endNew && oldLines[endOld - 1] === newLines[endNew - 1]) {
|
|
828
|
+
endOld--;
|
|
829
|
+
endNew--;
|
|
830
|
+
}
|
|
686
831
|
const rows = [];
|
|
687
832
|
let removed = 0;
|
|
688
833
|
let added = 0;
|
|
689
|
-
let
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
834
|
+
for (let i = 0; i < start; i++) rows.push({
|
|
835
|
+
kind: "context",
|
|
836
|
+
text: oldLines[i],
|
|
837
|
+
oldLine: i + 1,
|
|
838
|
+
newLine: i + 1
|
|
839
|
+
});
|
|
840
|
+
const midOld = oldLines.slice(start, endOld);
|
|
841
|
+
const midNew = newLines.slice(start, endNew);
|
|
842
|
+
if (midOld.length === 0 && midNew.length === 0) {} else if (midOld.length === 0) for (let j = 0; j < midNew.length; j++) {
|
|
843
|
+
rows.push({
|
|
844
|
+
kind: "add",
|
|
845
|
+
text: midNew[j],
|
|
846
|
+
oldLine: void 0,
|
|
847
|
+
newLine: start + j + 1
|
|
848
|
+
});
|
|
849
|
+
added++;
|
|
850
|
+
}
|
|
851
|
+
else if (midNew.length === 0) for (let i = 0; i < midOld.length; i++) {
|
|
852
|
+
rows.push({
|
|
853
|
+
kind: "del",
|
|
854
|
+
text: midOld[i],
|
|
855
|
+
oldLine: start + i + 1,
|
|
856
|
+
newLine: void 0
|
|
857
|
+
});
|
|
858
|
+
removed++;
|
|
859
|
+
}
|
|
860
|
+
else if (midOld.length * midNew.length > MIDDLE_CELL_CAP) {
|
|
861
|
+
const aligned = alignLargeMiddle(midOld, midNew, start);
|
|
862
|
+
rows.push(...aligned.rows);
|
|
863
|
+
removed += aligned.removed;
|
|
864
|
+
added += aligned.added;
|
|
865
|
+
} else {
|
|
866
|
+
const context = Math.max(1, midOld.length, midNew.length);
|
|
867
|
+
const patch = structuredPatch("", "", midOld.join("\n"), midNew.join("\n"), void 0, void 0, { context });
|
|
868
|
+
let oldLine = start;
|
|
869
|
+
let newLine = start;
|
|
870
|
+
for (const hunk of patch.hunks) for (const line of hunk.lines) {
|
|
871
|
+
if (line.startsWith("\\")) continue;
|
|
872
|
+
if (line.startsWith("-")) {
|
|
873
|
+
oldLine++;
|
|
874
|
+
rows.push({
|
|
875
|
+
kind: "del",
|
|
876
|
+
text: line.slice(1),
|
|
877
|
+
oldLine,
|
|
878
|
+
newLine: void 0
|
|
879
|
+
});
|
|
880
|
+
removed++;
|
|
881
|
+
} else if (line.startsWith("+")) {
|
|
882
|
+
newLine++;
|
|
883
|
+
rows.push({
|
|
884
|
+
kind: "add",
|
|
885
|
+
text: line.slice(1),
|
|
886
|
+
oldLine: void 0,
|
|
887
|
+
newLine
|
|
888
|
+
});
|
|
889
|
+
added++;
|
|
890
|
+
} else {
|
|
891
|
+
oldLine++;
|
|
892
|
+
newLine++;
|
|
893
|
+
rows.push({
|
|
894
|
+
kind: "context",
|
|
895
|
+
text: line.slice(1),
|
|
896
|
+
oldLine,
|
|
897
|
+
newLine
|
|
898
|
+
});
|
|
899
|
+
}
|
|
720
900
|
}
|
|
721
901
|
}
|
|
902
|
+
const suffixLen = oldLines.length - endOld;
|
|
903
|
+
for (let k = 0; k < suffixLen; k++) rows.push({
|
|
904
|
+
kind: "context",
|
|
905
|
+
text: oldLines[endOld + k],
|
|
906
|
+
oldLine: endOld + k + 1,
|
|
907
|
+
newLine: endNew + k + 1
|
|
908
|
+
});
|
|
909
|
+
normalizeChangeRuns(rows);
|
|
722
910
|
return {
|
|
723
911
|
rows,
|
|
724
912
|
removed,
|
|
@@ -7650,7 +7838,7 @@ window.__ModuleLoader__.load({
|
|
|
7650
7838
|
}
|
|
7651
7839
|
return { position: value.length };
|
|
7652
7840
|
}
|
|
7653
|
-
function parseColor(sequence) {
|
|
7841
|
+
function parseColor$1(sequence) {
|
|
7654
7842
|
const colorMode = sequence.shift();
|
|
7655
7843
|
if (colorMode === "2") {
|
|
7656
7844
|
const rgb = sequence.splice(0, 3).map((x) => Number.parseInt(x));
|
|
@@ -7700,7 +7888,7 @@ window.__ModuleLoader__.load({
|
|
|
7700
7888
|
}
|
|
7701
7889
|
});
|
|
7702
7890
|
else if (codeInt === 38) {
|
|
7703
|
-
const color = parseColor(sequence);
|
|
7891
|
+
const color = parseColor$1(sequence);
|
|
7704
7892
|
if (color) commands.push({
|
|
7705
7893
|
type: "setForegroundColor",
|
|
7706
7894
|
value: color
|
|
@@ -7714,7 +7902,7 @@ window.__ModuleLoader__.load({
|
|
|
7714
7902
|
}
|
|
7715
7903
|
});
|
|
7716
7904
|
else if (codeInt === 48) {
|
|
7717
|
-
const color = parseColor(sequence);
|
|
7905
|
+
const color = parseColor$1(sequence);
|
|
7718
7906
|
if (color) commands.push({
|
|
7719
7907
|
type: "setBackgroundColor",
|
|
7720
7908
|
value: color
|
|
@@ -12015,16 +12203,17 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12015
12203
|
return start === end ? String(start) : `${start}-${end}`;
|
|
12016
12204
|
}
|
|
12017
12205
|
/**
|
|
12018
|
-
* Build the
|
|
12019
|
-
*
|
|
12206
|
+
* Build the bare reference label for a selected line range — `path:range` with
|
|
12207
|
+
* no surrounding parentheses. Used for display (the status-bar copy control
|
|
12208
|
+
* shows the reference without the token-wrapping parens).
|
|
12020
12209
|
* @param path - the selected file's path.
|
|
12021
12210
|
* @param workspacePath - the current workspace root, or `undefined`.
|
|
12022
12211
|
* @param start - first selected line number.
|
|
12023
12212
|
* @param end - last selected line number.
|
|
12024
|
-
* @returns the `
|
|
12213
|
+
* @returns the `path:range` reference label.
|
|
12025
12214
|
*/
|
|
12026
|
-
function
|
|
12027
|
-
return
|
|
12215
|
+
function referenceLabelOf(path, workspacePath, start, end) {
|
|
12216
|
+
return `${referencePathOf(path, workspacePath)}:${lineRangeLabel(start, end)}`;
|
|
12028
12217
|
}
|
|
12029
12218
|
/**
|
|
12030
12219
|
* Map one referenced line range from `oldContent` coordinates to `newContent`
|
|
@@ -12091,6 +12280,132 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12091
12280
|
});
|
|
12092
12281
|
}
|
|
12093
12282
|
//#endregion
|
|
12283
|
+
//#region lib/types/client/produced-diff.js
|
|
12284
|
+
/**
|
|
12285
|
+
* Inject a "查看差异" button beside each DSH produced-file chip.
|
|
12286
|
+
*
|
|
12287
|
+
* The harness's `ProducedFiles` component renders each produced file as a
|
|
12288
|
+
* `<button>` chip inside `[data-produced-files-row]`; the full path rides the
|
|
12289
|
+
* chip's `title`. This plugin wants a quick "view this file's diff" affordance
|
|
12290
|
+
* there, but the plugin should not have to touch the harness component. So this
|
|
12291
|
+
* module watches the DOM for those chips (via a MutationObserver, the same
|
|
12292
|
+
* bridge the dsh-pocket mobile fork uses to inject its 复制 buttons) and injects
|
|
12293
|
+
* a small button after each one. Clicking it dispatches a window event that the
|
|
12294
|
+
* diff-approval panel listens for (see PendingPanel), which opens the panel and
|
|
12295
|
+
* selects the file when it is still pending, or toasts otherwise.
|
|
12296
|
+
*
|
|
12297
|
+
* The injected button is intentionally self-contained (inline styles + a fixed
|
|
12298
|
+
* label) so it needs no stylesheet and no harness change.
|
|
12299
|
+
*/
|
|
12300
|
+
/** Window event dispatched by the injected button; PendingPanel listens for it. */
|
|
12301
|
+
const OPEN_FILE_EVENT = "diff-approval:open-file";
|
|
12302
|
+
/** Marker set on a produced-file chip once its diff button has been injected. */
|
|
12303
|
+
const INJECTED_ATTR = "data-diff-approval-produced-diff";
|
|
12304
|
+
/** Marker set on the injected "查看差异" button itself (so cleanup can find it). */
|
|
12305
|
+
const BUTTON_ATTR = "data-diff-approval-produced-diff-btn";
|
|
12306
|
+
/** The produced-file chip selector (the container row itself is not needed). */
|
|
12307
|
+
const CHIP_SELECTOR = "[data-produced-files-row] button";
|
|
12308
|
+
/** Read the produced-file path from a chip (`title` carries the full path). */
|
|
12309
|
+
function producedPathOf(chip) {
|
|
12310
|
+
const path = chip.getAttribute("title")?.trim();
|
|
12311
|
+
return path === void 0 || path === "" ? void 0 : path;
|
|
12312
|
+
}
|
|
12313
|
+
/** Inline layout styles matching the file chip's measured values: the chip is
|
|
12314
|
+
* 22px tall / 6px radius / 0 8px inline padding on the `--dsw-alias-bg-base`
|
|
12315
|
+
* surface. `color` is inlined (the chip's gray text) so the icon is always right;
|
|
12316
|
+
* `background` (rest + a deeper hover) stays in the injected <style> rule.
|
|
12317
|
+
* `display` is set separately (see inject) to mirror the chip's visibility. */
|
|
12318
|
+
function buttonStyle() {
|
|
12319
|
+
return {
|
|
12320
|
+
flex: "none",
|
|
12321
|
+
marginLeft: "-4px",
|
|
12322
|
+
alignItems: "center",
|
|
12323
|
+
justifyContent: "center",
|
|
12324
|
+
boxSizing: "border-box",
|
|
12325
|
+
height: "22px",
|
|
12326
|
+
padding: "0 6px",
|
|
12327
|
+
border: "none",
|
|
12328
|
+
borderRadius: "6px",
|
|
12329
|
+
cursor: "pointer",
|
|
12330
|
+
color: "var(--dsw-alias-label-secondary)"
|
|
12331
|
+
};
|
|
12332
|
+
}
|
|
12333
|
+
/** The DSH "open / jump" icon (IconRightUpOutline16): a diagonal arrow pointing
|
|
12334
|
+
* top-right, i.e. the classic "navigate to / open" affordance — a clean, already
|
|
12335
|
+
* theme-consistent glyph to use instead of hand-drawing +/-. 16×16 matches the
|
|
12336
|
+
* harness's own action glyph; `currentColor` rides the chip's gray text. */
|
|
12337
|
+
const DIFF_ICON_SVG = "<svg width=\"7\" height=\"7\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\" focusable=\"false\" style=\"color:var(--dsw-alias-label-secondary)\"><path d=\"M13.588429 5.147807C13.588429 4.739638 13.587271 4.403003 13.582013 4.118684L1.703098 15.99968L0.85155 15.148178L0 14.294485L11.878915 2.413442C11.594721 2.408199 11.257569 2.409154 10.849776 2.409154H2.400594V0.000001H10.849776C11.644471 0.000001 12.338899 -0.001059 12.901622 0.059909C13.486363 0.123352 14.071136 0.265493 14.598303 0.648292C14.886598 0.857751 15.141981 1.110984 15.351433 1.399281C15.734578 1.926807 15.876362 2.512925 15.939743 3.098105C16.000775 3.660718 15.99968 4.353347 15.99968 5.147807V13.599133H13.588429V5.147807Z\" fill=\"currentColor\"/></svg>";
|
|
12338
|
+
/**
|
|
12339
|
+
* Start injecting diff buttons into the produced-files row.
|
|
12340
|
+
* @param label - localized "查看差异" text, used as the icon button's accessible
|
|
12341
|
+
* name + hover title (the button renders only an icon).
|
|
12342
|
+
* @param openPath - called with a produced-file path when its injected button is
|
|
12343
|
+
* clicked; the diff-approval panel decides whether that file is still pending.
|
|
12344
|
+
* @returns a cleanup that disconnects the observer and removes injected buttons.
|
|
12345
|
+
*/
|
|
12346
|
+
function startProducedDiffInjection(label, openPath) {
|
|
12347
|
+
let ownedStyleEl = null;
|
|
12348
|
+
if (document.querySelector("style[data-diff-approval-produced-diff]") === null) {
|
|
12349
|
+
ownedStyleEl = document.createElement("style");
|
|
12350
|
+
ownedStyleEl.setAttribute("data-diff-approval-produced-diff", "");
|
|
12351
|
+
ownedStyleEl.textContent = `[${BUTTON_ATTR}]{background:rgba(38, 49, 72, 0.06);}[${BUTTON_ATTR}]:hover{background:rgba(38, 49, 72, 0.14);}`;
|
|
12352
|
+
document.head.appendChild(ownedStyleEl);
|
|
12353
|
+
}
|
|
12354
|
+
const inject = () => {
|
|
12355
|
+
const chips = [...document.querySelectorAll(CHIP_SELECTOR)];
|
|
12356
|
+
for (const chip of chips) {
|
|
12357
|
+
const path = producedPathOf(chip);
|
|
12358
|
+
if (path === void 0) continue;
|
|
12359
|
+
if (chip.getAttribute(INJECTED_ATTR) === "1") continue;
|
|
12360
|
+
if ([...document.querySelectorAll(`[${BUTTON_ATTR}]`)].some((btn) => btn.getAttribute("data-path") === path)) {
|
|
12361
|
+
chip.setAttribute(INJECTED_ATTR, "1");
|
|
12362
|
+
continue;
|
|
12363
|
+
}
|
|
12364
|
+
chip.setAttribute(INJECTED_ATTR, "1");
|
|
12365
|
+
const btn = document.createElement("span");
|
|
12366
|
+
btn.setAttribute("role", "button");
|
|
12367
|
+
btn.setAttribute("tabindex", "0");
|
|
12368
|
+
btn.setAttribute(BUTTON_ATTR, "1");
|
|
12369
|
+
btn.setAttribute("data-path", path);
|
|
12370
|
+
btn.setAttribute("aria-label", `${label}: ${path}`);
|
|
12371
|
+
btn.setAttribute("title", `${label}: ${path}`);
|
|
12372
|
+
Object.assign(btn.style, buttonStyle());
|
|
12373
|
+
btn.innerHTML = DIFF_ICON_SVG;
|
|
12374
|
+
btn.addEventListener("click", (event) => {
|
|
12375
|
+
event.preventDefault();
|
|
12376
|
+
event.stopImmediatePropagation();
|
|
12377
|
+
openPath(path);
|
|
12378
|
+
});
|
|
12379
|
+
btn.addEventListener("keydown", (event) => {
|
|
12380
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
12381
|
+
event.preventDefault();
|
|
12382
|
+
openPath(path);
|
|
12383
|
+
}
|
|
12384
|
+
});
|
|
12385
|
+
chip.insertAdjacentElement("afterend", btn);
|
|
12386
|
+
}
|
|
12387
|
+
for (const btn of document.querySelectorAll(`[${BUTTON_ATTR}]`)) {
|
|
12388
|
+
const chip = btn.previousElementSibling;
|
|
12389
|
+
const chipHidden = chip !== null && getComputedStyle(chip).display === "none";
|
|
12390
|
+
btn.style.display = chipHidden ? "none" : "inline-flex";
|
|
12391
|
+
}
|
|
12392
|
+
};
|
|
12393
|
+
inject();
|
|
12394
|
+
const observer = new MutationObserver(() => inject());
|
|
12395
|
+
observer.observe(document.body, {
|
|
12396
|
+
childList: true,
|
|
12397
|
+
subtree: true
|
|
12398
|
+
});
|
|
12399
|
+
const onResize = () => inject();
|
|
12400
|
+
window.addEventListener("resize", onResize);
|
|
12401
|
+
return () => {
|
|
12402
|
+
observer.disconnect();
|
|
12403
|
+
window.removeEventListener("resize", onResize);
|
|
12404
|
+
document.querySelectorAll(`[${BUTTON_ATTR}]`).forEach((el) => el.remove());
|
|
12405
|
+
if (ownedStyleEl !== null) ownedStyleEl.remove();
|
|
12406
|
+
};
|
|
12407
|
+
}
|
|
12408
|
+
//#endregion
|
|
12094
12409
|
//#region lib/types/client/settings.js
|
|
12095
12410
|
/** Client preferences for the review panel, persisted in localStorage. */
|
|
12096
12411
|
const PASTE_ON_COPY_KEY = "diff-approval:paste-on-copy";
|
|
@@ -12098,6 +12413,10 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12098
12413
|
const TAB_WIDTH_KEY = "diff-approval:tab-size";
|
|
12099
12414
|
const SPLIT_MODE_KEY = "diff-approval:split-mode";
|
|
12100
12415
|
const NAV_LEAD_KEY = "diff-approval:nav-lead-rows";
|
|
12416
|
+
const DIFF_FONT_SCALE_KEY = "diff-approval:diff-font-scale";
|
|
12417
|
+
const DIFF_LINE_HEIGHT_KEY = "diff-approval:diff-line-height";
|
|
12418
|
+
const DIFF_ADD_COLOR_KEY = "diff-approval:diff-add-color";
|
|
12419
|
+
const DIFF_DEL_COLOR_KEY = "diff-approval:diff-del-color";
|
|
12101
12420
|
const WRAP_PREFIX = "diff-approval:wrap:";
|
|
12102
12421
|
/**
|
|
12103
12422
|
* Whether copying a reference should also paste it into the chat input and
|
|
@@ -12154,6 +12473,68 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12154
12473
|
localStorage.setItem(TAB_WIDTH_KEY, String(value));
|
|
12155
12474
|
}
|
|
12156
12475
|
/**
|
|
12476
|
+
* The diff code font size as a percentage of the current (theme) size. Defaults
|
|
12477
|
+
* to 100 (the current look); the settings UI steps it by ±10.
|
|
12478
|
+
* @returns the font-size scale, as a percentage (e.g. 100, 110, 90).
|
|
12479
|
+
*/
|
|
12480
|
+
function diffFontScale() {
|
|
12481
|
+
const raw = Number.parseInt(localStorage.getItem(DIFF_FONT_SCALE_KEY) ?? "", 10);
|
|
12482
|
+
if (!Number.isFinite(raw)) return 100;
|
|
12483
|
+
return Math.max(50, Math.min(200, raw));
|
|
12484
|
+
}
|
|
12485
|
+
/** Persist the diff's code font-size scale (a percentage). */
|
|
12486
|
+
function setDiffFontScale(value) {
|
|
12487
|
+
localStorage.setItem(DIFF_FONT_SCALE_KEY, String(Math.max(50, Math.min(200, value))));
|
|
12488
|
+
}
|
|
12489
|
+
/**
|
|
12490
|
+
* The diff code line height in px (the fixed row height the virtual window and
|
|
12491
|
+
* jump math are keyed to). Defaults to 22 (the pre-customization value).
|
|
12492
|
+
* @returns the line height in px.
|
|
12493
|
+
*/
|
|
12494
|
+
function diffLineHeight() {
|
|
12495
|
+
const raw = Number.parseInt(localStorage.getItem(DIFF_LINE_HEIGHT_KEY) ?? "", 10);
|
|
12496
|
+
if (!Number.isFinite(raw)) return 22;
|
|
12497
|
+
return Math.max(10, Math.min(36, raw));
|
|
12498
|
+
}
|
|
12499
|
+
/** Persist the diff's code line height (px). */
|
|
12500
|
+
function setDiffLineHeight(value) {
|
|
12501
|
+
localStorage.setItem(DIFF_LINE_HEIGHT_KEY, String(Math.max(10, Math.min(36, value))));
|
|
12502
|
+
}
|
|
12503
|
+
/** Read a theme CSS custom property, with a fallback when it is unavailable. */
|
|
12504
|
+
function themeColor(name, fallback) {
|
|
12505
|
+
if (typeof document !== "undefined") {
|
|
12506
|
+
const v = getComputedStyle(document.documentElement).getPropertyValue(name).trim();
|
|
12507
|
+
if (/^#[0-9a-f]{6}$/i.test(v)) return v;
|
|
12508
|
+
}
|
|
12509
|
+
return fallback;
|
|
12510
|
+
}
|
|
12511
|
+
/** The added-line base color the user chose, or `undefined` (theme color). */
|
|
12512
|
+
function diffAddColor() {
|
|
12513
|
+
const v = localStorage.getItem(DIFF_ADD_COLOR_KEY);
|
|
12514
|
+
return v !== null && v.length > 0 ? v : void 0;
|
|
12515
|
+
}
|
|
12516
|
+
/** Persist the added-line base color (a hex like `#22c55e`). */
|
|
12517
|
+
function setDiffAddColor(value) {
|
|
12518
|
+
localStorage.setItem(DIFF_ADD_COLOR_KEY, value);
|
|
12519
|
+
}
|
|
12520
|
+
/** The removed-line base color the user chose, or `undefined` (theme color). */
|
|
12521
|
+
function diffDelColor() {
|
|
12522
|
+
const v = localStorage.getItem(DIFF_DEL_COLOR_KEY);
|
|
12523
|
+
return v !== null && v.length > 0 ? v : void 0;
|
|
12524
|
+
}
|
|
12525
|
+
/** Persist the removed-line base color (a hex like `#ef4444`). */
|
|
12526
|
+
function setDiffDelColor(value) {
|
|
12527
|
+
localStorage.setItem(DIFF_DEL_COLOR_KEY, value);
|
|
12528
|
+
}
|
|
12529
|
+
/** The theme's added-line base color, for the settings swatch default. */
|
|
12530
|
+
function currentDiffAddColor() {
|
|
12531
|
+
return themeColor("--dsw-alias-state-success-primary", "#22c55e");
|
|
12532
|
+
}
|
|
12533
|
+
/** The theme's removed-line base color, for the settings swatch default. */
|
|
12534
|
+
function currentDiffDelColor() {
|
|
12535
|
+
return themeColor("--dsw-alias-state-error-primary", "#ef4444");
|
|
12536
|
+
}
|
|
12537
|
+
/**
|
|
12157
12538
|
* Whether the whole-file diff view uses the two-column (side-by-side) layout.
|
|
12158
12539
|
* Default off (single column): the unified diff. Only an explicit `'1'` enables
|
|
12159
12540
|
* split mode.
|
|
@@ -12194,6 +12575,29 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12194
12575
|
function setQuickSummonKey(value) {
|
|
12195
12576
|
localStorage.setItem(QUICK_SUMMON_KEY, value);
|
|
12196
12577
|
}
|
|
12578
|
+
const KEY_PREFIX = "diff-approval:key:";
|
|
12579
|
+
/** Default chord for each configurable action (every supported key except the
|
|
12580
|
+
* panel's own ESC-to-close, which is intentionally not remapped). */
|
|
12581
|
+
const DEFAULT_KEYBINDINGS = {
|
|
12582
|
+
jumpUp: "Ctrl+ArrowUp",
|
|
12583
|
+
jumpDown: "Ctrl+ArrowDown",
|
|
12584
|
+
copyRef: "Ctrl+L",
|
|
12585
|
+
openSearch: "Ctrl+F",
|
|
12586
|
+
searchNext: "F3",
|
|
12587
|
+
searchPrev: "Shift+F3",
|
|
12588
|
+
undo: "Ctrl+Z",
|
|
12589
|
+
redo: "Ctrl+Shift+Z",
|
|
12590
|
+
cycleNext: "Ctrl+Tab",
|
|
12591
|
+
cyclePrev: "Ctrl+Shift+Tab"
|
|
12592
|
+
};
|
|
12593
|
+
/** The currently configured chord for one action; falls back to its default. */
|
|
12594
|
+
function keybindingOf(action) {
|
|
12595
|
+
return localStorage.getItem(`${KEY_PREFIX}${action}`) ?? DEFAULT_KEYBINDINGS[action] ?? "";
|
|
12596
|
+
}
|
|
12597
|
+
/** Persist one action's chord. */
|
|
12598
|
+
function setKeybinding(action, chord) {
|
|
12599
|
+
localStorage.setItem(`${KEY_PREFIX}${action}`, chord);
|
|
12600
|
+
}
|
|
12197
12601
|
/**
|
|
12198
12602
|
* Whether a keyboard event matches a chord string like `Ctrl+D`. Modifier
|
|
12199
12603
|
* names are matched case-insensitively (`Ctrl`/`Control`, `Alt`/`Option`,
|
|
@@ -12216,7 +12620,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12216
12620
|
}
|
|
12217
12621
|
//#endregion
|
|
12218
12622
|
//#region \0dsh-css:/home/runner/work/dsh-diff-approval/dsh-diff-approval/src/client/PendingPanel.module.css.mjs
|
|
12219
|
-
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_toggle{border:1px solid var(--dsw-alias-border-l2);cursor:pointer;background:0 0;border-radius:18px;flex:none;width:60px;height:36px;padding:0;position:relative}.F1KBNa_toggle:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_toggle:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}.F1KBNa_toggleOn{border-color:var(--dsw-alias-state-business-primary);background:var(--dsw-alias-state-business-primary)}.F1KBNa_toggleOn:hover{background:var(--dsw-alias-state-business-primary)}.F1KBNa_toggleThumb{background:var(--dsw-alias-label-primary);border-radius:50%;width:28px;height:28px;transition:left .12s;position:absolute;top:3px;left:3px}.F1KBNa_toggleOn .F1KBNa_toggleThumb{background:#fff;left:27px}.F1KBNa_stepper{align-items:center;gap:6px;display:inline-flex}.F1KBNa_stepperButton{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-module-platform);width:32px;height:32px;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;border-radius:8px;font-size:16px;line-height:1}.F1KBNa_stepperButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_stepperButton:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.F1KBNa_stepperValue{text-align:center;min-width:2ch;color:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums;font-size:14px;line-height:22px}.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_confirmBackdrop{z-index:5;background:color-mix(in srgb, var(--dsw-alias-bg-base) 55%, transparent);justify-content:center;align-items:center;padding:24px;display:flex;position:absolute;inset:0}.F1KBNa_confirmCard{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);max-width:340px;box-shadow:var(--dsw-shadow-lv3);border-radius:12px;flex-direction:column;gap:12px;padding:16px;display:flex}.F1KBNa_confirmText{font:var(--dsw-font-caption);color:var(--dsw-alias-label-primary);overflow-wrap:anywhere;margin:0;line-height:1.5}.F1KBNa_confirmActions{justify-content:flex-end;gap:8px;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{white-space:nowrap;min-width:0;color:var(--dsw-alias-label-primary);font:var(--dsw-font-markdown-code-block);-webkit-user-select:text;user-select:text;flex:1;font-size:12px;line-height:18px;overflow:auto 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_divider{background:var(--dsw-alias-border-l1);align-self:stretch;width:1px;margin:2px 0}.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);-webkit-text-size-adjust:100%;text-size-adjust:100%;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{-webkit-user-select:none;user-select:none;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;-webkit-user-select:none;user-select:none;cursor:default;padding-right:10px;display:table-cell}.F1KBNa_code{white-space:pre;-webkit-user-select:text;user-select:text;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)}.F1KBNa_intraDel{background-color:color-mix(in srgb, var(--dsw-alias-state-error-primary) 26%, transparent);text-decoration:line-through}.F1KBNa_intraAdd{background-color:color-mix(in srgb, var(--dsw-alias-state-success-primary) 24%, transparent)}";
|
|
12623
|
+
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_settingsGroup{border-bottom:1px solid var(--dsw-alias-border-l2);margin-top:8px}.F1KBNa_settingsGroupHeader{width:100%;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;text-align:left;background:0 0;border:none;align-items:center;gap:8px;padding:12px 0;display:flex}.F1KBNa_settingsGroupText{text-align:left;flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.F1KBNa_settingsGroupTitle{font-size:14px;font-weight:400;line-height:22px}.F1KBNa_settingsGroupDesc{color:var(--dsw-alias-label-tertiary);font-size:12px;font-weight:400;line-height:18px}.F1KBNa_settingsGroupChevron{margin-left:auto;transition:transform .15s}.F1KBNa_settingsGroup[data-open] .F1KBNa_settingsGroupChevron{transform:rotate(180deg)}.F1KBNa_settingsGroup[data-open] .F1KBNa_settingsGroupHeader{border-bottom:1px solid var(--dsw-alias-border-l2)}.F1KBNa_settingsGroupBody{flex-direction:column;display:flex}.F1KBNa_settingsGroupBody .F1KBNa_settingsRow{padding-left:16px}.F1KBNa_settingsGroupBody .F1KBNa_settingsRow:last-child,.F1KBNa_settingsPage>.F1KBNa_settingsRow:last-child{border-bottom:none}.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_colorPicker{position:relative}.F1KBNa_colorPickerTrigger{background:var(--dsw-alias-bg-module-platform);width:120px;height:36px;font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;border:none;border-radius:18px;align-items:center;gap:8px;padding:0 8px;font-size:12px;line-height:18px;display:inline-flex}.F1KBNa_colorPickerTrigger:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_colorSwatch{border:1px solid var(--dsw-alias-border-l2);border-radius:50%;flex:none;width:24px;height:24px}.F1KBNa_colorValue{text-overflow:ellipsis;white-space:nowrap;font-variant-numeric:tabular-nums;flex:1;min-width:0;overflow:hidden}.F1KBNa_colorPickerChevron{flex:none}.F1KBNa_colorBackdrop{z-index:40;position:fixed;inset:0}.F1KBNa_colorPickerPopover{z-index:41;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);box-shadow:var(--dsw-shadow-lv2);border-radius:10px;padding:10px;position:absolute;top:calc(100% + 6px);right:0}.F1KBNa_colorPickerPanel{flex-direction:column;gap:8px;display:flex}.F1KBNa_colorPickerInputRow{align-items:center;gap:8px;display:flex}.F1KBNa_colorPickerPreview{border:1px solid var(--dsw-alias-border-l2);border-radius:6px;flex:none;width:22px;height:22px}.F1KBNa_colorPickerInput{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-module-platform);min-width:0;height:30px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;flex:1;padding:0 8px;font-size:12px;line-height:28px}.F1KBNa_colorPickerInput:focus{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:-1px}.F1KBNa_colorSv{border:1px solid var(--dsw-alias-border-l1);cursor:crosshair;touch-action:none;border-radius:8px;height:140px;position:relative}.F1KBNa_colorSvCursor{pointer-events:none;border:2px solid #fff;border-radius:50%;width:14px;height:14px;position:absolute;transform:translate(-50%,-50%);box-shadow:0 0 0 1px #00000080}.F1KBNa_colorHue{border:1px solid var(--dsw-alias-border-l1);cursor:pointer;touch-action:none;border-radius:7px;height:14px;position:relative}.F1KBNa_colorHueCursor{pointer-events:none;border:2px solid #fff;border-radius:50%;width:16px;height:16px;position:absolute;top:50%;transform:translate(-50%,-50%);box-shadow:0 0 0 1px #00000080}.F1KBNa_diffPreview{z-index:2;border:1px solid var(--dsw-alias-border-l1);font:var(--dsw-font-markdown-code-block);background:var(--dsw-alias-markdown-code-block);border-radius:8px;margin-bottom:8px;padding:8px;position:sticky;top:0;overflow:hidden}.F1KBNa_diffPreviewTitle{color:var(--dsw-alias-label-tertiary);margin-bottom:6px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_diffPreviewScroll{height:132px;overflow-y:auto}.F1KBNa_toggle{border:1px solid var(--dsw-alias-border-l2);cursor:pointer;background:0 0;border-radius:18px;flex:none;width:60px;height:36px;padding:0;position:relative}.F1KBNa_toggle:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_toggle:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}.F1KBNa_toggleOn{border-color:var(--dsw-alias-state-business-primary);background:var(--dsw-alias-state-business-primary)}.F1KBNa_toggleOn:hover{background:var(--dsw-alias-state-business-primary)}.F1KBNa_toggleThumb{background:var(--dsw-alias-label-primary);border-radius:50%;width:28px;height:28px;transition:left .12s;position:absolute;top:3px;left:3px}.F1KBNa_toggleOn .F1KBNa_toggleThumb{background:#fff;left:27px}.F1KBNa_stepper{align-items:center;gap:6px;display:inline-flex}.F1KBNa_stepperButton{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-module-platform);width:32px;height:32px;color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:8px;padding:0;position:relative}.F1KBNa_stepperButton:before,.F1KBNa_stepperButton:after{content:\"\";background:currentColor;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}.F1KBNa_stepperButton:before{width:10px;height:1px}.F1KBNa_stepperButton:after{width:1px;height:10px;display:none}.F1KBNa_stepperButtonUp:after{display:block}.F1KBNa_stepperButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_stepperButton:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.F1KBNa_stepperValue{text-align:center;min-width:2ch;color:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums;font-size:14px;line-height:22px}.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_confirmBackdrop{z-index:5;background:color-mix(in srgb, var(--dsw-alias-bg-base) 55%, transparent);justify-content:center;align-items:center;padding:24px;display:flex;position:absolute;inset:0}.F1KBNa_confirmCard{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);max-width:340px;box-shadow:var(--dsw-shadow-lv3);border-radius:12px;flex-direction:column;gap:12px;padding:16px;display:flex}.F1KBNa_confirmText{font:var(--dsw-font-caption);color:var(--dsw-alias-label-primary);overflow-wrap:anywhere;margin:0;line-height:1.5}.F1KBNa_confirmActions{justify-content:flex-end;gap:8px;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(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 60%, var(--dsw-alias-label-primary))}.F1KBNa_delCount{color:color-mix(in srgb, var(--dsh-diff-del-color,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{white-space:nowrap;min-width:0;color:var(--dsw-alias-label-primary);font:var(--dsw-font-markdown-code-block);-webkit-user-select:text;user-select:text;flex:1;font-size:12px;line-height:18px;overflow:auto 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_divider{background:var(--dsw-alias-border-l1);align-self:stretch;width:1px;margin:2px 0}.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);-webkit-text-size-adjust:100%;text-size-adjust:100%;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_searchMatch{background-color:#facc1542;border-radius:2px}.F1KBNa_searchMatchCurrent{background-color:#facc1599;border-radius:2px}.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_diffFlashFade;position:absolute;left:0;right:0}.F1KBNa_blockFlashShake{animation:.7s ease-out forwards F1KBNa_diffFlashShake}@keyframes F1KBNa_diffFlashFade{0%{opacity:1}to{opacity:0}}@keyframes F1KBNa_diffFlashShake{0%{opacity:1;transform:translateY(0)}10%{transform:translateY(1px)}20%{transform:translateY(-1px)}30%{transform:translateY(1px)}40%{transform:translateY(-1px)}50%{transform:translateY(1px)}60%{transform:translateY(-1px)}70%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(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%;font-size:calc(1em * var(--dsh-diff-font-scale,1));display:table}.F1KBNa_line{height:var(--dsh-diff-line-height,22px);line-height:var(--dsh-diff-line-height,22px);-webkit-user-select:none;user-select:none;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;-webkit-user-select:none;user-select:none;cursor:default;padding-right:10px;display:table-cell}.F1KBNa_code{white-space:pre;-webkit-user-select:text;user-select:text;display:table-cell}.F1KBNa_context{color:var(--dsw-alias-label-primary)}.F1KBNa_del{background-color:color-mix(in srgb, var(--dsh-diff-del-color,var(--dsw-alias-state-error-primary)) 12%, transparent)}.F1KBNa_add{background-color:color-mix(in srgb, var(--dsh-diff-add-color,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:var(--dsh-diff-line-height,22px)}.F1KBNa_subline{height:var(--dsh-diff-line-height,22px);line-height:var(--dsh-diff-line-height,22px);white-space:pre;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(--dsh-diff-del-color,var(--dsw-alias-state-error-primary)) 12%, transparent)}.F1KBNa_splitLadd{background-color:color-mix(in srgb, var(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 10%, transparent)}.F1KBNa_splitRdel{background-color:color-mix(in srgb, var(--dsh-diff-del-color,var(--dsw-alias-state-error-primary)) 12%, transparent)}.F1KBNa_splitRadd{background-color:color-mix(in srgb, var(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 10%, transparent)}.F1KBNa_intraDel{background-color:color-mix(in srgb, var(--dsh-diff-del-color,var(--dsw-alias-state-error-primary)) 26%, transparent);text-decoration:line-through}.F1KBNa_intraAdd{background-color:color-mix(in srgb, var(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 24%, transparent)}";
|
|
12220
12624
|
const tagId = "dsh-diff-approval/PendingPanel.module.css";
|
|
12221
12625
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
12222
12626
|
const tag = document.createElement("style");
|
|
@@ -12226,124 +12630,154 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12226
12630
|
document.head.appendChild(tag);
|
|
12227
12631
|
}
|
|
12228
12632
|
var PendingPanel_module_css_default = {
|
|
12229
|
-
"
|
|
12230
|
-
"
|
|
12231
|
-
"
|
|
12232
|
-
"
|
|
12233
|
-
"badgeLabel": "F1KBNa_badgeLabel",
|
|
12234
|
-
"panel": "F1KBNa_panel",
|
|
12235
|
-
"hint": "F1KBNa_hint",
|
|
12236
|
-
"importButton": "F1KBNa_importButton",
|
|
12237
|
-
"addCount": "F1KBNa_addCount",
|
|
12238
|
-
"rowPath": "F1KBNa_rowPath",
|
|
12239
|
-
"searchInput": "F1KBNa_searchInput",
|
|
12240
|
-
"title": "F1KBNa_title",
|
|
12241
|
-
"actionPrimary": "F1KBNa_actionPrimary",
|
|
12242
|
-
"blockActions": "F1KBNa_blockActions",
|
|
12243
|
-
"del": "F1KBNa_del",
|
|
12244
|
-
"importNote": "F1KBNa_importNote",
|
|
12245
|
-
"diffBodySplit": "F1KBNa_diffBodySplit",
|
|
12246
|
-
"splitCols": "F1KBNa_splitCols",
|
|
12247
|
-
"note": "F1KBNa_note",
|
|
12248
|
-
"divergedHint": "F1KBNa_divergedHint",
|
|
12249
|
-
"noteCentered": "F1KBNa_noteCentered",
|
|
12250
|
-
"kindHint": "F1KBNa_kindHint",
|
|
12633
|
+
"confirmBackdrop": "F1KBNa_confirmBackdrop",
|
|
12634
|
+
"statusBar": "F1KBNa_statusBar",
|
|
12635
|
+
"layer": "F1KBNa_layer",
|
|
12636
|
+
"flexSpacer": "F1KBNa_flexSpacer",
|
|
12251
12637
|
"fileListFloat": "F1KBNa_fileListFloat",
|
|
12638
|
+
"searchBar": "F1KBNa_searchBar",
|
|
12639
|
+
"splitHScrollRow": "F1KBNa_splitHScrollRow",
|
|
12640
|
+
"intraAdd": "F1KBNa_intraAdd",
|
|
12641
|
+
"settingsRowDesc": "F1KBNa_settingsRowDesc",
|
|
12642
|
+
"settingsRow": "F1KBNa_settingsRow",
|
|
12252
12643
|
"toggleOn": "F1KBNa_toggleOn",
|
|
12253
|
-
"
|
|
12644
|
+
"noteCentered": "F1KBNa_noteCentered",
|
|
12645
|
+
"colorPickerInput": "F1KBNa_colorPickerInput",
|
|
12646
|
+
"divider": "F1KBNa_divider",
|
|
12647
|
+
"del": "F1KBNa_del",
|
|
12648
|
+
"emptyState": "F1KBNa_emptyState",
|
|
12649
|
+
"settingsGroup": "F1KBNa_settingsGroup",
|
|
12650
|
+
"expand": "F1KBNa_expand",
|
|
12651
|
+
"diffFlashFade": "F1KBNa_diffFlashFade",
|
|
12652
|
+
"vSpacer": "F1KBNa_vSpacer",
|
|
12653
|
+
"settingsPage": "F1KBNa_settingsPage",
|
|
12254
12654
|
"kindTag": "F1KBNa_kindTag",
|
|
12255
|
-
"
|
|
12256
|
-
"
|
|
12257
|
-
"
|
|
12258
|
-
"
|
|
12259
|
-
"
|
|
12655
|
+
"splitRoot": "F1KBNa_splitRoot",
|
|
12656
|
+
"searchMatch": "F1KBNa_searchMatch",
|
|
12657
|
+
"rowMeta": "F1KBNa_rowMeta",
|
|
12658
|
+
"splitDivider": "F1KBNa_splitDivider",
|
|
12659
|
+
"colorSv": "F1KBNa_colorSv",
|
|
12660
|
+
"iconAction": "F1KBNa_iconAction",
|
|
12260
12661
|
"blockPosition": "F1KBNa_blockPosition",
|
|
12261
|
-
"
|
|
12262
|
-
"
|
|
12263
|
-
"
|
|
12264
|
-
"
|
|
12265
|
-
"
|
|
12266
|
-
"
|
|
12267
|
-
"
|
|
12268
|
-
"
|
|
12662
|
+
"stepperValue": "F1KBNa_stepperValue",
|
|
12663
|
+
"kindHint": "F1KBNa_kindHint",
|
|
12664
|
+
"colorValue": "F1KBNa_colorValue",
|
|
12665
|
+
"toggle": "F1KBNa_toggle",
|
|
12666
|
+
"diffPreviewScroll": "F1KBNa_diffPreviewScroll",
|
|
12667
|
+
"row": "F1KBNa_row",
|
|
12668
|
+
"gutter": "F1KBNa_gutter",
|
|
12669
|
+
"actionPrimary": "F1KBNa_actionPrimary",
|
|
12670
|
+
"noticeButton": "F1KBNa_noticeButton",
|
|
12671
|
+
"wrapActive": "F1KBNa_wrapActive",
|
|
12672
|
+
"markerAdd": "F1KBNa_markerAdd",
|
|
12269
12673
|
"stepperButton": "F1KBNa_stepperButton",
|
|
12270
|
-
"
|
|
12271
|
-
"
|
|
12674
|
+
"colorBackdrop": "F1KBNa_colorBackdrop",
|
|
12675
|
+
"wrap": "F1KBNa_wrap",
|
|
12676
|
+
"markerDel": "F1KBNa_markerDel",
|
|
12677
|
+
"actionError": "F1KBNa_actionError",
|
|
12678
|
+
"missingHint": "F1KBNa_missingHint",
|
|
12679
|
+
"settingsGroupTitle": "F1KBNa_settingsGroupTitle",
|
|
12680
|
+
"searchMatchCurrent": "F1KBNa_searchMatchCurrent",
|
|
12681
|
+
"addCount": "F1KBNa_addCount",
|
|
12682
|
+
"searchInput": "F1KBNa_searchInput",
|
|
12683
|
+
"footerButtons": "F1KBNa_footerButtons",
|
|
12684
|
+
"colorPickerPanel": "F1KBNa_colorPickerPanel",
|
|
12685
|
+
"rail": "F1KBNa_rail",
|
|
12272
12686
|
"close": "F1KBNa_close",
|
|
12273
|
-
"
|
|
12274
|
-
"
|
|
12275
|
-
"
|
|
12687
|
+
"noticeText": "F1KBNa_noticeText",
|
|
12688
|
+
"confirmCard": "F1KBNa_confirmCard",
|
|
12689
|
+
"intraDel": "F1KBNa_intraDel",
|
|
12690
|
+
"header": "F1KBNa_header",
|
|
12691
|
+
"settingsSelectorChevron": "F1KBNa_settingsSelectorChevron",
|
|
12692
|
+
"blockActions": "F1KBNa_blockActions",
|
|
12276
12693
|
"splitHScroll": "F1KBNa_splitHScroll",
|
|
12277
|
-
"
|
|
12278
|
-
"
|
|
12694
|
+
"splitRadd": "F1KBNa_splitRadd",
|
|
12695
|
+
"rowFailed": "F1KBNa_rowFailed",
|
|
12696
|
+
"badge": "F1KBNa_badge",
|
|
12697
|
+
"settingsSelector": "F1KBNa_settingsSelector",
|
|
12698
|
+
"badgeCount": "F1KBNa_badgeCount",
|
|
12279
12699
|
"readError": "F1KBNa_readError",
|
|
12700
|
+
"importNote": "F1KBNa_importNote",
|
|
12280
12701
|
"statusAction": "F1KBNa_statusAction",
|
|
12702
|
+
"title": "F1KBNa_title",
|
|
12703
|
+
"notice": "F1KBNa_notice",
|
|
12704
|
+
"bulkActions": "F1KBNa_bulkActions",
|
|
12705
|
+
"blockFlash": "F1KBNa_blockFlash",
|
|
12706
|
+
"rowHead": "F1KBNa_rowHead",
|
|
12707
|
+
"colorSwatch": "F1KBNa_colorSwatch",
|
|
12708
|
+
"split": "F1KBNa_split",
|
|
12709
|
+
"panel": "F1KBNa_panel",
|
|
12281
12710
|
"diffStats": "F1KBNa_diffStats",
|
|
12282
|
-
"
|
|
12283
|
-
"
|
|
12284
|
-
"
|
|
12285
|
-
"confirmCard": "F1KBNa_confirmCard",
|
|
12286
|
-
"group": "F1KBNa_group",
|
|
12711
|
+
"detail": "F1KBNa_detail",
|
|
12712
|
+
"code": "F1KBNa_code",
|
|
12713
|
+
"settingsGroupChevron": "F1KBNa_settingsGroupChevron",
|
|
12287
12714
|
"settingsRowText": "F1KBNa_settingsRowText",
|
|
12288
|
-
"
|
|
12289
|
-
"
|
|
12290
|
-
"
|
|
12291
|
-
"
|
|
12292
|
-
"
|
|
12293
|
-
"
|
|
12715
|
+
"actionQuietDisabled": "F1KBNa_actionQuietDisabled",
|
|
12716
|
+
"splitHScrollFill": "F1KBNa_splitHScrollFill",
|
|
12717
|
+
"toggleThumb": "F1KBNa_toggleThumb",
|
|
12718
|
+
"line": "F1KBNa_line",
|
|
12719
|
+
"detailEmpty": "F1KBNa_detailEmpty",
|
|
12720
|
+
"colorSvCursor": "F1KBNa_colorSvCursor",
|
|
12721
|
+
"splitCol": "F1KBNa_splitCol",
|
|
12722
|
+
"colorPickerTrigger": "F1KBNa_colorPickerTrigger",
|
|
12723
|
+
"confirmText": "F1KBNa_confirmText",
|
|
12724
|
+
"colorPickerChevron": "F1KBNa_colorPickerChevron",
|
|
12725
|
+
"fileList": "F1KBNa_fileList",
|
|
12294
12726
|
"listScroll": "F1KBNa_listScroll",
|
|
12295
|
-
"
|
|
12296
|
-
"
|
|
12727
|
+
"confirmActions": "F1KBNa_confirmActions",
|
|
12728
|
+
"headerActions": "F1KBNa_headerActions",
|
|
12729
|
+
"importButton": "F1KBNa_importButton",
|
|
12730
|
+
"settingsGroupHeader": "F1KBNa_settingsGroupHeader",
|
|
12731
|
+
"diffBodyWrap": "F1KBNa_diffBodyWrap",
|
|
12732
|
+
"diffPreviewTitle": "F1KBNa_diffPreviewTitle",
|
|
12733
|
+
"note": "F1KBNa_note",
|
|
12734
|
+
"rows": "F1KBNa_rows",
|
|
12735
|
+
"diffHeader": "F1KBNa_diffHeader",
|
|
12736
|
+
"hint": "F1KBNa_hint",
|
|
12737
|
+
"fullscreenBackdrop": "F1KBNa_fullscreenBackdrop",
|
|
12738
|
+
"searchCount": "F1KBNa_searchCount",
|
|
12739
|
+
"splitRdel": "F1KBNa_splitRdel",
|
|
12740
|
+
"colorHueCursor": "F1KBNa_colorHueCursor",
|
|
12741
|
+
"lines": "F1KBNa_lines",
|
|
12742
|
+
"stepperButtonUp": "F1KBNa_stepperButtonUp",
|
|
12743
|
+
"delCount": "F1KBNa_delCount",
|
|
12744
|
+
"resizeHandle": "F1KBNa_resizeHandle",
|
|
12297
12745
|
"splitLdel": "F1KBNa_splitLdel",
|
|
12298
|
-
"
|
|
12299
|
-
"rowHead": "F1KBNa_rowHead",
|
|
12300
|
-
"action": "F1KBNa_action",
|
|
12301
|
-
"toggle": "F1KBNa_toggle",
|
|
12302
|
-
"code": "F1KBNa_code",
|
|
12303
|
-
"resizeHandle": "F1KBNa_resizeHandle",
|
|
12304
|
-
"intraAdd": "F1KBNa_intraAdd",
|
|
12305
|
-
"layer": "F1KBNa_layer",
|
|
12306
|
-
"settingsPage": "F1KBNa_settingsPage",
|
|
12307
|
-
"fileList": "F1KBNa_fileList",
|
|
12308
|
-
"rowFailed": "F1KBNa_rowFailed",
|
|
12309
|
-
"gutter": "F1KBNa_gutter",
|
|
12310
|
-
"wrapActive": "F1KBNa_wrapActive",
|
|
12311
|
-
"blockFlash": "F1KBNa_blockFlash",
|
|
12312
|
-
"splitHScrollFill": "F1KBNa_splitHScrollFill",
|
|
12313
|
-
"noticeText": "F1KBNa_noticeText",
|
|
12314
|
-
"emptyState": "F1KBNa_emptyState",
|
|
12315
|
-
"bulkActions": "F1KBNa_bulkActions",
|
|
12316
|
-
"diffHeader": "F1KBNa_diffHeader",
|
|
12317
|
-
"markerAdd": "F1KBNa_markerAdd",
|
|
12318
|
-
"intraDel": "F1KBNa_intraDel",
|
|
12319
|
-
"splitHScrollRow": "F1KBNa_splitHScrollRow",
|
|
12320
|
-
"header": "F1KBNa_header",
|
|
12321
|
-
"splitLadd": "F1KBNa_splitLadd",
|
|
12322
|
-
"notice": "F1KBNa_notice",
|
|
12323
|
-
"confirmText": "F1KBNa_confirmText",
|
|
12324
|
-
"diffBodyWrap": "F1KBNa_diffBodyWrap",
|
|
12325
|
-
"line": "F1KBNa_line",
|
|
12326
|
-
"noticeButton": "F1KBNa_noticeButton",
|
|
12327
|
-
"lines": "F1KBNa_lines",
|
|
12328
|
-
"confirmBackdrop": "F1KBNa_confirmBackdrop",
|
|
12329
|
-
"searchCount": "F1KBNa_searchCount",
|
|
12330
|
-
"stepperValue": "F1KBNa_stepperValue",
|
|
12331
|
-
"split": "F1KBNa_split",
|
|
12332
|
-
"splitCol": "F1KBNa_splitCol",
|
|
12333
|
-
"splitDivider": "F1KBNa_splitDivider",
|
|
12334
|
-
"badgeCount": "F1KBNa_badgeCount",
|
|
12335
|
-
"detail": "F1KBNa_detail",
|
|
12336
|
-
"searchBar": "F1KBNa_searchBar",
|
|
12746
|
+
"missing": "F1KBNa_missing",
|
|
12337
12747
|
"add": "F1KBNa_add",
|
|
12338
|
-
"
|
|
12339
|
-
"
|
|
12340
|
-
"stepper": "F1KBNa_stepper",
|
|
12341
|
-
"diff": "F1KBNa_diff",
|
|
12748
|
+
"states": "F1KBNa_states",
|
|
12749
|
+
"colorPicker": "F1KBNa_colorPicker",
|
|
12342
12750
|
"expandExpanded": "F1KBNa_expandExpanded",
|
|
12343
|
-
"
|
|
12344
|
-
"
|
|
12345
|
-
"
|
|
12346
|
-
"
|
|
12751
|
+
"diffFlashShake": "F1KBNa_diffFlashShake",
|
|
12752
|
+
"splitLadd": "F1KBNa_splitLadd",
|
|
12753
|
+
"subline": "F1KBNa_subline",
|
|
12754
|
+
"blockFlashShake": "F1KBNa_blockFlashShake",
|
|
12755
|
+
"langSelect": "F1KBNa_langSelect",
|
|
12756
|
+
"settingsGroupBody": "F1KBNa_settingsGroupBody",
|
|
12757
|
+
"colorPickerPreview": "F1KBNa_colorPickerPreview",
|
|
12758
|
+
"diffPreview": "F1KBNa_diffPreview",
|
|
12759
|
+
"rowPath": "F1KBNa_rowPath",
|
|
12760
|
+
"overviewMarker": "F1KBNa_overviewMarker",
|
|
12761
|
+
"colorPickerPopover": "F1KBNa_colorPickerPopover",
|
|
12762
|
+
"settingsRowTitle": "F1KBNa_settingsRowTitle",
|
|
12763
|
+
"badgeLabel": "F1KBNa_badgeLabel",
|
|
12764
|
+
"colorPickerInputRow": "F1KBNa_colorPickerInputRow",
|
|
12765
|
+
"colorHue": "F1KBNa_colorHue",
|
|
12766
|
+
"action": "F1KBNa_action",
|
|
12767
|
+
"group": "F1KBNa_group",
|
|
12768
|
+
"langLabel": "F1KBNa_langLabel",
|
|
12769
|
+
"diffBody": "F1KBNa_diffBody",
|
|
12770
|
+
"diffBodySplit": "F1KBNa_diffBodySplit",
|
|
12771
|
+
"divergedHint": "F1KBNa_divergedHint",
|
|
12772
|
+
"settingsGroupText": "F1KBNa_settingsGroupText",
|
|
12773
|
+
"diff": "F1KBNa_diff",
|
|
12774
|
+
"diffPath": "F1KBNa_diffPath",
|
|
12775
|
+
"settingsGroupDesc": "F1KBNa_settingsGroupDesc",
|
|
12776
|
+
"diffActions": "F1KBNa_diffActions",
|
|
12777
|
+
"stepper": "F1KBNa_stepper",
|
|
12778
|
+
"overviewRuler": "F1KBNa_overviewRuler",
|
|
12779
|
+
"context": "F1KBNa_context",
|
|
12780
|
+
"splitCols": "F1KBNa_splitCols"
|
|
12347
12781
|
};
|
|
12348
12782
|
//#endregion
|
|
12349
12783
|
//#region lib/types/client/PendingPanel.js
|
|
@@ -12377,12 +12811,29 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12377
12811
|
const MAX_LIST_WIDTH_PX = 560;
|
|
12378
12812
|
/** Inset of the floating file-list card from the code scroll box, in px. */
|
|
12379
12813
|
const FLOAT_LIST_MARGIN_PX = 12;
|
|
12380
|
-
/**
|
|
12381
|
-
|
|
12382
|
-
|
|
12383
|
-
|
|
12384
|
-
|
|
12385
|
-
|
|
12814
|
+
/** Normalize a path for comparison: forward slashes, no trailing slash. */
|
|
12815
|
+
function normalizeDiffPath(p) {
|
|
12816
|
+
return p.replaceAll("\\", "/").replace(/\/+$/, "");
|
|
12817
|
+
}
|
|
12818
|
+
/** Whether a produced-file chip path and a pending file path refer to the same
|
|
12819
|
+
* file, tolerant of separator style (\\ vs /) and of a workspace-relative vs
|
|
12820
|
+
* absolute form. `chipPath` is typically the harness's workspace-relative
|
|
12821
|
+
* forward-slash path; `filePath` is the host's absolute native-separator path.
|
|
12822
|
+
* Matching is case-insensitive so a Windows drive/segment case difference does
|
|
12823
|
+
* not miss the file the user clicked. */
|
|
12824
|
+
function diffPathsMatch(chipPath, filePath, workspacePath) {
|
|
12825
|
+
const toAbsolute = (p) => {
|
|
12826
|
+
const norm = normalizeDiffPath(p);
|
|
12827
|
+
if (/^[A-Za-z]:\//.test(norm) || norm.startsWith("/")) return norm;
|
|
12828
|
+
if (workspacePath !== void 0 && workspacePath !== "") return `${normalizeDiffPath(workspacePath).replace(/\/+$/, "")}/${norm}`;
|
|
12829
|
+
return norm;
|
|
12830
|
+
};
|
|
12831
|
+
const absolute = toAbsolute(chipPath).toLowerCase();
|
|
12832
|
+
const file = toAbsolute(filePath).toLowerCase();
|
|
12833
|
+
if (absolute === file) return true;
|
|
12834
|
+
const rel = normalizeDiffPath(chipPath).toLowerCase();
|
|
12835
|
+
return file === rel || file.endsWith(`/${rel}`);
|
|
12836
|
+
}
|
|
12386
12837
|
/** The diff view-mode toggle glyph: the whole file as one column of text lines
|
|
12387
12838
|
* (unified) or two side-by-side columns of text lines (split). Hand-drawn
|
|
12388
12839
|
* because the icon library has no single/double-column glyph. Rendered 1:1
|
|
@@ -12687,6 +13138,53 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12687
13138
|
}, i);
|
|
12688
13139
|
});
|
|
12689
13140
|
}
|
|
13141
|
+
/** Character ranges of each case-insensitive occurrence of `query` in `text`. */
|
|
13142
|
+
function matchRangesOf(text, query) {
|
|
13143
|
+
if (query === "") return [];
|
|
13144
|
+
const lower = text.toLowerCase();
|
|
13145
|
+
const q = query.toLowerCase();
|
|
13146
|
+
const out = [];
|
|
13147
|
+
let from = 0;
|
|
13148
|
+
for (;;) {
|
|
13149
|
+
const at = lower.indexOf(q, from);
|
|
13150
|
+
if (at === -1) return out;
|
|
13151
|
+
out.push([at, at + query.length]);
|
|
13152
|
+
from = at + query.length;
|
|
13153
|
+
}
|
|
13154
|
+
}
|
|
13155
|
+
/** Render `text[segStart, segEnd)` with every `query` match wrapped in a search
|
|
13156
|
+
* highlight, keeping the syntax highlight and intra-line chips on the non-match
|
|
13157
|
+
* parts. When no match is present it renders exactly as before (syntax / intra /
|
|
13158
|
+
* plain). `segStart`/`segEnd` let the caller render a wrapped sub-line range. */
|
|
13159
|
+
function textWithSearch(text, runs, intra, query, segStart = 0, segEnd = text.length, current = false) {
|
|
13160
|
+
const segText = text.slice(segStart, segEnd);
|
|
13161
|
+
const ranges = matchRangesOf(segText, query);
|
|
13162
|
+
if (ranges.length === 0) return intra !== void 0 && intra.length > 0 ? renderIntra(runs, intra, segStart, segEnd) : runs !== void 0 && runs.length > 0 ? clipRuns(runs, segStart, segEnd) : segText === "" ? "\xA0" : segText;
|
|
13163
|
+
const nodes = [];
|
|
13164
|
+
const push = (absStart, absEnd, isMatch) => {
|
|
13165
|
+
if (isMatch) {
|
|
13166
|
+
nodes.push((0, react_jsx_runtime.jsx)("span", {
|
|
13167
|
+
className: current ? PendingPanel_module_css_default.searchMatchCurrent : PendingPanel_module_css_default.searchMatch,
|
|
13168
|
+
"data-diff-search-match": current ? "current" : "hit",
|
|
13169
|
+
children: text.slice(absStart, absEnd)
|
|
13170
|
+
}, nodes.length));
|
|
13171
|
+
return;
|
|
13172
|
+
}
|
|
13173
|
+
if (intra !== void 0 && intra.length > 0) nodes.push((0, react_jsx_runtime.jsx)("span", { children: renderIntra(runs, intra, absStart, absEnd) }, nodes.length));
|
|
13174
|
+
else if (runs !== void 0 && runs.length > 0) nodes.push((0, react_jsx_runtime.jsx)("span", { children: clipRuns(runs, absStart, absEnd) }, nodes.length));
|
|
13175
|
+
else nodes.push((0, react_jsx_runtime.jsx)("span", { children: text.slice(absStart, absEnd) }, nodes.length));
|
|
13176
|
+
};
|
|
13177
|
+
let cursor = segStart;
|
|
13178
|
+
for (const [s, e] of ranges) {
|
|
13179
|
+
const absS = segStart + s;
|
|
13180
|
+
const absE = segStart + e;
|
|
13181
|
+
if (absS > cursor) push(cursor, absS, false);
|
|
13182
|
+
push(absS, absE, true);
|
|
13183
|
+
cursor = absE;
|
|
13184
|
+
}
|
|
13185
|
+
if (cursor < segEnd) push(cursor, segEnd, false);
|
|
13186
|
+
return nodes;
|
|
13187
|
+
}
|
|
12690
13188
|
/**
|
|
12691
13189
|
* One rendered diff row, memoized so a poll or an unrelated state change
|
|
12692
13190
|
* does not re-render rows whose content, highlight, and focus are unchanged.
|
|
@@ -12695,22 +13193,18 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12695
13193
|
* is `wrappedLines.length * 22` by construction.
|
|
12696
13194
|
*/
|
|
12697
13195
|
const DiffRow = (0, react.memo)(function DiffRow(props) {
|
|
12698
|
-
const { index, row, runs, focused, searchHit, searchCurrent, onRowHover, wrappedLines } = props;
|
|
13196
|
+
const { index, row, runs, focused, searchHit, searchCurrent, searchQuery, onRowHover, wrappedLines } = props;
|
|
12699
13197
|
const lineNumber = row.kind === "del" ? row.oldLine : row.newLine;
|
|
12700
13198
|
const sideRuns = row.kind === "del" ? runs?.oldRuns : runs?.newRuns;
|
|
12701
13199
|
const lineRuns = lineNumber === void 0 ? void 0 : sideRuns?.[lineNumber - 1];
|
|
12702
13200
|
let code;
|
|
12703
|
-
if (wrappedLines === void 0) code = lineRuns
|
|
12704
|
-
style: span.style,
|
|
12705
|
-
children: span.text
|
|
12706
|
-
}, spanIndex)) : row.text === "" ? "\xA0" : row.text;
|
|
13201
|
+
if (wrappedLines === void 0) code = textWithSearch(row.text, lineRuns, void 0, searchQuery, 0, row.text.length, searchCurrent);
|
|
12707
13202
|
else {
|
|
12708
|
-
const highlighted = lineRuns !== void 0 && lineRuns.length > 0;
|
|
12709
13203
|
let offset = 0;
|
|
12710
13204
|
code = wrappedLines.map((line, lineIndex) => {
|
|
12711
13205
|
const start = offset;
|
|
12712
13206
|
offset += line.length;
|
|
12713
|
-
const content =
|
|
13207
|
+
const content = textWithSearch(row.text, lineRuns, void 0, searchQuery, start, offset, searchCurrent);
|
|
12714
13208
|
return (0, react_jsx_runtime.jsx)("div", {
|
|
12715
13209
|
className: PendingPanel_module_css_default.subline,
|
|
12716
13210
|
children: content
|
|
@@ -12729,10 +13223,12 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12729
13223
|
children: [
|
|
12730
13224
|
(0, react_jsx_runtime.jsx)("span", {
|
|
12731
13225
|
className: PendingPanel_module_css_default.gutter,
|
|
13226
|
+
"data-diff-gutter": true,
|
|
12732
13227
|
children: row.oldLine ?? ""
|
|
12733
13228
|
}),
|
|
12734
13229
|
(0, react_jsx_runtime.jsx)("span", {
|
|
12735
13230
|
className: PendingPanel_module_css_default.gutter,
|
|
13231
|
+
"data-diff-gutter": true,
|
|
12736
13232
|
children: row.newLine ?? ""
|
|
12737
13233
|
}),
|
|
12738
13234
|
(0, react_jsx_runtime.jsx)("span", {
|
|
@@ -12806,20 +13302,23 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12806
13302
|
});
|
|
12807
13303
|
return blocks;
|
|
12808
13304
|
}
|
|
13305
|
+
/** Row indices whose text contains `query` (case-insensitive); empty for ''. */
|
|
13306
|
+
function matchingRows(rows, query) {
|
|
13307
|
+
if (query === "") return [];
|
|
13308
|
+
const lower = query.toLowerCase();
|
|
13309
|
+
const out = [];
|
|
13310
|
+
for (let i = 0; i < rows.length; i++) if (rows[i].text.toLowerCase().includes(lower)) out.push(i);
|
|
13311
|
+
return out;
|
|
13312
|
+
}
|
|
12809
13313
|
/** One side's line-content for the split view: the highlighted runs or plain text. */
|
|
12810
|
-
function splitSideContent(side, wrapped, runs, intra) {
|
|
13314
|
+
function splitSideContent(side, wrapped, runs, intra, query, current) {
|
|
12811
13315
|
if (side === void 0) return "";
|
|
12812
|
-
|
|
12813
|
-
const hasIntra = intra !== void 0 && intra.length > 0;
|
|
12814
|
-
if (wrapped === void 0) return hasIntra ? renderIntra(runs, intra, 0, side.text.length) : highlighted ? runs.map((span, i) => (0, react_jsx_runtime.jsx)("span", {
|
|
12815
|
-
style: span.style,
|
|
12816
|
-
children: span.text
|
|
12817
|
-
}, i)) : side.text === "" ? "\xA0" : side.text;
|
|
13316
|
+
if (wrapped === void 0) return textWithSearch(side.text, runs, intra, query, 0, side.text.length, current);
|
|
12818
13317
|
let offset = 0;
|
|
12819
13318
|
return wrapped.map((line, i) => {
|
|
12820
13319
|
const start = offset;
|
|
12821
13320
|
offset += line.length;
|
|
12822
|
-
const content =
|
|
13321
|
+
const content = textWithSearch(side.text, runs, intra, query, start, offset, current);
|
|
12823
13322
|
return (0, react_jsx_runtime.jsx)("div", {
|
|
12824
13323
|
className: PendingPanel_module_css_default.subline,
|
|
12825
13324
|
children: content
|
|
@@ -12835,7 +13334,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12835
13334
|
* one side is longer. The gutter and code are top-aligned so sub-lines line up
|
|
12836
13335
|
* across the divider.
|
|
12837
13336
|
*/
|
|
12838
|
-
function SplitSideRow({ index, side, wrapped, runs, kind, isLeft, height, focused, searchHit, searchCurrent, onHover, intra }) {
|
|
13337
|
+
function SplitSideRow({ index, side, wrapped, runs, kind, isLeft, height, focused, searchHit, searchCurrent, searchQuery, onHover, intra }) {
|
|
12839
13338
|
const tint = isLeft ? kind === "del" || kind === "replace" ? PendingPanel_module_css_default.splitLdel : "" : kind === "add" || kind === "replace" ? PendingPanel_module_css_default.splitRadd : "";
|
|
12840
13339
|
return (0, react_jsx_runtime.jsxs)("div", {
|
|
12841
13340
|
className: PendingPanel_module_css_default.line,
|
|
@@ -12848,16 +13347,19 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12848
13347
|
onMouseEnter: onHover,
|
|
12849
13348
|
children: [(0, react_jsx_runtime.jsx)("span", {
|
|
12850
13349
|
className: PendingPanel_module_css_default.gutter,
|
|
13350
|
+
"data-diff-gutter": true,
|
|
12851
13351
|
children: side?.line ?? ""
|
|
12852
13352
|
}), (0, react_jsx_runtime.jsx)("span", {
|
|
12853
13353
|
className: `${PendingPanel_module_css_default.code} ${tint}`,
|
|
12854
13354
|
"data-diff-code": true,
|
|
12855
|
-
children: splitSideContent(side, wrapped, runs, intra)
|
|
13355
|
+
children: splitSideContent(side, wrapped, runs, intra, searchQuery, searchCurrent)
|
|
12856
13356
|
})]
|
|
12857
13357
|
});
|
|
12858
13358
|
}
|
|
12859
13359
|
/** The two-column (side-by-side) whole-file diff view. */
|
|
12860
|
-
const SplitDiff = (0, react.forwardRef)(function SplitDiff({ file, model, runs, langWrap, tabWidthSpaces, busy, t, selection, leadRows, onBlockKeep, onBlockRevert }, ref) {
|
|
13360
|
+
const SplitDiff = (0, react.forwardRef)(function SplitDiff({ file, model, runs, langWrap, tabWidthSpaces, busy, t, selection, leadRows, onBlockKeep, onBlockRevert, onWrapToast }, ref) {
|
|
13361
|
+
const ROW_HEIGHT_PX = diffLineHeight();
|
|
13362
|
+
const NAV_ANCHOR_TOLERANCE_PX = ROW_HEIGHT_PX / 4;
|
|
12861
13363
|
const { pairs, pairOfRow } = (0, react.useMemo)(() => computeSideBySideDiff(model.diff.rows, true), [model]);
|
|
12862
13364
|
const pairCount = pairs.length;
|
|
12863
13365
|
const pairRowIndices = (0, react.useMemo)(() => {
|
|
@@ -12879,6 +13381,11 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12879
13381
|
const [hoveredBlock, setHoveredBlock] = (0, react.useState)(void 0);
|
|
12880
13382
|
const [focus, setFocus] = (0, react.useState)(0);
|
|
12881
13383
|
const [flashKey, setFlashKey] = (0, react.useState)(0);
|
|
13384
|
+
const pinShakeRef = (0, react.useRef)(false);
|
|
13385
|
+
const bumpFlash = (shake) => {
|
|
13386
|
+
pinShakeRef.current = shake;
|
|
13387
|
+
setFlashKey((prev) => prev + 1);
|
|
13388
|
+
};
|
|
12882
13389
|
const hoveredBlockRef = (0, react.useRef)(void 0);
|
|
12883
13390
|
const leftColRef = (0, react.useRef)(null);
|
|
12884
13391
|
const rightColRef = (0, react.useRef)(null);
|
|
@@ -12895,7 +13402,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12895
13402
|
(0, react.useEffect)(() => {
|
|
12896
13403
|
setFocus(0);
|
|
12897
13404
|
bodyRef.current?.focus();
|
|
12898
|
-
|
|
13405
|
+
bumpFlash(false);
|
|
12899
13406
|
setHoveredBlock(void 0);
|
|
12900
13407
|
setSearchOpen(false);
|
|
12901
13408
|
setSearchQuery("");
|
|
@@ -13025,6 +13532,30 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13025
13532
|
bodyRef.current?.focus();
|
|
13026
13533
|
};
|
|
13027
13534
|
const openSearch = () => {
|
|
13535
|
+
if (searchOpen) {
|
|
13536
|
+
searchInputRef.current?.focus();
|
|
13537
|
+
searchInputRef.current?.select();
|
|
13538
|
+
return;
|
|
13539
|
+
}
|
|
13540
|
+
const live = window.getSelection();
|
|
13541
|
+
const liveRange = splitRowRangeOf(live);
|
|
13542
|
+
const range = liveRange !== void 0 ? liveRange : selection;
|
|
13543
|
+
const liveText = (live?.toString() ?? "").trim();
|
|
13544
|
+
const value = liveText !== "" && !liveText.includes("\n") ? liveText : "";
|
|
13545
|
+
setSearchQuery(value);
|
|
13546
|
+
const matches = value === "" ? [] : searchPairs(pairs, value);
|
|
13547
|
+
let index = 0;
|
|
13548
|
+
if (matches.length > 0) {
|
|
13549
|
+
const inSel = range === void 0 ? -1 : matches.findIndex((i) => i >= range.start && i <= range.end);
|
|
13550
|
+
if (inSel !== -1) index = inSel;
|
|
13551
|
+
else {
|
|
13552
|
+
const body = bodyRef.current;
|
|
13553
|
+
const top = body === null ? 0 : pairAtY(body.scrollTop);
|
|
13554
|
+
const at = matches.findIndex((i) => i >= top);
|
|
13555
|
+
index = at === -1 ? 0 : at;
|
|
13556
|
+
}
|
|
13557
|
+
}
|
|
13558
|
+
setSearchIndex(index);
|
|
13028
13559
|
setSearchOpen(true);
|
|
13029
13560
|
requestAnimationFrame(() => {
|
|
13030
13561
|
searchInputRef.current?.focus();
|
|
@@ -13040,7 +13571,15 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13040
13571
|
if (pairIndex === void 0) return;
|
|
13041
13572
|
const body = bodyRef.current;
|
|
13042
13573
|
if (body === null) return;
|
|
13043
|
-
|
|
13574
|
+
if (body.clientHeight <= 0) return;
|
|
13575
|
+
const viewTop = body.scrollTop;
|
|
13576
|
+
const viewBottom = viewTop + body.clientHeight;
|
|
13577
|
+
const pairTop = off(pairIndex);
|
|
13578
|
+
const pairBottom = pairTop + ROW_HEIGHT_PX;
|
|
13579
|
+
let target;
|
|
13580
|
+
if (pairTop < viewTop) target = pairTop;
|
|
13581
|
+
else if (pairBottom > viewBottom) target = pairBottom - body.clientHeight;
|
|
13582
|
+
if (target === void 0) return;
|
|
13044
13583
|
const clamped = Math.max(0, Math.min(target, body.scrollHeight - body.clientHeight));
|
|
13045
13584
|
if (body.scrollTop !== clamped) body.scrollTop = clamped;
|
|
13046
13585
|
setScrollTop(clamped);
|
|
@@ -13056,7 +13595,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13056
13595
|
const next = Math.max(0, Math.min(operated, count - 1));
|
|
13057
13596
|
setFocus(next);
|
|
13058
13597
|
setHoveredBlock(void 0);
|
|
13059
|
-
|
|
13598
|
+
bumpFlash(false);
|
|
13060
13599
|
};
|
|
13061
13600
|
const pairAtY = (y) => {
|
|
13062
13601
|
if (pairOffsets === null) return Math.floor(y / ROW_HEIGHT_PX);
|
|
@@ -13077,20 +13616,52 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13077
13616
|
end = Math.max(end, selection.end + 1);
|
|
13078
13617
|
}
|
|
13079
13618
|
const visiblePairs = pairs.slice(start, end);
|
|
13080
|
-
const
|
|
13081
|
-
|
|
13619
|
+
const wrapArmedRef = (0, react.useRef)(0);
|
|
13620
|
+
const jump = (direction, wrapGuard = false) => {
|
|
13621
|
+
const count = blockOfPair.length;
|
|
13622
|
+
if (count === 0) return;
|
|
13623
|
+
if (wrapGuard) {
|
|
13624
|
+
if (count === 1) onWrapToast(t("panel.blockSingle"));
|
|
13625
|
+
else if (direction === 1 && focus === count - 1 || direction === -1 && focus === 0) {
|
|
13626
|
+
if (wrapArmedRef.current !== direction) {
|
|
13627
|
+
wrapArmedRef.current = direction;
|
|
13628
|
+
onWrapToast(t(direction === 1 ? "panel.blockAtEnd" : "panel.blockAtStart"));
|
|
13629
|
+
bumpFlash(true);
|
|
13630
|
+
return;
|
|
13631
|
+
}
|
|
13632
|
+
wrapArmedRef.current = 0;
|
|
13633
|
+
} else wrapArmedRef.current = 0;
|
|
13634
|
+
}
|
|
13082
13635
|
setFocus((current) => {
|
|
13083
|
-
if (direction === -1) return (current - 1 +
|
|
13636
|
+
if (direction === -1) return (current - 1 + count) % count;
|
|
13084
13637
|
const top = bodyRef.current?.scrollTop ?? 0;
|
|
13085
|
-
for (let index = current + 1; index <
|
|
13638
|
+
for (let index = current + 1; index < count; index++) if (off(blockOfPair[index].start) >= top) return index;
|
|
13086
13639
|
return 0;
|
|
13087
13640
|
});
|
|
13088
|
-
|
|
13641
|
+
bumpFlash(false);
|
|
13642
|
+
};
|
|
13643
|
+
const stepBlock = (direction) => {
|
|
13644
|
+
const count = blockOfPair.length;
|
|
13645
|
+
if (count === 0) return;
|
|
13646
|
+
const target = ((hoveredBlock ?? focus) + direction + count) % count;
|
|
13647
|
+
setHoveredBlock(target);
|
|
13648
|
+
setFocus(target);
|
|
13649
|
+
bumpFlash(false);
|
|
13650
|
+
};
|
|
13651
|
+
const searchNext = (direction) => {
|
|
13652
|
+
if (!searchOpen) return false;
|
|
13653
|
+
goSearch(direction);
|
|
13654
|
+
return true;
|
|
13089
13655
|
};
|
|
13090
13656
|
(0, react.useImperativeHandle)(ref, () => ({
|
|
13091
13657
|
jump,
|
|
13092
|
-
openSearch
|
|
13093
|
-
|
|
13658
|
+
openSearch,
|
|
13659
|
+
searchNext
|
|
13660
|
+
}), [
|
|
13661
|
+
jump,
|
|
13662
|
+
openSearch,
|
|
13663
|
+
searchNext
|
|
13664
|
+
]);
|
|
13094
13665
|
(0, react.useLayoutEffect)(() => {
|
|
13095
13666
|
if (pairCount === 0) return;
|
|
13096
13667
|
const block = blockOfPair[focus];
|
|
@@ -13108,9 +13679,16 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13108
13679
|
setScrollTop(body.scrollTop);
|
|
13109
13680
|
const count = blockOfPair.length;
|
|
13110
13681
|
if (count === 0) return;
|
|
13111
|
-
const anchor = body.scrollTop + leadRows * ROW_HEIGHT_PX;
|
|
13112
13682
|
let ref = -1;
|
|
13113
|
-
|
|
13683
|
+
if (body.clientHeight > 0) {
|
|
13684
|
+
const viewportBottom = body.scrollTop + body.clientHeight;
|
|
13685
|
+
if (body.scrollTop <= NAV_ANCHOR_TOLERANCE_PX) ref = 0;
|
|
13686
|
+
else if (body.scrollHeight - viewportBottom <= NAV_ANCHOR_TOLERANCE_PX) ref = count - 1;
|
|
13687
|
+
}
|
|
13688
|
+
if (ref === -1) {
|
|
13689
|
+
const anchor = body.scrollTop + leadRows * ROW_HEIGHT_PX;
|
|
13690
|
+
for (let index = 0; index < count; index++) if (off(blockOfPair[index].start) <= anchor + NAV_ANCHOR_TOLERANCE_PX) ref = index;
|
|
13691
|
+
}
|
|
13114
13692
|
setFocus(ref === -1 ? 0 : ref);
|
|
13115
13693
|
};
|
|
13116
13694
|
const inFocused = (k) => {
|
|
@@ -13165,6 +13743,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13165
13743
|
focused: inFocused(index),
|
|
13166
13744
|
searchHit: searchHitSet.has(index),
|
|
13167
13745
|
searchCurrent: index === currentSearchPair,
|
|
13746
|
+
searchQuery,
|
|
13168
13747
|
onHover: () => onPairHover(index),
|
|
13169
13748
|
intra: sideIndex?.left === void 0 ? void 0 : model.intra.get(sideIndex.left)
|
|
13170
13749
|
}, index);
|
|
@@ -13206,6 +13785,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13206
13785
|
focused: inFocused(index),
|
|
13207
13786
|
searchHit: searchHitSet.has(index),
|
|
13208
13787
|
searchCurrent: index === currentSearchPair,
|
|
13788
|
+
searchQuery,
|
|
13209
13789
|
onHover: () => onPairHover(index),
|
|
13210
13790
|
intra: sideIndex?.right === void 0 ? void 0 : model.intra.get(sideIndex.right)
|
|
13211
13791
|
}, index);
|
|
@@ -13267,8 +13847,15 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13267
13847
|
value: searchQuery,
|
|
13268
13848
|
placeholder: t("panel.searchPlaceholder"),
|
|
13269
13849
|
onChange: (event) => {
|
|
13270
|
-
|
|
13271
|
-
|
|
13850
|
+
const value = event.target.value;
|
|
13851
|
+
setSearchQuery(value);
|
|
13852
|
+
if (value !== "") {
|
|
13853
|
+
const body = bodyRef.current;
|
|
13854
|
+
const matches = searchPairs(pairs, value);
|
|
13855
|
+
const anchor = currentSearchPair ?? (body === null ? 0 : pairAtY(body.scrollTop));
|
|
13856
|
+
const at = matches.findIndex((index) => index >= anchor);
|
|
13857
|
+
setSearchIndex(at === -1 ? 0 : at);
|
|
13858
|
+
} else setSearchIndex(0);
|
|
13272
13859
|
},
|
|
13273
13860
|
onKeyDown: (event) => {
|
|
13274
13861
|
if (event.key === "Enter") {
|
|
@@ -13282,27 +13869,37 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13282
13869
|
"data-diff-search-count": true,
|
|
13283
13870
|
children: searchMatches.length === 0 ? "0/0" : `${searchIndex % searchMatches.length + 1}/${searchMatches.length}`
|
|
13284
13871
|
}),
|
|
13285
|
-
(0, react_jsx_runtime.jsx)(
|
|
13286
|
-
|
|
13287
|
-
|
|
13288
|
-
|
|
13289
|
-
|
|
13290
|
-
|
|
13291
|
-
|
|
13292
|
-
|
|
13293
|
-
|
|
13294
|
-
|
|
13872
|
+
(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
13873
|
+
label: `${t("action.prevDiff")} (Shift+F3)`,
|
|
13874
|
+
side: "bottom",
|
|
13875
|
+
delayMs: 500,
|
|
13876
|
+
children: (0, react_jsx_runtime.jsx)("button", {
|
|
13877
|
+
type: "button",
|
|
13878
|
+
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.iconAction}`,
|
|
13879
|
+
"data-diff-search-prev": true,
|
|
13880
|
+
"aria-label": t("action.prevDiff"),
|
|
13881
|
+
disabled: searchMatches.length === 0,
|
|
13882
|
+
onClick: () => {
|
|
13883
|
+
goSearch(-1);
|
|
13884
|
+
},
|
|
13885
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronUpOutline14, { size: 14 })
|
|
13886
|
+
})
|
|
13295
13887
|
}),
|
|
13296
|
-
(0, react_jsx_runtime.jsx)(
|
|
13297
|
-
|
|
13298
|
-
|
|
13299
|
-
|
|
13300
|
-
|
|
13301
|
-
|
|
13302
|
-
|
|
13303
|
-
|
|
13304
|
-
|
|
13305
|
-
|
|
13888
|
+
(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
13889
|
+
label: `${t("action.nextDiff")} (F3)`,
|
|
13890
|
+
side: "bottom",
|
|
13891
|
+
delayMs: 500,
|
|
13892
|
+
children: (0, react_jsx_runtime.jsx)("button", {
|
|
13893
|
+
type: "button",
|
|
13894
|
+
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.iconAction}`,
|
|
13895
|
+
"data-diff-search-next": true,
|
|
13896
|
+
"aria-label": t("action.nextDiff"),
|
|
13897
|
+
disabled: searchMatches.length === 0,
|
|
13898
|
+
onClick: () => {
|
|
13899
|
+
goSearch(1);
|
|
13900
|
+
},
|
|
13901
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { size: 14 })
|
|
13902
|
+
})
|
|
13306
13903
|
}),
|
|
13307
13904
|
(0, react_jsx_runtime.jsx)("button", {
|
|
13308
13905
|
type: "button",
|
|
@@ -13315,7 +13912,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13315
13912
|
]
|
|
13316
13913
|
}),
|
|
13317
13914
|
focusedBlock !== void 0 && flashKey > 0 && (0, react_jsx_runtime.jsx)("div", {
|
|
13318
|
-
className: PendingPanel_module_css_default.blockFlash,
|
|
13915
|
+
className: pinShakeRef.current ? `${PendingPanel_module_css_default.blockFlash} ${PendingPanel_module_css_default.blockFlashShake}` : PendingPanel_module_css_default.blockFlash,
|
|
13319
13916
|
"data-diff-block-flash": true,
|
|
13320
13917
|
style: {
|
|
13321
13918
|
top: flashTop,
|
|
@@ -13341,7 +13938,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13341
13938
|
"data-diff-block-prev": true,
|
|
13342
13939
|
"aria-label": t("action.prevDiff"),
|
|
13343
13940
|
disabled: busy,
|
|
13344
|
-
onClick: () =>
|
|
13941
|
+
onClick: () => stepBlock(-1),
|
|
13345
13942
|
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronUpOutline14, { size: 14 })
|
|
13346
13943
|
}),
|
|
13347
13944
|
(0, react_jsx_runtime.jsx)("button", {
|
|
@@ -13350,7 +13947,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13350
13947
|
"data-diff-block-next": true,
|
|
13351
13948
|
"aria-label": t("action.nextDiff"),
|
|
13352
13949
|
disabled: busy,
|
|
13353
|
-
onClick: () =>
|
|
13950
|
+
onClick: () => stepBlock(1),
|
|
13354
13951
|
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { size: 14 })
|
|
13355
13952
|
}),
|
|
13356
13953
|
(0, react_jsx_runtime.jsx)("button", {
|
|
@@ -13490,6 +14087,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13490
14087
|
}
|
|
13491
14088
|
if (!(node instanceof Element)) return;
|
|
13492
14089
|
const el = node;
|
|
14090
|
+
if (el.dataset.diffGutter !== void 0) return;
|
|
13493
14091
|
if ((el.dataset.diffRow !== void 0 || el.dataset.diffSplitRow !== void 0 || el.dataset.diffSplitIndex !== void 0) && !atLineStart) push("\n");
|
|
13494
14092
|
for (const child of node.childNodes) walk(child);
|
|
13495
14093
|
};
|
|
@@ -13593,10 +14191,25 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13593
14191
|
const [tabWidthSpaces] = (0, react.useState)(() => tabWidth());
|
|
13594
14192
|
const [splitView, setSplitView] = (0, react.useState)(() => splitMode());
|
|
13595
14193
|
const leadRows = navLeadRows();
|
|
14194
|
+
const diffFontScaleValue = diffFontScale();
|
|
14195
|
+
const diffLineHeightValue = diffLineHeight();
|
|
14196
|
+
const diffAddColorPx = diffAddColor();
|
|
14197
|
+
const diffDelColorPx = diffDelColor();
|
|
14198
|
+
const diffViewVars = {};
|
|
14199
|
+
diffViewVars["--dsh-diff-font-scale"] = String(diffFontScaleValue / 100);
|
|
14200
|
+
diffViewVars["--dsh-diff-line-height"] = `${diffLineHeightValue}px`;
|
|
14201
|
+
if (diffAddColorPx !== void 0) diffViewVars["--dsh-diff-add-color"] = diffAddColorPx;
|
|
14202
|
+
if (diffDelColorPx !== void 0) diffViewVars["--dsh-diff-del-color"] = diffDelColorPx;
|
|
14203
|
+
const ROW_HEIGHT_PX = diffLineHeightValue;
|
|
14204
|
+
const NAV_ANCHOR_TOLERANCE_PX = ROW_HEIGHT_PX / 4;
|
|
13596
14205
|
const toggleSplitView = () => {
|
|
13597
14206
|
const next = !splitView;
|
|
13598
14207
|
setSplitView(next);
|
|
13599
14208
|
setSplitMode(next);
|
|
14209
|
+
if (!next) {
|
|
14210
|
+
setScrollTop(0);
|
|
14211
|
+
setScrollTick((tick) => tick + 1);
|
|
14212
|
+
}
|
|
13600
14213
|
};
|
|
13601
14214
|
const splitDiffRef = (0, react.useRef)(null);
|
|
13602
14215
|
const model = (0, react.useMemo)(() => {
|
|
@@ -13675,17 +14288,23 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13675
14288
|
const [hScrollbarPx, setHScrollbarPx] = (0, react.useState)(0);
|
|
13676
14289
|
const [hoveredBlock, setHoveredBlock] = (0, react.useState)(void 0);
|
|
13677
14290
|
const [selection, setSelection] = (0, react.useState)(void 0);
|
|
14291
|
+
const selectionTextRef = (0, react.useRef)("");
|
|
13678
14292
|
const [copied, setCopied] = (0, react.useState)(false);
|
|
13679
14293
|
const [searchOpen, setSearchOpen] = (0, react.useState)(false);
|
|
13680
14294
|
const [searchQuery, setSearchQuery] = (0, react.useState)("");
|
|
13681
14295
|
const [searchIndex, setSearchIndex] = (0, react.useState)(0);
|
|
13682
14296
|
const searchInputRef = (0, react.useRef)(null);
|
|
13683
14297
|
const [flashKey, setFlashKey] = (0, react.useState)(0);
|
|
14298
|
+
const pinShakeRef = (0, react.useRef)(false);
|
|
14299
|
+
const bumpFlash = (shake) => {
|
|
14300
|
+
pinShakeRef.current = shake;
|
|
14301
|
+
setFlashKey((prev) => prev + 1);
|
|
14302
|
+
};
|
|
13684
14303
|
(0, react.useEffect)(() => {
|
|
13685
14304
|
setFocus(0);
|
|
13686
14305
|
setScrollTick((tick) => tick + 1);
|
|
13687
14306
|
bodyRef.current?.focus();
|
|
13688
|
-
|
|
14307
|
+
bumpFlash(false);
|
|
13689
14308
|
setHoveredBlock(void 0);
|
|
13690
14309
|
setSelection(void 0);
|
|
13691
14310
|
setLangOverride(void 0);
|
|
@@ -13699,7 +14318,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13699
14318
|
if (undoFlash === 0) return;
|
|
13700
14319
|
setFocus(0);
|
|
13701
14320
|
setScrollTick((tick) => tick + 1);
|
|
13702
|
-
|
|
14321
|
+
bumpFlash(false);
|
|
13703
14322
|
}, [undoFlash]);
|
|
13704
14323
|
const blockRanges = (0, react.useMemo)(() => {
|
|
13705
14324
|
return model.blocks.map((block) => blockRangesOf(model.diff.rows, block));
|
|
@@ -13730,27 +14349,74 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13730
14349
|
end: last.end
|
|
13731
14350
|
});
|
|
13732
14351
|
}, [coveredBlockIndices, model]);
|
|
13733
|
-
const searchMatches = (0, react.useMemo)(() =>
|
|
13734
|
-
if (searchQuery === "") return [];
|
|
13735
|
-
const lower = searchQuery.toLowerCase();
|
|
13736
|
-
const matches = [];
|
|
13737
|
-
for (let index = 0; index < model.diff.rows.length; index++) if (model.diff.rows[index].text.toLowerCase().includes(lower)) matches.push(index);
|
|
13738
|
-
return matches;
|
|
13739
|
-
}, [model, searchQuery]);
|
|
14352
|
+
const searchMatches = (0, react.useMemo)(() => matchingRows(model.diff.rows, searchQuery), [model, searchQuery]);
|
|
13740
14353
|
const searchHitSet = (0, react.useMemo)(() => new Set(searchMatches), [searchMatches]);
|
|
13741
14354
|
const currentSearchRow = searchMatches.length === 0 ? void 0 : searchMatches[searchIndex % searchMatches.length];
|
|
13742
14355
|
const goSearch = (direction) => {
|
|
13743
14356
|
if (searchMatches.length === 0) return;
|
|
14357
|
+
if (cursorPosRef.current !== void 0) {
|
|
14358
|
+
setSearchIndex(startIndexFor(searchQuery));
|
|
14359
|
+
return;
|
|
14360
|
+
}
|
|
13744
14361
|
setSearchIndex((current) => (current + direction + searchMatches.length) % searchMatches.length);
|
|
13745
14362
|
};
|
|
14363
|
+
/**
|
|
14364
|
+
* The search's start index for `value`. The recorded cursor (the selection, if
|
|
14365
|
+
* any) anchors ONE search, then is consumed; after that the current highlight
|
|
14366
|
+
* drives subsequent searches, and, with neither set, the viewport top is the
|
|
14367
|
+
* start (the "no cursor" fallback).
|
|
14368
|
+
*/
|
|
14369
|
+
const startIndexFor = (value) => {
|
|
14370
|
+
const matches = value === "" ? [] : matchingRows(model.diff.rows, value);
|
|
14371
|
+
const pos = cursorPosRef.current;
|
|
14372
|
+
cursorPosRef.current = void 0;
|
|
14373
|
+
if (matches.length === 0) return 0;
|
|
14374
|
+
const inPos = pos === void 0 ? -1 : matches.findIndex((i) => i >= pos.start && i <= pos.end);
|
|
14375
|
+
if (inPos !== -1) return inPos;
|
|
14376
|
+
const body = bodyRef.current;
|
|
14377
|
+
const fromRow = pos !== void 0 ? pos.start : currentSearchRow ?? (body === null ? 0 : rowAtY(body.scrollTop));
|
|
14378
|
+
const at = matches.findIndex((i) => i >= fromRow);
|
|
14379
|
+
return at === -1 ? 0 : at;
|
|
14380
|
+
};
|
|
14381
|
+
const cursorPosRef = (0, react.useRef)(void 0);
|
|
14382
|
+
const lastRecordedCursorRef = (0, react.useRef)(void 0);
|
|
14383
|
+
const openSearchWithSelection = () => {
|
|
14384
|
+
if (searchOpen) {
|
|
14385
|
+
searchInputRef.current?.focus();
|
|
14386
|
+
searchInputRef.current?.select();
|
|
14387
|
+
return;
|
|
14388
|
+
}
|
|
14389
|
+
const live = window.getSelection();
|
|
14390
|
+
const liveRange = splitView ? splitRowRangeOf(live) : rowRangeOf(live);
|
|
14391
|
+
const pos = liveRange !== void 0 ? liveRange : selection;
|
|
14392
|
+
cursorPosRef.current = pos;
|
|
14393
|
+
lastRecordedCursorRef.current = pos;
|
|
14394
|
+
const liveText = (live?.toString() ?? "").trim();
|
|
14395
|
+
const value = liveText !== "" && !liveText.includes("\n") ? liveText : selectionTextRef.current;
|
|
14396
|
+
setSearchQuery(value);
|
|
14397
|
+
setSearchIndex(startIndexFor(value));
|
|
14398
|
+
setSearchOpen(true);
|
|
14399
|
+
requestAnimationFrame(() => {
|
|
14400
|
+
searchInputRef.current?.focus();
|
|
14401
|
+
searchInputRef.current?.select();
|
|
14402
|
+
});
|
|
14403
|
+
};
|
|
14404
|
+
const openSearchRef = (0, react.useRef)(openSearchWithSelection);
|
|
14405
|
+
openSearchRef.current = openSearchWithSelection;
|
|
14406
|
+
const searchOpenRef = (0, react.useRef)(searchOpen);
|
|
14407
|
+
searchOpenRef.current = searchOpen;
|
|
13746
14408
|
const toggleSearch = () => {
|
|
13747
14409
|
if (searchOpen) {
|
|
14410
|
+
cursorPosRef.current = void 0;
|
|
14411
|
+
lastRecordedCursorRef.current = void 0;
|
|
13748
14412
|
setSearchOpen(false);
|
|
13749
14413
|
setSearchQuery("");
|
|
13750
14414
|
setSearchIndex(0);
|
|
13751
|
-
} else
|
|
14415
|
+
} else openSearchWithSelection();
|
|
13752
14416
|
};
|
|
13753
14417
|
const closeSearch = () => {
|
|
14418
|
+
cursorPosRef.current = void 0;
|
|
14419
|
+
lastRecordedCursorRef.current = void 0;
|
|
13754
14420
|
setSearchOpen(false);
|
|
13755
14421
|
setSearchQuery("");
|
|
13756
14422
|
setSearchIndex(0);
|
|
@@ -13758,15 +14424,20 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13758
14424
|
(0, react.useEffect)(() => {
|
|
13759
14425
|
if (searchOpen) searchInputRef.current?.focus();
|
|
13760
14426
|
}, [searchOpen]);
|
|
13761
|
-
(0, react.useEffect)(() => {
|
|
13762
|
-
setSearchIndex(0);
|
|
13763
|
-
}, [searchQuery, file.id]);
|
|
13764
14427
|
(0, react.useLayoutEffect)(() => {
|
|
13765
14428
|
const row = currentSearchRow;
|
|
13766
14429
|
if (row === void 0) return;
|
|
13767
14430
|
const body = bodyRef.current;
|
|
13768
14431
|
if (body === null) return;
|
|
13769
|
-
|
|
14432
|
+
if (body.clientHeight <= 0) return;
|
|
14433
|
+
const viewTop = body.scrollTop;
|
|
14434
|
+
const viewBottom = viewTop + body.clientHeight;
|
|
14435
|
+
const rowTop = offsetOf(row);
|
|
14436
|
+
const rowBottom = rowTop + extentOf(row, row);
|
|
14437
|
+
let target;
|
|
14438
|
+
if (rowTop < viewTop) target = rowTop;
|
|
14439
|
+
else if (rowBottom > viewBottom) target = rowBottom - body.clientHeight;
|
|
14440
|
+
if (target === void 0) return;
|
|
13770
14441
|
const clamped = Math.max(0, Math.min(target, body.scrollHeight - body.clientHeight));
|
|
13771
14442
|
if (body.scrollTop !== clamped) body.scrollTop = clamped;
|
|
13772
14443
|
setScrollTop(clamped);
|
|
@@ -13838,14 +14509,14 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13838
14509
|
}
|
|
13839
14510
|
const visibleRows = rows.slice(start, end);
|
|
13840
14511
|
const blockEnd = hoveredBlock === void 0 ? void 0 : model.blocks[hoveredBlock]?.end;
|
|
13841
|
-
const blockActionsTop = blockEnd === void 0 ? 0 : Math.max(0, Math.min(offsetOf(blockEnd + 1) - scrollTop, Math.max(0, viewportHeight - BLOCK_ACTIONS_FRAME_PX)));
|
|
14512
|
+
const blockActionsTop = blockEnd === void 0 ? 0 : Math.max(0, Math.min(offsetOf(blockEnd + 1) - scrollTop - 2, Math.max(0, viewportHeight - BLOCK_ACTIONS_FRAME_PX)));
|
|
13842
14513
|
const selectionBlockEnd = (() => {
|
|
13843
14514
|
if (coveredBlockIndices.length === 0) return void 0;
|
|
13844
14515
|
const lastIndex = coveredBlockIndices[coveredBlockIndices.length - 1];
|
|
13845
14516
|
if (lastIndex === void 0) return void 0;
|
|
13846
14517
|
return model.blocks[lastIndex]?.end;
|
|
13847
14518
|
})();
|
|
13848
|
-
const selectionActionsTop = selectionBlockEnd === void 0 ? 0 : Math.max(0, Math.min(offsetOf(selectionBlockEnd + 1) - scrollTop, Math.max(0, viewportHeight - BLOCK_ACTIONS_FRAME_PX)));
|
|
14519
|
+
const selectionActionsTop = selectionBlockEnd === void 0 ? 0 : Math.max(0, Math.min(offsetOf(selectionBlockEnd + 1) - scrollTop - 2, Math.max(0, viewportHeight - BLOCK_ACTIONS_FRAME_PX)));
|
|
13849
14520
|
const widestLine = (0, react.useMemo)(() => {
|
|
13850
14521
|
let widest = 0;
|
|
13851
14522
|
for (const row of model.diff.rows) if (row.text.length > widest) widest = row.text.length;
|
|
@@ -13863,7 +14534,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13863
14534
|
return () => {
|
|
13864
14535
|
observer?.disconnect();
|
|
13865
14536
|
};
|
|
13866
|
-
}, [file.id]);
|
|
14537
|
+
}, [file.id, splitView]);
|
|
13867
14538
|
(0, react.useEffect)(() => {
|
|
13868
14539
|
const body = bodyRef.current;
|
|
13869
14540
|
if (body === null) return;
|
|
@@ -13889,12 +14560,27 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13889
14560
|
if (body.scrollTop !== clamped) body.scrollTop = clamped;
|
|
13890
14561
|
setScrollTop(clamped);
|
|
13891
14562
|
}, [scrollTick, rowOffsets === null]);
|
|
13892
|
-
const
|
|
14563
|
+
const wrapArmedRef = (0, react.useRef)(0);
|
|
14564
|
+
const jump = (direction, wrapGuard = false) => {
|
|
13893
14565
|
if (rowCount === 0) return;
|
|
14566
|
+
const count = model.blocks.length;
|
|
14567
|
+
if (count === 0) return;
|
|
14568
|
+
if (wrapGuard) {
|
|
14569
|
+
if (count === 1) onToast(t("panel.blockSingle"));
|
|
14570
|
+
else if (direction === 1 && focus === count - 1 || direction === -1 && focus === 0) {
|
|
14571
|
+
if (wrapArmedRef.current !== direction) {
|
|
14572
|
+
wrapArmedRef.current = direction;
|
|
14573
|
+
onToast(t(direction === 1 ? "panel.blockAtEnd" : "panel.blockAtStart"));
|
|
14574
|
+
bumpFlash(true);
|
|
14575
|
+
return;
|
|
14576
|
+
}
|
|
14577
|
+
wrapArmedRef.current = 0;
|
|
14578
|
+
} else wrapArmedRef.current = 0;
|
|
14579
|
+
}
|
|
13894
14580
|
setFocus((current) => {
|
|
13895
|
-
if (direction === -1) return (current - 1 +
|
|
14581
|
+
if (direction === -1) return (current - 1 + count) % count;
|
|
13896
14582
|
const top = bodyRef.current?.scrollTop ?? 0;
|
|
13897
|
-
for (let index = current + 1; index <
|
|
14583
|
+
for (let index = current + 1; index < count; index++) {
|
|
13898
14584
|
const block = model.blocks[index];
|
|
13899
14585
|
if (block === void 0) continue;
|
|
13900
14586
|
if (offsetOf(block.start) >= top) return index;
|
|
@@ -13902,14 +14588,14 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13902
14588
|
return 0;
|
|
13903
14589
|
});
|
|
13904
14590
|
setScrollTick((tick) => tick + 1);
|
|
13905
|
-
|
|
14591
|
+
bumpFlash(false);
|
|
13906
14592
|
};
|
|
13907
|
-
const jumpBlock = (direction) => {
|
|
14593
|
+
const jumpBlock = (direction, wrapGuard = false) => {
|
|
13908
14594
|
if (splitView) {
|
|
13909
|
-
splitDiffRef.current?.jump(direction);
|
|
14595
|
+
splitDiffRef.current?.jump(direction, wrapGuard);
|
|
13910
14596
|
return;
|
|
13911
14597
|
}
|
|
13912
|
-
jump(direction);
|
|
14598
|
+
jump(direction, wrapGuard);
|
|
13913
14599
|
};
|
|
13914
14600
|
const jumpBlockRef = (0, react.useRef)(jumpBlock);
|
|
13915
14601
|
jumpBlockRef.current = jumpBlock;
|
|
@@ -13920,7 +14606,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13920
14606
|
setHoveredBlock(target);
|
|
13921
14607
|
setFocus(target);
|
|
13922
14608
|
setScrollTick((tick) => tick + 1);
|
|
13923
|
-
|
|
14609
|
+
bumpFlash(false);
|
|
13924
14610
|
};
|
|
13925
14611
|
const runBlockAction = async (action, range, operated) => {
|
|
13926
14612
|
await (action === "keep" ? onBlockKeep(file.sessionId, file.id, range) : onBlockRevert(file.sessionId, file.id, range));
|
|
@@ -13930,7 +14616,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13930
14616
|
setFocus(next);
|
|
13931
14617
|
setHoveredBlock(void 0);
|
|
13932
14618
|
setScrollTick((tick) => tick + 1);
|
|
13933
|
-
|
|
14619
|
+
bumpFlash(false);
|
|
13934
14620
|
};
|
|
13935
14621
|
const handleBlockAction = async (action) => {
|
|
13936
14622
|
if (busy || hoveredBlock === void 0) return;
|
|
@@ -13943,10 +14629,12 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13943
14629
|
const firstCovered = coveredBlockIndices[0];
|
|
13944
14630
|
if (firstCovered === void 0) return;
|
|
13945
14631
|
await runBlockAction(action, selectionRange, firstCovered);
|
|
14632
|
+
setSelection(void 0);
|
|
14633
|
+
window.getSelection()?.removeAllRanges?.();
|
|
13946
14634
|
};
|
|
13947
14635
|
(0, react.useEffect)(() => {
|
|
13948
14636
|
if (jumpSignal === 0) return;
|
|
13949
|
-
jumpBlock(1);
|
|
14637
|
+
jumpBlock(1, true);
|
|
13950
14638
|
}, [jumpSignal]);
|
|
13951
14639
|
const onScroll = () => {
|
|
13952
14640
|
const body = bodyRef.current;
|
|
@@ -13955,16 +14643,39 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13955
14643
|
setViewportHeight(body.clientHeight);
|
|
13956
14644
|
const count = model.blocks.length;
|
|
13957
14645
|
if (rowCount === 0 || count === 0) return;
|
|
13958
|
-
const anchor = body.scrollTop + leadRows * ROW_HEIGHT_PX;
|
|
13959
14646
|
let ref = -1;
|
|
13960
|
-
|
|
13961
|
-
const
|
|
13962
|
-
if (
|
|
14647
|
+
if (body.clientHeight > 0) {
|
|
14648
|
+
const viewportBottom = body.scrollTop + body.clientHeight;
|
|
14649
|
+
if (body.scrollTop <= NAV_ANCHOR_TOLERANCE_PX) ref = 0;
|
|
14650
|
+
else if (body.scrollHeight - viewportBottom <= NAV_ANCHOR_TOLERANCE_PX) ref = count - 1;
|
|
14651
|
+
}
|
|
14652
|
+
if (ref === -1) {
|
|
14653
|
+
const anchor = body.scrollTop + leadRows * ROW_HEIGHT_PX;
|
|
14654
|
+
for (let index = 0; index < count; index++) {
|
|
14655
|
+
const block = model.blocks[index];
|
|
14656
|
+
if (block !== void 0 && offsetOf(block.start) <= anchor + NAV_ANCHOR_TOLERANCE_PX) ref = index;
|
|
14657
|
+
}
|
|
13963
14658
|
}
|
|
13964
14659
|
setFocus(ref === -1 ? 0 : ref);
|
|
13965
14660
|
};
|
|
13966
14661
|
(0, react.useEffect)(() => {
|
|
13967
|
-
const update = () =>
|
|
14662
|
+
const update = () => {
|
|
14663
|
+
const live = window.getSelection();
|
|
14664
|
+
const range = splitView ? splitRowRangeOf(live) : rowRangeOf(live);
|
|
14665
|
+
let text = "";
|
|
14666
|
+
if (range !== void 0) {
|
|
14667
|
+
const raw = live?.toString() ?? "";
|
|
14668
|
+
text = raw !== "" && !raw.includes("\n") ? raw.trim() : "";
|
|
14669
|
+
}
|
|
14670
|
+
selectionTextRef.current = text;
|
|
14671
|
+
setSelection(range);
|
|
14672
|
+
const last = lastRecordedCursorRef.current;
|
|
14673
|
+
const sameRange = last !== void 0 && range !== void 0 && last.start === range.start && last.end === range.end;
|
|
14674
|
+
if (searchOpenRef.current && range !== void 0 && text !== "" && !sameRange) {
|
|
14675
|
+
lastRecordedCursorRef.current = range;
|
|
14676
|
+
cursorPosRef.current = range;
|
|
14677
|
+
}
|
|
14678
|
+
};
|
|
13968
14679
|
document.addEventListener("selectionchange", update);
|
|
13969
14680
|
update();
|
|
13970
14681
|
return () => {
|
|
@@ -13985,7 +14696,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13985
14696
|
document.removeEventListener("copy", onCopy);
|
|
13986
14697
|
};
|
|
13987
14698
|
}, []);
|
|
13988
|
-
const
|
|
14699
|
+
const selectionReferenceLabel = (() => {
|
|
13989
14700
|
if (selection === void 0) return void 0;
|
|
13990
14701
|
if (splitView) {
|
|
13991
14702
|
if (selection.side === void 0 || splitPairs === null) return void 0;
|
|
@@ -13997,12 +14708,13 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
13997
14708
|
if (line !== void 0) lineNumbers.push(line);
|
|
13998
14709
|
}
|
|
13999
14710
|
if (lineNumbers.length === 0) return void 0;
|
|
14000
|
-
return
|
|
14711
|
+
return referenceLabelOf(file.path, workspacePath, Math.min(...lineNumbers), Math.max(...lineNumbers));
|
|
14001
14712
|
}
|
|
14002
14713
|
const lineNumbers = model.diff.rows.slice(selection.start, selection.end + 1).map((row) => row.newLine).filter((number) => number !== void 0);
|
|
14003
14714
|
if (lineNumbers.length === 0) return void 0;
|
|
14004
|
-
return
|
|
14715
|
+
return referenceLabelOf(file.path, workspacePath, Math.min(...lineNumbers), Math.max(...lineNumbers));
|
|
14005
14716
|
})();
|
|
14717
|
+
const selectionReference = selectionReferenceLabel === void 0 ? void 0 : `(${selectionReferenceLabel})`;
|
|
14006
14718
|
const copySelection = (0, react.useCallback)(async () => {
|
|
14007
14719
|
if (selectionReference === void 0) return;
|
|
14008
14720
|
if (pasteOnCopyEnabled()) {
|
|
@@ -14024,8 +14736,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14024
14736
|
]);
|
|
14025
14737
|
(0, react.useEffect)(() => {
|
|
14026
14738
|
const onKeyDown = (event) => {
|
|
14027
|
-
if (!(event
|
|
14028
|
-
if (event.key.toLowerCase() !== "l") return;
|
|
14739
|
+
if (!matchesShortcut(event, keybindingOf("copyRef"))) return;
|
|
14029
14740
|
if (selectionReference === void 0) return;
|
|
14030
14741
|
event.preventDefault();
|
|
14031
14742
|
copySelection();
|
|
@@ -14037,33 +14748,55 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14037
14748
|
}, [copySelection]);
|
|
14038
14749
|
(0, react.useEffect)(() => {
|
|
14039
14750
|
const onKeyDown = (event) => {
|
|
14040
|
-
if (!(event
|
|
14041
|
-
if (event.key.toLowerCase() !== "f") return;
|
|
14751
|
+
if (!matchesShortcut(event, keybindingOf("openSearch"))) return;
|
|
14042
14752
|
event.preventDefault();
|
|
14043
14753
|
if (splitView) {
|
|
14044
14754
|
splitDiffRef.current?.openSearch();
|
|
14045
14755
|
return;
|
|
14046
14756
|
}
|
|
14047
|
-
|
|
14048
|
-
searchInputRef.current?.focus();
|
|
14049
|
-
searchInputRef.current?.select();
|
|
14757
|
+
openSearchRef.current?.();
|
|
14050
14758
|
};
|
|
14051
14759
|
window.addEventListener("keydown", onKeyDown, true);
|
|
14052
14760
|
return () => {
|
|
14053
14761
|
window.removeEventListener("keydown", onKeyDown, true);
|
|
14054
14762
|
};
|
|
14055
|
-
}, []);
|
|
14763
|
+
}, [searchOpen, splitView]);
|
|
14764
|
+
(0, react.useEffect)(() => {
|
|
14765
|
+
const onKeyDown = (event) => {
|
|
14766
|
+
let direction = 0;
|
|
14767
|
+
if (matchesShortcut(event, keybindingOf("searchNext"))) direction = 1;
|
|
14768
|
+
else if (matchesShortcut(event, keybindingOf("searchPrev"))) direction = -1;
|
|
14769
|
+
if (direction === 0) return;
|
|
14770
|
+
if (splitView) {
|
|
14771
|
+
if (splitDiffRef.current?.searchNext(direction)) event.preventDefault();
|
|
14772
|
+
return;
|
|
14773
|
+
}
|
|
14774
|
+
if (searchOpen && searchMatches.length > 0) {
|
|
14775
|
+
event.preventDefault();
|
|
14776
|
+
goSearch(direction);
|
|
14777
|
+
}
|
|
14778
|
+
};
|
|
14779
|
+
window.addEventListener("keydown", onKeyDown, true);
|
|
14780
|
+
return () => {
|
|
14781
|
+
window.removeEventListener("keydown", onKeyDown, true);
|
|
14782
|
+
};
|
|
14783
|
+
}, [
|
|
14784
|
+
searchOpen,
|
|
14785
|
+
searchMatches,
|
|
14786
|
+
splitView
|
|
14787
|
+
]);
|
|
14056
14788
|
const jumpRef = (0, react.useRef)(jumpBlock);
|
|
14057
14789
|
jumpRef.current = jumpBlock;
|
|
14058
14790
|
(0, react.useEffect)(() => {
|
|
14059
14791
|
const onKeyDown = (event) => {
|
|
14060
|
-
|
|
14061
|
-
|
|
14062
|
-
if (
|
|
14792
|
+
let direction = 0;
|
|
14793
|
+
if (matchesShortcut(event, keybindingOf("jumpUp"))) direction = -1;
|
|
14794
|
+
else if (matchesShortcut(event, keybindingOf("jumpDown"))) direction = 1;
|
|
14795
|
+
if (direction === 0) return;
|
|
14063
14796
|
const target = event.target;
|
|
14064
14797
|
if (target instanceof Element && target.closest("input, textarea, [contenteditable=\"true\"]") !== null) return;
|
|
14065
14798
|
event.preventDefault();
|
|
14066
|
-
jumpRef.current(
|
|
14799
|
+
jumpRef.current(direction, true);
|
|
14067
14800
|
};
|
|
14068
14801
|
window.addEventListener("keydown", onKeyDown, true);
|
|
14069
14802
|
return () => {
|
|
@@ -14084,6 +14817,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14084
14817
|
return (0, react_jsx_runtime.jsxs)("div", {
|
|
14085
14818
|
className: PendingPanel_module_css_default.diff,
|
|
14086
14819
|
"data-diff-approval-diff": true,
|
|
14820
|
+
style: diffViewVars,
|
|
14087
14821
|
children: [
|
|
14088
14822
|
(0, react_jsx_runtime.jsxs)("div", {
|
|
14089
14823
|
className: PendingPanel_module_css_default.diffHeader,
|
|
@@ -14158,7 +14892,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14158
14892
|
"aria-label": t("action.prevDiff"),
|
|
14159
14893
|
disabled: busy,
|
|
14160
14894
|
onClick: () => {
|
|
14161
|
-
jumpBlock(-1);
|
|
14895
|
+
jumpBlock(-1, true);
|
|
14162
14896
|
},
|
|
14163
14897
|
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronUpOutline14, { size: 14 })
|
|
14164
14898
|
})
|
|
@@ -14173,7 +14907,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14173
14907
|
"aria-label": t("action.nextDiff"),
|
|
14174
14908
|
disabled: busy,
|
|
14175
14909
|
onClick: () => {
|
|
14176
|
-
jumpBlock(1);
|
|
14910
|
+
jumpBlock(1, true);
|
|
14177
14911
|
},
|
|
14178
14912
|
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { size: 14 })
|
|
14179
14913
|
})
|
|
@@ -14249,7 +14983,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14249
14983
|
selection,
|
|
14250
14984
|
leadRows,
|
|
14251
14985
|
onBlockKeep,
|
|
14252
|
-
onBlockRevert
|
|
14986
|
+
onBlockRevert,
|
|
14987
|
+
onWrapToast: (text) => onToast(text)
|
|
14253
14988
|
}) : (0, react_jsx_runtime.jsxs)("div", {
|
|
14254
14989
|
className: PendingPanel_module_css_default.diffBodyWrap,
|
|
14255
14990
|
onMouseLeave: () => {
|
|
@@ -14284,6 +15019,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14284
15019
|
focused: inFocusedBlock(index),
|
|
14285
15020
|
searchHit: searchHitSet.has(index),
|
|
14286
15021
|
searchCurrent: index === currentSearchRow,
|
|
15022
|
+
searchQuery,
|
|
14287
15023
|
onRowHover,
|
|
14288
15024
|
wrappedLines: rowWrapped?.[index]
|
|
14289
15025
|
}, index);
|
|
@@ -14377,7 +15113,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14377
15113
|
]
|
|
14378
15114
|
}) : null,
|
|
14379
15115
|
focusedBlock !== void 0 && flashKey > 0 && (0, react_jsx_runtime.jsx)("div", {
|
|
14380
|
-
className: PendingPanel_module_css_default.blockFlash,
|
|
15116
|
+
className: pinShakeRef.current ? `${PendingPanel_module_css_default.blockFlash} ${PendingPanel_module_css_default.blockFlashShake}` : PendingPanel_module_css_default.blockFlash,
|
|
14381
15117
|
"data-diff-block-flash": true,
|
|
14382
15118
|
style: {
|
|
14383
15119
|
top: flashTop,
|
|
@@ -14396,7 +15132,9 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14396
15132
|
value: searchQuery,
|
|
14397
15133
|
placeholder: t("panel.searchPlaceholder"),
|
|
14398
15134
|
onChange: (event) => {
|
|
14399
|
-
|
|
15135
|
+
const value = event.target.value;
|
|
15136
|
+
setSearchQuery(value);
|
|
15137
|
+
setSearchIndex(startIndexFor(value));
|
|
14400
15138
|
},
|
|
14401
15139
|
onKeyDown: (event) => {
|
|
14402
15140
|
if (event.key === "Enter") {
|
|
@@ -14410,27 +15148,37 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14410
15148
|
"data-diff-search-count": true,
|
|
14411
15149
|
children: searchMatches.length === 0 ? "0/0" : `${searchIndex % searchMatches.length + 1}/${searchMatches.length}`
|
|
14412
15150
|
}),
|
|
14413
|
-
(0, react_jsx_runtime.jsx)(
|
|
14414
|
-
|
|
14415
|
-
|
|
14416
|
-
|
|
14417
|
-
|
|
14418
|
-
|
|
14419
|
-
|
|
14420
|
-
|
|
14421
|
-
|
|
14422
|
-
|
|
15151
|
+
(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
15152
|
+
label: `${t("action.prevDiff")} (Shift+F3)`,
|
|
15153
|
+
side: "bottom",
|
|
15154
|
+
delayMs: 500,
|
|
15155
|
+
children: (0, react_jsx_runtime.jsx)("button", {
|
|
15156
|
+
type: "button",
|
|
15157
|
+
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.iconAction}`,
|
|
15158
|
+
"data-diff-search-prev": true,
|
|
15159
|
+
"aria-label": t("action.prevDiff"),
|
|
15160
|
+
disabled: searchMatches.length === 0,
|
|
15161
|
+
onClick: () => {
|
|
15162
|
+
goSearch(-1);
|
|
15163
|
+
},
|
|
15164
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronUpOutline14, { size: 14 })
|
|
15165
|
+
})
|
|
14423
15166
|
}),
|
|
14424
|
-
(0, react_jsx_runtime.jsx)(
|
|
14425
|
-
|
|
14426
|
-
|
|
14427
|
-
|
|
14428
|
-
|
|
14429
|
-
|
|
14430
|
-
|
|
14431
|
-
|
|
14432
|
-
|
|
14433
|
-
|
|
15167
|
+
(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
15168
|
+
label: `${t("action.nextDiff")} (F3)`,
|
|
15169
|
+
side: "bottom",
|
|
15170
|
+
delayMs: 500,
|
|
15171
|
+
children: (0, react_jsx_runtime.jsx)("button", {
|
|
15172
|
+
type: "button",
|
|
15173
|
+
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.iconAction}`,
|
|
15174
|
+
"data-diff-search-next": true,
|
|
15175
|
+
"aria-label": t("action.nextDiff"),
|
|
15176
|
+
disabled: searchMatches.length === 0,
|
|
15177
|
+
onClick: () => {
|
|
15178
|
+
goSearch(1);
|
|
15179
|
+
},
|
|
15180
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { size: 14 })
|
|
15181
|
+
})
|
|
14434
15182
|
}),
|
|
14435
15183
|
(0, react_jsx_runtime.jsx)("button", {
|
|
14436
15184
|
type: "button",
|
|
@@ -14466,17 +15214,25 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14466
15214
|
label: copied ? t("action.copied") : `${t("action.copyHint")} (Ctrl+L)`,
|
|
14467
15215
|
side: "top",
|
|
14468
15216
|
delayMs: 300,
|
|
14469
|
-
children: (0, react_jsx_runtime.jsx)("
|
|
14470
|
-
|
|
15217
|
+
children: (0, react_jsx_runtime.jsx)("span", {
|
|
15218
|
+
role: "button",
|
|
15219
|
+
tabIndex: 0,
|
|
14471
15220
|
className: PendingPanel_module_css_default.statusAction,
|
|
14472
15221
|
"data-diff-copy": true,
|
|
15222
|
+
"data-mobile-nav-copy": "1",
|
|
14473
15223
|
onMouseDown: (event) => {
|
|
14474
15224
|
event.preventDefault();
|
|
14475
15225
|
},
|
|
14476
15226
|
onClick: () => {
|
|
14477
15227
|
copySelection();
|
|
14478
15228
|
},
|
|
14479
|
-
|
|
15229
|
+
onKeyDown: (event) => {
|
|
15230
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
15231
|
+
event.preventDefault();
|
|
15232
|
+
copySelection();
|
|
15233
|
+
}
|
|
15234
|
+
},
|
|
15235
|
+
children: copied ? t("action.copied") : selectionReferenceLabel
|
|
14480
15236
|
})
|
|
14481
15237
|
}),
|
|
14482
15238
|
(0, react_jsx_runtime.jsx)("span", { className: PendingPanel_module_css_default.flexSpacer }),
|
|
@@ -14536,7 +15292,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14536
15292
|
});
|
|
14537
15293
|
}
|
|
14538
15294
|
/** Render the pending-edit review panel and its unified footer action. */
|
|
14539
|
-
function PendingPanel({ wide, useSessions, usePending, onRefresh, onKeep, onRevert, onBlockKeep, onBlockRevert, onOpen, onPasteReference, onUndo, onRedo, onImportVcs, onAckRedoCleared,
|
|
15295
|
+
function PendingPanel({ wide, useSessions, usePending, onRefresh, onKeep, onRevert, onBlockKeep, onBlockRevert, onOpen, onPasteReference, onUndo, onRedo, onImportVcs, onAckRedoCleared, collapseSidebar, t }) {
|
|
14540
15296
|
const current = useSessions((state) => state.current);
|
|
14541
15297
|
const currentBlank = useSessions((state) => {
|
|
14542
15298
|
const id = state.current;
|
|
@@ -14566,10 +15322,38 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14566
15322
|
const [actionToast, setActionToast] = (0, react.useState)(null);
|
|
14567
15323
|
/** A transient banner confirming a reference was copied to the clipboard. */
|
|
14568
15324
|
const [copyToast, setCopyToast] = (0, react.useState)(null);
|
|
15325
|
+
const showCopyToast = (text) => {
|
|
15326
|
+
setCopyToast((prev) => ({
|
|
15327
|
+
text,
|
|
15328
|
+
n: (prev?.n ?? 0) + 1
|
|
15329
|
+
}));
|
|
15330
|
+
};
|
|
15331
|
+
const handleOpenFileRef = (0, react.useRef)();
|
|
15332
|
+
handleOpenFileRef.current = (path) => {
|
|
15333
|
+
const entry = snapshot.files.find((file) => diffPathsMatch(path, file.path, snapshot.workspacePath));
|
|
15334
|
+
if (entry === void 0) {
|
|
15335
|
+
showCopyToast(t("panel.fileNotPending"));
|
|
15336
|
+
return;
|
|
15337
|
+
}
|
|
15338
|
+
setOpen(true);
|
|
15339
|
+
setSelected(entry.id);
|
|
15340
|
+
};
|
|
15341
|
+
(0, react.useEffect)(() => {
|
|
15342
|
+
const onOpenFile = (event) => {
|
|
15343
|
+
const path = event.detail?.path;
|
|
15344
|
+
if (typeof path !== "string") return;
|
|
15345
|
+
handleOpenFileRef.current?.(path);
|
|
15346
|
+
};
|
|
15347
|
+
window.addEventListener(OPEN_FILE_EVENT, onOpenFile);
|
|
15348
|
+
return () => {
|
|
15349
|
+
window.removeEventListener(OPEN_FILE_EVENT, onOpenFile);
|
|
15350
|
+
};
|
|
15351
|
+
}, []);
|
|
14569
15352
|
/** Whether the redo-cleared notice is showing (bottom-right, OK to dismiss). */
|
|
14570
15353
|
const [redoClearedNotice, setRedoClearedNotice] = (0, react.useState)(false);
|
|
14571
|
-
/** A
|
|
14572
|
-
|
|
15354
|
+
/** A last-block keep/revert awaiting the user's remove-or-keep choice; the
|
|
15355
|
+
* choice rides the same block RPC as its `removeWhenResolved` flag. */
|
|
15356
|
+
const [blockPrompt, setBlockPrompt] = (0, react.useState)(null);
|
|
14573
15357
|
/** Bottom offset tracking the chat composer's top edge so the input stays visible. */
|
|
14574
15358
|
const [bottomPx, setBottomPx] = (0, react.useState)(FALLBACK_BOTTOM_PX);
|
|
14575
15359
|
/** Fullscreen expanded: the panel bottom pins to the window edge, ignoring the composer offset. */
|
|
@@ -14708,6 +15492,32 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14708
15492
|
};
|
|
14709
15493
|
}, [open]);
|
|
14710
15494
|
const files = snapshot.files.filter((file) => current !== void 0 && (file.sessionIds ?? [file.sessionId]).includes(current)).sort((left, right) => compareFileNames(left.path, right.path));
|
|
15495
|
+
const blockKeepWithPrompt = (sessionId, id, block, removeWhenResolved) => {
|
|
15496
|
+
const file = files.find((entry) => entry.id === id);
|
|
15497
|
+
if (removeWhenResolved === void 0 && file !== void 0 && changeBlocksOf(computeWholeFileDiff(file.oldText, file.newText)).length === 1) {
|
|
15498
|
+
setBlockPrompt({
|
|
15499
|
+
action: "keep",
|
|
15500
|
+
sessionId,
|
|
15501
|
+
id,
|
|
15502
|
+
block
|
|
15503
|
+
});
|
|
15504
|
+
return Promise.resolve();
|
|
15505
|
+
}
|
|
15506
|
+
return removeWhenResolved === void 0 ? onBlockKeep(sessionId, id, block) : onBlockKeep(sessionId, id, block, removeWhenResolved);
|
|
15507
|
+
};
|
|
15508
|
+
const blockRevertWithPrompt = (sessionId, id, block, removeWhenResolved) => {
|
|
15509
|
+
const file = files.find((entry) => entry.id === id);
|
|
15510
|
+
if (removeWhenResolved === void 0 && file !== void 0 && changeBlocksOf(computeWholeFileDiff(file.oldText, file.newText)).length === 1) {
|
|
15511
|
+
setBlockPrompt({
|
|
15512
|
+
action: "revert",
|
|
15513
|
+
sessionId,
|
|
15514
|
+
id,
|
|
15515
|
+
block
|
|
15516
|
+
});
|
|
15517
|
+
return Promise.resolve();
|
|
15518
|
+
}
|
|
15519
|
+
return removeWhenResolved === void 0 ? onBlockRevert(sessionId, id, block) : onBlockRevert(sessionId, id, block, removeWhenResolved);
|
|
15520
|
+
};
|
|
14711
15521
|
/** Per-file keep/revert failures, surfaced inline on the row and detail. */
|
|
14712
15522
|
const failed = snapshot.failed ?? EMPTY_FAILED_MAP;
|
|
14713
15523
|
const failedInitialized = (0, react.useRef)(false);
|
|
@@ -14724,11 +15534,6 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14724
15534
|
if (fresh.length > 0) setActionToast(fresh[0][1]);
|
|
14725
15535
|
failedRef.current = current;
|
|
14726
15536
|
}, [snapshot.failed]);
|
|
14727
|
-
(0, react.useEffect)(() => {
|
|
14728
|
-
if (snapshot.justResolved === void 0) return;
|
|
14729
|
-
setConfirmDismiss(snapshot.justResolved);
|
|
14730
|
-
onAckJustResolved();
|
|
14731
|
-
}, [snapshot.justResolved, onAckJustResolved]);
|
|
14732
15537
|
(0, react.useEffect)(() => {
|
|
14733
15538
|
if (!open) return;
|
|
14734
15539
|
if (selected !== "" && files.some((file) => file.id === selected)) return;
|
|
@@ -14786,8 +15591,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14786
15591
|
}
|
|
14787
15592
|
}, entry.id);
|
|
14788
15593
|
const selectedFile = files.find((file) => file.id === selected);
|
|
14789
|
-
/** The file whose removal is being confirmed, if any. */
|
|
14790
|
-
const
|
|
15594
|
+
/** The file whose removal is being confirmed (a last-block action), if any. */
|
|
15595
|
+
const promptFile = blockPrompt === null ? void 0 : files.find((file) => file.id === blockPrompt.id);
|
|
14791
15596
|
const fileListBody = (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("div", {
|
|
14792
15597
|
className: PendingPanel_module_css_default.listScroll,
|
|
14793
15598
|
children: files.length > 0 && (0, react_jsx_runtime.jsxs)("section", { children: [(0, react_jsx_runtime.jsx)("h3", {
|
|
@@ -14835,15 +15640,17 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14835
15640
|
if (!open || current === void 0) return;
|
|
14836
15641
|
const onKeyDown = (event) => {
|
|
14837
15642
|
if (!(event.ctrlKey || event.metaKey) || event.altKey) return;
|
|
14838
|
-
const key = event.key.toLowerCase();
|
|
14839
|
-
if (key !== "z" && key !== "y") return;
|
|
14840
15643
|
const target = event.target;
|
|
14841
15644
|
if (target instanceof Element && target.closest("input, textarea, [contenteditable=\"true\"]") !== null) return;
|
|
14842
|
-
event
|
|
14843
|
-
|
|
14844
|
-
|
|
14845
|
-
|
|
14846
|
-
}
|
|
15645
|
+
if (matchesShortcut(event, keybindingOf("undo"))) {
|
|
15646
|
+
event.preventDefault();
|
|
15647
|
+
handleUndo(current);
|
|
15648
|
+
return;
|
|
15649
|
+
}
|
|
15650
|
+
if (matchesShortcut(event, keybindingOf("redo")) || matchesShortcut(event, "Ctrl+Y")) {
|
|
15651
|
+
event.preventDefault();
|
|
15652
|
+
handleRedo(current);
|
|
15653
|
+
}
|
|
14847
15654
|
};
|
|
14848
15655
|
window.addEventListener("keydown", onKeyDown, true);
|
|
14849
15656
|
return () => {
|
|
@@ -14858,14 +15665,15 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14858
15665
|
(0, react.useEffect)(() => {
|
|
14859
15666
|
if (!open || current === void 0) return;
|
|
14860
15667
|
const onKeyDown = (event) => {
|
|
14861
|
-
|
|
14862
|
-
if (event
|
|
15668
|
+
let direction = 0;
|
|
15669
|
+
if (matchesShortcut(event, keybindingOf("cycleNext"))) direction = 1;
|
|
15670
|
+
else if (matchesShortcut(event, keybindingOf("cyclePrev"))) direction = -1;
|
|
15671
|
+
if (direction === 0) return;
|
|
14863
15672
|
const target = event.target;
|
|
14864
15673
|
if (target instanceof Element && target.closest("input, textarea, [contenteditable=\"true\"]") !== null) return;
|
|
14865
15674
|
if (files.length === 0) return;
|
|
14866
15675
|
event.preventDefault();
|
|
14867
15676
|
const index = files.findIndex((file) => file.id === selected);
|
|
14868
|
-
const direction = event.shiftKey ? -1 : 1;
|
|
14869
15677
|
const next = files[(index + direction + files.length) % files.length];
|
|
14870
15678
|
if (next !== void 0) setSelected(next.id);
|
|
14871
15679
|
};
|
|
@@ -14949,11 +15757,11 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
14949
15757
|
}
|
|
14950
15758
|
}),
|
|
14951
15759
|
copyToast !== null && (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Toast, {
|
|
14952
|
-
text: copyToast,
|
|
15760
|
+
text: copyToast.text,
|
|
14953
15761
|
onDone: () => {
|
|
14954
15762
|
setCopyToast(null);
|
|
14955
15763
|
}
|
|
14956
|
-
}),
|
|
15764
|
+
}, copyToast.n),
|
|
14957
15765
|
open && (0, react_dom.createPortal)((0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [expanded && (0, react_jsx_runtime.jsx)("div", {
|
|
14958
15766
|
className: PendingPanel_module_css_default.fullscreenBackdrop,
|
|
14959
15767
|
"data-diff-fullscreen-backdrop": true
|
|
@@ -15087,14 +15895,12 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
15087
15895
|
undoFlash,
|
|
15088
15896
|
failedMessage: failed.get(selectedFile.id),
|
|
15089
15897
|
onPasteReference,
|
|
15090
|
-
onToast:
|
|
15091
|
-
setCopyToast(text);
|
|
15092
|
-
},
|
|
15898
|
+
onToast: showCopyToast,
|
|
15093
15899
|
t,
|
|
15094
15900
|
onKeep,
|
|
15095
15901
|
onRevert,
|
|
15096
|
-
onBlockKeep,
|
|
15097
|
-
onBlockRevert,
|
|
15902
|
+
onBlockKeep: blockKeepWithPrompt,
|
|
15903
|
+
onBlockRevert: blockRevertWithPrompt,
|
|
15098
15904
|
onOpen,
|
|
15099
15905
|
floatMode,
|
|
15100
15906
|
floatOpen,
|
|
@@ -15114,7 +15920,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
15114
15920
|
})
|
|
15115
15921
|
]
|
|
15116
15922
|
}),
|
|
15117
|
-
|
|
15923
|
+
blockPrompt !== null && promptFile !== void 0 && (0, react_jsx_runtime.jsx)("div", {
|
|
15118
15924
|
className: PendingPanel_module_css_default.confirmBackdrop,
|
|
15119
15925
|
"data-diff-confirm": true,
|
|
15120
15926
|
children: (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -15123,7 +15929,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
15123
15929
|
"aria-modal": "true",
|
|
15124
15930
|
children: [(0, react_jsx_runtime.jsx)("p", {
|
|
15125
15931
|
className: PendingPanel_module_css_default.confirmText,
|
|
15126
|
-
children: t("panel.resolvedAsk", { file: basenameOf(
|
|
15932
|
+
children: t("panel.resolvedAsk", { file: basenameOf(promptFile.path) })
|
|
15127
15933
|
}), (0, react_jsx_runtime.jsxs)("div", {
|
|
15128
15934
|
className: PendingPanel_module_css_default.confirmActions,
|
|
15129
15935
|
children: [(0, react_jsx_runtime.jsx)("button", {
|
|
@@ -15131,8 +15937,9 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
15131
15937
|
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.actionPrimary}`,
|
|
15132
15938
|
"data-diff-confirm-remove": true,
|
|
15133
15939
|
onClick: () => {
|
|
15134
|
-
|
|
15135
|
-
|
|
15940
|
+
setBlockPrompt(null);
|
|
15941
|
+
const { action, sessionId, id, block } = blockPrompt;
|
|
15942
|
+
action === "keep" ? onBlockKeep(sessionId, id, block, true) : onBlockRevert(sessionId, id, block, true);
|
|
15136
15943
|
},
|
|
15137
15944
|
children: t("row.dismiss")
|
|
15138
15945
|
}), (0, react_jsx_runtime.jsx)("button", {
|
|
@@ -15140,7 +15947,9 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
15140
15947
|
className: PendingPanel_module_css_default.action,
|
|
15141
15948
|
"data-diff-confirm-keep": true,
|
|
15142
15949
|
onClick: () => {
|
|
15143
|
-
|
|
15950
|
+
setBlockPrompt(null);
|
|
15951
|
+
const { action, sessionId, id, block } = blockPrompt;
|
|
15952
|
+
action === "keep" ? onBlockKeep(sessionId, id, block, false) : onBlockRevert(sessionId, id, block, false);
|
|
15144
15953
|
},
|
|
15145
15954
|
children: t("panel.keepInList")
|
|
15146
15955
|
})]
|
|
@@ -15194,6 +16003,215 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
15194
16003
|
});
|
|
15195
16004
|
}
|
|
15196
16005
|
//#endregion
|
|
16006
|
+
//#region lib/types/client/ColorPicker.js
|
|
16007
|
+
/** A compact HSV color picker (saturation/value square + hue bar + hex/RGB
|
|
16008
|
+
* input). Avoids the browser-native color dialog, which cannot be themed, so
|
|
16009
|
+
* it matches DSH. Pure helpers are exported for testing. */
|
|
16010
|
+
/** Clamp `n` to `[min, max]`. */
|
|
16011
|
+
function clamp(n, min, max) {
|
|
16012
|
+
return Math.max(min, Math.min(max, n));
|
|
16013
|
+
}
|
|
16014
|
+
/** Parse `#rrggbb` / `#rgb` / `rrggbb` / `rgb(r,g,b)` into a normalised
|
|
16015
|
+
* `#rrggbb`, or `undefined` when the text is not a color. */
|
|
16016
|
+
function parseColor(input) {
|
|
16017
|
+
const text = input.trim();
|
|
16018
|
+
let m = /^#?([0-9a-f]{6})$/i.exec(text);
|
|
16019
|
+
if (m !== null) return `#${m[1].toLowerCase()}`;
|
|
16020
|
+
m = /^#?([0-9a-f]{3})$/i.exec(text);
|
|
16021
|
+
if (m !== null) return `#${m[1].split("").map((c) => c + c).join("").toLowerCase()}`;
|
|
16022
|
+
m = /^rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})(?:\s*,\s*[\d.]+\s*)?\)$/i.exec(text);
|
|
16023
|
+
if (m !== null) return `#${[
|
|
16024
|
+
Math.min(255, Number(m[1])),
|
|
16025
|
+
Math.min(255, Number(m[2])),
|
|
16026
|
+
Math.min(255, Number(m[3]))
|
|
16027
|
+
].map((n) => n.toString(16).padStart(2, "0")).join("")}`;
|
|
16028
|
+
}
|
|
16029
|
+
/** Convert a `#rrggbb` hex to HSV (h 0-360, s 0-1, v 0-1). */
|
|
16030
|
+
function hexToHsv(hex) {
|
|
16031
|
+
const m = /^#?([0-9a-f]{6})$/i.exec(hex.trim());
|
|
16032
|
+
const int = m === null ? 2278750 : Number.parseInt(m[1], 16);
|
|
16033
|
+
const r = (int >> 16 & 255) / 255;
|
|
16034
|
+
const g = (int >> 8 & 255) / 255;
|
|
16035
|
+
const b = (int & 255) / 255;
|
|
16036
|
+
const max = Math.max(r, g, b);
|
|
16037
|
+
const d = max - Math.min(r, g, b);
|
|
16038
|
+
let h = 0;
|
|
16039
|
+
if (d !== 0) {
|
|
16040
|
+
if (max === r) h = (g - b) / d % 6;
|
|
16041
|
+
else if (max === g) h = (b - r) / d + 2;
|
|
16042
|
+
else h = (r - g) / d + 4;
|
|
16043
|
+
h *= 60;
|
|
16044
|
+
if (h < 0) h += 360;
|
|
16045
|
+
}
|
|
16046
|
+
const s = max === 0 ? 0 : d / max;
|
|
16047
|
+
return {
|
|
16048
|
+
h,
|
|
16049
|
+
s,
|
|
16050
|
+
v: max
|
|
16051
|
+
};
|
|
16052
|
+
}
|
|
16053
|
+
/** Convert HSV (h 0-360, s 0-1, v 0-1) to a `#rrggbb` hex. */
|
|
16054
|
+
function hsvToHex(h, s, v) {
|
|
16055
|
+
const c = v * s;
|
|
16056
|
+
const x = c * (1 - Math.abs((h % 360 + 360) % 360 / 60 % 2 - 1));
|
|
16057
|
+
const m = v - c;
|
|
16058
|
+
const hp = (h % 360 + 360) % 360;
|
|
16059
|
+
let r = 0;
|
|
16060
|
+
let g = 0;
|
|
16061
|
+
let b = 0;
|
|
16062
|
+
if (hp < 60) {
|
|
16063
|
+
r = c;
|
|
16064
|
+
g = x;
|
|
16065
|
+
b = 0;
|
|
16066
|
+
} else if (hp < 120) {
|
|
16067
|
+
r = x;
|
|
16068
|
+
g = c;
|
|
16069
|
+
b = 0;
|
|
16070
|
+
} else if (hp < 180) {
|
|
16071
|
+
r = 0;
|
|
16072
|
+
g = c;
|
|
16073
|
+
b = x;
|
|
16074
|
+
} else if (hp < 240) {
|
|
16075
|
+
r = 0;
|
|
16076
|
+
g = x;
|
|
16077
|
+
b = c;
|
|
16078
|
+
} else if (hp < 300) {
|
|
16079
|
+
r = x;
|
|
16080
|
+
g = 0;
|
|
16081
|
+
b = c;
|
|
16082
|
+
} else {
|
|
16083
|
+
r = c;
|
|
16084
|
+
g = 0;
|
|
16085
|
+
b = x;
|
|
16086
|
+
}
|
|
16087
|
+
const to8 = (n) => Math.round((n + m) * 255).toString(16).padStart(2, "0");
|
|
16088
|
+
return `#${to8(r)}${to8(g)}${to8(b)}`;
|
|
16089
|
+
}
|
|
16090
|
+
/** A draggable HSV picker: saturation/value square + hue bar + a hex/RGB text
|
|
16091
|
+
* input. `onChange` reports a normalised `#rrggbb`; `onClose` fires after a
|
|
16092
|
+
* committed text value so the caller can close the popover. */
|
|
16093
|
+
function ColorPicker({ value, onChange, onClose, ariaLabel }) {
|
|
16094
|
+
const [hsv, setHsv] = (0, react.useState)(() => hexToHsv(value));
|
|
16095
|
+
const [text, setText] = (0, react.useState)(() => value.toUpperCase());
|
|
16096
|
+
const svRef = (0, react.useRef)(null);
|
|
16097
|
+
const hueRef = (0, react.useRef)(null);
|
|
16098
|
+
(0, react.useEffect)(() => {
|
|
16099
|
+
setHsv(hexToHsv(value));
|
|
16100
|
+
setText(value.toUpperCase());
|
|
16101
|
+
}, [value]);
|
|
16102
|
+
const hueColor = `hsl(${hsv.h.toFixed(1)}, 100%, 50%)`;
|
|
16103
|
+
const commit = (next) => {
|
|
16104
|
+
const normalized = parseColor(next);
|
|
16105
|
+
if (normalized !== void 0 && normalized.toLowerCase() !== value.toLowerCase()) {
|
|
16106
|
+
onChange(normalized);
|
|
16107
|
+
onClose?.();
|
|
16108
|
+
}
|
|
16109
|
+
};
|
|
16110
|
+
const updateSv = (clientX, clientY) => {
|
|
16111
|
+
const el = svRef.current;
|
|
16112
|
+
if (el === null) return;
|
|
16113
|
+
const rect = el.getBoundingClientRect();
|
|
16114
|
+
const s = clamp((clientX - rect.left) / rect.width, 0, 1);
|
|
16115
|
+
const v = 1 - clamp((clientY - rect.top) / rect.height, 0, 1);
|
|
16116
|
+
const hex = hsvToHex(hsv.h, s, v);
|
|
16117
|
+
setHsv((prev) => ({
|
|
16118
|
+
h: prev.h,
|
|
16119
|
+
s,
|
|
16120
|
+
v
|
|
16121
|
+
}));
|
|
16122
|
+
setText(hex.toUpperCase());
|
|
16123
|
+
onChange(hex);
|
|
16124
|
+
};
|
|
16125
|
+
const updateHue = (clientX) => {
|
|
16126
|
+
const el = hueRef.current;
|
|
16127
|
+
if (el === null) return;
|
|
16128
|
+
const rect = el.getBoundingClientRect();
|
|
16129
|
+
const h = clamp((clientX - rect.left) / rect.width, 0, 1) * 360;
|
|
16130
|
+
const hex = hsvToHex(h, hsv.s, hsv.v);
|
|
16131
|
+
setHsv((prev) => ({
|
|
16132
|
+
h,
|
|
16133
|
+
s: prev.s,
|
|
16134
|
+
v: prev.v
|
|
16135
|
+
}));
|
|
16136
|
+
setText(hex.toUpperCase());
|
|
16137
|
+
onChange(hex);
|
|
16138
|
+
};
|
|
16139
|
+
const onSvPointerDown = (e) => {
|
|
16140
|
+
e.currentTarget.setPointerCapture?.(e.pointerId);
|
|
16141
|
+
updateSv(e.clientX, e.clientY);
|
|
16142
|
+
};
|
|
16143
|
+
const onSvPointerMove = (e) => {
|
|
16144
|
+
if (e.buttons > 0) updateSv(e.clientX, e.clientY);
|
|
16145
|
+
};
|
|
16146
|
+
const onHuePointerDown = (e) => {
|
|
16147
|
+
e.currentTarget.setPointerCapture?.(e.pointerId);
|
|
16148
|
+
updateHue(e.clientX);
|
|
16149
|
+
};
|
|
16150
|
+
const onHuePointerMove = (e) => {
|
|
16151
|
+
if (e.buttons > 0) updateHue(e.clientX);
|
|
16152
|
+
};
|
|
16153
|
+
return (0, react_jsx_runtime.jsxs)("div", {
|
|
16154
|
+
className: PendingPanel_module_css_default.colorPickerPanel,
|
|
16155
|
+
children: [
|
|
16156
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
16157
|
+
className: PendingPanel_module_css_default.colorPickerInputRow,
|
|
16158
|
+
children: [(0, react_jsx_runtime.jsx)("span", {
|
|
16159
|
+
className: PendingPanel_module_css_default.colorPickerPreview,
|
|
16160
|
+
style: { background: value },
|
|
16161
|
+
"aria-hidden": "true"
|
|
16162
|
+
}), (0, react_jsx_runtime.jsx)("input", {
|
|
16163
|
+
className: PendingPanel_module_css_default.colorPickerInput,
|
|
16164
|
+
value: text,
|
|
16165
|
+
"aria-label": ariaLabel,
|
|
16166
|
+
"data-diff-color-input": true,
|
|
16167
|
+
onChange: (e) => {
|
|
16168
|
+
setText(e.target.value.toUpperCase());
|
|
16169
|
+
},
|
|
16170
|
+
onBlur: () => {
|
|
16171
|
+
commit(text);
|
|
16172
|
+
},
|
|
16173
|
+
onKeyDown: (e) => {
|
|
16174
|
+
if (e.key === "Enter") e.currentTarget.blur();
|
|
16175
|
+
}
|
|
16176
|
+
})]
|
|
16177
|
+
}),
|
|
16178
|
+
(0, react_jsx_runtime.jsx)("div", {
|
|
16179
|
+
className: PendingPanel_module_css_default.colorSv,
|
|
16180
|
+
ref: svRef,
|
|
16181
|
+
style: { background: `linear-gradient(to top, #000, transparent), linear-gradient(to right, #fff, ${hueColor})` },
|
|
16182
|
+
onPointerDown: onSvPointerDown,
|
|
16183
|
+
onPointerMove: onSvPointerMove,
|
|
16184
|
+
role: "slider",
|
|
16185
|
+
"aria-label": `${ariaLabel} color`,
|
|
16186
|
+
"aria-valuetext": value,
|
|
16187
|
+
children: (0, react_jsx_runtime.jsx)("span", {
|
|
16188
|
+
className: PendingPanel_module_css_default.colorSvCursor,
|
|
16189
|
+
style: {
|
|
16190
|
+
left: `${hsv.s * 100}%`,
|
|
16191
|
+
top: `${(1 - hsv.v) * 100}%`,
|
|
16192
|
+
background: value
|
|
16193
|
+
},
|
|
16194
|
+
"aria-hidden": "true"
|
|
16195
|
+
})
|
|
16196
|
+
}),
|
|
16197
|
+
(0, react_jsx_runtime.jsx)("div", {
|
|
16198
|
+
className: PendingPanel_module_css_default.colorHue,
|
|
16199
|
+
ref: hueRef,
|
|
16200
|
+
style: { background: "linear-gradient(to right, #f00 0%, #ff0 17%, #0f0 33%, #0ff 50%, #00f 67%, #f0f 83%, #f00 100%)" },
|
|
16201
|
+
onPointerDown: onHuePointerDown,
|
|
16202
|
+
onPointerMove: onHuePointerMove,
|
|
16203
|
+
role: "slider",
|
|
16204
|
+
"aria-label": `${ariaLabel} hue`,
|
|
16205
|
+
children: (0, react_jsx_runtime.jsx)("span", {
|
|
16206
|
+
className: PendingPanel_module_css_default.colorHueCursor,
|
|
16207
|
+
style: { left: `${hsv.h / 360 * 100}%` },
|
|
16208
|
+
"aria-hidden": "true"
|
|
16209
|
+
})
|
|
16210
|
+
})
|
|
16211
|
+
]
|
|
16212
|
+
});
|
|
16213
|
+
}
|
|
16214
|
+
//#endregion
|
|
15197
16215
|
//#region lib/types/client/SettingsTab.js
|
|
15198
16216
|
/** DSH Settings top-level section for this plugin's preferences. */
|
|
15199
16217
|
/** A toggle switch offering the two boolean states 打开 / 关闭. */
|
|
@@ -15293,8 +16311,10 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
15293
16311
|
})]
|
|
15294
16312
|
});
|
|
15295
16313
|
}
|
|
15296
|
-
/** A +/- number stepper for an integer preference, clamped to [min, max].
|
|
15297
|
-
|
|
16314
|
+
/** A +/- number stepper for an integer preference, clamped to [min, max]. The
|
|
16315
|
+
* optional `step` changes the increment (default 1) and `unit` is appended to
|
|
16316
|
+
* the shown value (e.g. '%'). */
|
|
16317
|
+
function StepperRow({ title, description, value, onChange, min, max, dataAttribute, t, step = 1, unit = "" }) {
|
|
15298
16318
|
return (0, react_jsx_runtime.jsxs)("div", {
|
|
15299
16319
|
className: PendingPanel_module_css_default.settingsRow,
|
|
15300
16320
|
children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -15316,25 +16336,23 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
15316
16336
|
"aria-label": t("action.decrease"),
|
|
15317
16337
|
disabled: value <= min,
|
|
15318
16338
|
onClick: () => {
|
|
15319
|
-
onChange(Math.max(min, value -
|
|
15320
|
-
}
|
|
15321
|
-
children: "−"
|
|
16339
|
+
onChange(Math.max(min, value - step));
|
|
16340
|
+
}
|
|
15322
16341
|
}),
|
|
15323
|
-
(0, react_jsx_runtime.
|
|
16342
|
+
(0, react_jsx_runtime.jsxs)("span", {
|
|
15324
16343
|
className: PendingPanel_module_css_default.stepperValue,
|
|
15325
16344
|
[dataAttribute]: true,
|
|
15326
|
-
children: value
|
|
16345
|
+
children: [value, unit]
|
|
15327
16346
|
}),
|
|
15328
16347
|
(0, react_jsx_runtime.jsx)("button", {
|
|
15329
16348
|
type: "button",
|
|
15330
|
-
className: PendingPanel_module_css_default.stepperButton
|
|
16349
|
+
className: `${PendingPanel_module_css_default.stepperButton} ${PendingPanel_module_css_default.stepperButtonUp}`,
|
|
15331
16350
|
"data-diff-stepper-up": true,
|
|
15332
16351
|
"aria-label": t("action.increase"),
|
|
15333
16352
|
disabled: value >= max,
|
|
15334
16353
|
onClick: () => {
|
|
15335
|
-
onChange(Math.min(max, value +
|
|
15336
|
-
}
|
|
15337
|
-
children: "+"
|
|
16354
|
+
onChange(Math.min(max, value + step));
|
|
16355
|
+
}
|
|
15338
16356
|
})
|
|
15339
16357
|
]
|
|
15340
16358
|
})]
|
|
@@ -15403,6 +16421,162 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
15403
16421
|
})]
|
|
15404
16422
|
});
|
|
15405
16423
|
}
|
|
16424
|
+
/** One color-picker row: title + description left, a DSH pill trigger that opens
|
|
16425
|
+
* a small HSV dial (a real color picker, not preset swatches) with a hex/RGB
|
|
16426
|
+
* input. The native color dialog is browser-styled and is avoided. */
|
|
16427
|
+
function ColorRow({ title, description, value, onChange, dataAttribute }) {
|
|
16428
|
+
const [open, setOpen] = (0, react.useState)(false);
|
|
16429
|
+
return (0, react_jsx_runtime.jsxs)("div", {
|
|
16430
|
+
className: PendingPanel_module_css_default.settingsRow,
|
|
16431
|
+
children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
16432
|
+
className: PendingPanel_module_css_default.settingsRowText,
|
|
16433
|
+
children: [(0, react_jsx_runtime.jsx)("div", {
|
|
16434
|
+
className: PendingPanel_module_css_default.settingsRowTitle,
|
|
16435
|
+
children: title
|
|
16436
|
+
}), (0, react_jsx_runtime.jsx)("div", {
|
|
16437
|
+
className: PendingPanel_module_css_default.settingsRowDesc,
|
|
16438
|
+
children: description
|
|
16439
|
+
})]
|
|
16440
|
+
}), (0, react_jsx_runtime.jsxs)("div", {
|
|
16441
|
+
className: PendingPanel_module_css_default.colorPicker,
|
|
16442
|
+
children: [(0, react_jsx_runtime.jsxs)("button", {
|
|
16443
|
+
type: "button",
|
|
16444
|
+
className: PendingPanel_module_css_default.colorPickerTrigger,
|
|
16445
|
+
[dataAttribute]: true,
|
|
16446
|
+
"aria-haspopup": "dialog",
|
|
16447
|
+
"aria-expanded": open,
|
|
16448
|
+
"data-diff-color-trigger": true,
|
|
16449
|
+
onClick: () => {
|
|
16450
|
+
setOpen((value) => !value);
|
|
16451
|
+
},
|
|
16452
|
+
children: [
|
|
16453
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
16454
|
+
className: PendingPanel_module_css_default.colorSwatch,
|
|
16455
|
+
style: { background: value },
|
|
16456
|
+
"aria-hidden": "true"
|
|
16457
|
+
}),
|
|
16458
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
16459
|
+
className: PendingPanel_module_css_default.colorValue,
|
|
16460
|
+
children: value.toUpperCase()
|
|
16461
|
+
}),
|
|
16462
|
+
(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { className: PendingPanel_module_css_default.colorPickerChevron })
|
|
16463
|
+
]
|
|
16464
|
+
}), open && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("div", {
|
|
16465
|
+
className: PendingPanel_module_css_default.colorBackdrop,
|
|
16466
|
+
onClick: () => {
|
|
16467
|
+
setOpen(false);
|
|
16468
|
+
}
|
|
16469
|
+
}), (0, react_jsx_runtime.jsx)("div", {
|
|
16470
|
+
className: PendingPanel_module_css_default.colorPickerPopover,
|
|
16471
|
+
children: (0, react_jsx_runtime.jsx)(ColorPicker, {
|
|
16472
|
+
value,
|
|
16473
|
+
onChange,
|
|
16474
|
+
onClose: () => {
|
|
16475
|
+
setOpen(false);
|
|
16476
|
+
},
|
|
16477
|
+
ariaLabel: title
|
|
16478
|
+
})
|
|
16479
|
+
})] })]
|
|
16480
|
+
})]
|
|
16481
|
+
});
|
|
16482
|
+
}
|
|
16483
|
+
/** A live single-column diff preview driven by the current diff-view settings.
|
|
16484
|
+
* It reuses the real diff's CSS (`.line`/`.gutter`/`.code`/`.del`/`.add`/intra)
|
|
16485
|
+
* and applies the same CSS variables, so it reflects the actual look. */
|
|
16486
|
+
function DiffViewPreview({ fontScale, lineHeight, addColor, delColor, tabSize, t }) {
|
|
16487
|
+
const vars = {
|
|
16488
|
+
"--dsh-diff-font-scale": String(fontScale / 100),
|
|
16489
|
+
"--dsh-diff-line-height": `${lineHeight}px`,
|
|
16490
|
+
"--dsh-diff-add-color": addColor,
|
|
16491
|
+
"--dsh-diff-del-color": delColor
|
|
16492
|
+
};
|
|
16493
|
+
const rows = [
|
|
16494
|
+
{
|
|
16495
|
+
kind: PendingPanel_module_css_default.context,
|
|
16496
|
+
old: "1",
|
|
16497
|
+
next: "1",
|
|
16498
|
+
code: "export function review(file) {"
|
|
16499
|
+
},
|
|
16500
|
+
{
|
|
16501
|
+
kind: PendingPanel_module_css_default.context,
|
|
16502
|
+
old: "2",
|
|
16503
|
+
next: "2",
|
|
16504
|
+
code: " // 旧实现:保留当前改动"
|
|
16505
|
+
},
|
|
16506
|
+
{
|
|
16507
|
+
kind: PendingPanel_module_css_default.del,
|
|
16508
|
+
old: "3",
|
|
16509
|
+
next: "",
|
|
16510
|
+
code: (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
16511
|
+
" return ",
|
|
16512
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
16513
|
+
className: PendingPanel_module_css_default.intraDel,
|
|
16514
|
+
children: "keep"
|
|
16515
|
+
}),
|
|
16516
|
+
"(file)"
|
|
16517
|
+
] })
|
|
16518
|
+
},
|
|
16519
|
+
{
|
|
16520
|
+
kind: PendingPanel_module_css_default.context,
|
|
16521
|
+
old: "3",
|
|
16522
|
+
next: "3",
|
|
16523
|
+
code: " // 新实现:回退该改动"
|
|
16524
|
+
},
|
|
16525
|
+
{
|
|
16526
|
+
kind: PendingPanel_module_css_default.add,
|
|
16527
|
+
old: "",
|
|
16528
|
+
next: "3",
|
|
16529
|
+
code: (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
16530
|
+
" return ",
|
|
16531
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
16532
|
+
className: PendingPanel_module_css_default.intraAdd,
|
|
16533
|
+
children: "revert"
|
|
16534
|
+
}),
|
|
16535
|
+
"(file)"
|
|
16536
|
+
] })
|
|
16537
|
+
},
|
|
16538
|
+
{
|
|
16539
|
+
kind: PendingPanel_module_css_default.context,
|
|
16540
|
+
old: "4",
|
|
16541
|
+
next: "4",
|
|
16542
|
+
code: "}"
|
|
16543
|
+
}
|
|
16544
|
+
];
|
|
16545
|
+
return (0, react_jsx_runtime.jsxs)("div", {
|
|
16546
|
+
className: PendingPanel_module_css_default.diffPreview,
|
|
16547
|
+
style: {
|
|
16548
|
+
...vars,
|
|
16549
|
+
tabSize
|
|
16550
|
+
},
|
|
16551
|
+
"data-diff-view-preview": true,
|
|
16552
|
+
children: [(0, react_jsx_runtime.jsx)("div", {
|
|
16553
|
+
className: PendingPanel_module_css_default.diffPreviewTitle,
|
|
16554
|
+
children: t("settings.diffPreview")
|
|
16555
|
+
}), (0, react_jsx_runtime.jsx)("div", {
|
|
16556
|
+
className: PendingPanel_module_css_default.diffPreviewScroll,
|
|
16557
|
+
children: (0, react_jsx_runtime.jsx)("div", {
|
|
16558
|
+
className: PendingPanel_module_css_default.lines,
|
|
16559
|
+
children: rows.map((row, index) => (0, react_jsx_runtime.jsxs)("div", {
|
|
16560
|
+
className: `${PendingPanel_module_css_default.line} ${row.kind}`,
|
|
16561
|
+
children: [
|
|
16562
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
16563
|
+
className: PendingPanel_module_css_default.gutter,
|
|
16564
|
+
children: row.old
|
|
16565
|
+
}),
|
|
16566
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
16567
|
+
className: PendingPanel_module_css_default.gutter,
|
|
16568
|
+
children: row.next
|
|
16569
|
+
}),
|
|
16570
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
16571
|
+
className: PendingPanel_module_css_default.code,
|
|
16572
|
+
children: row.code
|
|
16573
|
+
})
|
|
16574
|
+
]
|
|
16575
|
+
}, index))
|
|
16576
|
+
})
|
|
16577
|
+
})]
|
|
16578
|
+
});
|
|
16579
|
+
}
|
|
15406
16580
|
/**
|
|
15407
16581
|
* The plugin's preferences: auto-paste a copied reference into the input,
|
|
15408
16582
|
* whether importing workspace VCS changes includes untracked files, and the
|
|
@@ -15417,7 +16591,27 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
15417
16591
|
const [tabOpen, setTabOpen] = (0, react.useState)(false);
|
|
15418
16592
|
const [split, setSplitState] = (0, react.useState)(splitMode);
|
|
15419
16593
|
const [lead, setLeadState] = (0, react.useState)(navLeadRows);
|
|
16594
|
+
const [fontScale, setFontScaleState] = (0, react.useState)(diffFontScale);
|
|
16595
|
+
const [lineHeight, setLineHeightState] = (0, react.useState)(diffLineHeight);
|
|
16596
|
+
const [addColor, setAddColorState] = (0, react.useState)(() => diffAddColor() ?? currentDiffAddColor());
|
|
16597
|
+
const [delColor, setDelColorState] = (0, react.useState)(() => diffDelColor() ?? currentDiffDelColor());
|
|
16598
|
+
const addDefault = currentDiffAddColor();
|
|
16599
|
+
const delDefault = currentDiffDelColor();
|
|
16600
|
+
const [diffOpen, setDiffOpen] = (0, react.useState)(true);
|
|
15420
16601
|
const [summon, setSummonState] = (0, react.useState)(quickSummonKey);
|
|
16602
|
+
const [keysOpen, setKeysOpen] = (0, react.useState)(false);
|
|
16603
|
+
const [keybindings, setKeybindingsState] = (0, react.useState)(() => {
|
|
16604
|
+
const initial = {};
|
|
16605
|
+
for (const action of Object.keys(DEFAULT_KEYBINDINGS)) initial[action] = keybindingOf(action);
|
|
16606
|
+
return initial;
|
|
16607
|
+
});
|
|
16608
|
+
const setKB = (action, chord) => {
|
|
16609
|
+
setKeybindingsState((prev) => ({
|
|
16610
|
+
...prev,
|
|
16611
|
+
[action]: chord
|
|
16612
|
+
}));
|
|
16613
|
+
setKeybinding(action, chord);
|
|
16614
|
+
};
|
|
15421
16615
|
const setSummon = (value) => {
|
|
15422
16616
|
setSummonState(value);
|
|
15423
16617
|
setQuickSummonKey(value);
|
|
@@ -15442,17 +16636,171 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
15442
16636
|
setLeadState(value);
|
|
15443
16637
|
setNavLeadRows(value);
|
|
15444
16638
|
};
|
|
16639
|
+
const setFontScale = (value) => {
|
|
16640
|
+
setFontScaleState(value);
|
|
16641
|
+
setDiffFontScale(value);
|
|
16642
|
+
};
|
|
16643
|
+
const setLineHeight = (value) => {
|
|
16644
|
+
setLineHeightState(value);
|
|
16645
|
+
setDiffLineHeight(value);
|
|
16646
|
+
};
|
|
16647
|
+
const setAddColor = (value) => {
|
|
16648
|
+
setAddColorState(value);
|
|
16649
|
+
setDiffAddColor(value);
|
|
16650
|
+
};
|
|
16651
|
+
const setDelColor = (value) => {
|
|
16652
|
+
setDelColorState(value);
|
|
16653
|
+
setDiffDelColor(value);
|
|
16654
|
+
};
|
|
15445
16655
|
return (0, react_jsx_runtime.jsxs)("div", {
|
|
15446
16656
|
className: PendingPanel_module_css_default.settingsPage,
|
|
15447
16657
|
"data-diff-settings": true,
|
|
15448
16658
|
children: [
|
|
15449
|
-
(0, react_jsx_runtime.
|
|
15450
|
-
|
|
15451
|
-
|
|
15452
|
-
|
|
15453
|
-
|
|
15454
|
-
|
|
15455
|
-
|
|
16659
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
16660
|
+
className: PendingPanel_module_css_default.settingsGroup,
|
|
16661
|
+
"data-open": diffOpen || void 0,
|
|
16662
|
+
children: [(0, react_jsx_runtime.jsxs)("button", {
|
|
16663
|
+
type: "button",
|
|
16664
|
+
className: PendingPanel_module_css_default.settingsGroupHeader,
|
|
16665
|
+
onClick: () => {
|
|
16666
|
+
setDiffOpen((open) => !open);
|
|
16667
|
+
},
|
|
16668
|
+
"data-diff-view-toggle": true,
|
|
16669
|
+
children: [(0, react_jsx_runtime.jsxs)("span", {
|
|
16670
|
+
className: PendingPanel_module_css_default.settingsGroupText,
|
|
16671
|
+
children: [(0, react_jsx_runtime.jsx)("span", {
|
|
16672
|
+
className: PendingPanel_module_css_default.settingsGroupTitle,
|
|
16673
|
+
children: t("settings.diffView")
|
|
16674
|
+
}), (0, react_jsx_runtime.jsx)("span", {
|
|
16675
|
+
className: PendingPanel_module_css_default.settingsGroupDesc,
|
|
16676
|
+
children: t("settings.diffViewDesc")
|
|
16677
|
+
})]
|
|
16678
|
+
}), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { className: PendingPanel_module_css_default.settingsGroupChevron })]
|
|
16679
|
+
}), diffOpen && (0, react_jsx_runtime.jsxs)("div", {
|
|
16680
|
+
className: PendingPanel_module_css_default.settingsGroupBody,
|
|
16681
|
+
children: [
|
|
16682
|
+
(0, react_jsx_runtime.jsx)(DiffViewPreview, {
|
|
16683
|
+
fontScale,
|
|
16684
|
+
lineHeight,
|
|
16685
|
+
addColor,
|
|
16686
|
+
delColor,
|
|
16687
|
+
tabSize: tab,
|
|
16688
|
+
t
|
|
16689
|
+
}),
|
|
16690
|
+
(0, react_jsx_runtime.jsx)(StepperRow, {
|
|
16691
|
+
title: t("panel.diffFontSize"),
|
|
16692
|
+
description: t("panel.diffFontSizeDesc"),
|
|
16693
|
+
value: fontScale,
|
|
16694
|
+
onChange: setFontScale,
|
|
16695
|
+
min: 50,
|
|
16696
|
+
max: 200,
|
|
16697
|
+
step: 10,
|
|
16698
|
+
unit: "%",
|
|
16699
|
+
dataAttribute: "data-diff-font-size",
|
|
16700
|
+
t
|
|
16701
|
+
}),
|
|
16702
|
+
(0, react_jsx_runtime.jsx)(StepperRow, {
|
|
16703
|
+
title: t("panel.diffLineHeight"),
|
|
16704
|
+
description: t("panel.diffLineHeightDesc"),
|
|
16705
|
+
value: lineHeight,
|
|
16706
|
+
onChange: setLineHeight,
|
|
16707
|
+
min: 10,
|
|
16708
|
+
max: 36,
|
|
16709
|
+
dataAttribute: "data-diff-line-height",
|
|
16710
|
+
t
|
|
16711
|
+
}),
|
|
16712
|
+
(0, react_jsx_runtime.jsx)(ColorRow, {
|
|
16713
|
+
title: t("panel.diffAddColor"),
|
|
16714
|
+
description: t("panel.diffAddColorDesc", { default: addDefault.toUpperCase() }),
|
|
16715
|
+
value: addColor,
|
|
16716
|
+
onChange: setAddColor,
|
|
16717
|
+
dataAttribute: "data-diff-add-color"
|
|
16718
|
+
}),
|
|
16719
|
+
(0, react_jsx_runtime.jsx)(ColorRow, {
|
|
16720
|
+
title: t("panel.diffDelColor"),
|
|
16721
|
+
description: t("panel.diffDelColorDesc", { default: delDefault.toUpperCase() }),
|
|
16722
|
+
value: delColor,
|
|
16723
|
+
onChange: setDelColor,
|
|
16724
|
+
dataAttribute: "data-diff-del-color"
|
|
16725
|
+
}),
|
|
16726
|
+
(0, react_jsx_runtime.jsx)(TabWidthRow, {
|
|
16727
|
+
title: t("panel.tabWidth"),
|
|
16728
|
+
description: t("panel.tabWidthDesc"),
|
|
16729
|
+
value: tab,
|
|
16730
|
+
open: tabOpen,
|
|
16731
|
+
onOpenChange: setTabOpen,
|
|
16732
|
+
onSelect: setTab,
|
|
16733
|
+
dataAttribute: "data-diff-tab-width-select"
|
|
16734
|
+
}),
|
|
16735
|
+
(0, react_jsx_runtime.jsx)(PreferenceRow, {
|
|
16736
|
+
title: t("panel.splitMode"),
|
|
16737
|
+
description: t("panel.splitModeDesc"),
|
|
16738
|
+
value: split,
|
|
16739
|
+
onSelect: setSplit,
|
|
16740
|
+
dataAttribute: "data-diff-split-mode-select",
|
|
16741
|
+
t
|
|
16742
|
+
}),
|
|
16743
|
+
(0, react_jsx_runtime.jsx)(StepperRow, {
|
|
16744
|
+
title: t("panel.navLeadRows"),
|
|
16745
|
+
description: t("panel.navLeadRowsDesc"),
|
|
16746
|
+
value: lead,
|
|
16747
|
+
onChange: setLead,
|
|
16748
|
+
min: 0,
|
|
16749
|
+
max: 10,
|
|
16750
|
+
dataAttribute: "data-diff-nav-lead-rows",
|
|
16751
|
+
t
|
|
16752
|
+
}),
|
|
16753
|
+
(0, react_jsx_runtime.jsx)(PreferenceRow, {
|
|
16754
|
+
title: t("panel.pasteOnCopy"),
|
|
16755
|
+
description: t("panel.pasteOnCopyDesc"),
|
|
16756
|
+
value: pasteOnCopy,
|
|
16757
|
+
onSelect: setPasteOnCopy,
|
|
16758
|
+
dataAttribute: "data-diff-paste-on-copy-select",
|
|
16759
|
+
t
|
|
16760
|
+
})
|
|
16761
|
+
]
|
|
16762
|
+
})]
|
|
16763
|
+
}),
|
|
16764
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
16765
|
+
className: PendingPanel_module_css_default.settingsGroup,
|
|
16766
|
+
"data-open": keysOpen || void 0,
|
|
16767
|
+
children: [(0, react_jsx_runtime.jsxs)("button", {
|
|
16768
|
+
type: "button",
|
|
16769
|
+
className: PendingPanel_module_css_default.settingsGroupHeader,
|
|
16770
|
+
onClick: () => {
|
|
16771
|
+
setKeysOpen((open) => !open);
|
|
16772
|
+
},
|
|
16773
|
+
"data-diff-keybindings-toggle": true,
|
|
16774
|
+
children: [(0, react_jsx_runtime.jsxs)("span", {
|
|
16775
|
+
className: PendingPanel_module_css_default.settingsGroupText,
|
|
16776
|
+
children: [(0, react_jsx_runtime.jsx)("span", {
|
|
16777
|
+
className: PendingPanel_module_css_default.settingsGroupTitle,
|
|
16778
|
+
children: t("settings.keybindings")
|
|
16779
|
+
}), (0, react_jsx_runtime.jsx)("span", {
|
|
16780
|
+
className: PendingPanel_module_css_default.settingsGroupDesc,
|
|
16781
|
+
children: t("settings.keybindingsDesc")
|
|
16782
|
+
})]
|
|
16783
|
+
}), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { className: PendingPanel_module_css_default.settingsGroupChevron })]
|
|
16784
|
+
}), keysOpen && (0, react_jsx_runtime.jsxs)("div", {
|
|
16785
|
+
className: PendingPanel_module_css_default.settingsGroupBody,
|
|
16786
|
+
children: [(0, react_jsx_runtime.jsx)(ShortcutRow, {
|
|
16787
|
+
title: t("panel.quickSummon"),
|
|
16788
|
+
description: t("panel.quickSummonDesc"),
|
|
16789
|
+
value: summon,
|
|
16790
|
+
onChange: setSummon,
|
|
16791
|
+
dataAttribute: "data-diff-quick-summon-key",
|
|
16792
|
+
placeholder: t("panel.recordShortcut")
|
|
16793
|
+
}), Object.keys(DEFAULT_KEYBINDINGS).map((action) => (0, react_jsx_runtime.jsx)(ShortcutRow, {
|
|
16794
|
+
title: t(`panel.key.${action}`),
|
|
16795
|
+
description: t("panel.keyDesc"),
|
|
16796
|
+
value: keybindings[action] ?? DEFAULT_KEYBINDINGS[action] ?? "",
|
|
16797
|
+
onChange: (chord) => {
|
|
16798
|
+
setKB(action, chord);
|
|
16799
|
+
},
|
|
16800
|
+
dataAttribute: `data-diff-key-${action}`,
|
|
16801
|
+
placeholder: t("panel.recordShortcut")
|
|
16802
|
+
}, action))]
|
|
16803
|
+
})]
|
|
15456
16804
|
}),
|
|
15457
16805
|
(0, react_jsx_runtime.jsx)(PreferenceRow, {
|
|
15458
16806
|
title: t("panel.importUntracked"),
|
|
@@ -15461,41 +16809,6 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
15461
16809
|
onSelect: setIncludeUntracked,
|
|
15462
16810
|
dataAttribute: "data-diff-import-untracked-select",
|
|
15463
16811
|
t
|
|
15464
|
-
}),
|
|
15465
|
-
(0, react_jsx_runtime.jsx)(TabWidthRow, {
|
|
15466
|
-
title: t("panel.tabWidth"),
|
|
15467
|
-
description: t("panel.tabWidthDesc"),
|
|
15468
|
-
value: tab,
|
|
15469
|
-
open: tabOpen,
|
|
15470
|
-
onOpenChange: setTabOpen,
|
|
15471
|
-
onSelect: setTab,
|
|
15472
|
-
dataAttribute: "data-diff-tab-width-select"
|
|
15473
|
-
}),
|
|
15474
|
-
(0, react_jsx_runtime.jsx)(PreferenceRow, {
|
|
15475
|
-
title: t("panel.splitMode"),
|
|
15476
|
-
description: t("panel.splitModeDesc"),
|
|
15477
|
-
value: split,
|
|
15478
|
-
onSelect: setSplit,
|
|
15479
|
-
dataAttribute: "data-diff-split-mode-select",
|
|
15480
|
-
t
|
|
15481
|
-
}),
|
|
15482
|
-
(0, react_jsx_runtime.jsx)(StepperRow, {
|
|
15483
|
-
title: t("panel.navLeadRows"),
|
|
15484
|
-
description: t("panel.navLeadRowsDesc"),
|
|
15485
|
-
value: lead,
|
|
15486
|
-
onChange: setLead,
|
|
15487
|
-
min: 0,
|
|
15488
|
-
max: 10,
|
|
15489
|
-
dataAttribute: "data-diff-nav-lead-rows",
|
|
15490
|
-
t
|
|
15491
|
-
}),
|
|
15492
|
-
(0, react_jsx_runtime.jsx)(ShortcutRow, {
|
|
15493
|
-
title: t("panel.quickSummon"),
|
|
15494
|
-
description: t("panel.quickSummonDesc"),
|
|
15495
|
-
value: summon,
|
|
15496
|
-
onChange: setSummon,
|
|
15497
|
-
dataAttribute: "data-diff-quick-summon-key",
|
|
15498
|
-
placeholder: t("panel.recordShortcut")
|
|
15499
16812
|
})
|
|
15500
16813
|
]
|
|
15501
16814
|
});
|
|
@@ -15531,18 +16844,20 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
15531
16844
|
id
|
|
15532
16845
|
}));
|
|
15533
16846
|
},
|
|
15534
|
-
async blockKeep(sessionId, id, block) {
|
|
16847
|
+
async blockKeep(sessionId, id, block, removeWhenResolved) {
|
|
15535
16848
|
return actionOf(await rpc.call(DIFF_APPROVAL_CHANNEL, "block-keep", {
|
|
15536
16849
|
sessionId,
|
|
15537
16850
|
id,
|
|
15538
|
-
block
|
|
16851
|
+
block,
|
|
16852
|
+
removeWhenResolved
|
|
15539
16853
|
}));
|
|
15540
16854
|
},
|
|
15541
|
-
async blockRevert(sessionId, id, block) {
|
|
16855
|
+
async blockRevert(sessionId, id, block, removeWhenResolved) {
|
|
15542
16856
|
return actionOf(await rpc.call(DIFF_APPROVAL_CHANNEL, "block-revert", {
|
|
15543
16857
|
sessionId,
|
|
15544
16858
|
id,
|
|
15545
|
-
block
|
|
16859
|
+
block,
|
|
16860
|
+
removeWhenResolved
|
|
15546
16861
|
}));
|
|
15547
16862
|
},
|
|
15548
16863
|
async undo(sessionId) {
|
|
@@ -15681,17 +16996,12 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
15681
16996
|
};
|
|
15682
16997
|
const listeners = /* @__PURE__ */ new Set();
|
|
15683
16998
|
let redoCleared = false;
|
|
15684
|
-
let justResolved;
|
|
15685
16999
|
const publish = (next) => {
|
|
15686
17000
|
let result = next;
|
|
15687
17001
|
if (redoCleared) result = {
|
|
15688
17002
|
...result,
|
|
15689
17003
|
redoCleared: true
|
|
15690
17004
|
};
|
|
15691
|
-
if (justResolved !== void 0) result = {
|
|
15692
|
-
...result,
|
|
15693
|
-
justResolved
|
|
15694
|
-
};
|
|
15695
17005
|
snapshot = result;
|
|
15696
17006
|
for (const listener of [...listeners]) listener();
|
|
15697
17007
|
};
|
|
@@ -15795,15 +17105,15 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
15795
17105
|
await port.revert(sessionId, id);
|
|
15796
17106
|
});
|
|
15797
17107
|
},
|
|
15798
|
-
async blockKeep(sessionId, id, block) {
|
|
17108
|
+
async blockKeep(sessionId, id, block, removeWhenResolved) {
|
|
15799
17109
|
const { error: _cleared, ...base } = snapshot;
|
|
15800
17110
|
publish({
|
|
15801
17111
|
...base,
|
|
15802
17112
|
busy: /* @__PURE__ */ new Set([...snapshot.busy, id])
|
|
15803
17113
|
});
|
|
15804
|
-
let value;
|
|
15805
17114
|
try {
|
|
15806
|
-
|
|
17115
|
+
if (removeWhenResolved === void 0) await port.blockKeep(sessionId, id, block);
|
|
17116
|
+
else await port.blockKeep(sessionId, id, block, removeWhenResolved);
|
|
15807
17117
|
} catch (error) {
|
|
15808
17118
|
markFailed(id, error instanceof Error ? error.message : String(error));
|
|
15809
17119
|
publish({
|
|
@@ -15813,18 +17123,17 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
15813
17123
|
return;
|
|
15814
17124
|
}
|
|
15815
17125
|
clearFailed(id);
|
|
15816
|
-
if (value.resolved === true) justResolved = id;
|
|
15817
17126
|
await this.refresh(sessionId);
|
|
15818
17127
|
},
|
|
15819
|
-
async blockRevert(sessionId, id, block) {
|
|
17128
|
+
async blockRevert(sessionId, id, block, removeWhenResolved) {
|
|
15820
17129
|
const { error: _cleared, ...base } = snapshot;
|
|
15821
17130
|
publish({
|
|
15822
17131
|
...base,
|
|
15823
17132
|
busy: /* @__PURE__ */ new Set([...snapshot.busy, id])
|
|
15824
17133
|
});
|
|
15825
|
-
let value;
|
|
15826
17134
|
try {
|
|
15827
|
-
|
|
17135
|
+
if (removeWhenResolved === void 0) await port.blockRevert(sessionId, id, block);
|
|
17136
|
+
else await port.blockRevert(sessionId, id, block, removeWhenResolved);
|
|
15828
17137
|
} catch (error) {
|
|
15829
17138
|
markFailed(id, error instanceof Error ? error.message : String(error));
|
|
15830
17139
|
publish({
|
|
@@ -15834,7 +17143,6 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
15834
17143
|
return;
|
|
15835
17144
|
}
|
|
15836
17145
|
clearFailed(id);
|
|
15837
|
-
if (value.resolved === true) justResolved = id;
|
|
15838
17146
|
await this.refresh(sessionId);
|
|
15839
17147
|
},
|
|
15840
17148
|
async undo(sessionId) {
|
|
@@ -15873,7 +17181,6 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
15873
17181
|
}
|
|
15874
17182
|
},
|
|
15875
17183
|
reset() {
|
|
15876
|
-
justResolved = void 0;
|
|
15877
17184
|
publish({
|
|
15878
17185
|
read: false,
|
|
15879
17186
|
files: [],
|
|
@@ -15884,11 +17191,6 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
15884
17191
|
redoCleared = false;
|
|
15885
17192
|
const { redoCleared: _omit, ...rest } = snapshot;
|
|
15886
17193
|
publish(rest);
|
|
15887
|
-
},
|
|
15888
|
-
clearJustResolved() {
|
|
15889
|
-
justResolved = void 0;
|
|
15890
|
-
const { justResolved: _omit, ...rest } = snapshot;
|
|
15891
|
-
publish(rest);
|
|
15892
17194
|
}
|
|
15893
17195
|
};
|
|
15894
17196
|
}
|
|
@@ -16002,6 +17304,13 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
16002
17304
|
if (scoped === void 0) return;
|
|
16003
17305
|
scoped.conversation.input.for(scoped.actx).setDraft(text);
|
|
16004
17306
|
},
|
|
17307
|
+
appendDraft: (suffix) => {
|
|
17308
|
+
const scoped = resolveConversation(ctx, sessionId());
|
|
17309
|
+
if (scoped === void 0) return;
|
|
17310
|
+
const input = scoped.conversation.input.for(scoped.actx);
|
|
17311
|
+
const current = input.state.getSnapshot().draft ?? "";
|
|
17312
|
+
input.setDraft(current === "" ? suffix : `${current} ${suffix}`);
|
|
17313
|
+
},
|
|
16005
17314
|
readQueue: () => {
|
|
16006
17315
|
const scoped = resolveConversation(ctx, sessionId());
|
|
16007
17316
|
if (scoped === void 0) return [];
|
|
@@ -16032,6 +17341,11 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
16032
17341
|
"panel.aria": "待处理改动",
|
|
16033
17342
|
"panel.stats": "+{added} -{removed}",
|
|
16034
17343
|
"panel.blockPosition": "第 {current}/{total} 块",
|
|
17344
|
+
"panel.blockAtEnd": "已在最后一个差异块,再按一次即可跳到第一个",
|
|
17345
|
+
"panel.blockAtStart": "已在第一个差异块,再按一次即可跳到最后一个",
|
|
17346
|
+
"panel.blockSingle": "仅有一个差异块",
|
|
17347
|
+
"panel.viewDiff": "查看差异",
|
|
17348
|
+
"panel.fileNotPending": "该文件不在待处理差异列表中",
|
|
16035
17349
|
"panel.selectHint": "点击每项查看整个文件的差异;选中文本后,用底部状态栏或 Ctrl+L 复制引用",
|
|
16036
17350
|
"panel.searchPlaceholder": "搜索",
|
|
16037
17351
|
"panel.missing": "文件已不存在",
|
|
@@ -16048,9 +17362,33 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
16048
17362
|
"panel.splitModeDesc": "开启后整文件差异用左「改前」|右「当前」双栏、逐行对齐的视图展示,默认关闭使用单栏(合并)视图。",
|
|
16049
17363
|
"panel.navLeadRows": "差异跳转行距",
|
|
16050
17364
|
"panel.navLeadRowsDesc": "按上/下跳转差异时,目标差异上方保留的行数(默认 2)。也用于从当前滚动位置定位上/下一个差异。",
|
|
17365
|
+
"panel.diffFontSize": "字号",
|
|
17366
|
+
"panel.diffFontSizeDesc": "差异代码的文字大小,按当前字号的百分比缩放(默认为100%,每次 ±10%)。",
|
|
17367
|
+
"panel.diffLineHeight": "行高",
|
|
17368
|
+
"panel.diffLineHeightDesc": "差异代码每行的高度(像素,默认 22),滚动与跳转定位会随之调整。",
|
|
17369
|
+
"panel.diffAddColor": "新增颜色",
|
|
17370
|
+
"panel.diffAddColorDesc": "新增行的基础色;行背景与逐词差异由它派生。默认色:{default}。",
|
|
17371
|
+
"panel.diffDelColor": "删除颜色",
|
|
17372
|
+
"panel.diffDelColorDesc": "删除行的基础色;行背景与逐词差异由它派生。默认色:{default}。",
|
|
16051
17373
|
"panel.quickSummon": "快速呼出",
|
|
16052
17374
|
"panel.quickSummonDesc": "用键盘快捷键打开/关闭差异面板。点击右侧按钮后按下新的按键组合即可修改。",
|
|
16053
17375
|
"panel.recordShortcut": "按下快捷键…",
|
|
17376
|
+
"settings.keybindings": "快捷键",
|
|
17377
|
+
"settings.keybindingsDesc": "展开后可配置各项操作的按键组合。",
|
|
17378
|
+
"settings.diffView": "差异视图",
|
|
17379
|
+
"settings.diffViewDesc": "调整差异的显示效果(字号、行高、新增/删除颜色)与布局偏好。",
|
|
17380
|
+
"settings.diffPreview": "预览",
|
|
17381
|
+
"panel.keyDesc": "点击右侧按钮后按下新的按键组合即可修改。",
|
|
17382
|
+
"panel.key.jumpUp": "跳转到上一个差异块",
|
|
17383
|
+
"panel.key.jumpDown": "跳转到下一个差异块",
|
|
17384
|
+
"panel.key.copyRef": "复制引用",
|
|
17385
|
+
"panel.key.openSearch": "打开差异搜索",
|
|
17386
|
+
"panel.key.searchNext": "下一个搜索结果",
|
|
17387
|
+
"panel.key.searchPrev": "上一个搜索结果",
|
|
17388
|
+
"panel.key.undo": "撤销",
|
|
17389
|
+
"panel.key.redo": "重做",
|
|
17390
|
+
"panel.key.cycleNext": "下一个待处理文件",
|
|
17391
|
+
"panel.key.cyclePrev": "上一个待处理文件",
|
|
16054
17392
|
"settings.tabLabel": "改动审批",
|
|
16055
17393
|
"row.create": "新增文件",
|
|
16056
17394
|
"row.failed": "失败",
|
|
@@ -16109,6 +17447,11 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
16109
17447
|
"panel.aria": "Pending changes",
|
|
16110
17448
|
"panel.stats": "+{added} -{removed}",
|
|
16111
17449
|
"panel.blockPosition": "{current}/{total}",
|
|
17450
|
+
"panel.blockAtEnd": "At the last diff block, press again to jump to the first",
|
|
17451
|
+
"panel.blockAtStart": "At the first diff block, press again to jump to the last",
|
|
17452
|
+
"panel.blockSingle": "Only one diff block",
|
|
17453
|
+
"panel.viewDiff": "View diff",
|
|
17454
|
+
"panel.fileNotPending": "This file is not in the pending diff list",
|
|
16112
17455
|
"panel.selectHint": "Select an item to review its whole-file diff; select text and copy its reference from the status bar (Ctrl+L)",
|
|
16113
17456
|
"panel.searchPlaceholder": "Search",
|
|
16114
17457
|
"panel.missing": "File is gone",
|
|
@@ -16125,9 +17468,33 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
16125
17468
|
"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.",
|
|
16126
17469
|
"panel.navLeadRows": "Block jump lead rows",
|
|
16127
17470
|
"panel.navLeadRowsDesc": "Rows left above the jumped-to diff block on up/down navigation (default 2). Also used to locate the previous/next diff from the current scroll position.",
|
|
17471
|
+
"panel.diffFontSize": "Font size",
|
|
17472
|
+
"panel.diffFontSizeDesc": "Diff code text size as a percentage of the current size (defaults to 100%, ±10% per step).",
|
|
17473
|
+
"panel.diffLineHeight": "Line height",
|
|
17474
|
+
"panel.diffLineHeightDesc": "The diff code line height, in pixels (default 22); scrolling and jump positioning follow it.",
|
|
17475
|
+
"panel.diffAddColor": "Added color",
|
|
17476
|
+
"panel.diffAddColorDesc": "Base color for added lines; the row background and intra-line diff are derived from it. Default: {default}.",
|
|
17477
|
+
"panel.diffDelColor": "Removed color",
|
|
17478
|
+
"panel.diffDelColorDesc": "Base color for removed lines; the row background and intra-line diff are derived from it. Default: {default}.",
|
|
16128
17479
|
"panel.quickSummon": "Quick summon",
|
|
16129
17480
|
"panel.quickSummonDesc": "Open or close the diff panel with a keyboard shortcut. Click the button and press a new chord to change it.",
|
|
16130
17481
|
"panel.recordShortcut": "Press keys…",
|
|
17482
|
+
"settings.keybindings": "Shortcuts",
|
|
17483
|
+
"settings.keybindingsDesc": "Expand to configure the key combo for each action.",
|
|
17484
|
+
"settings.diffView": "Diff view",
|
|
17485
|
+
"settings.diffViewDesc": "Adjust the diff appearance (font size, line height, add/delete colors) and layout preferences.",
|
|
17486
|
+
"settings.diffPreview": "Preview",
|
|
17487
|
+
"panel.keyDesc": "Click the button, then press a new chord to rebind it.",
|
|
17488
|
+
"panel.key.jumpUp": "Jump to the previous diff block",
|
|
17489
|
+
"panel.key.jumpDown": "Jump to the next diff block",
|
|
17490
|
+
"panel.key.copyRef": "Copy reference",
|
|
17491
|
+
"panel.key.openSearch": "Open diff search",
|
|
17492
|
+
"panel.key.searchNext": "Next search result",
|
|
17493
|
+
"panel.key.searchPrev": "Previous search result",
|
|
17494
|
+
"panel.key.undo": "Undo",
|
|
17495
|
+
"panel.key.redo": "Redo",
|
|
17496
|
+
"panel.key.cycleNext": "Next pending file",
|
|
17497
|
+
"panel.key.cyclePrev": "Previous pending file",
|
|
16131
17498
|
"settings.tabLabel": "Diff Approval",
|
|
16132
17499
|
"row.create": "New file",
|
|
16133
17500
|
"row.failed": "Failed",
|
|
@@ -16298,27 +17665,21 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
16298
17665
|
if (filePath !== void 0 && before !== void 0 && after !== void 0) remapFile(filePath, before, after);
|
|
16299
17666
|
});
|
|
16300
17667
|
},
|
|
16301
|
-
onBlockKeep: (sessionId, id, block) => store.blockKeep(sessionId, id, block),
|
|
16302
|
-
onBlockRevert: (sessionId, id, block) => store.blockRevert(sessionId, id, block),
|
|
17668
|
+
onBlockKeep: (sessionId, id, block, removeWhenResolved) => store.blockKeep(sessionId, id, block, removeWhenResolved),
|
|
17669
|
+
onBlockRevert: (sessionId, id, block, removeWhenResolved) => store.blockRevert(sessionId, id, block, removeWhenResolved),
|
|
16303
17670
|
onOpen: (sessionId, id, action) => store.open(sessionId, id, action),
|
|
16304
17671
|
onUndo: (sessionId) => store.undo(sessionId),
|
|
16305
17672
|
onRedo: (sessionId) => store.redo(sessionId),
|
|
16306
17673
|
onImportVcs: (sessionId, includeUntracked) => store.importVcs(sessionId, includeUntracked),
|
|
16307
17674
|
onAckRedoCleared: () => store.clearRedoCleared(),
|
|
16308
|
-
onAckJustResolved: () => store.clearJustResolved(),
|
|
16309
17675
|
onPasteReference: (sessionId, reference) => {
|
|
16310
|
-
|
|
16311
|
-
|
|
16312
|
-
const conversation = actx.get("conversation");
|
|
16313
|
-
if (conversation?.input === void 0) return;
|
|
16314
|
-
const textarea = document.querySelector("[data-composer-card] textarea");
|
|
16315
|
-
const base = textarea?.value ?? "";
|
|
16316
|
-
conversation.input.for(actx).setDraft(base === "" ? reference : `${base} ${reference}`);
|
|
16317
|
-
textarea?.focus();
|
|
17676
|
+
conversationAccess(ctx, () => sessionId).appendDraft(reference);
|
|
17677
|
+
document.querySelector("[data-composer-input]")?.focus();
|
|
16318
17678
|
},
|
|
16319
17679
|
collapseSidebar
|
|
16320
17680
|
})
|
|
16321
17681
|
}, PendingPanel));
|
|
17682
|
+
if (typeof window !== "undefined") ctx.effect(() => startProducedDiffInjection(t("panel.viewDiff"), (path) => window.dispatchEvent(new CustomEvent(OPEN_FILE_EVENT, { detail: { path } }))), "diff-approval: produced-files diff buttons");
|
|
16322
17683
|
ctx.slots.inject("settings.section", () => ctx.slots.register({
|
|
16323
17684
|
name: "settings.section",
|
|
16324
17685
|
id: "diff-approval",
|