dsh-vscode-mode 0.1.30 → 0.1.35
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/LICENSE +21 -0
- package/README.md +30 -0
- package/lib/client.js +1439 -46
- package/lib/client.js.map +1 -1
- package/lib/index.js +3519 -222
- package/lib/index.js.map +1 -1
- package/package.json +2 -2
- package/src/capture.ts +3 -0
- package/src/client/events.ts +11 -0
- package/src/client/index.ts +20 -2
- package/src/client/monaco/lsp/index.ts +30 -0
- package/src/client/monaco/lsp/lspClient.ts +192 -0
- package/src/client/monaco/lsp/providers.ts +229 -0
- package/src/client/outline/OutlinePanel.tsx +1 -1
- package/src/client/outline/lspSource.ts +49 -0
- package/src/client/outline/parse.ts +31 -1
- package/src/client/outline/types.ts +2 -0
- package/src/client/paths.ts +36 -0
- package/src/client/sidebar/panels/FileExplorer.ts +95 -30
- package/src/client/sidebar/panels/SearchPanel.ts +11 -2
- package/src/client/state/explorerCache.ts +3 -1
- package/src/client/state/explorerEntriesCache.ts +172 -0
- package/src/client/state/viewStateCache.ts +3 -1
- package/src/client/styles/editor.css +16 -0
- package/src/client/styles/mcp.css +63 -0
- package/src/client/ui/EditorView.ts +61 -6
- package/src/client/ui/LspSettings.ts +268 -0
- package/src/client/ui/McpSettings.ts +5 -1
- package/src/client/ui/PerfSettings.ts +242 -0
- package/src/client/ui/PerfSizeBadge.ts +54 -0
- package/src/compat.ts +3 -2
- package/src/fileOpenSettings.ts +1 -0
- package/src/index.ts +25 -2
- package/src/lsp/client.ts +205 -0
- package/src/lsp/config.ts +107 -0
- package/src/lsp/extmgr.ts +208 -0
- package/src/lsp/jsonrpc.ts +86 -0
- package/src/lsp/manager.ts +133 -0
- package/src/lsp/providers.ts +235 -0
- package/src/lsp/rpc.ts +334 -0
- package/src/lsp/server.ts +346 -0
- package/src/lsp/settings.ts +44 -0
- package/src/lsp/transport.ts +143 -0
- package/src/lsp/uri.ts +62 -0
- package/src/lsp/zip.ts +82 -0
- package/src/paths.ts +284 -0
- package/src/perf.ts +340 -0
- package/src/perfPatch.ts +76 -0
- package/src/routes.ts +7 -12
- package/src/rpc.ts +184 -36
- package/src/search/content.ts +14 -7
- package/src/search/ripgrep.ts +54 -1
- package/src/search/types.ts +4 -1
- package/src/shared/lsp.ts +138 -0
- package/src/shared/rpc.ts +103 -2
- package/src/store.ts +2 -2
- package/src/treeIndex.ts +397 -0
- package/src/treeRead.ts +87 -0
package/src/treeRead.ts
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-vscode-mode host — 目录快速列取(edrv.listDir 数据来源,树索引 miss 时走这里)。
|
|
3
|
+
* dsh-fs.listDir 对每个子项顺序 realpath+stat(2 次 open/项),在本部署被中介的
|
|
4
|
+
* open(0.3–3s/次)下大目录呈分钟级;这里用原生 readdir(withFileTypes) 一次取型
|
|
5
|
+
* (O(1) open),仅对 symlink/junction(Windows junction 在 dirent 中报 symlink,
|
|
6
|
+
* 已实测)并行 follow-stat 判型,延迟按轮摊平而非按条目累加。
|
|
7
|
+
* 结果形状与 dsh-fs 一致(name/type),由调用方 toTreeEntries 整形排序。
|
|
8
|
+
* 作者 ddj 2026-08-31
|
|
9
|
+
*/
|
|
10
|
+
import { readdir, stat } from 'node:fs/promises'
|
|
11
|
+
import { join } from 'node:path'
|
|
12
|
+
import type { DirChildLike } from './tree.js'
|
|
13
|
+
|
|
14
|
+
// --region 常量
|
|
15
|
+
/** symlink 并行 stat 分块并发数(并行摊平单次 open 延迟)。 */
|
|
16
|
+
export const SYMLINK_CONCURRENCY = 32
|
|
17
|
+
/** symlink 并行 stat 总数上限:超出部分按 other(防御病态 symlink 目录)。 */
|
|
18
|
+
export const MAX_SYMLINK_STATS = 256
|
|
19
|
+
// --endregion
|
|
20
|
+
|
|
21
|
+
/** 列取失败(带稳定语义 code,调用方转文案)。 */
|
|
22
|
+
export class DirListError extends Error {
|
|
23
|
+
constructor(
|
|
24
|
+
readonly code: 'not-found' | 'not-dir' | 'permission' | 'io',
|
|
25
|
+
message: string,
|
|
26
|
+
) {
|
|
27
|
+
super(message)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** node fs 错误码 → 稳定语义错误。 */
|
|
32
|
+
function codeOf(err: unknown): DirListError {
|
|
33
|
+
const code = (err as NodeJS.ErrnoException | undefined)?.code
|
|
34
|
+
if (code === 'ENOENT') return new DirListError('not-found', '目录不存在')
|
|
35
|
+
if (code === 'ENOTDIR') return new DirListError('not-dir', '不是目录')
|
|
36
|
+
if (code === 'EACCES' || code === 'EPERM' || code === 'EBUSY') return new DirListError('permission', '权限不足')
|
|
37
|
+
return new DirListError('io', String((err as Error | undefined)?.message ?? err))
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** 并行 stat 一批绝对路径 → 目录/文件/other(follow symlink,失败按 other)。 */
|
|
41
|
+
async function statTypes(paths: string[], out: Map<string, 'directory' | 'file' | 'other'>): Promise<void> {
|
|
42
|
+
const cap = Math.min(paths.length, MAX_SYMLINK_STATS)
|
|
43
|
+
for (let i = 0; i < cap; i += SYMLINK_CONCURRENCY) {
|
|
44
|
+
const chunk = paths.slice(i, i + SYMLINK_CONCURRENCY)
|
|
45
|
+
await Promise.all(chunk.map(async (p) => {
|
|
46
|
+
try {
|
|
47
|
+
const info = await stat(p)
|
|
48
|
+
out.set(p, info.isDirectory() ? 'directory' : info.isFile() ? 'file' : 'other')
|
|
49
|
+
} catch (error) {
|
|
50
|
+
out.set(p, 'other')
|
|
51
|
+
}
|
|
52
|
+
}))
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* 快速列取目录:一次 readdir(withFileTypes) 判型;symlink 并行 follow-stat。
|
|
58
|
+
* @author ddj 2026年08月31号
|
|
59
|
+
* @param absDir 绝对目录路径(fs.resolve 后的 targetKey)
|
|
60
|
+
* @returns 子项列表(name/type;size 缺省,树界面不展示大小)
|
|
61
|
+
* @throws DirListError 目录不存在/不是目录/权限不足/IO 失败
|
|
62
|
+
*/
|
|
63
|
+
export async function listDirCheap(absDir: string): Promise<DirChildLike[]> {
|
|
64
|
+
let dirents
|
|
65
|
+
try {
|
|
66
|
+
dirents = await readdir(absDir, { withFileTypes: true, encoding: 'utf8' })
|
|
67
|
+
} catch (error) {
|
|
68
|
+
throw codeOf(error)
|
|
69
|
+
}
|
|
70
|
+
const out: DirChildLike[] = []
|
|
71
|
+
const syms: string[] = []
|
|
72
|
+
for (const d of dirents) {
|
|
73
|
+
if (d.isDirectory()) out.push({ name: d.name, type: 'directory' })
|
|
74
|
+
else if (d.isFile()) out.push({ name: d.name, type: 'file' })
|
|
75
|
+
else if (d.isSymbolicLink()) syms.push(d.name)
|
|
76
|
+
else out.push({ name: d.name, type: 'other' })
|
|
77
|
+
}
|
|
78
|
+
if (syms.length) {
|
|
79
|
+
const symAbs = syms.map((name) => join(absDir, name))
|
|
80
|
+
const types = new Map<string, 'directory' | 'file' | 'other'>()
|
|
81
|
+
await statTypes(symAbs, types)
|
|
82
|
+
for (let i = 0; i < syms.length; i++) {
|
|
83
|
+
out.push({ name: syms[i], type: types.get(symAbs[i]) ?? 'other' })
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return out
|
|
87
|
+
}
|