@trim21/personal-pi-extensions 0.1.576 → 0.1.577
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
CHANGED
package/src/lib/lsp/client.ts
CHANGED
|
@@ -307,6 +307,16 @@ interface ServerCapabilities {
|
|
|
307
307
|
export const clientDefaults = {
|
|
308
308
|
diagnosticsDebounceMs: 150,
|
|
309
309
|
diagnosticsDocumentWaitTimeoutMs: 5_000,
|
|
310
|
+
/**
|
|
311
|
+
* document 模式等待上限的补充:该文档上一份诊断为空(服务器手里是干净文档)时,
|
|
312
|
+
* 内容变化后只用这段安静期等新 push,不再等满 diagnosticsDocumentWaitTimeoutMs。
|
|
313
|
+
*
|
|
314
|
+
* typescript-language-server 的 FileDiagnostics.update 在「该类诊断上一轮为空、
|
|
315
|
+
* 这一轮仍为空」时直接 return 不推送,且它不实现 pull 诊断;这类文档等满整个
|
|
316
|
+
* 窗口也只会在窗口末尾返回同样的「无诊断」,白等一次编辑。诊断集合变成非空时
|
|
317
|
+
* 服务器必定推送,所以短安静期不会漏掉这次变更引入的错误。
|
|
318
|
+
*/
|
|
319
|
+
diagnosticsSilentWaitTimeoutMs: 1_500,
|
|
310
320
|
diagnosticsFullWaitTimeoutMs: 10_000,
|
|
311
321
|
diagnosticsRequestTimeoutMs: 3_000,
|
|
312
322
|
initializeTimeoutMs: 45_000,
|
|
@@ -321,6 +331,8 @@ export interface CreateInput {
|
|
|
321
331
|
/** 可覆盖的超时参数(缺省用 client 默认值,由全局/本地 lsp.json 配置注入)。 */
|
|
322
332
|
diagnosticsDebounceMs?: number;
|
|
323
333
|
diagnosticsDocumentWaitTimeoutMs?: number;
|
|
334
|
+
/** 上一份诊断为空的文档的等待上限;缺省见 clientDefaults。 */
|
|
335
|
+
diagnosticsSilentWaitTimeoutMs?: number;
|
|
324
336
|
diagnosticsFullWaitTimeoutMs?: number;
|
|
325
337
|
diagnosticsRequestTimeoutMs?: number;
|
|
326
338
|
initializeTimeoutMs?: number;
|
|
@@ -522,6 +534,8 @@ export async function create(input: CreateInput): Promise<LspClient> {
|
|
|
522
534
|
const diagnosticsDebounceMs = input.diagnosticsDebounceMs ?? clientDefaults.diagnosticsDebounceMs;
|
|
523
535
|
const diagnosticsDocumentWaitTimeoutMs =
|
|
524
536
|
input.diagnosticsDocumentWaitTimeoutMs ?? clientDefaults.diagnosticsDocumentWaitTimeoutMs;
|
|
537
|
+
const diagnosticsSilentWaitTimeoutMs =
|
|
538
|
+
input.diagnosticsSilentWaitTimeoutMs ?? clientDefaults.diagnosticsSilentWaitTimeoutMs;
|
|
525
539
|
const diagnosticsFullWaitTimeoutMs =
|
|
526
540
|
input.diagnosticsFullWaitTimeoutMs ?? clientDefaults.diagnosticsFullWaitTimeoutMs;
|
|
527
541
|
const diagnosticsRequestTimeoutMs =
|
|
@@ -599,6 +613,8 @@ export async function create(input: CreateInput): Promise<LspClient> {
|
|
|
599
613
|
at: Date.now(),
|
|
600
614
|
version: typeof params.version === "number" ? params.version : undefined,
|
|
601
615
|
});
|
|
616
|
+
const document = files[filePath];
|
|
617
|
+
if (document !== undefined) document.lastPushEmpty = params.diagnostics.length === 0;
|
|
602
618
|
updatePushDiagnostics(filePath, params.diagnostics);
|
|
603
619
|
},
|
|
604
620
|
);
|
|
@@ -702,7 +718,15 @@ export async function create(input: CreateInput): Promise<LspClient> {
|
|
|
702
718
|
await connection.sendNotification("workspace/didChangeConfiguration", { settings });
|
|
703
719
|
}
|
|
704
720
|
|
|
705
|
-
|
|
721
|
+
/**
|
|
722
|
+
* syncedAt:最后一次把该文档内容同步给服务器的时刻(didOpen / didChange)。
|
|
723
|
+
* lastPushEmpty:服务器对该文档最近一次 push 是否为空(无诊断),随驻留记录
|
|
724
|
+
* 一起在 didClose 时清除——只在当前驻留周期内成立。
|
|
725
|
+
*/
|
|
726
|
+
const files: Record<
|
|
727
|
+
string,
|
|
728
|
+
{ version: number; text: string; syncedAt: number; lastPushEmpty?: boolean } | undefined
|
|
729
|
+
> = {};
|
|
706
730
|
|
|
707
731
|
// ── 驻留 LRU ────────────────────────────────────────────────────────────────
|
|
708
732
|
|
|
@@ -1009,7 +1033,20 @@ export async function create(input: CreateInput): Promise<LspClient> {
|
|
|
1009
1033
|
after?: number;
|
|
1010
1034
|
signal?: AbortSignal;
|
|
1011
1035
|
}): Promise<void> {
|
|
1036
|
+
// 服务器对当前内容的最新结论已在手(最后一次 push 晚于最后一次内容同步,
|
|
1037
|
+
// 即此后没有再通知过内容变化):直接返回已有结果。部分服务器在诊断集合
|
|
1038
|
+
// 不变时不再推送(typescript-language-server 空→空不发布),等新 push 只会
|
|
1039
|
+
// 耗满整个窗口后得到同样的「无诊断」。
|
|
1040
|
+
const known = published.get(request.path);
|
|
1041
|
+
const document = files[request.path];
|
|
1042
|
+
if (known !== undefined && document !== undefined && known.at >= document.syncedAt) return;
|
|
1043
|
+
|
|
1012
1044
|
const startedAt = request.after ?? Date.now();
|
|
1045
|
+
// 「上一份 push 为空」的文档用短安静期(见 clientDefaults.diagnosticsSilentWaitTimeoutMs)。
|
|
1046
|
+
const budget =
|
|
1047
|
+
files[request.path]?.lastPushEmpty === true
|
|
1048
|
+
? Math.min(diagnosticsDocumentWaitTimeoutMs, diagnosticsSilentWaitTimeoutMs)
|
|
1049
|
+
: diagnosticsDocumentWaitTimeoutMs;
|
|
1013
1050
|
// pull 与 push 语义相同:都是等「当前文档版本」的诊断结果,统一一个循环。
|
|
1014
1051
|
// 先 pull(拿到即返回);pull 超时说明服务器未响应,不再重试 pull,只等
|
|
1015
1052
|
// 版本匹配的 push 兜底;版本不匹配的 push 一律忽略(防迟到旧结果)。
|
|
@@ -1017,11 +1054,11 @@ export async function create(input: CreateInput): Promise<LspClient> {
|
|
|
1017
1054
|
path: request.path,
|
|
1018
1055
|
version: request.version,
|
|
1019
1056
|
after: startedAt,
|
|
1020
|
-
timeout:
|
|
1057
|
+
timeout: budget,
|
|
1021
1058
|
});
|
|
1022
1059
|
|
|
1023
1060
|
while (!connectionClosed && !request.signal?.aborted) {
|
|
1024
|
-
const remaining =
|
|
1061
|
+
const remaining = budget - (Date.now() - startedAt);
|
|
1025
1062
|
if (remaining <= 0) return;
|
|
1026
1063
|
const result = await requestDocumentDiagnostics(request.path);
|
|
1027
1064
|
if (result.matched) return;
|
|
@@ -1088,13 +1125,21 @@ export async function create(input: CreateInput): Promise<LspClient> {
|
|
|
1088
1125
|
|
|
1089
1126
|
const document = files[resolvedPath];
|
|
1090
1127
|
if (document !== undefined) {
|
|
1128
|
+
// 内容与服务器已知文本一致:不重复通知(didChange 会把已有诊断判为过期,
|
|
1129
|
+
// 而部分服务器对内容未产生新结论的文档不再推送,见 diagnosticsSilentWaitTimeoutMs)。
|
|
1130
|
+
if (document.text === text) {
|
|
1131
|
+
touch(resolvedPath);
|
|
1132
|
+
return document.version;
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1091
1135
|
// didChange:内容已变,旧诊断立即失效。清空缓存避免等待窗口内服务器
|
|
1092
1136
|
// 重算未完成时(大项目可远超窗口)聚合到过期诊断;新 push 到达即填充。
|
|
1093
1137
|
pushDiagnostics.delete(resolvedPath);
|
|
1094
1138
|
pullDiagnostics.delete(resolvedPath);
|
|
1095
1139
|
|
|
1096
1140
|
const next = document.version + 1;
|
|
1097
|
-
|
|
1141
|
+
// 保留 lastPushEmpty:安静期判据看的是「变更前服务器最后一份结论是否为空」
|
|
1142
|
+
files[resolvedPath] = { ...document, version: next, text, syncedAt: Date.now() };
|
|
1098
1143
|
documentVersions.set(resolvedPath, next);
|
|
1099
1144
|
await connection.sendNotification("textDocument/didChange", {
|
|
1100
1145
|
textDocument: { uri, version: next },
|
|
@@ -1118,7 +1163,7 @@ export async function create(input: CreateInput): Promise<LspClient> {
|
|
|
1118
1163
|
await connection.sendNotification("textDocument/didOpen", {
|
|
1119
1164
|
textDocument: { uri, languageId, version: 0, text },
|
|
1120
1165
|
});
|
|
1121
|
-
files[resolvedPath] = { version: 0, text };
|
|
1166
|
+
files[resolvedPath] = { version: 0, text, syncedAt: Date.now() };
|
|
1122
1167
|
documentVersions.set(resolvedPath, 0);
|
|
1123
1168
|
touch(resolvedPath);
|
|
1124
1169
|
await evictExcess();
|
package/src/lib/lsp/lsp.ts
CHANGED
|
@@ -86,6 +86,8 @@ const lspConfigSchema = Type.Object({
|
|
|
86
86
|
diagnosticsDebounceMs: Type.Optional(timeoutValue),
|
|
87
87
|
/** document 模式诊断等待上限(ms)。 */
|
|
88
88
|
diagnosticsDocumentWaitTimeoutMs: Type.Optional(timeoutValue),
|
|
89
|
+
/** 上一份诊断为空的文档的等待上限(ms);见 clientDefaults.diagnosticsSilentWaitTimeoutMs。 */
|
|
90
|
+
diagnosticsSilentWaitTimeoutMs: Type.Optional(timeoutValue),
|
|
89
91
|
/** full 模式诊断等待上限(ms)。 */
|
|
90
92
|
diagnosticsFullWaitTimeoutMs: Type.Optional(timeoutValue),
|
|
91
93
|
/** 单次 pull 诊断请求超时(ms)。 */
|
|
@@ -140,6 +142,7 @@ export interface ResolvedLspConfig {
|
|
|
140
142
|
/** 以下超时均为换算后的毫秒数(缺省见 configDefaults / clientDefaults)。 */
|
|
141
143
|
diagnosticsDebounceMs: number;
|
|
142
144
|
diagnosticsDocumentWaitTimeoutMs: number;
|
|
145
|
+
diagnosticsSilentWaitTimeoutMs: number;
|
|
143
146
|
diagnosticsFullWaitTimeoutMs: number;
|
|
144
147
|
diagnosticsRequestTimeoutMs: number;
|
|
145
148
|
initializeTimeoutMs: number;
|
|
@@ -198,6 +201,8 @@ export function resolveConfig(raw: LspConfig): ResolvedLspConfig {
|
|
|
198
201
|
diagnosticsDebounceMs: toMs(raw.diagnosticsDebounceMs) ?? clientDefaults.diagnosticsDebounceMs,
|
|
199
202
|
diagnosticsDocumentWaitTimeoutMs:
|
|
200
203
|
toMs(raw.diagnosticsDocumentWaitTimeoutMs) ?? clientDefaults.diagnosticsDocumentWaitTimeoutMs,
|
|
204
|
+
diagnosticsSilentWaitTimeoutMs:
|
|
205
|
+
toMs(raw.diagnosticsSilentWaitTimeoutMs) ?? clientDefaults.diagnosticsSilentWaitTimeoutMs,
|
|
201
206
|
diagnosticsFullWaitTimeoutMs:
|
|
202
207
|
toMs(raw.diagnosticsFullWaitTimeoutMs) ?? clientDefaults.diagnosticsFullWaitTimeoutMs,
|
|
203
208
|
diagnosticsRequestTimeoutMs:
|
|
@@ -791,6 +796,7 @@ export function createLspService(
|
|
|
791
796
|
diagnosticsDebounceMs: config.diagnosticsDebounceMs,
|
|
792
797
|
diagnosticsDocumentWaitTimeoutMs:
|
|
793
798
|
adapter.diagnosticsWaitMs ?? config.diagnosticsDocumentWaitTimeoutMs,
|
|
799
|
+
diagnosticsSilentWaitTimeoutMs: config.diagnosticsSilentWaitTimeoutMs,
|
|
794
800
|
diagnosticsFullWaitTimeoutMs: config.diagnosticsFullWaitTimeoutMs,
|
|
795
801
|
diagnosticsRequestTimeoutMs: config.diagnosticsRequestTimeoutMs,
|
|
796
802
|
initializeTimeoutMs: adapter.startupTimeoutMs ?? config.initializeTimeoutMs,
|
|
@@ -27,12 +27,13 @@ description: Use when 编写、检查或排查 LSP 语言服务器配置 ——
|
|
|
27
27
|
|
|
28
28
|
```
|
|
29
29
|
version / servers / enabled / disabled / watch / maxOpenDocuments /
|
|
30
|
-
diagnosticsDebounceMs / diagnosticsDocumentWaitTimeoutMs /
|
|
30
|
+
diagnosticsDebounceMs / diagnosticsDocumentWaitTimeoutMs / diagnosticsSilentWaitTimeoutMs /
|
|
31
31
|
diagnosticsFullWaitTimeoutMs / diagnosticsRequestTimeoutMs / initializeTimeoutMs
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
- `enabled`:只启用列出的服务器 id(缺省 = 全部启用);`disabled`:从启用集中排除
|
|
35
|
-
- 时长字段:毫秒数字,或带单位的字符串(`"300ms"` / `"5s"` / `"1m"` / `"2h"`,空单位按 ms);默认值见 `clientDefaults`(client.ts):debounce 150ms、document 等待 5s、full 等待 10s、pull 请求 3s、initialize 45s、`maxOpenDocuments` 32
|
|
35
|
+
- 时长字段:毫秒数字,或带单位的字符串(`"300ms"` / `"5s"` / `"1m"` / `"2h"`,空单位按 ms);默认值见 `clientDefaults`(client.ts):debounce 150ms、document 等待 5s、安静期 1.5s、full 等待 10s、pull 请求 3s、initialize 45s、`maxOpenDocuments` 32
|
|
36
|
+
- `diagnosticsSilentWaitTimeoutMs`:只用于「该文档上一份诊断为空」的情形——内容变化后最多只等这段安静期,不再等满 `diagnosticsDocumentWaitTimeoutMs`。typescript-language-server 在诊断集合空→空时不重复推送且不实现 pull 诊断,这类文档等满整个窗口也只会得到同样的「无诊断」,白等一次编辑;集合变成非空时服务器必定推送,所以调小它不会漏掉变更引入的错误,调大则更保守(默认 1.5s,约等于实测热态推送延迟的三倍)。设为不小于 `diagnosticsDocumentWaitTimeoutMs` 即等价于不做这个缩短
|
|
36
37
|
- `watch`:`enabled` / `debounceMs`(缺省 300)/ `maxBatch`(缺省 500)/ `ignore`(glob,相对**每个被监听的项目根**的 POSIX 路径)。注意 `flushMs` 只在默认值里、**不可配**
|
|
37
38
|
- 监听范围不是整个 cwd,而是**当前活跃服务器 client 的项目根**:root 在 cwd 内就只监听 root(被其他 root 包含的 root 不重复监听,root 是 cwd 的祖先时退化为 cwd);没有活跃 client 就不监听。因此容器 cwd(`~/projects` 下多个仓库)里只有活跃服务器所在的项目会被 watch;`ignore` 的匹配基准也随之是各自的项目根。资源耗尽(ENOSPC)时该 root 的监听器会停止并提示一次,调大 `fs.inotify.max_user_watches` 后跑 `/lsp-reload` 重试
|
|
38
39
|
|