dsh-vscode-mode 0.5.3 → 0.7.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 +72 -2
- package/lib/client.js +12082 -6420
- package/lib/client.js.map +1 -1
- package/lib/index.js +2750 -147
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
- package/src/client/copyText.ts +28 -0
- package/src/client/dap/BpWidget.ts +262 -0
- package/src/client/dap/bpMenu.ts +91 -0
- package/src/client/dap/bpRowMenu.ts +53 -0
- package/src/client/dap/breakpoints.ts +222 -0
- package/src/client/dap/decorate.ts +128 -0
- package/src/client/dap/hintLine.ts +29 -0
- package/src/client/dap/hover.ts +166 -0
- package/src/client/dap/hoverMode.ts +159 -0
- package/src/client/dap/hoverTree.ts +722 -0
- package/src/client/dap/launchInsert.ts +229 -0
- package/src/client/dap/launchSnippetProvider.ts +206 -0
- package/src/client/dap/modelPath.ts +23 -0
- package/src/client/dap/panelSplit.ts +105 -0
- package/src/client/dap/pidPick.ts +24 -0
- package/src/client/dap/store.ts +571 -0
- package/src/client/dap/toolbarDrag.ts +51 -0
- package/src/client/dap/trace.ts +22 -0
- package/src/client/dap/variableTree.ts +62 -0
- package/src/client/fileClipboard.ts +46 -0
- package/src/client/index.ts +12 -3
- package/src/client/monaco/lsp/index.ts +15 -0
- package/src/client/monaco/lsp/providers.ts +2 -0
- package/src/client/monaco/theme.ts +15 -0
- package/src/client/openWithDialog.ts +66 -0
- package/src/client/searchSeed.ts +36 -0
- package/src/client/sidebar/contextMenu.ts +51 -10
- package/src/client/sidebar/menuItems.ts +473 -50
- package/src/client/sidebar/panels/DebugPanel.ts +613 -0
- package/src/client/sidebar/panels/SearchPanel.ts +24 -3
- package/src/client/sidebar/panels/SvnPanel.ts +167 -23
- package/src/client/sidebar/panels/index.ts +19 -0
- package/src/client/sidebar/types.ts +8 -0
- package/src/client/styles/editor.css +176 -0
- package/src/client/svnActions.ts +18 -1
- package/src/client/svnLog.ts +3 -3
- package/src/client/svnStatus.ts +140 -2
- package/src/client/tabActions.ts +22 -10
- package/src/client/ui/EditorView.ts +625 -23
- package/src/client/ui/OfficialSideTab.ts +1 -0
- package/src/client/ui/PromptDialog.ts +63 -0
- package/src/client/ui/SideBySideDiff.tsx +214 -29
- package/src/client/ui/SideEditorTab.ts +1 -0
- package/src/client/ui/SvnDiffPanel.ts +21 -8
- package/src/client/ui/SvnLogDialog.ts +44 -2
- package/src/client/ui/SvnPatchDialog.ts +63 -0
- package/src/client/ui/SvnSumDialog.ts +77 -0
- package/src/client/ui/commandCatalog.ts +63 -0
- package/src/client/ui/svnExport.ts +71 -0
- package/src/dap/configSnippets.ts +269 -0
- package/src/dap/discovery.ts +198 -0
- package/src/dap/launchConfig.ts +127 -0
- package/src/dap/manager.ts +588 -0
- package/src/dap/processList.ts +76 -0
- package/src/dap/protocol.ts +80 -0
- package/src/dap/provider.ts +49 -0
- package/src/dap/rpc.ts +192 -0
- package/src/dap/sourcePath.ts +82 -0
- package/src/index.ts +7 -3
- package/src/lsp/providers.ts +3 -2
- package/src/reveal.ts +31 -20
- package/src/rpc.ts +209 -5
- package/src/search/ripgrep.ts +127 -11
- package/src/shared/dap.ts +262 -0
- package/src/shared/fsNames.ts +115 -0
- package/src/shared/keybindings.ts +9 -0
- package/src/shared/rpc.ts +52 -2
- package/src/shared/svn.ts +147 -0
- package/src/shared/svnActions.ts +20 -0
- package/src/svn.ts +320 -11
- package/src/workspace.ts +0 -75
|
@@ -22,10 +22,12 @@ import {
|
|
|
22
22
|
SVN_STATUS_LETTER,
|
|
23
23
|
SVN_STATUS_TONE,
|
|
24
24
|
isSvnDiffable,
|
|
25
|
+
pairMissingWithUnversioned,
|
|
25
26
|
svnVisibleChanges,
|
|
26
27
|
} from '../../../shared/svn.js'
|
|
27
28
|
import { CACHE_KEY } from '../../paths.js'
|
|
28
|
-
import { refreshSvnChanges, svnAdd, svnRevert } from '../../svnStatus.js'
|
|
29
|
+
import { refreshSvnChanges, svnAdd, svnConflictArtifacts, svnFileSizes, svnRemoteStatus, svnRevert } from '../../svnStatus.js'
|
|
30
|
+
import { csvOf, downloadText, htmlTableOf } from '../../ui/svnExport.js'
|
|
29
31
|
import type { SidebarCtx } from '../types.js'
|
|
30
32
|
|
|
31
33
|
/** 未分组条目的分组键(changelist 为空)。 */
|
|
@@ -44,7 +46,7 @@ const REVERT_CONFIRM_TAIL = ' 个文件的本地改动?新增(A)文件在
|
|
|
44
46
|
* @returns 开关(默认:显示未版本控制、隐藏忽略项)
|
|
45
47
|
*/
|
|
46
48
|
function loadFilter(scope) {
|
|
47
|
-
const fallback = { unversioned: true, ignored: false }
|
|
49
|
+
const fallback = { unversioned: true, ignored: false, name: '' }
|
|
48
50
|
if (!scope) return fallback
|
|
49
51
|
try {
|
|
50
52
|
const raw = window.localStorage.getItem(CACHE_KEY.svn + scope)
|
|
@@ -53,6 +55,8 @@ function loadFilter(scope) {
|
|
|
53
55
|
return {
|
|
54
56
|
unversioned: parsed?.unversioned !== false,
|
|
55
57
|
ignored: parsed?.ignored === true,
|
|
58
|
+
// W1-2 名称过滤随开关一并持久化(旧数据缺字段 = 不过滤,向后兼容)
|
|
59
|
+
name: typeof parsed?.name === 'string' ? parsed.name : '',
|
|
56
60
|
}
|
|
57
61
|
} catch (error) {
|
|
58
62
|
return fallback
|
|
@@ -121,16 +125,18 @@ export function groupByChangelist(entries) {
|
|
|
121
125
|
|
|
122
126
|
/**
|
|
123
127
|
* 单条变更行(状态字母 + 路径 + 行内动作;双击 = 与基线比较)。
|
|
124
|
-
* @author ddj 2026年09月16号
|
|
128
|
+
* @author ddj 2026年09月16号 / 2026年09月20号
|
|
125
129
|
* @param props.entry 变更条目
|
|
126
130
|
* @param props.busy 批量动作进行中(按钮置灰)
|
|
127
131
|
* @param props.onDiff 打开基线差异
|
|
128
132
|
* @param props.onAdd 加入版本控制
|
|
129
133
|
* @param props.onRevert 还原
|
|
134
|
+
* @param props.onConflict 冲突副本对比(W2-4;仅冲突行出现按钮)
|
|
135
|
+
* @param props.pairNote 疑似改名标记文案(W2-5;空 = 无配对)
|
|
130
136
|
* @returns 行元素
|
|
131
137
|
*/
|
|
132
138
|
function SvnRow(props) {
|
|
133
|
-
const { entry, busy, onDiff, onAdd, onRevert } = props
|
|
139
|
+
const { entry, busy, onDiff, onAdd, onRevert, onConflict, pairNote } = props
|
|
134
140
|
const diffable = isSvnDiffable(entry.path, entry.status)
|
|
135
141
|
const act = (label, title, danger, run) => React.createElement('button', {
|
|
136
142
|
className: 'edrv-svn-act' + (danger ? ' edrv-svn-act-danger' : ''),
|
|
@@ -145,7 +151,9 @@ function SvnRow(props) {
|
|
|
145
151
|
},
|
|
146
152
|
statusLetterEl(entry),
|
|
147
153
|
React.createElement('span', { className: 'edrv-svn-path' }, entry.path),
|
|
154
|
+
(pairNote ? React.createElement('span', { className: 'edrv-svn-pair-mark', title: pairNote }, '⇄') : null),
|
|
148
155
|
React.createElement('span', { className: 'edrv-svn-acts' },
|
|
156
|
+
(entry.status === 'conflicted' ? act('冲突对比', '与 .mine/.rN 冲突副本并排对比(解决指引见差异视图顶部)', false, () => onConflict(entry.path)) : null),
|
|
149
157
|
(diffable ? act('比较', SVN_DIFF_BASE_LABEL + '(BASE 与工作区并排)', false, () => onDiff(entry.path)) : null),
|
|
150
158
|
(!entry.versioned ? act('加入', SVN_ADD_LABEL, false, () => onAdd([entry.path])) : null),
|
|
151
159
|
(entry.versioned ? act('还原', SVN_REVERT_LABEL + '(放弃本地改动)', true, () => onRevert([entry.path])) : null)))
|
|
@@ -161,7 +169,11 @@ function SvnRow(props) {
|
|
|
161
169
|
function svnListBody(state, handlers) {
|
|
162
170
|
if (!state.managed) return React.createElement('div', { className: 'edrv-tree-loading' }, '当前工作区不受 SVN 管理')
|
|
163
171
|
if (state.entries === null) return React.createElement('div', { className: 'edrv-tree-loading' }, '读取变更中…')
|
|
164
|
-
if (!state.visible.length)
|
|
172
|
+
if (!state.visible.length) {
|
|
173
|
+
// W1-2:名称过滤生效时区分「无匹配」与「无变更」,提示清空过滤框
|
|
174
|
+
return React.createElement('div', { className: 'edrv-tree-loading' },
|
|
175
|
+
state.nameFiltered ? '无匹配条目(名称过滤生效中,清空过滤框可看全部)' : '无变更(工作副本干净)')
|
|
176
|
+
}
|
|
165
177
|
const rows = []
|
|
166
178
|
for (const group of state.groups) {
|
|
167
179
|
if (state.groups.length > 1 || group.name !== NO_CHANGELIST) {
|
|
@@ -170,47 +182,64 @@ function svnListBody(state, handlers) {
|
|
|
170
182
|
React.createElement('span', { className: 'edrv-svn-group-n' }, String(group.entries.length))))
|
|
171
183
|
}
|
|
172
184
|
for (const entry of group.entries) {
|
|
173
|
-
rows.push(React.createElement(SvnRow, Object.assign({ key: entry.path, entry }, handlers)))
|
|
185
|
+
rows.push(React.createElement(SvnRow, Object.assign({ key: entry.path, entry, pairNote: handlers.pairNotes?.[entry.path] }, handlers)))
|
|
174
186
|
}
|
|
175
187
|
}
|
|
176
188
|
return rows
|
|
177
189
|
}
|
|
178
190
|
|
|
179
191
|
/**
|
|
180
|
-
* 工具条(显示开关 +
|
|
181
|
-
* @author ddj 2026年09月16号
|
|
182
|
-
* @param props.filter
|
|
183
|
-
* @param props.count
|
|
184
|
-
* @param props.
|
|
185
|
-
* @param props.
|
|
192
|
+
* 工具条(显示开关 + 名称过滤 + 批量动作 + 导出)。
|
|
193
|
+
* @author ddj 2026年09月16号 / 2026年09月20号
|
|
194
|
+
* @param props.filter 当前开关(含 W1-2 name)
|
|
195
|
+
* @param props.count 可见条目数(名称过滤后)
|
|
196
|
+
* @param props.countAll 全量条数(未按名称过滤,供「x/y 项」展示)
|
|
197
|
+
* @param props.paths 批量动作目标(add/revert 各自清单;按未过滤集合计算)
|
|
198
|
+
* @param props.handlers 动作回调(toggle/add/revert/onNameFilter/onExportCsv/onExportHtml/busy)
|
|
186
199
|
* @returns 工具条元素数组
|
|
187
200
|
*/
|
|
188
201
|
function svnToolbarEl(props) {
|
|
189
|
-
const { filter, count, paths, handlers } = props
|
|
202
|
+
const { filter, count, countAll, paths, handlers } = props
|
|
190
203
|
const check = (label, title, checked, onChange) => React.createElement('label', {
|
|
191
204
|
className: 'edrv-svn-check', title,
|
|
192
205
|
},
|
|
193
206
|
React.createElement('input', { type: 'checkbox', checked, onChange }),
|
|
194
207
|
React.createElement('span', null, label))
|
|
208
|
+
const nameFiltered = String(filter.name || '').trim() !== ''
|
|
195
209
|
return [
|
|
196
210
|
React.createElement('div', { key: 'tools', className: 'edrv-svn-toolbar' },
|
|
197
211
|
check('未版本控制', '显示未纳入版本控制的文件', filter.unversioned, handlers.toggleUnversioned),
|
|
198
|
-
check('忽略项', '显示被忽略的文件', filter.ignored, handlers.toggleIgnored)
|
|
212
|
+
check('忽略项', '显示被忽略的文件', filter.ignored, handlers.toggleIgnored),
|
|
213
|
+
React.createElement('input', {
|
|
214
|
+
className: 'edrv-svn-name-filter',
|
|
215
|
+
placeholder: '名称过滤:* ? 通配或子串',
|
|
216
|
+
title: '按路径过滤条目(* 任意串、? 单字符;无通配符按子串包含,忽略大小写;只影响列表展示,不缩小批量动作范围)',
|
|
217
|
+
value: filter.name || '',
|
|
218
|
+
onChange: (event) => handlers.onNameFilter(event.target.value),
|
|
219
|
+
})),
|
|
199
220
|
(count
|
|
200
221
|
? React.createElement('div', { key: 'bulk', className: 'edrv-svn-bulk' },
|
|
201
|
-
React.createElement('span', { className: 'edrv-svn-count' }, String(count) + ' 项'),
|
|
222
|
+
React.createElement('span', { className: 'edrv-svn-count' }, String(count) + (nameFiltered ? '/' + countAll : '') + ' 项'),
|
|
202
223
|
React.createElement('span', { style: { flex: 1 } }),
|
|
224
|
+
React.createElement('button', {
|
|
225
|
+
className: 'edrv-svn-act', title: '导出当前列表为 CSV(带 BOM,Excel 直开;状态/路径/changelist/修订)',
|
|
226
|
+
onClick: handlers.onExportCsv,
|
|
227
|
+
}, '导出CSV'),
|
|
228
|
+
React.createElement('button', {
|
|
229
|
+
className: 'edrv-svn-act', title: '导出当前列表为 HTML 报表(仅本地查看,不外发)',
|
|
230
|
+
onClick: handlers.onExportHtml,
|
|
231
|
+
}, '导出HTML'),
|
|
203
232
|
(paths.unversioned.length
|
|
204
233
|
? React.createElement('button', {
|
|
205
234
|
className: 'edrv-svn-act', disabled: handlers.busy,
|
|
206
|
-
title: '
|
|
235
|
+
title: '把全部未版本控制文件加入版本控制(不受名称过滤影响)',
|
|
207
236
|
onClick: () => handlers.add(paths.unversioned),
|
|
208
237
|
}, '全部加入')
|
|
209
238
|
: null),
|
|
210
239
|
(paths.revert.length
|
|
211
240
|
? React.createElement('button', {
|
|
212
241
|
className: 'edrv-svn-act edrv-svn-act-danger', disabled: handlers.busy,
|
|
213
|
-
title: '
|
|
242
|
+
title: '还原全部已受版本控制文件的本地改动(不受名称过滤影响)',
|
|
214
243
|
onClick: () => handlers.revert(paths.revert),
|
|
215
244
|
}, '全部还原')
|
|
216
245
|
: null))
|
|
@@ -233,10 +262,17 @@ export function SvnPanel(props) {
|
|
|
233
262
|
const managed = Boolean(ctx?.svn?.managed && ctx?.svn?.svnCli)
|
|
234
263
|
const [filter, setFilter] = React.useState(() => loadFilter(scope))
|
|
235
264
|
const [busy, setBusy] = React.useState(false)
|
|
265
|
+
// W2-3:远端检查结果(null = 未检查;{ failed: true } = 失败降级;否则 { outdated, againstRev })
|
|
266
|
+
const [remote, setRemote] = React.useState(null)
|
|
267
|
+
const [remoteBusy, setRemoteBusy] = React.useState(false)
|
|
268
|
+
// W2-5:配对候选的文件大小(path → size|null)与成对结果
|
|
269
|
+
const [sizes, setSizes] = React.useState({})
|
|
236
270
|
|
|
237
|
-
//
|
|
271
|
+
// 作用域切换:重读该作用域自己的开关(同一工作区共享)并清掉远端/配对的会话内状态
|
|
238
272
|
React.useEffect(() => {
|
|
239
273
|
setFilter(loadFilter(scope))
|
|
274
|
+
setRemote(null)
|
|
275
|
+
setSizes({})
|
|
240
276
|
}, [scope])
|
|
241
277
|
|
|
242
278
|
const applyFilter = (next) => {
|
|
@@ -264,40 +300,148 @@ export function SvnPanel(props) {
|
|
|
264
300
|
}).finally(() => setBusy(false))
|
|
265
301
|
}
|
|
266
302
|
|
|
267
|
-
|
|
303
|
+
/**
|
|
304
|
+
* 远端更新检查(W2-3;host 侧 15s 短超时,离线/超时降级为提示条文案,不阻塞面板)。
|
|
305
|
+
* @author ddj 2026年09月20号
|
|
306
|
+
*/
|
|
307
|
+
const checkRemote = () => {
|
|
308
|
+
if (remoteBusy) return
|
|
309
|
+
setRemoteBusy(true)
|
|
310
|
+
void svnRemoteStatus(sessionId, '').then((outcome) => {
|
|
311
|
+
if (!outcome.ok) {
|
|
312
|
+
setRemote({ failed: true })
|
|
313
|
+
ctx?.notify?.(outcome.message)
|
|
314
|
+
return
|
|
315
|
+
}
|
|
316
|
+
setRemote({ outdated: outcome.outdated ?? [], againstRev: outcome.againstRev ?? null })
|
|
317
|
+
}).finally(() => setRemoteBusy(false))
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* 冲突副本对比入口(W2-4,只读):扫描 .mine/.working/.rN → 默认首个 .rN ↔ .mine 并排;
|
|
322
|
+
* resolve 指引在差异视图顶部展示,本入口绝不自动执行 svn resolve(归 P2 破坏性批次)。
|
|
323
|
+
* @author ddj 2026年09月20号
|
|
324
|
+
* @param path 冲突文件的工作区相对路径
|
|
325
|
+
*/
|
|
326
|
+
const openConflictDiff = (path) => {
|
|
327
|
+
void svnConflictArtifacts(sessionId, path).then((outcome) => {
|
|
328
|
+
if (!outcome.ok) { ctx?.notify?.(outcome.message); return }
|
|
329
|
+
const artifacts = outcome.artifacts ?? []
|
|
330
|
+
const revSide = artifacts.find((item) => item.kind === 'rev')
|
|
331
|
+
const mineSide = artifacts.find((item) => item.kind === 'mine')
|
|
332
|
+
if (!revSide || !mineSide) {
|
|
333
|
+
ctx?.notify?.('未发现冲突副本(.mine/.rN):' + artifacts.map((item) => item.name).join('、'))
|
|
334
|
+
return
|
|
335
|
+
}
|
|
336
|
+
if (!ctx?.openSvnLocalPair) { ctx?.notify?.('当前视图不支持冲突对比'); return }
|
|
337
|
+
ctx.openSvnLocalPair(revSide.path, mineSide.path, '.r' + (revSide.rev ?? '?'), '.mine', path)
|
|
338
|
+
})
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// W1-2:展示集合(含名称过滤)与批量动作集合(不含名称过滤)分离,「全部加入/还原」不缩小范围
|
|
342
|
+
const shown = entries === null ? [] : svnVisibleChanges(entries, filter)
|
|
343
|
+
const actionable = entries === null ? [] : svnVisibleChanges(entries, { unversioned: filter.unversioned, ignored: filter.ignored })
|
|
344
|
+
const nameFiltered = String(filter.name || '').trim() !== ''
|
|
345
|
+
|
|
346
|
+
// W2-5:`!`(missing)与 `?`(unversioned)共存时才做大小查询(候选少,一次批量查完成对)
|
|
347
|
+
const missingEntries = entries === null ? [] : entries.filter((entry) => entry.status === 'missing')
|
|
348
|
+
const unversionedEntries = entries === null ? [] : entries.filter((entry) => entry.status === 'unversioned')
|
|
349
|
+
const candidates = [...missingEntries, ...unversionedEntries].map((entry) => entry.path)
|
|
350
|
+
const pairsKnown = missingEntries.length > 0 && unversionedEntries.length > 0
|
|
351
|
+
&& candidates.every((path) => path in sizes)
|
|
352
|
+
React.useEffect(() => {
|
|
353
|
+
if (!pairsKnown && candidates.length) {
|
|
354
|
+
void svnFileSizes(sessionId, candidates).then((table) => setSizes(table))
|
|
355
|
+
}
|
|
356
|
+
}, [pairsKnown, candidates.join('\n'), sessionId]) // eslint-disable-line react-hooks/exhaustive-deps
|
|
357
|
+
const pairNoteOf = pairsKnown
|
|
358
|
+
? (() => {
|
|
359
|
+
const notes = {}
|
|
360
|
+
for (const pair of pairMissingWithUnversioned(entries ?? [], sizes)) {
|
|
361
|
+
notes[pair.missingPath] = '疑似改名:原文件 → ' + pair.unversionedPath
|
|
362
|
+
notes[pair.unversionedPath] = '疑似改名:← 原文件 ' + pair.missingPath
|
|
363
|
+
}
|
|
364
|
+
return notes
|
|
365
|
+
})()
|
|
366
|
+
: {}
|
|
367
|
+
|
|
268
368
|
const openSvnDiff = (p) => ctx?.openSvnDiff?.(p)
|
|
269
369
|
const handlers = {
|
|
270
370
|
busy,
|
|
271
371
|
onDiff: openSvnDiff,
|
|
372
|
+
onConflict: openConflictDiff,
|
|
373
|
+
pairNotes: pairNoteOf,
|
|
272
374
|
onAdd: (paths) => runBatch('add', paths),
|
|
273
375
|
onRevert: (paths) => runBatch('revert', paths),
|
|
274
376
|
}
|
|
275
|
-
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* 导出当前展示列表(W1-4):CSV 带 BOM 供 Excel 直开;HTML 本地报表;失败经 notify 提示。
|
|
380
|
+
* @author ddj 2026年09月20号
|
|
381
|
+
* @param kind 导出格式('csv' | 'html')
|
|
382
|
+
*/
|
|
383
|
+
const onExport = (kind) => {
|
|
384
|
+
const rows = shown.map((entry) => [
|
|
385
|
+
SVN_STATUS_LETTER[entry.status] || '',
|
|
386
|
+
entry.path,
|
|
387
|
+
entry.changelist || '',
|
|
388
|
+
entry.revision && entry.revision > 0 ? String(entry.revision) : '',
|
|
389
|
+
])
|
|
390
|
+
const headers = ['状态', '路径', 'changelist', '修订']
|
|
391
|
+
const stamp = new Date().toISOString().slice(0, 10)
|
|
392
|
+
const done = kind === 'html'
|
|
393
|
+
? downloadText('svn-changes-' + stamp + '.html', htmlTableOf(headers, rows, 'SVN 变更列表 ' + stamp), 'text/html')
|
|
394
|
+
: downloadText('svn-changes-' + stamp + '.csv', csvOf([headers, ...rows]), 'text/csv')
|
|
395
|
+
if (!done) ctx?.notify?.('导出失败:浏览器下载能力不可用')
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
const listState = { managed, entries, visible: shown, groups: groupByChangelist(shown), nameFiltered }
|
|
276
399
|
const toolbar = svnToolbarEl({
|
|
277
400
|
filter,
|
|
278
|
-
count:
|
|
401
|
+
count: shown.length,
|
|
402
|
+
countAll: actionable.length,
|
|
279
403
|
paths: {
|
|
280
|
-
unversioned:
|
|
281
|
-
revert:
|
|
404
|
+
unversioned: actionable.filter((entry) => !entry.versioned).map((entry) => entry.path),
|
|
405
|
+
revert: actionable.filter((entry) => entry.versioned).map((entry) => entry.path),
|
|
282
406
|
},
|
|
283
407
|
handlers: Object.assign({}, handlers, {
|
|
284
408
|
toggleUnversioned: () => applyFilter({ ...filter, unversioned: !filter.unversioned }),
|
|
285
409
|
toggleIgnored: () => applyFilter({ ...filter, ignored: !filter.ignored }),
|
|
410
|
+
onNameFilter: (name) => applyFilter({ ...filter, name }),
|
|
411
|
+
onExportCsv: () => onExport('csv'),
|
|
412
|
+
onExportHtml: () => onExport('html'),
|
|
286
413
|
add: (paths) => runBatch('add', paths),
|
|
287
414
|
revert: (paths) => runBatch('revert', paths),
|
|
288
415
|
}),
|
|
289
416
|
})
|
|
290
417
|
const rootName = ctx?.svn?.wcRoot ? String(ctx.svn.wcRoot).split(/[\\/]/).pop() || ctx.svn.wcRoot : ''
|
|
291
418
|
|
|
419
|
+
// W2-3:远端更新提示条(null = 未检查;failed = 降级文案;否则展示落后数与 against 修订)
|
|
420
|
+
const remoteEl = remote === null
|
|
421
|
+
? null
|
|
422
|
+
: React.createElement('div', { className: 'edrv-svn-hintbar' + (remote.failed ? ' edrv-svn-hintbar-warn' : '') },
|
|
423
|
+
React.createElement('span', { style: { flex: 1 } },
|
|
424
|
+
remote.failed
|
|
425
|
+
? '远端检查失败(网络不可达或超时;可用 ⟳ 或「检查远端」重试)'
|
|
426
|
+
: (remote.outdated.length
|
|
427
|
+
? '远端有 ' + remote.outdated.length + ' 个更新(against r' + (remote.againstRev ?? '?') + '),其中本地已改 ' + remote.outdated.filter((item) => item.path && entries?.some((entry) => entry.path === item.path && entry.versioned)).length + ' 个;更新前请先提交或还原'
|
|
428
|
+
: '远端无更新(against r' + (remote.againstRev ?? '?') + ')')),
|
|
429
|
+
React.createElement('button', { className: 'edrv-svn-act', title: '关闭提示条', onClick: () => setRemote(null) }, '✕'))
|
|
430
|
+
|
|
292
431
|
return React.createElement('div', { className: 'edrv-side-panel' },
|
|
293
432
|
React.createElement('div', { className: 'edrv-side-head' },
|
|
294
433
|
React.createElement('span', { className: 'edrv-side-title' }, 'SVN 变更'),
|
|
295
434
|
React.createElement('span', { className: 'edrv-side-root', title: ctx?.svn?.wcRoot || '' }, rootName),
|
|
296
435
|
React.createElement('span', { style: { flex: 1 } }),
|
|
436
|
+
React.createElement('button', {
|
|
437
|
+
className: 'edrv-side-btn', title: '检查远端更新(svn status -u;约数秒,离线自动降级)',
|
|
438
|
+
onClick: checkRemote,
|
|
439
|
+
}, remoteBusy ? '…' : '⇅'),
|
|
297
440
|
React.createElement('button', {
|
|
298
441
|
className: 'edrv-side-btn', title: '刷新变更',
|
|
299
442
|
onClick: () => { refreshSvnChanges(sessionId, scope); ctx?.refreshRecords?.() },
|
|
300
443
|
}, refreshIconEl())),
|
|
444
|
+
remoteEl,
|
|
301
445
|
...toolbar,
|
|
302
446
|
React.createElement('div', { className: 'edrv-svn-list' }, svnListBody(listState, handlers)))
|
|
303
447
|
}
|
|
@@ -7,10 +7,12 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import React from 'react'
|
|
9
9
|
import { IconBranchOutline16, IconFolderOpenOutline16, IconListPenOutline16, IconSearchOutline16 } from '@deepseek-ai/dsh-client-ui-primitives'
|
|
10
|
+
import { dapStore } from '../../dap/store.js'
|
|
10
11
|
import { FileExplorer } from './FileExplorer.js'
|
|
11
12
|
import { SearchPanel } from './SearchPanel.js'
|
|
12
13
|
import { RulesPanel } from './RulesPanel.js'
|
|
13
14
|
import { SvnPanel } from './SvnPanel.js'
|
|
15
|
+
import { DebugPanel } from './DebugPanel.js'
|
|
14
16
|
import type { SidebarPanelDef, SidebarCtx } from '../types.js'
|
|
15
17
|
|
|
16
18
|
/**
|
|
@@ -97,3 +99,20 @@ function svnVisibleCount(entries) {
|
|
|
97
99
|
}
|
|
98
100
|
return count
|
|
99
101
|
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* 构造「调试」面板定义(VS Code 调试视图四段布局 + REPL)。
|
|
105
|
+
* 图标用文本回落(官方原语图标集未含调试类图标时由 SidebarView 文本渲染)。
|
|
106
|
+
* @author ddj 2026年09月29号
|
|
107
|
+
* @returns 面板定义(徽标 = 已暂停时显示 1,吸引注意)
|
|
108
|
+
*/
|
|
109
|
+
export function createDebugPanel(): SidebarPanelDef {
|
|
110
|
+
return {
|
|
111
|
+
id: 'debug',
|
|
112
|
+
title: '调试',
|
|
113
|
+
icon: '🐞',
|
|
114
|
+
order: 22,
|
|
115
|
+
badge: () => (dapStore.getSnapshot().phase === 'paused' ? 1 : null),
|
|
116
|
+
render: (ctx: SidebarCtx) => React.createElement(DebugPanel, { ctx }),
|
|
117
|
+
}
|
|
118
|
+
}
|
|
@@ -41,6 +41,8 @@ export interface SidebarCtx {
|
|
|
41
41
|
svnChangeMap?: Record<string, SvnChangeEntry>
|
|
42
42
|
/** 打开 SVN 基线差异视图(变更面板行内「与基线比较」;缺省时面板降级提示)。 */
|
|
43
43
|
openSvnDiff?: (path: string) => void
|
|
44
|
+
/** 打开双侧本地文件差异(W2-4 冲突副本 `.rN` ↔ `.mine`;缺省时面板降级提示)。 */
|
|
45
|
+
openSvnLocalPair?: (left: string, right: string, leftLabel: string, rightLabel: string, title: string) => void
|
|
44
46
|
/** 重查 SVN 变更清单(CLI 更新/还原/加入版本控制后由菜单动作调用)。 */
|
|
45
47
|
refreshSvnChanges?: () => void
|
|
46
48
|
/** 打开 SVN 日志弹窗(P3;菜单/命令栏「查看日志」)。 */
|
|
@@ -49,6 +51,12 @@ export interface SidebarCtx {
|
|
|
49
51
|
confirm?: (message: string) => boolean
|
|
50
52
|
/** 面板动作反馈(如右键菜单操作结果 → 编辑区路径栏状态)。 */
|
|
51
53
|
notify?: (message: string) => void
|
|
54
|
+
/** 名称输入弹窗(资源管理器右键的新建/重命名;取消/空输入返回 null,缺省时相关项降级提示)。 */
|
|
55
|
+
prompt?: (title: string, initial: string) => Promise<string | null>
|
|
56
|
+
/** 「打开方式…」:在已注册打开器间选择并打开(缺省时该项隐藏)。 */
|
|
57
|
+
openWith?: (path: string) => void
|
|
58
|
+
/** 「在文件夹中查找…」:限定目录并跳到搜索面板(缺省时该项隐藏)。 */
|
|
59
|
+
searchInFolder?: (dir: string) => void
|
|
52
60
|
}
|
|
53
61
|
|
|
54
62
|
/** 单个侧边栏面板定义。 */
|
|
@@ -330,6 +330,44 @@
|
|
|
330
330
|
[data-edrv-view] .edrv-svndiff-tag { padding: 1px 6px; border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-tertiary, #9aa5b1); }
|
|
331
331
|
[data-edrv-view] .edrv-svndiff-host { flex: 1 1 auto; min-height: 0; }
|
|
332
332
|
[data-edrv-view] .edrv-svndiff-empty { display: flex; flex: 1 1 auto; align-items: center; justify-content: center; padding: 24px; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 12px; text-align: center; }
|
|
333
|
+
/* 差异整行色块与行首 +/- 指示符:vendored Monaco(diffEditorWidget2)静态 CSS 无
|
|
334
|
+
.line-insert/.line-delete 背景规则,整行色块靠主题键 + 此处固定色兜底保证可见。
|
|
335
|
+
注意不要用 --dsw-alias-interactive-bg-hover 类 token:实测为 92% 透明中性色,肉眼不可见。
|
|
336
|
+
固定色取自研差异 UI 同色相(绿 #0f9d58 / 红 #d9534f),alpha 提到肉眼可辨。 */
|
|
337
|
+
[data-edrv-view] .monaco-editor .line-insert { background: rgba(15, 157, 88, 0.18); }
|
|
338
|
+
[data-edrv-view] .monaco-editor .line-delete { background: rgba(217, 83, 79, 0.16); }
|
|
339
|
+
[data-edrv-view] .monaco-editor .gutter-insert { background: rgba(15, 157, 88, 0.35); }
|
|
340
|
+
[data-edrv-view] .monaco-editor .gutter-delete { background: rgba(217, 83, 79, 0.35); }
|
|
341
|
+
[data-edrv-view] .monaco-editor .insert-sign { color: var(--dsw-alias-state-success-primary, #0f9d58); }
|
|
342
|
+
[data-edrv-view] .monaco-editor .delete-sign { color: var(--dsw-alias-state-error-primary, #d9534f); }
|
|
343
|
+
/* 差异条快速跳转簇(对齐自研审查条 ↑ i/N ↓ 的形态) */
|
|
344
|
+
[data-edrv-view] .edrv-svndiff-nav { display: flex; align-items: center; gap: 2px; flex-shrink: 0; }
|
|
345
|
+
[data-edrv-view] .edrv-svndiff-nav-count { min-width: 36px; text-align: center; font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); }
|
|
346
|
+
/* W1-3 差异统计徽标(+新增/修改 −删除/修改;色相与行块绿红一致) @author ddj 2026-09-20 */
|
|
347
|
+
[data-edrv-view] .edrv-svndiff-stat { display: inline-flex; align-items: center; gap: 4px; flex-shrink: 0; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; font-variant-numeric: tabular-nums; }
|
|
348
|
+
[data-edrv-view] .edrv-svndiff-stat-add { color: var(--dsw-alias-state-success-primary, #0f9d58); }
|
|
349
|
+
[data-edrv-view] .edrv-svndiff-stat-del { color: var(--dsw-alias-state-error-primary, #d9534f); }
|
|
350
|
+
/* W1-1 差异视图选项条(右端开关组;复用 .edrv-svn-check 的 label 形态) */
|
|
351
|
+
[data-edrv-view] .edrv-svndiff-opts { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
|
|
352
|
+
/* W1-2 变更面板名称过滤输入框(工具条行内,紧凑) @author ddj 2026-09-20 */
|
|
353
|
+
[data-edrv-view] .edrv-svn-name-filter { width: 168px; padding: 1px 6px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 5px; background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #1f2933); font-size: 11px; line-height: 14px; }
|
|
354
|
+
[data-edrv-view] .edrv-svn-name-filter:focus { outline: none; border-color: var(--dsw-alias-brand-primary, #0f9d58); }
|
|
355
|
+
[data-edrv-view] .edrv-svn-name-filter::placeholder { color: var(--dsw-alias-label-tertiary, #9aa5b1); }
|
|
356
|
+
/* W2-3 远端更新提示条(工具条上方;warn = 失败降级) @author ddj 2026-09-20 */
|
|
357
|
+
[data-edrv-view] .edrv-svn-hintbar { display: flex; align-items: center; gap: 6px; margin: 0 10px 4px 12px; padding: 3px 8px; border-radius: 5px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-secondary, #52606d); font-size: 11px; flex-shrink: 0; }
|
|
358
|
+
[data-edrv-view] .edrv-svn-hintbar-warn { background: rgba(217, 83, 79, 0.12); color: var(--dsw-alias-state-error-primary, #d9534f); }
|
|
359
|
+
/* W2-5 疑似改名标记(行内 ⇄;hover 见 tooltip) */
|
|
360
|
+
[data-edrv-view] .edrv-svn-pair-mark { flex-shrink: 0; color: var(--dsw-alias-state-warn-primary, #7c3aed); font-size: 11px; cursor: help; }
|
|
361
|
+
/* W2-1 补丁对话框 / W2-2 目录对比对话框 @author ddj 2026-09-20 */
|
|
362
|
+
[data-edrv-view] .edrv-svn-patch-dialog { max-width: calc(100vw - 48px); }
|
|
363
|
+
[data-edrv-view] .edrv-svn-patch-head { display: flex; align-items: center; gap: 8px; padding-bottom: 8px; }
|
|
364
|
+
[data-edrv-view] .edrv-svn-patch-notes { display: flex; flex-direction: column; gap: 4px; padding-bottom: 6px; }
|
|
365
|
+
[data-edrv-view] .edrv-svn-patch-warn { color: var(--dsw-alias-state-error-primary, #d9534f); font-size: 11px; }
|
|
366
|
+
[data-edrv-view] .edrv-svn-patch-pre { max-height: 46vh; overflow: auto; margin: 0 0 8px; padding: 8px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-2, #f7f9f9); color: var(--dsw-alias-label-primary, #1f2933); font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; line-height: 1.5; white-space: pre; user-select: text; }
|
|
367
|
+
[data-edrv-view] .edrv-svn-patch-foot { display: flex; align-items: center; gap: 8px; }
|
|
368
|
+
[data-edrv-view] .edrv-svn-sum-form { display: flex; align-items: center; gap: 10px; padding-bottom: 8px; }
|
|
369
|
+
[data-edrv-view] .edrv-svn-sum-list { max-height: 44vh; overflow: auto; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; padding: 2px; margin-bottom: 8px; }
|
|
370
|
+
[data-edrv-view] .edrv-svnlog-path-kind { flex-shrink: 0; padding: 0 5px; border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 10px; }
|
|
333
371
|
|
|
334
372
|
/* ===== 通用弹窗外壳(ModalShell)+ SVN 日志弹窗 @author ddj 2026-09-16 ===== */
|
|
335
373
|
/* z-index 190:落在既有阶梯内(命令栏 200 > 片段二级 197 > 片段一级 195 > 190),
|
|
@@ -623,3 +661,141 @@
|
|
|
623
661
|
|
|
624
662
|
|
|
625
663
|
|
|
664
|
+
|
|
665
|
+
/* 调试(DAP):断点圆点 / 停帧行 / 浮动调试工具条。
|
|
666
|
+
圆点挂在 Monaco glyphMargin(glyphMarginClassName),行背景为 isWholeLine className;
|
|
667
|
+
工具条绝对定位于编辑区右上(editorArea relative 由 .edrv-editor-area 自身定位)。 */
|
|
668
|
+
/* 断点圆点:装饰类占满整行,圆点经 ::before 在本行盒子内居中(行归属明确、不跨行界) */
|
|
669
|
+
[data-edrv-view] .edrv-dap-bp { cursor: pointer; }
|
|
670
|
+
[data-edrv-view] .edrv-dap-bp::before { content: ''; display: block; width: 7px; height: 7px; margin: 6px auto 0; border-radius: 50%; background: var(--dsw-alias-state-error-primary, #e51400); }
|
|
671
|
+
[data-edrv-view] .edrv-dap-bp-off { cursor: pointer; }
|
|
672
|
+
[data-edrv-view] .edrv-dap-bp-off::before { content: ''; display: block; box-sizing: border-box; width: 7px; height: 7px; margin: 6px auto 0; border-radius: 50%; border: 1px solid var(--dsw-alias-label-tertiary, #9aa5b1); opacity: .6; }
|
|
673
|
+
/* 未验证断点(适配器真实回执 verified:false):空心红圈,对齐 VS Code 空心圆语义 */
|
|
674
|
+
[data-edrv-view] .edrv-dap-bp-unverified { cursor: pointer; }
|
|
675
|
+
[data-edrv-view] .edrv-dap-bp-unverified::before { content: ''; display: block; box-sizing: border-box; width: 7px; height: 7px; margin: 6px auto 0; border-radius: 50%; border: 1px solid var(--dsw-alias-state-error-primary, #e51400); opacity: .75; }
|
|
676
|
+
[data-edrv-view] .edrv-dap-paused-line { background: var(--dsw-alias-state-warn-tertiary, rgba(229, 185, 63, .22)); }
|
|
677
|
+
[data-edrv-view] .edrv-dap-paused-glyph { cursor: pointer; }
|
|
678
|
+
[data-edrv-view] .edrv-dap-paused-glyph::before { content: ''; display: block; width: 5px; height: 12px; margin: 4px auto 0; border-radius: 2px; background: var(--dsw-alias-state-warn-primary, #e5b93f); }
|
|
679
|
+
[data-edrv-view] .edrv-editor-area { position: relative; }
|
|
680
|
+
/* launch.json 右下角「添加配置」按钮(VSCode 同款形态):仅 launch.json 打开时渲染 */
|
|
681
|
+
[data-edrv-view] .edrv-addcfg { position: absolute; right: 14px; bottom: 10px; z-index: 13; padding: 4px 12px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #f7f9fa); color: var(--dsw-alias-label-secondary, #52606d); font-size: 12px; line-height: 18px; cursor: pointer; box-shadow: 0 1px 4px rgba(0, 0, 0, .1); }
|
|
682
|
+
[data-edrv-view] .edrv-addcfg:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .15)); color: var(--dsw-alias-label-primary, #1f2933); }
|
|
683
|
+
[data-edrv-view] .edrv-dapbar { position: absolute; top: 6px; right: 14px; z-index: 12; display: none; align-items: center; gap: 3px; padding: 3px 5px; border-radius: 8px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); background: var(--dsw-alias-bg-layer-1, #f7f9fa); box-shadow: 0 2px 8px rgba(0, 0, 0, .12); }
|
|
684
|
+
[data-edrv-view] .edrv-dapbar.on { display: flex; border-color: var(--dsw-alias-border-l2, #cdd6da); }
|
|
685
|
+
[data-edrv-view] .edrv-dapbar-grip { flex: 0 0 auto; width: 16px; height: 22px; display: inline-flex; align-items: center; justify-content: center; cursor: grab; user-select: none; color: var(--dsw-alias-label-tertiary, #7b8794); font-size: 12px; }
|
|
686
|
+
[data-edrv-view] .edrv-dapbar-grip:active, [data-edrv-view] .edrv-dapbar.dragging .edrv-dapbar-grip { cursor: grabbing; }
|
|
687
|
+
[data-edrv-view] .edrv-dapbar.dragging { user-select: none; }
|
|
688
|
+
[data-edrv-view] .edrv-dapbar-cfg { max-width: 220px; height: 22px; font-size: 11px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-base, transparent); color: var(--dsw-alias-label-primary, inherit); }
|
|
689
|
+
[data-edrv-view] .edrv-dapbar-btn { min-width: 24px; height: 22px; padding: 0 6px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-primary, inherit); font-size: 12px; line-height: 1; cursor: pointer; }
|
|
690
|
+
[data-edrv-view] .edrv-dapbar-btn:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .15)); }
|
|
691
|
+
[data-edrv-view] .edrv-dapbar-btn:disabled { opacity: .35; cursor: default; }
|
|
692
|
+
[data-edrv-view] .edrv-dapbar-phase { padding: 0 4px; font-size: 11px; white-space: nowrap; color: var(--dsw-alias-label-secondary, #52606d); }
|
|
693
|
+
[data-edrv-view] .edrv-dapbar-phase.paused { color: var(--dsw-alias-state-warn-primary, #b7791f); font-weight: 600; }
|
|
694
|
+
[data-edrv-view] .edrv-dapbar-err { max-width: 260px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 11px; color: var(--dsw-alias-state-error-primary, #e05252); }
|
|
695
|
+
|
|
696
|
+
/* 调试面板(活动栏「调试」页签):四段折叠区 + 断点列表 + REPL。 */
|
|
697
|
+
[data-edrv-view] .edrv-dappanel { display: flex; flex-direction: column; gap: 10px; height: 100%; min-height: 0; overflow: auto; padding: 2px 2px 8px; }
|
|
698
|
+
[data-edrv-view] .edrv-dappanel-head { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; row-gap: 4px; font-size: 12px; color: var(--dsw-alias-label-secondary, #52606d); }
|
|
699
|
+
[data-edrv-view] .edrv-dappanel-phase { padding: 2px 8px; border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); }
|
|
700
|
+
[data-edrv-view] .edrv-dappanel-phase.paused { background: var(--dsw-alias-state-warn-tertiary, rgba(229, 185, 63, .18)); color: var(--dsw-alias-state-warn-primary, #b7791f); font-weight: 600; }
|
|
701
|
+
[data-edrv-view] .edrv-dappanel-cfg { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
702
|
+
[data-edrv-view] .edrv-dappanel-pid { font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; }
|
|
703
|
+
[data-edrv-view] .edrv-dappanel-err { color: var(--dsw-alias-state-error-primary, #e05252); }
|
|
704
|
+
[data-edrv-view] .edrv-dapseg { display: flex; flex-direction: column; gap: 2px; min-height: 0; }
|
|
705
|
+
[data-edrv-view] .edrv-dapseg-body { min-height: 0; overflow-y: auto; overflow-x: hidden; overscroll-behavior: contain; }
|
|
706
|
+
/* 段间分隔条(splitview sash):拖动调整相邻两段高度占比;各段高度由 DebugPanel 内联接管。 */
|
|
707
|
+
[data-edrv-view] .edrv-dapseg-sash { flex: 0 0 auto; height: 4px; margin: 2px 0; border-radius: 2px; background: transparent; cursor: row-resize; }
|
|
708
|
+
[data-edrv-view] .edrv-dapseg-sash:hover, [data-edrv-view] .edrv-dapseg-sash.dragging { background: var(--dsw-alias-border-l2, #cdd6da); }
|
|
709
|
+
/* 折叠段头:chevron + 标题 + 悬浮动作区(动作 hover 显隐;REPL 头不参与折叠)。 */
|
|
710
|
+
[data-edrv-view] .edrv-dapseg-head { display: flex; align-items: center; gap: 4px; font-size: 11px; font-weight: 600; color: var(--dsw-alias-label-tertiary, #7b8794); padding: 2px 2px; cursor: pointer; border-radius: 4px; }
|
|
711
|
+
[data-edrv-view] .edrv-dapseg-head:hover { color: var(--dsw-alias-label-secondary, #52606d); }
|
|
712
|
+
[data-edrv-view] .edrv-daprepl .edrv-dapseg-head { cursor: default; padding: 2px 0; }
|
|
713
|
+
[data-edrv-view] .edrv-dapseg-chevron { flex: 0 0 auto; width: 14px; text-align: center; font-size: 10px; }
|
|
714
|
+
[data-edrv-view] .edrv-dapseg-title { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
715
|
+
[data-edrv-view] .edrv-dapseg-act { flex: 0 0 auto; min-width: 20px; height: 18px; padding: 0 4px; border: none; border-radius: 4px; background: transparent; color: var(--dsw-alias-label-tertiary, #7b8794); font-size: 11px; line-height: 1; cursor: pointer; opacity: 0; }
|
|
716
|
+
[data-edrv-view] .edrv-dapseg-head:hover .edrv-dapseg-act { opacity: 1; }
|
|
717
|
+
[data-edrv-view] .edrv-dapseg-act:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .15)); color: var(--dsw-alias-label-primary, inherit); }
|
|
718
|
+
[data-edrv-view] .edrv-dapempty { font-size: 12px; color: var(--dsw-alias-label-tertiary, #9aa5b1); padding: 4px 2px; }
|
|
719
|
+
[data-edrv-view] .edrv-dapframe { display: flex; align-items: baseline; gap: 8px; padding: 3px 4px; border-radius: 6px; cursor: pointer; font-size: 12px; }
|
|
720
|
+
[data-edrv-view] .edrv-dapframe:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .12)); }
|
|
721
|
+
[data-edrv-view] .edrv-dapframe-name { color: var(--dsw-alias-label-primary, inherit); font-weight: 600; }
|
|
722
|
+
[data-edrv-view] .edrv-dapframe-loc { color: var(--dsw-alias-label-tertiary, #9aa5b1); font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
723
|
+
[data-edrv-view] .edrv-dapscope { font-size: 11px; font-weight: 600; color: var(--dsw-alias-label-secondary, #52606d); padding: 4px 2px 1px; }
|
|
724
|
+
[data-edrv-view] .edrv-dapvar { display: flex; align-items: baseline; gap: 6px; width: 100%; box-sizing: border-box; font-size: 12px; padding: 1px 2px; min-width: 0; }
|
|
725
|
+
[data-edrv-view] .edrv-dapvar-tw { flex: 0 0 auto; width: 14px; border: none; background: transparent; color: var(--dsw-alias-label-tertiary, #9aa5b1); cursor: pointer; font-size: 10px; padding: 0; }
|
|
726
|
+
[data-edrv-view] span.edrv-dapvar-tw { cursor: default; }
|
|
727
|
+
[data-edrv-view] .edrv-dapvar-name { flex: 0 1 34%; min-width: 0; overflow: hidden; text-overflow: ellipsis; color: var(--dsw-alias-label-primary, inherit); font-family: var(--ds-font-family-code, ui-monospace, monospace); white-space: nowrap; }
|
|
728
|
+
[data-edrv-view] .edrv-dapvar-val { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--dsw-alias-label-secondary, #52606d); }
|
|
729
|
+
[data-edrv-view] .edrv-dapvar-type { flex: 0 0 auto; font-size: 10px; color: var(--dsw-alias-label-tertiary, #9aa5b1); }
|
|
730
|
+
[data-edrv-view] .edrv-dapframe.selected { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .16)); outline: 1px solid var(--dsw-alias-border-l2, #cdd6da); }
|
|
731
|
+
[data-edrv-view] .edrv-dapwatch { display: flex; align-items: baseline; gap: 6px; width: 100%; box-sizing: border-box; min-width: 0; font-size: 12px; padding: 1px 2px; }
|
|
732
|
+
[data-edrv-view] .edrv-dapwatch-x { border: none; background: transparent; color: var(--dsw-alias-label-tertiary, #9aa5b1); cursor: pointer; width: 14px; }
|
|
733
|
+
[data-edrv-view] .edrv-dapwatch-x:hover { color: var(--dsw-alias-state-error-primary, #e05252); }
|
|
734
|
+
[data-edrv-view] .edrv-dapwatch-add { padding: 2px 0; }
|
|
735
|
+
[data-edrv-view] .edrv-dapbp { display: flex; align-items: center; gap: 6px; font-size: 12px; padding: 2px 2px; border-radius: 6px; cursor: pointer; }
|
|
736
|
+
[data-edrv-view] .edrv-dapbp:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .12)); }
|
|
737
|
+
[data-edrv-view] .edrv-dapbp:active { background: var(--dsw-alias-interactive-bg-pressed, rgba(127, 127, 127, .2)); }
|
|
738
|
+
[data-edrv-view] .edrv-dapbp-dot { flex: 0 0 auto; width: 9px; height: 9px; border-radius: 50%; background: var(--dsw-alias-state-error-primary, #e51400); }
|
|
739
|
+
[data-edrv-view] .edrv-dapbp-dot.off { background: transparent; border: 1.5px solid var(--dsw-alias-label-tertiary, #9aa5b1); opacity: .6; }
|
|
740
|
+
[data-edrv-view] .edrv-dapbp-file { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; border: none; background: transparent; color: var(--dsw-alias-label-primary, inherit); cursor: pointer; padding: 0; font-size: 12px; }
|
|
741
|
+
[data-edrv-view] .edrv-dapbp-dir { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; text-align: right; }
|
|
742
|
+
[data-edrv-view] .edrv-dapbp-line { flex: 0 0 auto; font-size: 10px; padding: 1px 6px; border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-secondary, #52606d); }
|
|
743
|
+
[data-edrv-view] .edrv-dapbp-x { flex: 0 0 auto; border: none; background: transparent; color: transparent; cursor: pointer; width: 14px; }
|
|
744
|
+
[data-edrv-view] .edrv-dapbp:hover .edrv-dapbp-x { color: var(--dsw-alias-label-tertiary, #9aa5b1); }
|
|
745
|
+
[data-edrv-view] .edrv-dapbp-x:hover { color: var(--dsw-alias-state-error-primary, #e05252) !important; }
|
|
746
|
+
[data-edrv-view] .edrv-daprepl { display: flex; flex-direction: column; gap: 4px; }
|
|
747
|
+
[data-edrv-view] .edrv-daprepl-log { display: flex; flex-direction: column; gap: 1px; max-height: 180px; overflow: auto; }
|
|
748
|
+
[data-edrv-view] .edrv-daprepl-line { font-size: 11px; font-family: var(--ds-font-family-code, ui-monospace, monospace); color: var(--dsw-alias-label-secondary, #52606d); white-space: pre-wrap; word-break: break-all; display: flex; gap: 6px; }
|
|
749
|
+
[data-edrv-view] .edrv-daprepl-line.out { color: var(--dsw-alias-label-tertiary, #9aa5b1); }
|
|
750
|
+
[data-edrv-view] .edrv-daprepl-in { width: 100%; box-sizing: border-box; height: 26px; padding: 0 8px; font-size: 12px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-base, transparent); color: var(--dsw-alias-label-primary, inherit); }
|
|
751
|
+
[data-edrv-view] .edrv-dappanel-run { flex: 0 0 auto; width: 24px; height: 24px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-primary, inherit); font-size: 13px; line-height: 1; cursor: pointer; }
|
|
752
|
+
[data-edrv-view] .edrv-dappanel-run:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .15)); }
|
|
753
|
+
[data-edrv-view] .edrv-dappanel-run:disabled { opacity: .35; cursor: default; background: transparent; }
|
|
754
|
+
/* 面板顶部配置下拉(与编辑器浮动条 .edrv-dapbar-cfg 同视觉)。 */
|
|
755
|
+
[data-edrv-view] .edrv-dappanel-cfg-select { max-width: 190px; height: 24px; padding: 0 4px; font-size: 11px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-base, transparent); color: var(--dsw-alias-label-primary, inherit); }
|
|
756
|
+
/* 断点行内编辑行(面板内展开编辑,控件复用 .edrv-bpwidget-* 视觉;左缩进对齐断点行文字列)。 */
|
|
757
|
+
[data-edrv-view] .edrv-dapbp-edit { display: flex; align-items: center; gap: 6px; padding: 3px 2px 3px 20px; border-radius: 6px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); }
|
|
758
|
+
[data-edrv-view] .edrv-dapbp-edit .edrv-bpwidget-mode { height: 20px; }
|
|
759
|
+
[data-edrv-view] .edrv-dapbp-edit .edrv-bpwidget-input { height: 20px; }
|
|
760
|
+
/* 断点回执:未验证空心红圈(须排在 .off 之后,禁用态优先展示灰圈语义)。 */
|
|
761
|
+
[data-edrv-view] .edrv-dapbp-dot.unverified { background: transparent; border: 1.5px solid var(--dsw-alias-state-error-primary, #e51400); opacity: .75; }
|
|
762
|
+
/* 断点行内编辑浮层(Monaco content widget,锚定断点行上方;对齐 VS Code breakpointWidget 形态)。 */
|
|
763
|
+
/* View Zone 浮层:宽度/左移由 BpWidget.syncWidth 按 layout 内联设置
|
|
764
|
+
(Monaco .view-zones 仅内容区宽,需补偿 contentLeft 与滚动条),此处只管视觉。 */
|
|
765
|
+
[data-edrv-view] .edrv-bpwidget { position: relative; box-sizing: border-box; display: flex; align-items: center; gap: 6px; padding: 3px 8px; border-top: 1px solid var(--dsw-alias-border-l2, #cdd6da); border-bottom: 1px solid var(--dsw-alias-border-l2, #cdd6da); background: var(--dsw-alias-bg-layer-1, #f7f9fa); }
|
|
766
|
+
/* 断点编辑中的目标行高亮(浮层打开期间) */
|
|
767
|
+
[data-edrv-view] .edrv-dap-editing-line { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .12)); }
|
|
768
|
+
[data-edrv-view] .edrv-bpwidget-mode { flex: 0 0 auto; height: 22px; padding: 0 4px; font-size: 12px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 3px; background: var(--dsw-alias-bg-base, transparent); color: var(--dsw-alias-label-primary, inherit); cursor: pointer; }
|
|
769
|
+
[data-edrv-view] .edrv-bpwidget-input { flex: 1 1 auto !important; min-width: 0; width: auto !important; box-sizing: border-box; height: 22px; padding: 0 6px; font-size: 12px; font-family: var(--ds-font-family-code, ui-monospace, monospace); border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 3px; background: var(--dsw-alias-bg-base, transparent); color: var(--dsw-alias-label-primary, inherit); }
|
|
770
|
+
[data-edrv-view] .edrv-bpwidget-input:focus { outline: 1px solid var(--dsw-alias-border-l2, #cdd6da); }
|
|
771
|
+
|
|
772
|
+
/* 断点 hover 预览(glyph 区):半透明小红点 + pointer 光标(对齐 VS Code .codicon-debug-hint)。 */
|
|
773
|
+
[data-edrv-view] .edrv-dap-bp-hint { cursor: pointer; }
|
|
774
|
+
[data-edrv-view] .edrv-dap-bp-hint::before { content: ''; display: block; width: 7px; height: 7px; margin: 6px auto 0; border-radius: 50%; background: var(--dsw-alias-state-error-primary, #e51400); opacity: .4; }
|
|
775
|
+
/* 行号区也给出可点提示(与 VS Code 一致:glyph 区与行号区都可点/可 hover);
|
|
776
|
+
不拦截折叠箭头等自有控件的光标。 */
|
|
777
|
+
[data-edrv-view] .edrv-editor-row .monaco-editor .margin-view-overlays .line-numbers:hover { cursor: pointer; }
|
|
778
|
+
|
|
779
|
+
/* 暂停态 hover 调试块 + 变量树(成员全量直显 + table 成员折叠展开)。
|
|
780
|
+
⚠️ 选择器一律用 data-*:本仓 vendored Monaco 的 markdown→DOM 管线会剥掉我们 HTML 里的
|
|
781
|
+
class(supportHtml/isTrusted 都不豁免),只有 data-* 存活;用 class 会静默失效。 */
|
|
782
|
+
[data-edrv-view] [data-edrv-dap] { display: block; min-width: 0; }
|
|
783
|
+
[data-edrv-view] [data-edrv-head] { display: flex; align-items: baseline; gap: 2px; }
|
|
784
|
+
[data-edrv-view] [data-edrv-head] [data-edrv-expr] { font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); }
|
|
785
|
+
[data-edrv-view] [data-edrv-head] [data-edrv-val] { font-family: var(--ds-font-family-code, ui-monospace, monospace); word-break: break-all; }
|
|
786
|
+
[data-edrv-view] [data-edrv-type] { margin-top: 2px; font-size: 12px; color: var(--dsw-alias-label-tertiary, #8a949b); }
|
|
787
|
+
[data-edrv-view] [data-edrv-tree] { margin: 2px 0 0; padding: 0; list-style: none; font-variant-numeric: tabular-nums; }
|
|
788
|
+
[data-edrv-view] [data-edrv-line] { display: flex; align-items: baseline; gap: 4px; padding: 1px 2px; border-radius: 3px; white-space: nowrap; }
|
|
789
|
+
[data-edrv-view] [data-edrv-line]:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .12)); }
|
|
790
|
+
/* 折叠按钮(对齐 CodeBuddy 调试浮窗变量树的 twist):热区 14px + hover 反馈,未可展开时留空占位 */
|
|
791
|
+
[data-edrv-view] [data-edrv-twist] { flex: 0 0 auto; box-sizing: border-box; width: 14px; height: 14px; line-height: 13px; text-align: center; border-radius: 3px; color: var(--dsw-alias-label-tertiary, #8a949b); }
|
|
792
|
+
[data-edrv-view] [data-edrv-twist]:not(:empty) { cursor: pointer; user-select: none; }
|
|
793
|
+
[data-edrv-view] [data-edrv-twist]:not(:empty):hover { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .2)); color: var(--dsw-alias-label-primary, #1f2933); }
|
|
794
|
+
[data-edrv-view] [data-edrv-name] { flex: 0 0 auto; color: var(--dsw-alias-label-primary, #1f2933); }
|
|
795
|
+
[data-edrv-view] [data-edrv-line] [data-edrv-eq] { flex: 0 0 auto; color: var(--dsw-alias-label-tertiary, #8a949b); }
|
|
796
|
+
[data-edrv-view] [data-edrv-line] [data-edrv-val] { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; color: var(--dsw-alias-label-secondary, #52606d); }
|
|
797
|
+
[data-edrv-view] [data-edrv-note] { color: var(--dsw-alias-label-tertiary, #8a949b); font-style: italic; }
|
|
798
|
+
/* Alt 提示层:由 hoverTree 注入到 .monaco-hover(滚动区之外)贴底常驻;容器预留同高内边距避免遮挡末行。
|
|
799
|
+
不再用 sticky / `:has()`:滚动链在 .monaco-hover-content 上,sticky 会被滚走。 */
|
|
800
|
+
[data-edrv-view] .monaco-hover[data-edrv-hint-host="1"] { padding-bottom: 22px; }
|
|
801
|
+
[data-edrv-view] [data-edrv-hint="1"] { position: absolute; left: 0; right: 0; bottom: 0; box-sizing: border-box; height: 22px; padding: 2px 8px; font-size: 11px; line-height: 18px; color: var(--dsw-alias-label-tertiary, #8a949b); background: var(--dsw-alias-bg-overlay, #ffffff); border-top: 1px solid var(--dsw-alias-border-l1, #e0e6e8); }
|
package/src/client/svnActions.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import type { SvnActionDef } from '../shared/svnActions.js'
|
|
13
13
|
import { svnCleanup } from './svnLog.js'
|
|
14
|
-
import { refreshSvnChanges, svnAdd, svnDiffBase, svnRevert, svnTortoise, svnUpdate } from './svnStatus.js'
|
|
14
|
+
import { refreshSvnChanges, svnAdd, svnDiffBase, svnPatchText, svnRevert, svnTortoise, svnUpdate } from './svnStatus.js'
|
|
15
15
|
|
|
16
16
|
/** 动作执行上下文(各入口把自身能力投影进来)。 */
|
|
17
17
|
export interface SvnActionRunCtx {
|
|
@@ -29,6 +29,10 @@ export interface SvnActionRunCtx {
|
|
|
29
29
|
openSvnDiffRev?: (path: string, revision: number) => void
|
|
30
30
|
/** 打开日志弹窗(log 动作)。 */
|
|
31
31
|
openSvnLog?: (path?: string) => void
|
|
32
|
+
/** 打开补丁对话框(create-patch 动作;执行器完成 RPC 后把载荷交回 UI)。 */
|
|
33
|
+
openPatchDialog?: (payload: { path: string; text: string; truncated: boolean; binary: boolean }) => void
|
|
34
|
+
/** 打开目录对比对话框(diff-summarize 动作;目标目录相对路径,'' = 工作副本根)。 */
|
|
35
|
+
openSumDialog?: (path: string) => void
|
|
32
36
|
/** 重查变更清单(写操作后)。 */
|
|
33
37
|
refreshChanges?: () => void
|
|
34
38
|
/** 就地打开文件(日志面板点击变更文件)。 */
|
|
@@ -92,6 +96,19 @@ export const SVN_ACTION_RUNNERS: Record<string, SvnActionRunner> = {
|
|
|
92
96
|
}, log: (ctx) => {
|
|
93
97
|
ctx.openSvnLog?.(ctx.path || undefined)
|
|
94
98
|
},
|
|
99
|
+
// W2-1:补丁生成(只读,仅生成不落盘应用);RPC 后把载荷交给 UI 对话框
|
|
100
|
+
'create-patch': (ctx) => {
|
|
101
|
+
if (!ctx.path) { ctx.notify?.('无活动文件'); return }
|
|
102
|
+
const target = ctx.path
|
|
103
|
+
void svnPatchText(ctx.sessionId, target).then((outcome) => {
|
|
104
|
+
if (!outcome.ok || typeof outcome.text !== 'string') { ctx.notify?.(outcome.message); return }
|
|
105
|
+
ctx.openPatchDialog?.({ path: target, text: outcome.text, truncated: outcome.truncated === true, binary: outcome.binary === true })
|
|
106
|
+
})
|
|
107
|
+
},
|
|
108
|
+
// W2-2:目录对比(RPC 在对话框内做,执行器只负责打开并传入默认目标目录)
|
|
109
|
+
'diff-summarize': (ctx) => {
|
|
110
|
+
ctx.openSumDialog?.(ctx.path ?? '')
|
|
111
|
+
},
|
|
95
112
|
cleanup: (ctx) => {
|
|
96
113
|
const options = ctx.cleanupOptions ?? {}
|
|
97
114
|
const destructive = options.removeUnversioned === true || options.removeIgnored === true
|