@mrclrchtr/supi-lsp 9.1.0 → 9.1.2
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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mrclrchtr/supi-lsp",
|
|
3
|
-
"version": "9.1.
|
|
3
|
+
"version": "9.1.2",
|
|
4
4
|
"description": "Language Server Protocol runtime for SuPi code intelligence",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -37,8 +37,8 @@
|
|
|
37
37
|
"vscode-jsonrpc": "^9.0.0",
|
|
38
38
|
"vscode-languageserver-protocol": "^3.18.0",
|
|
39
39
|
"vscode-languageserver-types": "^3.18.0",
|
|
40
|
-
"@mrclrchtr/supi-
|
|
41
|
-
"@mrclrchtr/supi-
|
|
40
|
+
"@mrclrchtr/supi-core": "9.1.2",
|
|
41
|
+
"@mrclrchtr/supi-code-runtime": "9.1.2"
|
|
42
42
|
},
|
|
43
43
|
"bundledDependencies": [
|
|
44
44
|
"@mrclrchtr/supi-code-runtime",
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { statSync } from "node:fs";
|
|
1
2
|
import * as path from "node:path";
|
|
2
3
|
import {
|
|
3
4
|
type CodeQueryResult,
|
|
@@ -6,6 +7,7 @@ import {
|
|
|
6
7
|
partialCodeQuery,
|
|
7
8
|
unavailableCodeQuery,
|
|
8
9
|
} from "@mrclrchtr/supi-code-runtime/api";
|
|
10
|
+
import { isWithinOrEqual } from "@mrclrchtr/supi-core/project";
|
|
9
11
|
import type { LspClient } from "../client/client.ts";
|
|
10
12
|
import type {
|
|
11
13
|
DocumentSymbol,
|
|
@@ -34,6 +36,8 @@ export interface WorkspaceSymbolWarmOptions {
|
|
|
34
36
|
maxMarkerDepth?: number;
|
|
35
37
|
/** Runtime-owned automatic path policy. */
|
|
36
38
|
policy?: AutomaticLspPathPolicy;
|
|
39
|
+
/** Absolute request scopes. Search only their intersection with the route root. */
|
|
40
|
+
scopes?: readonly string[];
|
|
37
41
|
}
|
|
38
42
|
|
|
39
43
|
export function getWorkspaceSymbolWarmPosition(
|
|
@@ -144,6 +148,31 @@ export function findWorkspaceSymbolWarmTargets(
|
|
|
144
148
|
const policy = options.policy ?? createDefaultAutomaticLspPathPolicy(resolvedRoot);
|
|
145
149
|
if (allowed.size === 0) return [];
|
|
146
150
|
|
|
151
|
+
if (options.scopes?.length) {
|
|
152
|
+
const targets = options.scopes.flatMap((scope) => {
|
|
153
|
+
const searchRoot = isWithinOrEqual(resolvedRoot, scope)
|
|
154
|
+
? scope
|
|
155
|
+
: isWithinOrEqual(scope, resolvedRoot)
|
|
156
|
+
? resolvedRoot
|
|
157
|
+
: null;
|
|
158
|
+
return searchRoot
|
|
159
|
+
? findWorkspaceSymbolWarmTargets(searchRoot, rootMarkers, fileTypes, {
|
|
160
|
+
...options,
|
|
161
|
+
policy,
|
|
162
|
+
scopes: undefined,
|
|
163
|
+
})
|
|
164
|
+
: [];
|
|
165
|
+
});
|
|
166
|
+
return [...new Map(targets.map((target) => [target.file, target])).values()];
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (statSync(resolvedRoot, { throwIfNoEntry: false })?.isFile()) {
|
|
170
|
+
return allowed.has(path.extname(resolvedRoot).slice(1).toLowerCase()) &&
|
|
171
|
+
policy.isEligible(resolvedRoot, "file")
|
|
172
|
+
? [{ projectRoot: path.dirname(resolvedRoot), file: resolvedRoot }]
|
|
173
|
+
: [];
|
|
174
|
+
}
|
|
175
|
+
|
|
147
176
|
const markerRoots = collectMarkerRoots(resolvedRoot, rootMarkers, maxMarkerDepth, policy);
|
|
148
177
|
const targets = markerRoots
|
|
149
178
|
.map((entry) => {
|
package/src/manager/manager.ts
CHANGED
|
@@ -334,8 +334,8 @@ export class LspManager {
|
|
|
334
334
|
private invalidationEpoch = 0;
|
|
335
335
|
/** Invalidation generation in which each route last received a recovery restart. */
|
|
336
336
|
private recoveryRestartEpochs = new Map<string, number>();
|
|
337
|
-
/**
|
|
338
|
-
private
|
|
337
|
+
/** Files already probed for workspace-symbol warm-up. */
|
|
338
|
+
private warmedWorkspaceSymbolFiles = new Set<string>();
|
|
339
339
|
/** Project roots whose semantic state was warmed with a readiness probe. */
|
|
340
340
|
private warmedSemanticProjects = new Set<string>();
|
|
341
341
|
/** In-flight warm-up probes keyed by project key so concurrent callers share one probe. */
|
|
@@ -527,7 +527,7 @@ export class LspManager {
|
|
|
527
527
|
root,
|
|
528
528
|
failureMessage: "The LSP client is not running.",
|
|
529
529
|
});
|
|
530
|
-
this.
|
|
530
|
+
this.clearWarmedWorkspaceSymbolFiles(existing.name, existing.root);
|
|
531
531
|
this.clearWarmedSemanticProjects(existing.name, existing.root);
|
|
532
532
|
this.clearPendingWarmProbes(existing.name, existing.root);
|
|
533
533
|
if (!retryFailedStart) return null;
|
|
@@ -1246,7 +1246,7 @@ export class LspManager {
|
|
|
1246
1246
|
): LspClient {
|
|
1247
1247
|
const key = route.key;
|
|
1248
1248
|
if (this.clients.get(key) === recovery.failedClient) this.clients.delete(key);
|
|
1249
|
-
this.
|
|
1249
|
+
this.clearWarmedWorkspaceSymbolFiles(route.serverName, route.root);
|
|
1250
1250
|
this.clearWarmedSemanticProjects(route.serverName, route.root);
|
|
1251
1251
|
this.clearPendingWarmProbes(route.serverName, route.root);
|
|
1252
1252
|
|
|
@@ -1402,7 +1402,7 @@ export class LspManager {
|
|
|
1402
1402
|
|
|
1403
1403
|
// Spawn new client
|
|
1404
1404
|
const client = this.createClient(serverName, serverConfig, root, key);
|
|
1405
|
-
this.
|
|
1405
|
+
this.clearWarmedWorkspaceSymbolFiles(serverName, root);
|
|
1406
1406
|
this.clearWarmedSemanticProjects(serverName, root);
|
|
1407
1407
|
this.clearPendingWarmProbes(serverName, root);
|
|
1408
1408
|
this.clients.set(key, client);
|
|
@@ -1532,7 +1532,7 @@ export class LspManager {
|
|
|
1532
1532
|
if (this.clients.get(key) !== client) return { files, restarted: false };
|
|
1533
1533
|
this.clients.delete(key);
|
|
1534
1534
|
this.unavailable.delete(key);
|
|
1535
|
-
this.
|
|
1535
|
+
this.clearWarmedWorkspaceSymbolFiles(client.name, client.root);
|
|
1536
1536
|
this.clearWarmedSemanticProjects(client.name, client.root);
|
|
1537
1537
|
this.clearPendingWarmProbes(client.name, client.root);
|
|
1538
1538
|
|
|
@@ -2307,7 +2307,7 @@ export class LspManager {
|
|
|
2307
2307
|
this.recoveryRestartEpochs.clear();
|
|
2308
2308
|
this.unavailable.clear();
|
|
2309
2309
|
this.knownRoots.clear();
|
|
2310
|
-
this.
|
|
2310
|
+
this.warmedWorkspaceSymbolFiles.clear();
|
|
2311
2311
|
this.warmedSemanticProjects.clear();
|
|
2312
2312
|
this.pendingWarmProbes.clear();
|
|
2313
2313
|
this.pendingRestarts.clear();
|
|
@@ -2671,6 +2671,7 @@ export class LspManager {
|
|
|
2671
2671
|
findWarmTargets: (root, rootMarkers, fileTypes) =>
|
|
2672
2672
|
findWorkspaceSymbolWarmTargets(root, rootMarkers, fileTypes, {
|
|
2673
2673
|
policy: this.automaticPathPolicy,
|
|
2674
|
+
scopes: resolvedScopes,
|
|
2674
2675
|
}),
|
|
2675
2676
|
getWarmPosition: getWorkspaceSymbolWarmPosition,
|
|
2676
2677
|
collect,
|
|
@@ -2696,22 +2697,21 @@ export class LspManager {
|
|
|
2696
2697
|
collection: WorkspaceSymbolCollection,
|
|
2697
2698
|
scopes: readonly string[] | undefined,
|
|
2698
2699
|
): WorkspaceSymbolCollection {
|
|
2699
|
-
const excludedExamples
|
|
2700
|
+
const excludedExamples = new Set(collection.excludedExamples ?? []);
|
|
2700
2701
|
let excludedCount = 0;
|
|
2701
2702
|
const results = collection.results.filter((result) => {
|
|
2702
2703
|
const file = uriToFile(result.location.uri);
|
|
2703
2704
|
if (this.isWorkspaceSymbolResultAllowed(file, scopes)) return true;
|
|
2704
2705
|
excludedCount++;
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
}
|
|
2706
|
+
const example = displayRelativeFilePath(file, this.cwd);
|
|
2707
|
+
if (excludedExamples.size < 5) excludedExamples.add(example);
|
|
2708
2708
|
return false;
|
|
2709
2709
|
});
|
|
2710
2710
|
return {
|
|
2711
2711
|
...collection,
|
|
2712
2712
|
results,
|
|
2713
2713
|
excludedCount: (collection.excludedCount ?? 0) + excludedCount,
|
|
2714
|
-
excludedExamples: [...
|
|
2714
|
+
excludedExamples: [...excludedExamples].slice(0, 5),
|
|
2715
2715
|
};
|
|
2716
2716
|
}
|
|
2717
2717
|
|
|
@@ -2803,6 +2803,7 @@ export class LspManager {
|
|
|
2803
2803
|
}): Promise<{ warmedAny: boolean; collection: WorkspaceSymbolCollection | null }> {
|
|
2804
2804
|
const { findWarmTargets, getWarmPosition, collect, routeMatches, query, control } = options;
|
|
2805
2805
|
let warmedAny = false;
|
|
2806
|
+
let latestCollection: WorkspaceSymbolCollection | null = null;
|
|
2806
2807
|
|
|
2807
2808
|
for (const client of Array.from(this.clients.values())) {
|
|
2808
2809
|
if (routeMatches && !routeMatches(client)) continue;
|
|
@@ -2819,8 +2820,9 @@ export class LspManager {
|
|
|
2819
2820
|
).slice(0, 24);
|
|
2820
2821
|
|
|
2821
2822
|
for (const target of warmTargets) {
|
|
2822
|
-
|
|
2823
|
-
|
|
2823
|
+
// A file probe does not load every program under the route root.
|
|
2824
|
+
const fileKey = `${client.name}:${path.resolve(target.file)}`;
|
|
2825
|
+
if (this.warmedWorkspaceSymbolFiles.has(fileKey)) continue;
|
|
2824
2826
|
|
|
2825
2827
|
const openedClient = await this.ensureFileOpen(target.file);
|
|
2826
2828
|
if (!openedClient) continue;
|
|
@@ -2834,18 +2836,19 @@ export class LspManager {
|
|
|
2834
2836
|
control,
|
|
2835
2837
|
);
|
|
2836
2838
|
if (available) {
|
|
2837
|
-
this.
|
|
2839
|
+
this.warmedWorkspaceSymbolFiles.add(fileKey);
|
|
2838
2840
|
warmedAny = true;
|
|
2839
2841
|
}
|
|
2840
2842
|
|
|
2841
|
-
|
|
2842
|
-
if (
|
|
2843
|
-
return { warmedAny, collection:
|
|
2843
|
+
latestCollection = await collect(this.clients.values(), query);
|
|
2844
|
+
if (latestCollection.hasSupport && latestCollection.results.length > 0) {
|
|
2845
|
+
return { warmedAny, collection: latestCollection };
|
|
2844
2846
|
}
|
|
2845
2847
|
}
|
|
2846
2848
|
}
|
|
2847
2849
|
|
|
2848
|
-
|
|
2850
|
+
// A completed-empty retry replaces an earlier failure too.
|
|
2851
|
+
return { warmedAny, collection: latestCollection };
|
|
2849
2852
|
}
|
|
2850
2853
|
|
|
2851
2854
|
private async warmSemanticProject(
|
|
@@ -2936,11 +2939,11 @@ export class LspManager {
|
|
|
2936
2939
|
return `${serverName}:${path.resolve(projectRoot)}`;
|
|
2937
2940
|
}
|
|
2938
2941
|
|
|
2939
|
-
private
|
|
2942
|
+
private clearWarmedWorkspaceSymbolFiles(serverName: string, root: string): void {
|
|
2940
2943
|
const prefix = `${serverName}:${path.resolve(root)}`;
|
|
2941
|
-
for (const key of Array.from(this.
|
|
2944
|
+
for (const key of Array.from(this.warmedWorkspaceSymbolFiles)) {
|
|
2942
2945
|
if (key === prefix || key.startsWith(`${prefix}${path.sep}`)) {
|
|
2943
|
-
this.
|
|
2946
|
+
this.warmedWorkspaceSymbolFiles.delete(key);
|
|
2944
2947
|
}
|
|
2945
2948
|
}
|
|
2946
2949
|
}
|