@trim21/personal-pi-extensions 0.1.496 → 0.1.497
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/package.json +1 -1
- package/src/lib/lsp/client.ts +22 -6
- package/src/lib/lsp/lsp.ts +153 -88
package/package.json
CHANGED
package/src/lib/lsp/client.ts
CHANGED
|
@@ -266,6 +266,19 @@ interface ServerCapabilities {
|
|
|
266
266
|
[key: string]: unknown;
|
|
267
267
|
}
|
|
268
268
|
|
|
269
|
+
/**
|
|
270
|
+
* create 的直连缺省(单一来源):lsp.ts 的 resolveConfig 解析超时/LRU 时引用
|
|
271
|
+
* 同一组数值,保证配置层缺省与直连调用方取值一致。
|
|
272
|
+
*/
|
|
273
|
+
export const clientDefaults = {
|
|
274
|
+
diagnosticsDebounceMs: 150,
|
|
275
|
+
diagnosticsDocumentWaitTimeoutMs: 5_000,
|
|
276
|
+
diagnosticsFullWaitTimeoutMs: 10_000,
|
|
277
|
+
diagnosticsRequestTimeoutMs: 3_000,
|
|
278
|
+
initializeTimeoutMs: 45_000,
|
|
279
|
+
maxOpenDocuments: 32,
|
|
280
|
+
} as const;
|
|
281
|
+
|
|
269
282
|
export interface CreateInput {
|
|
270
283
|
serverID: string;
|
|
271
284
|
server: LspServerHandle;
|
|
@@ -416,12 +429,15 @@ function stopProcess(process: LspServerHandle["process"]): Promise<void> {
|
|
|
416
429
|
}
|
|
417
430
|
|
|
418
431
|
export async function create(input: CreateInput): Promise<LspClient> {
|
|
419
|
-
const diagnosticsDebounceMs = input.diagnosticsDebounceMs ??
|
|
420
|
-
const diagnosticsDocumentWaitTimeoutMs =
|
|
421
|
-
|
|
422
|
-
const
|
|
423
|
-
|
|
424
|
-
const
|
|
432
|
+
const diagnosticsDebounceMs = input.diagnosticsDebounceMs ?? clientDefaults.diagnosticsDebounceMs;
|
|
433
|
+
const diagnosticsDocumentWaitTimeoutMs =
|
|
434
|
+
input.diagnosticsDocumentWaitTimeoutMs ?? clientDefaults.diagnosticsDocumentWaitTimeoutMs;
|
|
435
|
+
const diagnosticsFullWaitTimeoutMs =
|
|
436
|
+
input.diagnosticsFullWaitTimeoutMs ?? clientDefaults.diagnosticsFullWaitTimeoutMs;
|
|
437
|
+
const diagnosticsRequestTimeoutMs =
|
|
438
|
+
input.diagnosticsRequestTimeoutMs ?? clientDefaults.diagnosticsRequestTimeoutMs;
|
|
439
|
+
const initializeTimeoutMs = input.initializeTimeoutMs ?? clientDefaults.initializeTimeoutMs;
|
|
440
|
+
const maxOpenDocuments = input.maxOpenDocuments ?? clientDefaults.maxOpenDocuments;
|
|
425
441
|
|
|
426
442
|
const connection = createMessageConnection(
|
|
427
443
|
new StreamMessageReader(input.server.process.stdout),
|
package/src/lib/lsp/lsp.ts
CHANGED
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
* 闭包变量,不做成模块级全局;
|
|
6
6
|
* - 配置来源:全局 `~/.pi/agent/lsp.json` + 本地 `<cwd>/.pi/lsp.json`
|
|
7
7
|
* (本地覆盖全局):`servers` 按 id 合并(同名 id 整体覆盖、新增 id,全局
|
|
8
|
-
* 其余服务器保留),`
|
|
8
|
+
* 其余服务器保留),`watch` 按字段合并(本地逐字段覆盖、`ignore` 取并集);
|
|
9
|
+
* 合并结果解析为 `ResolvedLspConfig`(缺省值应用、超时换算为 ms、白名单转
|
|
10
|
+
* Set),消费方不接触"未配置"歧义;
|
|
9
11
|
* 没有内置默认服务器,所有服务器均须在配置里定义;
|
|
10
12
|
* 配置在每个工具的调用 cwd 下惰性读取;enabled 引用不存在的服务器 id
|
|
11
13
|
* 是配置错误:全局配置在扩展加载(createLspService)时抛错,本地配置在
|
|
@@ -29,8 +31,8 @@ import type { Hover, WorkspaceEdit } from "vscode-languageserver-types";
|
|
|
29
31
|
|
|
30
32
|
import { type LspServerAdapter } from "./adapter.js";
|
|
31
33
|
import {
|
|
34
|
+
clientDefaults,
|
|
32
35
|
create,
|
|
33
|
-
type CreateInput,
|
|
34
36
|
type Diagnostic,
|
|
35
37
|
type Info as LspClient,
|
|
36
38
|
type InspectLocation,
|
|
@@ -41,27 +43,32 @@ import {
|
|
|
41
43
|
WATCH_KIND_DELETE,
|
|
42
44
|
} from "./client.js";
|
|
43
45
|
import { report } from "./diagnostic.js";
|
|
44
|
-
import {
|
|
46
|
+
import {
|
|
47
|
+
createAdapters,
|
|
48
|
+
mergeServerRecords,
|
|
49
|
+
type ServerConfig,
|
|
50
|
+
serverConfigSchema,
|
|
51
|
+
} from "./server-config.js";
|
|
45
52
|
import { type FileChange, watchWorkspace, type WorkspaceWatcher } from "./watcher.js";
|
|
46
53
|
|
|
47
|
-
/** 超时值:number(毫秒,>=1)或字符串("500"、"5s"、"1m"
|
|
54
|
+
/** 超时值:number(毫秒,>=1)或字符串("500"、"5s"、"1m"),换算发生在 resolveConfig。 */
|
|
48
55
|
const timeoutValue = Type.Union([Type.Number({ minimum: 1 }), Type.String()]);
|
|
49
56
|
|
|
50
57
|
/** lsp.json 顶层 `watch` 段:工作区文件监听配置。 */
|
|
51
58
|
const watchConfigSchema = Type.Object({
|
|
52
|
-
/**
|
|
59
|
+
/** 是否启用工作区文件监听。 */
|
|
53
60
|
enabled: Type.Optional(Type.Boolean()),
|
|
54
|
-
/** 事件去抖时长(ms
|
|
61
|
+
/** 事件去抖时长(ms,沿用 timeoutValue 字符串写法)。 */
|
|
55
62
|
debounceMs: Type.Optional(timeoutValue),
|
|
56
|
-
/**
|
|
63
|
+
/** 单批事件上限,超出截断并提示一次。 */
|
|
57
64
|
maxBatch: Type.Optional(Type.Number({ minimum: 1 })),
|
|
58
65
|
/** 追加忽略 glob(相对工作区根的 POSIX 路径)。 */
|
|
59
66
|
ignore: Type.Optional(Type.Array(Type.String())),
|
|
60
67
|
});
|
|
61
68
|
|
|
62
|
-
/** lsp.json
|
|
69
|
+
/** lsp.json 的配置项(全局与本地同构;只描述用户可写的原始形态,缺省见 configDefaults)。 */
|
|
63
70
|
const lspConfigSchema = Type.Object({
|
|
64
|
-
/** 配置文件版本(当前 1);未知版本会被 typebox
|
|
71
|
+
/** 配置文件版本(当前 1);未知版本会被 typebox 严格校验拒绝。 */
|
|
65
72
|
version: Type.Optional(Type.Number()),
|
|
66
73
|
/** 配置驱动的语言服务器定义(id → 配置);无内置默认,全部在此定义。 */
|
|
67
74
|
servers: Type.Optional(Type.Record(Type.String(), serverConfigSchema)),
|
|
@@ -69,26 +76,69 @@ const lspConfigSchema = Type.Object({
|
|
|
69
76
|
enabled: Type.Optional(Type.Array(Type.String())),
|
|
70
77
|
/** 从启用集中排除的服务器 id(缺省 = 无)。 */
|
|
71
78
|
disabled: Type.Optional(Type.Array(Type.String())),
|
|
72
|
-
/**
|
|
79
|
+
/** 工作区文件监听配置(缺省全部字段见 configDefaults.watch)。 */
|
|
73
80
|
watch: Type.Optional(watchConfigSchema),
|
|
74
|
-
/** 驻留文档上限(LRU
|
|
81
|
+
/** 驻留文档上限(LRU 容量),超过时淘汰最久未使用并 didClose。 */
|
|
75
82
|
maxOpenDocuments: Type.Optional(Type.Number({ minimum: 1 })),
|
|
76
|
-
/** push 诊断去抖(ms
|
|
83
|
+
/** push 诊断去抖(ms)。 */
|
|
77
84
|
diagnosticsDebounceMs: Type.Optional(timeoutValue),
|
|
78
|
-
/** document 模式诊断等待上限(ms
|
|
85
|
+
/** document 模式诊断等待上限(ms)。 */
|
|
79
86
|
diagnosticsDocumentWaitTimeoutMs: Type.Optional(timeoutValue),
|
|
80
|
-
/** full 模式诊断等待上限(ms
|
|
87
|
+
/** full 模式诊断等待上限(ms)。 */
|
|
81
88
|
diagnosticsFullWaitTimeoutMs: Type.Optional(timeoutValue),
|
|
82
|
-
/** 单次 pull 诊断请求超时(ms
|
|
89
|
+
/** 单次 pull 诊断请求超时(ms)。 */
|
|
83
90
|
diagnosticsRequestTimeoutMs: Type.Optional(timeoutValue),
|
|
84
|
-
/** 服务器 initialize 握手超时(ms
|
|
91
|
+
/** 服务器 initialize 握手超时(ms)。 */
|
|
85
92
|
initializeTimeoutMs: Type.Optional(timeoutValue),
|
|
86
93
|
});
|
|
87
94
|
|
|
88
|
-
/**
|
|
95
|
+
/** 配置值(单文件解析结果);超时字段为原始写法(number 或字符串),换算在 resolveConfig。 */
|
|
89
96
|
export type LspConfig = Static<typeof lspConfigSchema>;
|
|
90
97
|
|
|
91
|
-
/**
|
|
98
|
+
/**
|
|
99
|
+
* 解析期缺省(单一来源)。超时/LRU 与 client.create 共用 clientDefaults;
|
|
100
|
+
* watch 无 client 对应项,数值在此集中。
|
|
101
|
+
*/
|
|
102
|
+
export const configDefaults = {
|
|
103
|
+
watch: {
|
|
104
|
+
enabled: true,
|
|
105
|
+
debounceMs: 300,
|
|
106
|
+
flushMs: 1_000,
|
|
107
|
+
maxBatch: 500,
|
|
108
|
+
},
|
|
109
|
+
maxOpenDocuments: clientDefaults.maxOpenDocuments,
|
|
110
|
+
} as const;
|
|
111
|
+
|
|
112
|
+
/** 生效的工作区监听配置(缺省值已应用)。 */
|
|
113
|
+
export interface EffectiveWatchConfig {
|
|
114
|
+
enabled: boolean;
|
|
115
|
+
debounceMs: number;
|
|
116
|
+
flushMs: number;
|
|
117
|
+
maxBatch: number;
|
|
118
|
+
ignore: string[];
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** 全局 + 本地合并并解析后的生效配置:所有字段为确定值,无"未配置"歧义。 */
|
|
122
|
+
export interface ResolvedLspConfig {
|
|
123
|
+
/** 合并后的服务器定义(未配置任何服务器时为空表)。 */
|
|
124
|
+
servers: Record<string, ServerConfig>;
|
|
125
|
+
/** enabled 白名单(undefined = 全部启用)。 */
|
|
126
|
+
enabled: Set<string> | undefined;
|
|
127
|
+
/** 从启用集中排除的服务器 id(undefined = 无排除)。 */
|
|
128
|
+
disabled: Set<string> | undefined;
|
|
129
|
+
/** 工作区监听配置(缺省值已应用)。 */
|
|
130
|
+
watch: EffectiveWatchConfig;
|
|
131
|
+
/** 驻留文档 LRU 容量。 */
|
|
132
|
+
maxOpenDocuments: number;
|
|
133
|
+
/** 以下超时均为换算后的毫秒数(缺省见 configDefaults / clientDefaults)。 */
|
|
134
|
+
diagnosticsDebounceMs: number;
|
|
135
|
+
diagnosticsDocumentWaitTimeoutMs: number;
|
|
136
|
+
diagnosticsFullWaitTimeoutMs: number;
|
|
137
|
+
diagnosticsRequestTimeoutMs: number;
|
|
138
|
+
initializeTimeoutMs: number;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** "500" → 500、"5s" → 5000、"1m" → 60000;无效字符串返回 NaN(由调用方兜底缺省)。 */
|
|
92
142
|
function parseTimeoutString(value: string): number {
|
|
93
143
|
// 单位组永远参与匹配(缺省为空串),避免"可选捕获组在类型上不可空"的歧义
|
|
94
144
|
const match = /^(\d+(?:\.\d+)?)(ms|s|m|h|)\s*$/.exec(value.trim());
|
|
@@ -105,65 +155,51 @@ function parseTimeoutString(value: string): number {
|
|
|
105
155
|
return amount * (factor ?? 1);
|
|
106
156
|
}
|
|
107
157
|
|
|
158
|
+
/** 时长字段换算为 ms:number 原样、字符串按 parseTimeoutString;无效值返回 undefined。 */
|
|
108
159
|
function toMs(value: number | string | undefined): number | undefined {
|
|
109
160
|
if (value === undefined) return undefined;
|
|
110
161
|
const ms = typeof value === "number" ? value : parseTimeoutString(value);
|
|
111
162
|
return Number.isFinite(ms) && ms > 0 ? ms : undefined;
|
|
112
163
|
}
|
|
113
164
|
|
|
114
|
-
/**
|
|
115
|
-
function
|
|
116
|
-
config: LspConfig,
|
|
117
|
-
): Pick<
|
|
118
|
-
CreateInput,
|
|
119
|
-
| "diagnosticsDebounceMs"
|
|
120
|
-
| "diagnosticsDocumentWaitTimeoutMs"
|
|
121
|
-
| "diagnosticsFullWaitTimeoutMs"
|
|
122
|
-
| "diagnosticsRequestTimeoutMs"
|
|
123
|
-
| "initializeTimeoutMs"
|
|
124
|
-
> {
|
|
165
|
+
/** 把合并后的原始配置解析为生效配置:应用 configDefaults 缺省、字符串时长换算、白名单转 Set。 */
|
|
166
|
+
export function resolveConfig(raw: LspConfig): ResolvedLspConfig {
|
|
125
167
|
return {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
const watch = config.watch;
|
|
146
|
-
return {
|
|
147
|
-
enabled: watch?.enabled ?? true,
|
|
148
|
-
debounceMs: toMs(watch?.debounceMs) ?? 300,
|
|
149
|
-
flushMs: 1_000,
|
|
150
|
-
maxBatch: watch?.maxBatch ?? 500,
|
|
151
|
-
ignore: watch?.ignore ?? [],
|
|
168
|
+
servers: raw.servers ?? {},
|
|
169
|
+
enabled: raw.enabled === undefined ? undefined : new Set(raw.enabled),
|
|
170
|
+
disabled: raw.disabled === undefined ? undefined : new Set(raw.disabled),
|
|
171
|
+
watch: {
|
|
172
|
+
enabled: raw.watch?.enabled ?? configDefaults.watch.enabled,
|
|
173
|
+
debounceMs: toMs(raw.watch?.debounceMs) ?? configDefaults.watch.debounceMs,
|
|
174
|
+
flushMs: configDefaults.watch.flushMs,
|
|
175
|
+
maxBatch: raw.watch?.maxBatch ?? configDefaults.watch.maxBatch,
|
|
176
|
+
ignore: raw.watch?.ignore ?? [],
|
|
177
|
+
},
|
|
178
|
+
maxOpenDocuments: raw.maxOpenDocuments ?? configDefaults.maxOpenDocuments,
|
|
179
|
+
diagnosticsDebounceMs: toMs(raw.diagnosticsDebounceMs) ?? clientDefaults.diagnosticsDebounceMs,
|
|
180
|
+
diagnosticsDocumentWaitTimeoutMs:
|
|
181
|
+
toMs(raw.diagnosticsDocumentWaitTimeoutMs) ?? clientDefaults.diagnosticsDocumentWaitTimeoutMs,
|
|
182
|
+
diagnosticsFullWaitTimeoutMs:
|
|
183
|
+
toMs(raw.diagnosticsFullWaitTimeoutMs) ?? clientDefaults.diagnosticsFullWaitTimeoutMs,
|
|
184
|
+
diagnosticsRequestTimeoutMs:
|
|
185
|
+
toMs(raw.diagnosticsRequestTimeoutMs) ?? clientDefaults.diagnosticsRequestTimeoutMs,
|
|
186
|
+
initializeTimeoutMs: toMs(raw.initializeTimeoutMs) ?? clientDefaults.initializeTimeoutMs,
|
|
152
187
|
};
|
|
153
188
|
}
|
|
154
189
|
|
|
155
|
-
/**
|
|
156
|
-
|
|
157
|
-
return
|
|
190
|
+
/** 文件不存在的读取错误(ENOENT),其余错误原样抛出。 */
|
|
191
|
+
function isMissingFile(error: unknown): boolean {
|
|
192
|
+
return (error as { code?: unknown }).code === "ENOENT";
|
|
158
193
|
}
|
|
159
194
|
|
|
160
|
-
/**
|
|
195
|
+
/** 读取并解析单个配置文件;文件不存在视为空配置,JSON / typebox 校验错误直接抛出。 */
|
|
161
196
|
async function readConfigFile(filePath: string): Promise<LspConfig> {
|
|
162
197
|
try {
|
|
163
198
|
const raw = await readFile(filePath, "utf8");
|
|
164
199
|
return Value.Parse(lspConfigSchema, JSON.parse(raw) as unknown);
|
|
165
|
-
} catch {
|
|
166
|
-
return {};
|
|
200
|
+
} catch (error) {
|
|
201
|
+
if (isMissingFile(error)) return {};
|
|
202
|
+
throw error;
|
|
167
203
|
}
|
|
168
204
|
}
|
|
169
205
|
|
|
@@ -172,8 +208,9 @@ function readConfigFileSync(filePath: string): LspConfig {
|
|
|
172
208
|
try {
|
|
173
209
|
const raw = readFileSync(filePath, "utf8");
|
|
174
210
|
return Value.Parse(lspConfigSchema, JSON.parse(raw) as unknown);
|
|
175
|
-
} catch {
|
|
176
|
-
return {};
|
|
211
|
+
} catch (error) {
|
|
212
|
+
if (isMissingFile(error)) return {};
|
|
213
|
+
throw error;
|
|
177
214
|
}
|
|
178
215
|
}
|
|
179
216
|
|
|
@@ -182,11 +219,11 @@ function readConfigFileSync(filePath: string): LspConfig {
|
|
|
182
219
|
* servers),否则抛配置错误(避免白名单静默失效)。disabled 中未注册的 id
|
|
183
220
|
* 直接忽略。
|
|
184
221
|
*/
|
|
185
|
-
function validateConfig(config:
|
|
222
|
+
function validateConfig(config: ResolvedLspConfig, adapters?: LspServerAdapter[]): void {
|
|
186
223
|
const available = new Set(
|
|
187
|
-
adapters ? adapters.map((adapter) => adapter.id) : Object.keys(config.servers
|
|
224
|
+
adapters ? adapters.map((adapter) => adapter.id) : Object.keys(config.servers),
|
|
188
225
|
);
|
|
189
|
-
const unknown =
|
|
226
|
+
const unknown = config.enabled === undefined ? [] : [...config.enabled.difference(available)];
|
|
190
227
|
if (unknown.length > 0) {
|
|
191
228
|
const list = [...available].toSorted().join(", ") || "none";
|
|
192
229
|
throw new Error(
|
|
@@ -195,26 +232,46 @@ function validateConfig(config: LspConfig, adapters?: LspServerAdapter[]): void
|
|
|
195
232
|
}
|
|
196
233
|
}
|
|
197
234
|
|
|
235
|
+
/** 合并 watch 段:全局为基底、本地逐字段覆盖;ignore 取并集去重(全局在前)。两边都未配置时返回 undefined,调用方据此省略 watch 键。 */
|
|
236
|
+
function mergeWatch(
|
|
237
|
+
globalWatch: LspConfig["watch"],
|
|
238
|
+
localWatch: LspConfig["watch"],
|
|
239
|
+
): LspConfig["watch"] {
|
|
240
|
+
if (!globalWatch && !localWatch) return undefined;
|
|
241
|
+
return {
|
|
242
|
+
...globalWatch,
|
|
243
|
+
...localWatch,
|
|
244
|
+
ignore: [...new Set([...(globalWatch?.ignore ?? []), ...(localWatch?.ignore ?? [])])],
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
|
|
198
248
|
/**
|
|
199
|
-
*
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
*
|
|
249
|
+
* 合并全局与本地两份原始配置(纯函数,供 loadLspConfig 与针对性测试使用):
|
|
250
|
+
* 全局为基底、本地逐字段覆盖;`servers` 按 id 合并(同名 id 整体覆盖、新增 id,
|
|
251
|
+
* 全局其余服务器保留);`watch` 按字段合并(本地逐字段覆盖、缺省用全局,
|
|
252
|
+
* `ignore` 取并集去重)。
|
|
203
253
|
*/
|
|
254
|
+
export function mergeConfig(globalConfig: LspConfig, localConfig: LspConfig): LspConfig {
|
|
255
|
+
const servers = mergeServerRecords(globalConfig.servers, localConfig.servers);
|
|
256
|
+
const watch = mergeWatch(globalConfig.watch, localConfig.watch);
|
|
257
|
+
return {
|
|
258
|
+
...globalConfig,
|
|
259
|
+
...localConfig,
|
|
260
|
+
...(servers && { servers }),
|
|
261
|
+
...(watch && { watch }),
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/** 读取全局 + 本地配置,合并并解析为生效配置。 */
|
|
204
266
|
export async function loadLspConfig(
|
|
205
267
|
cwd: string,
|
|
206
268
|
globalConfigPath: string = join(homedir(), ".pi", "agent", "lsp.json"),
|
|
207
|
-
): Promise<
|
|
269
|
+
): Promise<ResolvedLspConfig> {
|
|
208
270
|
const [globalConfig, localConfig] = await Promise.all([
|
|
209
271
|
readConfigFile(globalConfigPath),
|
|
210
272
|
readConfigFile(join(cwd, ".pi", "lsp.json")),
|
|
211
273
|
]);
|
|
212
|
-
|
|
213
|
-
return {
|
|
214
|
-
...globalConfig,
|
|
215
|
-
...localConfig,
|
|
216
|
-
...(servers && { servers }),
|
|
217
|
-
};
|
|
274
|
+
return resolveConfig(mergeConfig(globalConfig, localConfig));
|
|
218
275
|
}
|
|
219
276
|
|
|
220
277
|
/**
|
|
@@ -223,12 +280,12 @@ export async function loadLspConfig(
|
|
|
223
280
|
*/
|
|
224
281
|
export function filterAdapters(
|
|
225
282
|
adapters: LspServerAdapter[],
|
|
226
|
-
config:
|
|
283
|
+
config: ResolvedLspConfig,
|
|
227
284
|
): LspServerAdapter[] {
|
|
228
285
|
validateConfig(config, adapters);
|
|
229
286
|
return adapters.filter((adapter) => {
|
|
230
|
-
if (config.enabled && !config.enabled.
|
|
231
|
-
if (config.disabled?.
|
|
287
|
+
if (config.enabled && !config.enabled.has(adapter.id)) return false;
|
|
288
|
+
if (config.disabled?.has(adapter.id)) return false;
|
|
232
289
|
return true;
|
|
233
290
|
});
|
|
234
291
|
}
|
|
@@ -357,7 +414,9 @@ export function createLspService(
|
|
|
357
414
|
): LspService {
|
|
358
415
|
// 扩展加载时校验全局配置(本地配置在 session_start 预加载时校验)
|
|
359
416
|
validateConfig(
|
|
360
|
-
|
|
417
|
+
resolveConfig(
|
|
418
|
+
readConfigFileSync(globalConfigPath ?? join(homedir(), ".pi", "agent", "lsp.json")),
|
|
419
|
+
),
|
|
361
420
|
adapters,
|
|
362
421
|
);
|
|
363
422
|
const state: LspState = {
|
|
@@ -443,7 +502,7 @@ export function createLspService(
|
|
|
443
502
|
async function ensureWatcher(cwd: string, notify?: ExtensionUIContext["notify"]): Promise<void> {
|
|
444
503
|
if (state.closing || state.disabled) return;
|
|
445
504
|
const config = await loadLspConfig(cwd, globalConfigPath);
|
|
446
|
-
const watch =
|
|
505
|
+
const watch = config.watch;
|
|
447
506
|
if (!watch.enabled) return;
|
|
448
507
|
if (watcher && watcherCwd === cwd) return;
|
|
449
508
|
await stopWatcher();
|
|
@@ -502,7 +561,13 @@ export function createLspService(
|
|
|
502
561
|
if (state.closing || state.disabled) return [];
|
|
503
562
|
if (!containsPath(file, cwd)) return [];
|
|
504
563
|
const config = await loadLspConfig(cwd, globalConfigPath);
|
|
505
|
-
const timeout =
|
|
564
|
+
const timeout = {
|
|
565
|
+
diagnosticsDebounceMs: config.diagnosticsDebounceMs,
|
|
566
|
+
diagnosticsDocumentWaitTimeoutMs: config.diagnosticsDocumentWaitTimeoutMs,
|
|
567
|
+
diagnosticsFullWaitTimeoutMs: config.diagnosticsFullWaitTimeoutMs,
|
|
568
|
+
diagnosticsRequestTimeoutMs: config.diagnosticsRequestTimeoutMs,
|
|
569
|
+
initializeTimeoutMs: config.initializeTimeoutMs,
|
|
570
|
+
};
|
|
506
571
|
const active = filterAdapters(adapters ?? createAdapters(config.servers), config);
|
|
507
572
|
const extension = extname(file) || file;
|
|
508
573
|
const result: LspClient[] = [];
|
|
@@ -556,7 +621,7 @@ export function createLspService(
|
|
|
556
621
|
initializeTimeoutMs: adapter.startupTimeoutMs ?? timeout.initializeTimeoutMs,
|
|
557
622
|
diagnosticsDocumentWaitTimeoutMs:
|
|
558
623
|
adapter.diagnosticsWaitMs ?? timeout.diagnosticsDocumentWaitTimeoutMs,
|
|
559
|
-
maxOpenDocuments: maxOpenDocuments
|
|
624
|
+
maxOpenDocuments: config.maxOpenDocuments,
|
|
560
625
|
});
|
|
561
626
|
if (state.closing || state.disabled) {
|
|
562
627
|
await client.shutdown();
|
|
@@ -883,11 +948,11 @@ function getNoopService(): LspService {
|
|
|
883
948
|
}
|
|
884
949
|
|
|
885
950
|
/** 会话配置里生效(未被 enabled 白名单排除、未被 disabled)的服务器数量。 */
|
|
886
|
-
function enabledServerCount(config:
|
|
887
|
-
const ids = adapters ? adapters.map((adapter) => adapter.id) : Object.keys(config.servers
|
|
951
|
+
function enabledServerCount(config: ResolvedLspConfig, adapters?: LspServerAdapter[]): number {
|
|
952
|
+
const ids = adapters ? adapters.map((adapter) => adapter.id) : Object.keys(config.servers);
|
|
888
953
|
return ids.filter((id) => {
|
|
889
|
-
if (config.enabled && !config.enabled.
|
|
890
|
-
if (config.disabled?.
|
|
954
|
+
if (config.enabled && !config.enabled.has(id)) return false;
|
|
955
|
+
if (config.disabled?.has(id)) return false;
|
|
891
956
|
return true;
|
|
892
957
|
}).length;
|
|
893
958
|
}
|