dsh-ide-git 0.18.1 → 0.18.3
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/dsh.plugin.json +1 -1
- package/package.json +1 -1
- package/src/client.js +54 -23
package/dsh.plugin.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "dsh-external/dsh-ide-git",
|
|
3
|
-
"version": "0.18.
|
|
3
|
+
"version": "0.18.3",
|
|
4
4
|
"main": "./src/index.js",
|
|
5
5
|
"description": "IDE 级 Git 操作面板:分支树 + 提交图谱 + 变更/暂存/提交 + 提交详情。装了 dsh-better-sidebar 时挂成它的原生 tab(右侧栏 + 底部工作台);没装时直接挂 DSH 原生右侧栏,单独安装即可用。JetBrains 风格 Git 工具窗口 for DeepSeek Harness.",
|
|
6
6
|
"engines": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-ide-git",
|
|
3
|
-
"version": "0.18.
|
|
3
|
+
"version": "0.18.3",
|
|
4
4
|
"description": "DSH plugin: an IDE-grade Git tool window as a native dsh-better-sidebar tab — branch tree, commit graph, changes, commit details, JetBrains-style actions, in the right sidebar and the bottom panel. | DSH 插件:IDE 级 Git 工具窗口,以 dsh-better-sidebar 原生 Tab 挂载——分支树 / 提交图谱 / 变更与提交详情 / JetBrains 风格操作,右侧栏与底部面板双布局自适应。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
package/src/client.js
CHANGED
|
@@ -9829,8 +9829,12 @@ window.__ModuleLoader__.load({
|
|
|
9829
9829
|
}
|
|
9830
9830
|
const handlePick = useCallback((event, entry, selKey) => {
|
|
9831
9831
|
const ordered = visibleRef.current.map((leaf) => branchSelKeyOf(leaf.entry))
|
|
9832
|
-
if (event.shiftKey === true
|
|
9833
|
-
|
|
9832
|
+
if (event.shiftKey === true) {
|
|
9833
|
+
/* No anchor yet (fresh tree, nothing clicked): VS Code semantics —
|
|
9834
|
+
the range starts at the FIRST visible row, so a first-click Shift
|
|
9835
|
+
still multi-selects instead of silently degrading to single. */
|
|
9836
|
+
const anchorKey = pickAnchor.current !== null ? pickAnchor.current : ordered[0]
|
|
9837
|
+
const from = ordered.indexOf(anchorKey)
|
|
9834
9838
|
const to = ordered.indexOf(selKey)
|
|
9835
9839
|
if (from >= 0 && to >= 0) {
|
|
9836
9840
|
const low = Math.min(from, to)
|
|
@@ -9992,9 +9996,11 @@ window.__ModuleLoader__.load({
|
|
|
9992
9996
|
return E('div', {
|
|
9993
9997
|
className: 'dig-row dig-row-file' + (props.selected === true ? ' dig-row-selected' : ''),
|
|
9994
9998
|
title: item.origPath === undefined ? item.path : item.origPath + ' → ' + item.path,
|
|
9995
|
-
/* The click is handled ONE level up (ChangesPanel): plain click
|
|
9996
|
-
opens the diff
|
|
9999
|
+
/* The click is handled ONE level up (ChangesPanel): plain click only
|
|
10000
|
+
selects, DOUBLE-click opens the diff (v0.18.3 — one interaction model
|
|
10001
|
+
across every list). */
|
|
9997
10002
|
onClick: (event) => props.onRowClick(event, item, props.group),
|
|
10003
|
+
onDoubleClick: () => props.onDblClick(item, props.group),
|
|
9998
10004
|
onContextMenu: (event) => { event.preventDefault(); props.onMenu(event, item, props.group) },
|
|
9999
10005
|
},
|
|
10000
10006
|
FileTypeGlyph({ path: item.path }),
|
|
@@ -10075,9 +10081,12 @@ window.__ModuleLoader__.load({
|
|
|
10075
10081
|
of this handler (their memo compares item/group/t/selected, not the
|
|
10076
10082
|
callback — same stale-callback trade-off as the stage buttons), so
|
|
10077
10083
|
the selection must never be read from it. */
|
|
10078
|
-
if (event.shiftKey === true && anchorRef !== undefined
|
|
10084
|
+
if (event.shiftKey === true && anchorRef !== undefined) {
|
|
10079
10085
|
const ordered = orderedRowKeys()
|
|
10080
|
-
|
|
10086
|
+
/* Anchor falls back to the FIRST row (VS Code semantics): a Shift
|
|
10087
|
+
click on a fresh list must multi-select, not degrade to single. */
|
|
10088
|
+
const anchorKey = anchorRef.current !== null ? anchorRef.current : ordered[0]
|
|
10089
|
+
const from = ordered.indexOf(anchorKey)
|
|
10081
10090
|
const to = ordered.indexOf(key)
|
|
10082
10091
|
if (from >= 0 && to >= 0) {
|
|
10083
10092
|
const low = Math.min(from, to)
|
|
@@ -10101,8 +10110,10 @@ window.__ModuleLoader__.load({
|
|
|
10101
10110
|
return
|
|
10102
10111
|
}
|
|
10103
10112
|
anchorRef.current = key
|
|
10104
|
-
|
|
10105
|
-
|
|
10113
|
+
/* Plain click only SELECTS (single-replace, the branch tree's model):
|
|
10114
|
+
the diff moved to DOUBLE-click — a stray click mid-multi-select must
|
|
10115
|
+
not yank the pane away (v0.18.3). */
|
|
10116
|
+
setSelection((previous) => previous.size === 1 && previous.has(key) === true ? previous : new Set([key]))
|
|
10106
10117
|
}, [setSelection, anchorRef, props.onDiff])
|
|
10107
10118
|
/* ---- rubber-band selection over the windowed list: the fixed row
|
|
10108
10119
|
heights + the prefix-sum offsets turn a pixel span back into the
|
|
@@ -10244,6 +10255,7 @@ window.__ModuleLoader__.load({
|
|
|
10244
10255
|
key: key + ':' + item.path, item: item, group: key, t: t,
|
|
10245
10256
|
selected: selection.has(key + ':' + item.path) === true,
|
|
10246
10257
|
onRowClick: handleRowClick,
|
|
10258
|
+
onDblClick: props.onDiff,
|
|
10247
10259
|
onStage: props.onStage, onUnstage: props.onUnstage, onDiscard: props.onDiscard, onDiff: props.onDiff, onMenu: props.onChangeMenu,
|
|
10248
10260
|
})
|
|
10249
10261
|
const folderOf = (item) => {
|
|
@@ -10431,7 +10443,6 @@ window.__ModuleLoader__.load({
|
|
|
10431
10443
|
return E('div', { className: 'dig-changes' },
|
|
10432
10444
|
aiConfirmDialog,
|
|
10433
10445
|
head,
|
|
10434
|
-
selectionBar,
|
|
10435
10446
|
E('div', { className: 'dig-changes-body' },
|
|
10436
10447
|
E('div', {
|
|
10437
10448
|
className: 'dig-changes-list', ref: changesScrollRef,
|
|
@@ -10456,6 +10467,7 @@ window.__ModuleLoader__.load({
|
|
|
10456
10467
|
winLast < changeItems.length ? E('div', { key: 'pad-bottom', style: { height: String(changeOffsets[changeItems.length] - changeOffsets[winLast]) + 'px' } }) : null,
|
|
10457
10468
|
]),
|
|
10458
10469
|
composer),
|
|
10470
|
+
selectionBar,
|
|
10459
10471
|
marquee === null ? null : E('div', {
|
|
10460
10472
|
className: 'dig-marquee',
|
|
10461
10473
|
style: { left: marquee.x + 'px', top: marquee.y + 'px', width: marquee.w + 'px', height: marquee.h + 'px' },
|
|
@@ -10584,8 +10596,10 @@ window.__ModuleLoader__.load({
|
|
|
10584
10596
|
'data-lane': String(props.row.lane),
|
|
10585
10597
|
className: 'dig-commit' + (props.selected === true ? ' dig-commit-selected' : ''),
|
|
10586
10598
|
/* Modifier handling lives in HistoryList (it owns the rendered row
|
|
10587
|
-
order the Shift-range walks); a plain click
|
|
10599
|
+
order the Shift-range walks); a plain click only selects and the
|
|
10600
|
+
DOUBLE-click opens the detail (v0.18.3, same model as the tree). */
|
|
10588
10601
|
onClick: (event) => props.onRowClick(event, commit),
|
|
10602
|
+
onDoubleClick: () => props.onOpenDetail(commit),
|
|
10589
10603
|
onContextMenu: (event) => { event.preventDefault(); props.onMenu(event, commit) },
|
|
10590
10604
|
},
|
|
10591
10605
|
E('span', { className: 'dig-commit-date', title: shortDate(commit.date) }, relativeTime(commit.date)),
|
|
@@ -10691,10 +10705,12 @@ window.__ModuleLoader__.load({
|
|
|
10691
10705
|
const rows = useMemo(() => buildRows(filtered), [filtered])
|
|
10692
10706
|
/* Multi-select gestures (issue #13): the rendered row order is what the
|
|
10693
10707
|
Shift-range walks, and the range is computed over the FILTERED rows —
|
|
10694
|
-
the same list the eye sees.
|
|
10695
|
-
|
|
10696
|
-
|
|
10697
|
-
|
|
10708
|
+
the same list the eye sees. A plain click only SELECTS (single-replace,
|
|
10709
|
+
like the branch tree); it must NOT open the detail view — that killed
|
|
10710
|
+
any multi-select mid-flight and is now the DOUBLE-click's job (user
|
|
10711
|
+
request, v0.18.3). The stale-callback risk is nil: rows change identity
|
|
10712
|
+
with the filters, and every row re-renders whenever its commit
|
|
10713
|
+
reference changes. */
|
|
10698
10714
|
const handleRowClick = (event, commit) => {
|
|
10699
10715
|
const pickedHashes = props.pickedHashes
|
|
10700
10716
|
const setPicks = props.onPicksChange
|
|
@@ -10704,8 +10720,11 @@ window.__ModuleLoader__.load({
|
|
|
10704
10720
|
/* Functional updates only — memoised CommitRows may hold a stale
|
|
10705
10721
|
closure of this handler (their memo compares commit/row/selected),
|
|
10706
10722
|
so the picked set is never read from it. */
|
|
10707
|
-
if (event.shiftKey === true
|
|
10708
|
-
|
|
10723
|
+
if (event.shiftKey === true) {
|
|
10724
|
+
/* Anchor falls back to the FIRST row (VS Code semantics): a Shift
|
|
10725
|
+
click on a fresh list must multi-select, not degrade to single. */
|
|
10726
|
+
const anchorHash = pickAnchor.current !== null ? pickAnchor.current : ordered[0]
|
|
10727
|
+
const from = ordered.indexOf(anchorHash)
|
|
10709
10728
|
if (from >= 0 && index >= 0) {
|
|
10710
10729
|
const low = Math.min(from, index)
|
|
10711
10730
|
const high = Math.max(from, index)
|
|
@@ -10847,7 +10866,7 @@ window.__ModuleLoader__.load({
|
|
|
10847
10866
|
commit: row.commit, row: row, t: t,
|
|
10848
10867
|
selected: props.selectedHash === row.commit.hash
|
|
10849
10868
|
|| (props.pickedHashes !== undefined && props.pickedHashes.has(row.commit.hash) === true),
|
|
10850
|
-
onRowClick: handleRowClick, onMenu: props.onMenu, openMenuAt: props.openMenuAt,
|
|
10869
|
+
onRowClick: handleRowClick, onOpenDetail: props.onSelect, onMenu: props.onMenu, openMenuAt: props.openMenuAt,
|
|
10851
10870
|
})),
|
|
10852
10871
|
winEnd < rows.length ? E('div', { key: 'pad-bottom', style: { height: String((rows.length - winEnd) * HISTORY_ROW_H) + 'px' } }) : null,
|
|
10853
10872
|
props.hasMore === true
|
|
@@ -10874,7 +10893,10 @@ window.__ModuleLoader__.load({
|
|
|
10874
10893
|
key: file.path,
|
|
10875
10894
|
className: 'dig-row dig-row-file' + (props.selectedPath === file.path ? ' dig-row-selected' : ''),
|
|
10876
10895
|
title: file.path,
|
|
10896
|
+
/* Same click model as everywhere else (v0.18.3): plain click only
|
|
10897
|
+
selects, DOUBLE-click opens the diff. */
|
|
10877
10898
|
onClick: () => props.onSelectFile(file),
|
|
10899
|
+
onDoubleClick: () => props.onOpenFile(file),
|
|
10878
10900
|
onContextMenu: props.onFileMenu === undefined ? undefined : (event) => { event.preventDefault(); props.onFileMenu(event, file) },
|
|
10879
10901
|
},
|
|
10880
10902
|
FileTypeGlyph({ path: file.path }),
|
|
@@ -12231,7 +12253,10 @@ window.__ModuleLoader__.load({
|
|
|
12231
12253
|
? E(CommitDetail, {
|
|
12232
12254
|
t: t, detail: detail, selectedPath: selectedPath,
|
|
12233
12255
|
onBack: () => { setView('history'); setSelectedPath(null); setPatch(''); setDiffContext(null) },
|
|
12234
|
-
|
|
12256
|
+
/* Plain click only highlights the file; the DOUBLE-click opens its
|
|
12257
|
+
diff (v0.18.3, one click model across every list). */
|
|
12258
|
+
onSelectFile: (file) => { setSelectedPath(file.path) },
|
|
12259
|
+
onOpenFile: (file) => {
|
|
12235
12260
|
setSelectedPath(file.path)
|
|
12236
12261
|
showDiff({
|
|
12237
12262
|
hash: detail === null || detail === undefined ? undefined : detail.hash,
|
|
@@ -13279,10 +13304,12 @@ window.__ModuleLoader__.load({
|
|
|
13279
13304
|
'.dig-row-sub{color:var(--dsw-alias-label-tertiary);font-size:11px;flex:none;max-width:45%;overflow:hidden;text-overflow:ellipsis}',
|
|
13280
13305
|
'.dig-row-dir{margin-left:auto;opacity:.75}',
|
|
13281
13306
|
'.dig-badge{font-size:10px;padding:0 5px;border-radius:999px;corner-shape:round;background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary);flex:none}',
|
|
13282
|
-
/* Ahead/behind colours (user request): pending pushes read green,
|
|
13283
|
-
pulls read blue — the same semantics in the tree rows and the
|
|
13284
|
-
|
|
13285
|
-
'.dig-badge-
|
|
13307
|
+
/* Ahead/behind colours + size (user request): pending pushes read green,
|
|
13308
|
+
pending pulls read blue — the same semantics in the tree rows and the
|
|
13309
|
+
top bar. 12px/600 keeps the counts legible at a glance. */
|
|
13310
|
+
'.dig-badge-ahead,.dig-track-ahead{color:var(--dsw-alias-state-success-primary);font-size:12px;font-weight:600}',
|
|
13311
|
+
'.dig-badge-behind,.dig-track-behind{color:var(--dsw-alias-state-business-primary,var(--dsw-alias-brand-primary));font-size:12px;font-weight:600}',
|
|
13312
|
+
'.dig-badge.dig-badge-ahead,.dig-badge.dig-badge-behind{padding:0 6px}',
|
|
13286
13313
|
'.dig-badge-muted{opacity:.8}',
|
|
13287
13314
|
'.dig-badge-worktree{padding:0 3px;display:inline-flex;align-items:center;height:14px}',
|
|
13288
13315
|
'.dig-history{display:flex;flex-direction:column;min-height:0;flex:1}',
|
|
@@ -13319,7 +13346,11 @@ window.__ModuleLoader__.load({
|
|
|
13319
13346
|
VIEWPORT-space .dig-changes (invariant 13: position:fixed would be
|
|
13320
13347
|
captured by the workbench's contain:layout and flung off-panel). */
|
|
13321
13348
|
'.dig-marquee{position:absolute;border:1px solid var(--dsw-alias-brand-primary);background:color-mix(in srgb,var(--dsw-alias-brand-primary) 14%,transparent);pointer-events:none;z-index:6}',
|
|
13322
|
-
|
|
13349
|
+
/* The selection bar FLOATS over the top of the list (absolute, solid
|
|
13350
|
+
surface): as an in-flow bar it shoved the whole list down one row on
|
|
13351
|
+
the first selection — the second click of every double-click then
|
|
13352
|
+
landed on the shifted group head and the dblclick died (v0.18.3). */
|
|
13353
|
+
'.dig-selection-bar{position:absolute;top:0;left:0;right:0;z-index:6;display:flex;align-items:center;gap:12px;padding:3px 10px;font-size:11px;background:var(--dsw-alias-bg-layer-2,var(--dsw-alias-bg-layer-1));border-bottom:1px solid var(--dsw-alias-border-subtle,transparent);box-shadow:var(--dsw-elevation-prominent,0 4px 14px rgba(0,0,0,.3))}',
|
|
13323
13354
|
'.dig-selection-bar .dig-link{margin-left:0}',
|
|
13324
13355
|
'.dig-selection-bar .dig-link-danger{color:var(--dsw-alias-state-error-primary)}',
|
|
13325
13356
|
'.dig-selection-count{color:var(--dsw-alias-label-secondary);white-space:nowrap}',
|