dsh-vscode-mode 0.15.9 → 0.16.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 +5 -4
- package/lib/index.js +67 -17
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
- package/src/dap/discovery.ts +5 -3
- package/src/dap/provider.ts +26 -0
- package/src/lsp/providers.ts +9 -5
- package/src/lsp/server.ts +26 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-vscode-mode",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"description": "DSH 上的类 VSCode 编码体验:Monaco 编辑器(文件页签/QuickOpen/状态栏,可驻 DSH 0.1.5+ 官方右侧 Sidebar 与对话同屏)+ 命令栏(Ctrl+Shift+P)与可扩展指令系统 + VS Code 兼容代码片段(.code-snippets 全局/项目,IntelliSense 展开)+ Agent 编辑差异审查(整文件差异/采纳/拒绝/归档/回滚)+ SVN 集成(侧栏变更面板/日志弹窗/并排差异)+ 语言服务器(LSP)智能(跳转定义/引用/hover/大纲 + VSIX 扩展市场安装),状态持久化到工作区旁车,界面状态(页签/光标/侧栏/编辑 Tab/导航历史)镜像到 DSH home 跨重启恢复",
|
|
5
5
|
"icon": "assets/icon.svg",
|
|
6
6
|
"keywords": [
|
package/src/dap/discovery.ts
CHANGED
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
* ~/.vscode-server/extensions、插件扩展目录),读各扩展 package.json 的
|
|
5
5
|
* contributes.debuggers[] 声明,解析为 DapAdapterDecl:
|
|
6
6
|
* - program 按平台取 windows/linux/osx 覆盖,相对扩展根解析;
|
|
7
|
-
* - runtime='node' → 由 node 跑 js
|
|
7
|
+
* - runtime='node' → 由 node 跑 js 入口;runtime='dotnet' → 由 dotnet 跑 dll 入口;
|
|
8
|
+
* 无 runtime → program 即可执行(args 为清单声明);
|
|
8
9
|
* - 同 type 多扩展并存 → 按「清单版本降序(numeric) → 路径升序」取唯一(与 LSP 候选口径一致);
|
|
9
10
|
* - 入口不存在 / runtime 不支持 → available=false + reason(如 DotRush 按需下载的 clrdbg,
|
|
10
11
|
* 诚实标注不假成功,调用方据此在下拉置灰并提示原因)。
|
|
@@ -128,12 +129,13 @@ function declOf(extDir: string, entry: DebuggerEntry): DapAdapterDecl | null {
|
|
|
128
129
|
const languages = stringsOf(entry.languages)
|
|
129
130
|
const resolved = resolveProgram(extDir, entry)
|
|
130
131
|
const runtime = typeof entry.runtime === 'string' && entry.runtime ? entry.runtime : undefined
|
|
131
|
-
|
|
132
|
+
// node = 扩展 js 入口;dotnet = dotnet 承载的 dll(如 DotRush monodbg),provider 层解析 dotnet 路径
|
|
133
|
+
const runtimeBad = runtime !== undefined && runtime !== 'node' && runtime !== 'dotnet'
|
|
132
134
|
const available = resolved.available && !runtimeBad
|
|
133
135
|
const reason = !resolved.available
|
|
134
136
|
? resolved.reason
|
|
135
137
|
: runtimeBad
|
|
136
|
-
? '暂不支持运行时 "' + runtime + '"(仅支持 node 与原生可执行)'
|
|
138
|
+
? '暂不支持运行时 "' + runtime + '"(仅支持 node、dotnet 与原生可执行)'
|
|
137
139
|
: undefined
|
|
138
140
|
return {
|
|
139
141
|
type,
|
package/src/dap/provider.ts
CHANGED
|
@@ -2,12 +2,17 @@
|
|
|
2
2
|
* dsh-vscode-mode host — 调试适配器规格解析:按调试类型从扩展清单声明(discovery)
|
|
3
3
|
* 解析 spawn 规格,通用不限定语言:
|
|
4
4
|
* - runtime='node' → node 跑 js 入口(emmylua 形态,等价旧 process.execPath 硬编码);
|
|
5
|
+
* - runtime='dotnet' → dotnet 跑 dll 入口(DotRush monodbg 形态;按 dll runtimeconfig
|
|
6
|
+
* 要求的运行时大版本找满足的 dotnet,对齐 LSP 侧 dotrushLaunch 口径);
|
|
5
7
|
* - 无 runtime → program 即原生可执行(clrdbg/monodbg 形态,args 为清单声明如 --interpreter=vscode);
|
|
6
8
|
* - 其它 runtime 明确不支持(decl.available=false 带原因,不做假启动)。
|
|
7
9
|
* 旧版仅探测 tangzx.emmylua 两型(attach/new),由清单驱动后自然覆盖并扩展到任意适配器。
|
|
8
10
|
* 作者 ddj 2026年09月29号 / 2026年09月21号
|
|
9
11
|
*/
|
|
10
12
|
import { debuggerDecls } from './discovery.js'
|
|
13
|
+
import { dirname, join } from 'node:path'
|
|
14
|
+
import { existsSync } from 'node:fs'
|
|
15
|
+
import { dotnetWithRuntime, findDotnet, runtimeMajorOf } from '../lsp/providers.js'
|
|
11
16
|
|
|
12
17
|
/** 适配器启动规格(spawn 参数)。 */
|
|
13
18
|
export interface DapAdapterSpec {
|
|
@@ -42,8 +47,29 @@ export function resolveAdapterSpec(type: string, force = false, home?: string):
|
|
|
42
47
|
if (decl.runtime === 'node') {
|
|
43
48
|
return { ...base, command: process.execPath, args: [decl.program, ...decl.args] }
|
|
44
49
|
}
|
|
50
|
+
if (decl.runtime === 'dotnet') {
|
|
51
|
+
const dotnet = dotnetLaunch(decl.extensionPath, decl.program)
|
|
52
|
+
if (!dotnet) return null
|
|
53
|
+
return { ...base, command: dotnet, args: [decl.program, ...decl.args] }
|
|
54
|
+
}
|
|
45
55
|
if (!decl.runtime) {
|
|
46
56
|
return { ...base, command: decl.program, args: [...decl.args] }
|
|
47
57
|
}
|
|
48
58
|
return null
|
|
49
59
|
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* 为 dotnet 型适配器找启动用 dotnet:优先扩展内置 SDK,其次满足 dll runtimeconfig
|
|
63
|
+
* 要求的运行时大版本,兜底任意 dotnet(对齐 LSP 侧 dotrushLaunch 口径)。
|
|
64
|
+
* @author ddj 2026年10月19号
|
|
65
|
+
* @param extensionPath 扩展根目录
|
|
66
|
+
* @param program 适配器 dll 绝对路径
|
|
67
|
+
* @returns dotnet 可执行路径;找不到满足条件的返回 null
|
|
68
|
+
*/
|
|
69
|
+
function dotnetLaunch(extensionPath: string, program: string): string | null {
|
|
70
|
+
const sdkDotnet = join(extensionPath, 'extension', 'Sdk', 'dotnet' + (process.platform === 'win32' ? '.exe' : ''))
|
|
71
|
+
if (existsSync(sdkDotnet)) return sdkDotnet
|
|
72
|
+
const major = runtimeMajorOf(dirname(program))
|
|
73
|
+
if (major !== null) return dotnetWithRuntime(major) ?? findDotnet()
|
|
74
|
+
return findDotnet()
|
|
75
|
+
}
|
package/src/lsp/providers.ts
CHANGED
|
@@ -398,8 +398,8 @@ export function resolveLuaProvider(manual?: { command?: string; path?: string },
|
|
|
398
398
|
}
|
|
399
399
|
|
|
400
400
|
/**
|
|
401
|
-
* 解析 C# provider(优先级:手动 > 扩展源 > 自动发现;
|
|
402
|
-
*
|
|
401
|
+
* 解析 C# provider(优先级:手动 > 扩展源 > 自动发现;DotRush 优先——自带 sln 加载与
|
|
402
|
+
* 反编译跳转;Roslyn dll 需 dotnet,但无 C# Dev Kit 时不加载项目;或 OmniSharp)。
|
|
403
403
|
* @author ddj 2026年08月27号
|
|
404
404
|
* @param manual 手动配置
|
|
405
405
|
* @param home DSH home(缺省真实;测试可注入临时目录)
|
|
@@ -416,9 +416,10 @@ export function resolveCSharpProvider(manual?: { command?: string; path?: string
|
|
|
416
416
|
// SDK 环境注入:runtime-only 的 dotnet 会导致 MSBuild 求值/restore 退化
|
|
417
417
|
const sdkRoot = findSdkRoot()
|
|
418
418
|
const msbuildEnv = sdkRoot ? sdkEnvOf(sdkRoot) : undefined
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
419
|
+
// DotRush 优先:其服务器从 cwd 自动发现 sln 并自行加载(restore/compile/索引),
|
|
420
|
+
// 元数据符号可跳转反编译源码(实测 GameObject.Find → _decompiled_/UnityEngine.GameObject.cs)。
|
|
421
|
+
// Roslyn(ms-dotnettools.csharp)依赖 C# Dev Kit 的 serviceBroker 加载 sln;
|
|
422
|
+
// 无 Dev Kit 时即使发 solution/open 也不加载项目,references 不跨文件、元数据 definition 全空(实测 2026-10-19)。
|
|
422
423
|
let dotrushReason: string | null = null
|
|
423
424
|
let provisionMajor: number | undefined
|
|
424
425
|
if (discovered.dotrushDll) {
|
|
@@ -430,6 +431,9 @@ export function resolveCSharpProvider(manual?: { command?: string; path?: string
|
|
|
430
431
|
dotrushReason = launch.reason
|
|
431
432
|
provisionMajor = major ?? undefined
|
|
432
433
|
}
|
|
434
|
+
if (discovered.roslynDll && discovered.dotnet) {
|
|
435
|
+
return { ...base, kind: 'discover', argv: [discovered.dotnet, discovered.roslynDll, '--stdio'], env: msbuildEnv, ready: true }
|
|
436
|
+
}
|
|
433
437
|
if (discovered.omnisharpExe) {
|
|
434
438
|
return { ...base, kind: 'discover', argv: [discovered.omnisharpExe, '--stdio'], ready: true }
|
|
435
439
|
}
|
package/src/lsp/server.ts
CHANGED
|
@@ -8,7 +8,8 @@ import { spawnServer, type Transport } from './transport.js'
|
|
|
8
8
|
import { createLspClient, type LspClient } from './client.js'
|
|
9
9
|
import { pathToFileUri, toWorkspacePath, isAbsolutePath, fileUriToPath } from './uri.js'
|
|
10
10
|
import { deriveDefinitionFromLocations, deriveCrossFileDeclaration, isMisresolvedSameFileUsage } from './derive.js'
|
|
11
|
-
import { readFile } from 'node:fs/promises'
|
|
11
|
+
import { readFile, readdir } from 'node:fs/promises'
|
|
12
|
+
import { join } from 'node:path'
|
|
12
13
|
import type { LspProviderSpec } from './providers.js'
|
|
13
14
|
import { LSP_SEMANTIC_TOKEN_MODIFIERS, LSP_SEMANTIC_TOKEN_TYPES } from '../shared/lsp.js'
|
|
14
15
|
import type {
|
|
@@ -61,6 +62,26 @@ interface OpenDoc {
|
|
|
61
62
|
const RESTARTABLE = true
|
|
62
63
|
const MAX_DOC_VERSION = 2147483647
|
|
63
64
|
|
|
65
|
+
/**
|
|
66
|
+
* 找工作区根目录下的第一个 .sln(字典序)。
|
|
67
|
+
*
|
|
68
|
+
* 背景:Roslyn LSP 启动后若收不到 solution/project 通知,会停留在「杂项文件」模式——
|
|
69
|
+
* 工作区内自有符号可解析,但 Unity 引擎程序集 / NuGet 包等元数据符号的
|
|
70
|
+
* definition/hover 一律返回空(实测 2026-10-16,GameObject.Find 全空)。
|
|
71
|
+
* 需在握手后发 Roslyn 专有 `solution/open` 通知加载项目上下文。
|
|
72
|
+
* @author ddj 2026年10月19号
|
|
73
|
+
* @param root 工作区根(绝对路径)
|
|
74
|
+
* @returns sln 绝对路径;根目录无 sln 返回 null
|
|
75
|
+
*/
|
|
76
|
+
async function findSolutionFile(root: string): Promise<string | null> {
|
|
77
|
+
try {
|
|
78
|
+
const names = (await readdir(root)).filter((name) => name.toLowerCase().endsWith('.sln')).sort()
|
|
79
|
+
return names[0] ? join(root, names[0]) : null
|
|
80
|
+
} catch {
|
|
81
|
+
return null
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
64
85
|
/**
|
|
65
86
|
* 使用合法、递增的 Int32 文档版本;旧客户端的毫秒时间戳不能直发给 Roslyn。
|
|
66
87
|
* @author ddj 2026年09月24号
|
|
@@ -320,6 +341,10 @@ export function createLspServer(spec: LspProviderSpec, root: string, languageId:
|
|
|
320
341
|
// 对不认识的配置段按协议忽略,均安全
|
|
321
342
|
if (languageId === 'csharp') {
|
|
322
343
|
client.notify('workspace/didChangeConfiguration', { settings: { dotrush: { roslyn: {} } } })
|
|
344
|
+
// Roslyn 专有:加载解决方案后元数据符号(引擎/NuGet 程序集)才可跳转;
|
|
345
|
+
// 未知通知对其它 C# 服务器按协议安全忽略。无 sln 的纯脚本项目静默跳过。
|
|
346
|
+
const slnPath = await findSolutionFile(root)
|
|
347
|
+
if (slnPath) client.notify('solution/open', { solution: pathToFileUri(slnPath) })
|
|
323
348
|
}
|
|
324
349
|
capabilities = caps
|
|
325
350
|
return true
|