dsh-vscode-mode 0.4.4 → 0.4.6
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 +553 -407
- package/lib/client.js +56 -16
- package/lib/client.js.map +1 -1
- package/package.json +1 -1
- package/src/client/monaco/loader.ts +55 -9
- package/src/client/monaco/lsp/lspClient.ts +5 -1
- package/src/client/sidebar/panels/FileExplorer.ts +0 -2
- package/src/client/ui/EditorView.ts +4 -1
- package/src/client/ui/OfficialSideTab.ts +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-vscode-mode",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.6",
|
|
4
4
|
"description": "DSH 上的类 VSCode 编码体验:Monaco 编辑器(文件页签/QuickOpen/状态栏,可驻 DSH 0.1.5+ 官方右侧 Sidebar 与对话同屏)+ 命令栏(Ctrl+Shift+P)与可扩展指令系统 + VS Code 兼容代码片段(.code-snippets 全局/项目,IntelliSense 展开)+ Agent 编辑差异审查(整文件差异/采纳/拒绝/归档/回滚)+ 语言服务器(LSP)智能(跳转定义/引用/hover/大纲 + VSIX 扩展市场安装),状态持久化到工作区旁车",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"dsh",
|
|
@@ -107,7 +107,7 @@ export function snippetLanguageOf(path) {
|
|
|
107
107
|
|
|
108
108
|
/**
|
|
109
109
|
* 加载 Monaco Editor(AMD 构建,随插件包离线分发):注入 loader.js → require.config → editor.main。
|
|
110
|
-
* @author ddj 2026年08月20号
|
|
110
|
+
* @author ddj 2026年08月20号 / 2026年09月22号
|
|
111
111
|
* @returns Promise<object> window.monaco
|
|
112
112
|
*/
|
|
113
113
|
export function loadMonaco(onProgress) {
|
|
@@ -115,13 +115,58 @@ export function loadMonaco(onProgress) {
|
|
|
115
115
|
if (!monacoPromise) {
|
|
116
116
|
publishStage('loader', MONACO_STAGES.loader.progress, MONACO_STAGES.loader.message)
|
|
117
117
|
monacoPromise = new Promise((resolve, reject) => {
|
|
118
|
+
// 注入期间临时屏蔽全局 module/exports:Monaco loader.js 的 Environment._detect 用
|
|
119
|
+
// `typeof module < 'u' && !!module.exports` 判运行环境,其他插件(如 dsh-backup)注入的
|
|
120
|
+
// 全局 module 会让它误判为 Node 环境 → 只写 module.exports、不挂 window.require →
|
|
121
|
+
// 后续 window.require.config 抛 TypeError(issue #3 根因之一)。onload/onerror 后还原。
|
|
122
|
+
const hasModule = Object.prototype.hasOwnProperty.call(globalThis, 'module')
|
|
123
|
+
const hasExports = Object.prototype.hasOwnProperty.call(globalThis, 'exports')
|
|
124
|
+
const savedModule = globalThis.module
|
|
125
|
+
const savedExports = globalThis.exports
|
|
126
|
+
const hideNodeGlobals = () => {
|
|
127
|
+
try { delete globalThis.module } catch (error) { /* 只读/不可删忽略 */ }
|
|
128
|
+
try { delete globalThis.exports } catch (error) { /* 只读/不可删忽略 */ }
|
|
129
|
+
}
|
|
130
|
+
const restoreNodeGlobals = () => {
|
|
131
|
+
if (hasModule) globalThis.module = savedModule
|
|
132
|
+
else { try { delete globalThis.module } catch (error) { /* 只读/不可删忽略 */ } }
|
|
133
|
+
if (hasExports) globalThis.exports = savedExports
|
|
134
|
+
else { try { delete globalThis.exports } catch (error) { /* 只读/不可删忽略 */ } }
|
|
135
|
+
}
|
|
136
|
+
// 移除已注入的 loader 标签:失败/残留时防止下次命中残留分支同步 boot()(require 未就绪)
|
|
137
|
+
const removeLoaderTag = () => {
|
|
138
|
+
const existing = document.querySelector('script[data-edrv-monaco-loader]')
|
|
139
|
+
if (existing?.parentNode) existing.parentNode.removeChild(existing)
|
|
140
|
+
}
|
|
118
141
|
const fail = (error) => {
|
|
119
142
|
monacoPromise = null
|
|
143
|
+
removeLoaderTag()
|
|
144
|
+
restoreNodeGlobals()
|
|
120
145
|
publishStage('error', MONACO_STAGES.error.progress, MONACO_STAGES.error.message)
|
|
121
146
|
reject(error)
|
|
122
147
|
}
|
|
148
|
+
const inject = () => {
|
|
149
|
+
const s = document.createElement('script')
|
|
150
|
+
s.src = MONACO_BASE + '/loader.js'
|
|
151
|
+
s.dataset.edrvMonacoLoader = '1'
|
|
152
|
+
s.onload = boot
|
|
153
|
+
s.onerror = (event) => {
|
|
154
|
+
// 保留首次失败真实原因(网络/HTTP 层事件),不让后续 TypeError 覆盖
|
|
155
|
+
const hint = event && event.type ? '(' + event.type + ')' : ''
|
|
156
|
+
fail(new Error('Monaco loader 加载失败' + hint))
|
|
157
|
+
}
|
|
158
|
+
hideNodeGlobals()
|
|
159
|
+
document.head.appendChild(s)
|
|
160
|
+
}
|
|
123
161
|
const boot = () => {
|
|
162
|
+
restoreNodeGlobals()
|
|
124
163
|
try {
|
|
164
|
+
// loader 已执行但未挂载 require(全局 module 污染残留/文件异常):报真实原因,
|
|
165
|
+
// 不再重注入——残留标签场景已在注入前分支处理,此处重试只会无限循环
|
|
166
|
+
if (typeof window.require !== 'function' || typeof window.require.config !== 'function') {
|
|
167
|
+
fail(new Error('Monaco loader 未挂载 window.require(可能被其他脚本注入的全局 module 干扰)'))
|
|
168
|
+
return
|
|
169
|
+
}
|
|
125
170
|
window.require.config({ paths: { vs: MONACO_BASE } })
|
|
126
171
|
publishStage('core', MONACO_STAGES.core.progress, MONACO_STAGES.core.message)
|
|
127
172
|
window.require(['vs/editor/editor.main'], () => {
|
|
@@ -138,14 +183,15 @@ export function loadMonaco(onProgress) {
|
|
|
138
183
|
}
|
|
139
184
|
}
|
|
140
185
|
const existing = document.querySelector('script[data-edrv-monaco-loader]')
|
|
141
|
-
if (existing)
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
186
|
+
if (existing && typeof window.require === 'function' && typeof window.require.config === 'function') {
|
|
187
|
+
// 残留标签但 require 已就绪(上次注入已生效):直接 boot,不重复注入
|
|
188
|
+
boot()
|
|
189
|
+
} else if (existing) {
|
|
190
|
+
// 残留标签但 require 缺失(上次失败未清掉):移除后重新注入,避免同步 boot() 二次踩坑
|
|
191
|
+
removeLoaderTag()
|
|
192
|
+
inject()
|
|
193
|
+
} else {
|
|
194
|
+
inject()
|
|
149
195
|
}
|
|
150
196
|
})
|
|
151
197
|
}
|
|
@@ -224,7 +224,11 @@ export function toEdrvUri(uri, root) {
|
|
|
224
224
|
if (!uri) return ''
|
|
225
225
|
if (uri.startsWith('edrv://')) return uri
|
|
226
226
|
const path = relativeLspPath(uri, root)
|
|
227
|
-
|
|
227
|
+
// root 不匹配时 relativeLspPath 返回完整绝对路径(/home/x 或 D:/x):
|
|
228
|
+
// 直接拼 'edrv:///' 会得 edrv:////home/x(空 authority + // 开头)→ Uri.parse 抛
|
|
229
|
+
// UriError(issue #5/#6 同源隐患,LSP 定义/引用跳转工作区外文件时触发);
|
|
230
|
+
// 剥前导 / 后与编辑器 model URI 的相对路径约定一致(Windows 盘符形态不受影响)
|
|
231
|
+
return 'edrv:///' + encodeURI(String(path ?? '').replace(/^\/+/, ''))
|
|
228
232
|
}
|
|
229
233
|
|
|
230
234
|
/** 将 LSP 目标解析为当前工作区相对路径(跨文件跳转与 model URI 对齐)。 */
|
|
@@ -130,8 +130,6 @@ export function FileExplorer(props) {
|
|
|
130
130
|
const reloadDirRef = React.useRef(null) // loadDir 最新闭包(文件变化监听读取,防陈旧闭包)
|
|
131
131
|
const changedTimerRef = React.useRef(null) // 文件变化合并去抖计时器
|
|
132
132
|
const changedRelRef = React.useRef(new Set()) // 待重列的相对目录集合(去抖窗口内合并)
|
|
133
|
-
const dirsMapRef = React.useRef(null) // loadDir 最新闭包(文件变化监听读取,防陈旧闭包)
|
|
134
|
-
dirsMapRef.current = loadDir
|
|
135
133
|
|
|
136
134
|
/** 渲染取数:内存态 → 本地条目缓存 → null(显示加载态)。 */
|
|
137
135
|
const entriesOf = (rel) => dirsRef.current[rel] ?? entriesCacheGet(scope, rel) ?? null
|
|
@@ -1218,7 +1218,10 @@ export function EditorView(props) {
|
|
|
1218
1218
|
let model = cache.get(path)
|
|
1219
1219
|
if (!model) {
|
|
1220
1220
|
// 注册表守卫:同 URI 已存在的 model 直接复用(HMR 换 bundle 后防重复创建抛错)
|
|
1221
|
-
|
|
1221
|
+
// edrv URI 装「工作区相对路径」(对齐 toEdrvUri 约定):绝对路径剥前导 /,
|
|
1222
|
+
// 否则 'edrv:///' + '/home/x' 拼出 edrv:////home/x(空 authority + // 开头)→
|
|
1223
|
+
// Monaco Uri.parse 抛 UriError → 官方侧栏/差异入口打开绝对路径文件白屏(issue #5/#6)
|
|
1224
|
+
const uri = window.monaco.Uri.parse('edrv:///' + encodeURI(String(path ?? '').replace(/^\/+/, '')))
|
|
1222
1225
|
model = window.monaco.editor.getModel(uri) || window.monaco.editor.createModel(text ?? '', langOf(path), uri)
|
|
1223
1226
|
rememberModel(cache, path, model)
|
|
1224
1227
|
} else if (text !== undefined && model.getValue() !== text) {
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
import React from 'react'
|
|
11
11
|
import { EditorView } from './EditorView.js'
|
|
12
12
|
import { setSideEditorMounted } from '../sidebarBridge.js'
|
|
13
|
-
import { editorMountEpoch, markEditorMounted, parseOfficialFileAddress, resolveNavLine, resolveNavOpen } from '../officialSidebar.js'
|
|
13
|
+
import { editorMountEpoch, markEditorActive, markEditorMounted, parseOfficialFileAddress, resolveNavLine, resolveNavOpen } from '../officialSidebar.js'
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* 官方侧边栏 Tab 正文组件(keyed slot sidebar.right.pane.tab 装配)。
|