dsh-vscode-mode 0.4.6 → 0.5.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 +32 -2
- package/lib/client.js +8854 -4023
- package/lib/client.js.map +1 -1
- package/lib/index.js +1842 -65
- package/lib/index.js.map +1 -1
- package/package.json +2 -2
- package/src/client/index.ts +3 -0
- package/src/client/monaco/lsp/providers.ts +28 -6
- package/src/client/navHighlight.ts +96 -0
- package/src/client/paths.ts +2 -0
- package/src/client/rpc.ts +32 -12
- package/src/client/sidebar/SidebarView.ts +6 -2
- package/src/client/sidebar/menuItems.ts +93 -2
- package/src/client/sidebar/panels/FileExplorer.ts +18 -1
- package/src/client/sidebar/panels/SvnPanel.ts +303 -0
- package/src/client/sidebar/panels/index.ts +44 -3
- package/src/client/sidebar/types.ts +20 -0
- package/src/client/styles/editor.css +177 -0
- package/src/client/svnActions.ts +153 -0
- package/src/client/svnLog.ts +356 -0
- package/src/client/svnStatus.ts +363 -0
- package/src/client/svnStore.ts +150 -0
- package/src/client/tabMenu.ts +51 -0
- package/src/client/ui/EditorView.ts +583 -24
- package/src/client/ui/LogDialog.ts +333 -0
- package/src/client/ui/McpSettings.ts +98 -0
- package/src/client/ui/ModalShell.ts +79 -0
- package/src/client/ui/SideBySideDiff.tsx +139 -0
- package/src/client/ui/SnippetsPicker.ts +70 -58
- package/src/client/ui/SvnDiffPanel.ts +50 -0
- package/src/client/ui/SvnLogDialog.ts +1141 -0
- package/src/client/ui/SvnLogStats.ts +243 -0
- package/src/client/ui/commandCatalog.ts +72 -0
- package/src/debugLog.ts +81 -12
- package/src/fileOpenSettings.ts +40 -3
- package/src/index.ts +5 -1
- package/src/rpc.ts +41 -4
- package/src/shared/rpc.ts +53 -1
- package/src/shared/svn.ts +377 -0
- package/src/shared/svnActions.ts +296 -0
- package/src/svn.ts +870 -0
- package/src/svnLog.ts +315 -0
- package/src/svnText.ts +175 -0
- package/src/svnXml.ts +110 -0
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
* 作者 ddj 2026年09月10号
|
|
16
16
|
*/
|
|
17
17
|
import React from 'react'
|
|
18
|
-
import { createPortal } from 'react-dom'
|
|
19
18
|
import { rpc } from '../rpc.js'
|
|
19
|
+
import { ModalShell } from './ModalShell.js'
|
|
20
20
|
import { invalidateSnippets, listSnippetsFor } from '../snippets/provider.js'
|
|
21
21
|
import {
|
|
22
22
|
SNIPPET_LANGUAGES, languageLabelOf, normalizeSnippetFileName, snippetFileTemplate, snippetFileNameFor,
|
|
@@ -232,65 +232,77 @@ export function SnippetsPicker(props) {
|
|
|
232
232
|
'(' + currentLanguage + ')')
|
|
233
233
|
: '当前没有打开文件:可新建全语言片段,或先打开文件再新建对应语言的片段')
|
|
234
234
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
235
|
+
// 一级弹窗:走通用 ModalShell(遮罩/portal 单点保证);
|
|
236
|
+
// maskClass/dialogClass 保持既有类名,故 editor.css 的 .edrv-snip-* 样式与既有测试契约不变。
|
|
237
|
+
// Esc 关掉 closeOnEsc:本组件已注册「二级优先 → 一级」的 Esc 处理,
|
|
238
|
+
// 若外壳再注册一个会同时触发两级关闭(一次按键直接退出整个流程)。
|
|
239
|
+
const dialog = React.createElement(ModalShell, {
|
|
240
|
+
maskClass: 'edrv-snip-mask',
|
|
241
|
+
dialogClass: 'edrv-snip-dialog',
|
|
242
|
+
closeOnEsc: false,
|
|
243
|
+
onClose: () => onClose?.(),
|
|
244
|
+
},
|
|
245
|
+
React.createElement('h3', null, isInsert ? '插入代码片段' : '代码片段:配置代码片段'),
|
|
246
|
+
React.createElement('p', { className: 'edrv-snip-hint' }, isInsert
|
|
247
|
+
? '仅列出对当前文件语言生效的片段(选定后在光标处展开,支持 ${1:占位} 与 $TM_FILENAME 等变量)。'
|
|
248
|
+
: '代码片段按语言绑定:`<语言>.code-snippets` 只对该类文件生效,`global.code-snippets` 对所有文件生效。选中文件即在编辑界面打开。'),
|
|
249
|
+
isInsert ? null : languageBar,
|
|
250
|
+
renderBody(),
|
|
251
|
+
isInsert
|
|
252
|
+
? null
|
|
253
|
+
: React.createElement('div', { className: 'vsm-mcp-dialog-actions' },
|
|
254
|
+
React.createElement('button', {
|
|
255
|
+
disabled: busy,
|
|
256
|
+
onClick: () => openDraft('user', ''),
|
|
257
|
+
}, '新建全语言片段…'),
|
|
258
|
+
React.createElement('button', {
|
|
259
|
+
className: 'vsm-primary',
|
|
260
|
+
disabled: busy || !currentLanguage,
|
|
261
|
+
title: currentLanguage ? '' : '请先打开一个文件,或改用「新建全语言片段…」',
|
|
262
|
+
onClick: () => openDraft('user', currentLanguage),
|
|
263
|
+
}, currentLanguage ? '新建 ' + languageLabelOf(currentLanguage) + ' 片段文件…' : '新建当前语言片段…'),
|
|
264
|
+
React.createElement('button', {
|
|
265
|
+
disabled: busy || !cwd,
|
|
266
|
+
title: cwd ? '' : '当前会话没有工作区',
|
|
267
|
+
onClick: () => openDraft('project', currentLanguage),
|
|
268
|
+
}, '新建项目片段文件…')))
|
|
261
269
|
|
|
262
|
-
// 二级弹窗:新建片段文件(语言 +
|
|
270
|
+
// 二级弹窗:新建片段文件(语言 + 文件名;更高遮罩层,叠在一级之上)
|
|
263
271
|
const createDialog = draft
|
|
264
|
-
? React.createElement(
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
(
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
272
|
+
? React.createElement(ModalShell, {
|
|
273
|
+
maskClass: 'edrv-snip-mask edrv-snip-mask-top',
|
|
274
|
+
dialogClass: 'edrv-snip-dialog',
|
|
275
|
+
closeOnEsc: false,
|
|
276
|
+
onClose: closeDraft,
|
|
277
|
+
},
|
|
278
|
+
React.createElement('h3', null, draft.scope === 'project' ? '新建项目代码片段文件' : '新建全局代码片段文件'),
|
|
279
|
+
React.createElement('label', null, '生效语言',
|
|
280
|
+
React.createElement('select', {
|
|
281
|
+
value: draft.language,
|
|
282
|
+
disabled: busy,
|
|
283
|
+
onChange: (event) => { pickLanguage(event.target.value); setError('') },
|
|
284
|
+
}, options.map((item) => React.createElement('option', { key: 'lang-' + item.id, value: item.id }, item.label)))),
|
|
285
|
+
React.createElement('label', null, '文件名',
|
|
286
|
+
React.createElement('input', {
|
|
287
|
+
autoFocus: true,
|
|
288
|
+
spellCheck: false,
|
|
289
|
+
value: draft.fileName,
|
|
290
|
+
placeholder: snippetFileNameFor(draft.language),
|
|
291
|
+
onChange: (event) => { editFileName(event.target.value); setError('') },
|
|
292
|
+
onKeyDown: (event) => { if (event.key === 'Enter') createFile() },
|
|
293
|
+
})),
|
|
294
|
+
React.createElement('div', { className: 'edrv-snip-hint' },
|
|
295
|
+
(draft.scope === 'project' ? '将写入 ' + (cwd ?? '') + '/.dsh/snippets/' : '将写入 ~/.dsh/snippets/')
|
|
296
|
+
+ normalizeSnippetFileName(draft.fileName)
|
|
297
|
+
+ (draft.language
|
|
298
|
+
? '(仅对 ' + languageLabelOf(draft.language) + ' 文件生效)'
|
|
299
|
+
: '(对所有文件生效)')),
|
|
300
|
+
error ? React.createElement('div', { className: 'vsm-mcp-error vsm-mcp-banner' }, error) : null,
|
|
301
|
+
React.createElement('div', { className: 'vsm-mcp-dialog-actions' },
|
|
302
|
+
React.createElement('button', { disabled: busy, onClick: closeDraft }, '取消'),
|
|
303
|
+
React.createElement('button', { className: 'vsm-primary', disabled: busy, onClick: createFile }, busy ? '创建中…' : '创建并打开')))
|
|
292
304
|
: null
|
|
293
305
|
|
|
294
|
-
//
|
|
295
|
-
return
|
|
306
|
+
// 两个 ModalShell 各自 portal 到 body(根节点带 data-edrv-view 由外壳负责)
|
|
307
|
+
return React.createElement(React.Fragment, null, dialog, createDialog)
|
|
296
308
|
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
/**
|
|
3
|
+
* dsh-vscode-mode client — SVN 基线差异视图(P2 的 BASE ↔ 工作区比较)。
|
|
4
|
+
*
|
|
5
|
+
* 实际渲染由通用 `SideBySideDiff`(F5)承担:本文件只把「基线差异」的语义
|
|
6
|
+
* (BASE 侧缺失时的文案、左侧标签)映射到通用组件上,避免 Monaco 逻辑出现两份。
|
|
7
|
+
* 作者 ddj 2026年09月16号
|
|
8
|
+
*/
|
|
9
|
+
import React from 'react'
|
|
10
|
+
import { SideBySideDiff } from './SideBySideDiff.js'
|
|
11
|
+
|
|
12
|
+
/** 无 BASE 时的说明文案(新增未提交文件的正常语义,不是错误)。 */
|
|
13
|
+
const NO_PRESTINE_NOTE = '该文件尚无基线版本(新增未提交的文件),无法比较'
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* SVN 基线差异视图(BASE 左 / 工作区右,只读)。
|
|
17
|
+
* @author ddj 2026年09月16号
|
|
18
|
+
* @param props.monaco Monaco 实例(未就绪时为 null,显示加载态)
|
|
19
|
+
* @param props.path 目标文件路径
|
|
20
|
+
* @param props.base BASE 侧内容(null = 无 pristine)
|
|
21
|
+
* @param props.working 工作区侧内容
|
|
22
|
+
* @param props.reason 无 BASE 时的原因('no-pristine' | 'cat-failed')
|
|
23
|
+
* @param props.message 补充说明文案
|
|
24
|
+
* @param props.leftLabel 左侧标签(如 BASE / r12)
|
|
25
|
+
* @param props.rightLabel 右侧标签(如 工作区 / r13)
|
|
26
|
+
* @param props.scheme model URI scheme 前缀(区分不同来源,避免跨视图串内容)
|
|
27
|
+
* @param props.onClose 关闭回调
|
|
28
|
+
* @returns 差异视图元素
|
|
29
|
+
*/
|
|
30
|
+
export function SvnDiffPanel(props) {
|
|
31
|
+
const { monaco, path, base, working, reason, message, leftLabel, rightLabel, onClose } = props
|
|
32
|
+
const noBase = typeof base !== 'string'
|
|
33
|
+
const note = noBase
|
|
34
|
+
? (reason === 'no-pristine' ? NO_PRESTINE_NOTE : (reason === 'not-exist' ? '该版本尚无此文件,无可比较内容' : '读取基线失败'))
|
|
35
|
+
: ''
|
|
36
|
+
return React.createElement(SideBySideDiff, {
|
|
37
|
+
monaco,
|
|
38
|
+
path,
|
|
39
|
+
// 左侧无内容时传 ''(而非 null):仍展示编辑器,让用户看到右侧内容
|
|
40
|
+
left: noBase ? '' : base,
|
|
41
|
+
right: working,
|
|
42
|
+
title: path,
|
|
43
|
+
leftLabel: leftLabel || 'BASE',
|
|
44
|
+
rightLabel: rightLabel || '工作区',
|
|
45
|
+
emptyNote: note,
|
|
46
|
+
message: noBase ? '' : message,
|
|
47
|
+
scheme: props.scheme || 'edrv-svn-base',
|
|
48
|
+
onClose,
|
|
49
|
+
})
|
|
50
|
+
}
|