dsh-diff-approval 0.36.0 → 0.36.1

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.
Files changed (2) hide show
  1. package/lib/client.js +86 -45
  2. package/package.json +1 -1
package/lib/client.js CHANGED
@@ -27257,6 +27257,10 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
27257
27257
  const next = !mdPreview;
27258
27258
  setMdPreview(next);
27259
27259
  setMdPreviewEnabled(next);
27260
+ if (!next) {
27261
+ setScrollTop(0);
27262
+ setScrollTick((tick) => tick + 1);
27263
+ }
27260
27264
  }
27261
27265
  });
27262
27266
  toolbarItems.push({
@@ -28485,10 +28489,15 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
28485
28489
  */
28486
28490
  const [pickedComments, setPickedComments] = (0, react.useState)(() => /* @__PURE__ */ new Set());
28487
28491
  /**
28488
- * Where a Shift press in the COMMENTS list measures from: the comment the last non-Shift press landed on
28489
- * (a Ctrl/Cmd pick, or an ordinary press, which jumps to the comment). The comments list has no "open"
28490
- * item of its own — a press navigates away rather than selecting — so this is what stands in for the file
28491
- * list's open file, and it is the reason the two lists can share one rule (see `pickCommentRangeTo`).
28492
+ * Where a Shift press in the COMMENTS list measures from — the same idea as the file list's `pickAnchor`,
28493
+ * with one difference in where it comes from.
28494
+ *
28495
+ * The comments list has no "open" item of its own: a press navigates away rather than selecting, so there
28496
+ * is no focused row to stand in for an anchor the reader has not named. The row a Shift press lands on
28497
+ * therefore BECOMES the anchor when there is none (see `pickCommentRangeTo`), which is what lets the very
28498
+ * first Shift press start a range instead of selecting a row the next Shift press would have to start
28499
+ * over from. A press that only UNPICKS a comment leaves it alone, exactly as in the file list: it
28500
+ * selected nothing, so the span must still begin where the pick began (see `pickComment`).
28492
28501
  */
28493
28502
  const [commentAnchor, setCommentAnchor] = (0, react.useState)(void 0);
28494
28503
  /** End the picking, keeping the same set object when there is nothing to end (so nothing re-renders). */
@@ -28504,6 +28513,18 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
28504
28513
  return next;
28505
28514
  });
28506
28515
  };
28516
+ /**
28517
+ * Pick or unpick one comment with a Ctrl/Cmd press, moving the Shift anchor with it — but only when the
28518
+ * press PICKS.
28519
+ *
28520
+ * An unpick selected nothing: it took a row out, so the next Shift press must still measure from where the
28521
+ * pick began. Moving the anchor to the row just cleared would start the next span on a comment the reader
28522
+ * had removed from the pick — the same rule the file list follows (see `pickFile`).
28523
+ */
28524
+ const pickComment = (id) => {
28525
+ if (!pickedComments.has(id)) setCommentAnchor(id);
28526
+ togglePicked(id);
28527
+ };
28507
28528
  (0, react.useEffect)(() => {
28508
28529
  clearPicked();
28509
28530
  }, [selected, activeTab]);
@@ -28537,13 +28558,19 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
28537
28558
  */
28538
28559
  const [pickedFiles, setPickedFiles] = (0, react.useState)(() => /* @__PURE__ */ new Set());
28539
28560
  /**
28540
- * Where a Shift press measures from: the row the last NON-Shift press landed on — a Ctrl/Cmd pick, or an
28541
- * ordinary press, which opens the file. Shift never moves it, so pressing Shift twice measures from the
28542
- * same place and the range can shrink as well as grow (see `pickRangeTo`).
28561
+ * Where a Shift press measures from: the row the last press that SELECTED something landed on — an
28562
+ * ordinary press, which opens the file, or a Ctrl/Cmd press that ADDED a row to the pick.
28563
+ *
28564
+ * A Ctrl/Cmd press that took a row OUT leaves it alone. That press selected nothing: it removed something,
28565
+ * so measuring the next span from it would start the range on a row that is no longer picked at all — the
28566
+ * reader would Shift-click and watch the range begin at a row they had just cleared. Shift itself never
28567
+ * moves the anchor either, so pressing Shift again measures from the same place and the range can shrink
28568
+ * as well as grow (see `pickRangeTo`).
28543
28569
  *
28544
28570
  * Nothing has been pressed yet on a fresh panel, and `selected` was not the reader's doing (the list
28545
28571
  * opens on its first file), so the range falls back to the open file when this is unset: the row the
28546
- * reader is looking at is the only sensible place to measure from before they have touched anything.
28572
+ * reader is looking at is the only sensible place to measure from before they have touched anything. The
28573
+ * first Shift press PINS that stand-in, so a later auto-advance cannot move the range under the reader.
28547
28574
  */
28548
28575
  const [pickAnchor, setPickAnchor] = (0, react.useState)(void 0);
28549
28576
  /** End the file picking, keeping the same set object when there is nothing to end. */
@@ -29432,9 +29459,12 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
29432
29459
  * they are gathering rows out of the list they are looking at, and the row the detail pane is showing is
29433
29460
  * one of them. Only when the pick is empty — otherwise the open row could never be clicked OUT of a pick
29434
29461
  * it is already in, and Ctrl-click is the only way to take anything out.
29462
+ *
29463
+ * Only the press that PICKS moves the Shift anchor (see `pickAnchor`): an unpick selected nothing, so it
29464
+ * leaves the anchor where the pick began, and the span the next Shift press draws still starts there.
29435
29465
  */
29436
29466
  const pickFile = (id) => {
29437
- setPickAnchor(id);
29467
+ if (!pickedFiles.has(id)) setPickAnchor(id);
29438
29468
  setPickedFiles((current) => {
29439
29469
  const next = new Set(current);
29440
29470
  if (next.has(id)) {
@@ -29447,24 +29477,35 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
29447
29477
  });
29448
29478
  };
29449
29479
  /**
29450
- * Set the pick to exactly the rows between the OPEN file and `id`, both ends included — Shift-click.
29480
+ * Set the pick to exactly the rows between the ANCHOR and `id`, both ends included — Shift-click.
29451
29481
  *
29452
29482
  * Shift REPLACES the pick instead of adding to it. The reader names one end by looking at it (the open
29453
- * file) and the other by pressing, and the span between them IS the selection: anything picked earlier
29454
- * that falls outside that span goes. That is what makes the gesture work in both directions — press
29455
- * nearer than last time and the range shrinks, press further and it grows — with the anchor staying put.
29456
- * A stale open file (its row left the list) degrades to the pressed row alone: a Shift press must always
29457
- * leave something selected, since it has just thrown the old pick away.
29483
+ * file, until they have pressed a row themselves) and the other by pressing, and the span between them IS
29484
+ * the selection: anything picked earlier that falls outside that span goes. That is what makes the gesture
29485
+ * work in both directions — press nearer than last time and the range shrinks, press further and it grows
29486
+ * — with the anchor staying put.
29487
+ *
29488
+ * The open file is only a STAND-IN for an anchor the reader has not named yet, and the first Shift press
29489
+ * pins it (see `pickAnchor`): from then on the span measures from that row even when the detail pane
29490
+ * moves on by itself, because the range is about the rows the reader picked rather than about whatever
29491
+ * file happens to be open now.
29492
+ *
29493
+ * A stale anchor (its row left the list) is no anchor at all: the press stands in for it and becomes the
29494
+ * next one, so the gesture keeps working — a Shift press must always leave something selected, since it
29495
+ * has just thrown the old pick away, and something to measure from next time. The comments list adopts the
29496
+ * same way (see `pickCommentRangeTo`).
29458
29497
  */
29459
29498
  const pickRangeTo = (id) => {
29460
- setPickedFiles(() => {
29461
- const to = files.findIndex((file) => file.id === id);
29462
- if (to === -1) return /* @__PURE__ */ new Set();
29463
- const anchorId = pickAnchor ?? selected;
29464
- const from = anchorId === void 0 || anchorId === "" ? -1 : files.findIndex((file) => file.id === anchorId);
29465
- if (from === -1) return /* @__PURE__ */ new Set([id]);
29466
- return new Set(files.slice(Math.min(from, to), Math.max(from, to) + 1).map((file) => file.id));
29467
- });
29499
+ const to = files.findIndex((file) => file.id === id);
29500
+ if (to === -1) return setPickedFiles(() => /* @__PURE__ */ new Set());
29501
+ const anchorId = pickAnchor ?? selected;
29502
+ const from = anchorId === void 0 || anchorId === "" ? -1 : files.findIndex((file) => file.id === anchorId);
29503
+ if (from === -1) {
29504
+ setPickAnchor(id);
29505
+ return setPickedFiles(() => /* @__PURE__ */ new Set([id]));
29506
+ }
29507
+ if (pickAnchor === void 0) setPickAnchor(anchorId);
29508
+ setPickedFiles(() => new Set(files.slice(Math.min(from, to), Math.max(from, to) + 1).map((file) => file.id)));
29468
29509
  };
29469
29510
  /**
29470
29511
  * The row a modified press has already picked, so the `click` that follows it does not pick again (a Ctrl
@@ -29743,22 +29784,28 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
29743
29784
  /**
29744
29785
  * Set the comment pick to the span between the anchor and `id`, both ends included — Shift-click.
29745
29786
  *
29746
- * The same rule the file list follows (see `pickRangeTo`): Shift REPLACES the pick, the anchor is where
29747
- * the last non-Shift press landed, and Shift never moves it — so pressing Shift again measures from the
29748
- * same place and the span can shrink as well as grow. The span follows the RENDERED order, which is the
29749
- * order the reader sees: comments grouped by file, and inside a group the file's own comments — so a span
29750
- * may cross a file boundary, exactly as it reads on screen. With no anchor yet (nothing pressed in this
29751
- * tab), the pressed comment is the whole selection.
29787
+ * The same rule the file list follows (see `pickRangeTo`): Shift REPLACES the pick, and Shift never moves
29788
+ * the anchor — so pressing Shift again measures from the same place and the span can shrink as well as
29789
+ * grow. The span follows the RENDERED order, which is the order the reader sees: comments grouped by file,
29790
+ * and inside a group the file's own comments — so a span may cross a file boundary, exactly as it reads on
29791
+ * screen.
29792
+ *
29793
+ * With no anchor yet (nothing selected in this tab), the pressed comment is the whole selection AND
29794
+ * becomes the anchor: a Shift press from nothing names one row, and the next Shift press extends from it
29795
+ * rather than naming one row all over again. An anchor whose comment left the list is no anchor at all,
29796
+ * and the same adoption happens: the press must always leave something selected, and something to measure
29797
+ * from next time.
29752
29798
  */
29753
29799
  const pickCommentRangeTo = (id) => {
29754
- setPickedComments(() => {
29755
- const ids = commentEntries.map((entry) => entry.id);
29756
- const to = ids.indexOf(id);
29757
- if (to === -1) return /* @__PURE__ */ new Set();
29758
- const from = commentAnchor === void 0 ? -1 : ids.indexOf(commentAnchor);
29759
- if (from === -1) return /* @__PURE__ */ new Set([id]);
29760
- return new Set(ids.slice(Math.min(from, to), Math.max(from, to) + 1));
29761
- });
29800
+ const ids = commentEntries.map((entry) => entry.id);
29801
+ const to = ids.indexOf(id);
29802
+ if (to === -1) return setPickedComments(() => /* @__PURE__ */ new Set());
29803
+ const from = commentAnchor === void 0 ? -1 : ids.indexOf(commentAnchor);
29804
+ if (from === -1) {
29805
+ setCommentAnchor(id);
29806
+ return setPickedComments(() => /* @__PURE__ */ new Set([id]));
29807
+ }
29808
+ setPickedComments(() => new Set(ids.slice(Math.min(from, to), Math.max(from, to) + 1)));
29762
29809
  };
29763
29810
  /** Open the file a comment hangs in and land on the thread's own box, not on the rows it names:
29764
29811
  * the box hangs below the range it ends in, and the code an outdated comment named may be gone
@@ -30047,16 +30094,10 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
30047
30094
  "data-selected": pickedComments.has(entry.id) ? "" : void 0,
30048
30095
  "aria-pressed": pickedComments.has(entry.id),
30049
30096
  onMouseDown: (event) => {
30050
- consumePickPress(event, entry.id, (id) => {
30051
- setCommentAnchor(id);
30052
- togglePicked(id);
30053
- }, pickCommentRangeTo);
30097
+ consumePickPress(event, entry.id, pickComment, pickCommentRangeTo);
30054
30098
  },
30055
30099
  onClick: (event) => {
30056
- if (consumePickPress(event, entry.id, (id) => {
30057
- setCommentAnchor(id);
30058
- togglePicked(id);
30059
- }, pickCommentRangeTo)) return;
30100
+ if (consumePickPress(event, entry.id, pickComment, pickCommentRangeTo)) return;
30060
30101
  setCommentAnchor(entry.id);
30061
30102
  clearPicked();
30062
30103
  jumpToComment(entry.fileId, entry.line, entry.id, entry.oldSide);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-diff-approval",
3
- "version": "0.36.0",
3
+ "version": "0.36.1",
4
4
  "description": "DeepSeek Harness plugin: pending-edit review with whole-file diff and Keep/Revert",
5
5
  "packageManager": "pnpm@11.21.0",
6
6
  "author": "Wu Zhiwei",