@mrclrchtr/supi-lsp 3.2.0 → 4.1.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 +72 -62
- package/node_modules/@mrclrchtr/supi-code-runtime/README.md +8 -0
- package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/package.json +2 -4
- package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/api.ts +0 -4
- package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/evidence-badge.ts +3 -2
- package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/index.ts +0 -4
- package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/llm.ts +0 -10
- package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/path-utils.ts +19 -15
- package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings/settings-action-menu.ts +1 -0
- package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings/settings-schema.ts +9 -0
- package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/settings.ts +1 -0
- package/node_modules/@mrclrchtr/supi-code-runtime/package.json +2 -2
- package/node_modules/@mrclrchtr/supi-code-runtime/src/api.ts +10 -1
- package/node_modules/@mrclrchtr/supi-code-runtime/src/capability/types.ts +19 -29
- package/node_modules/@mrclrchtr/supi-code-runtime/src/index.ts +7 -1
- package/node_modules/@mrclrchtr/supi-code-runtime/src/query-result.ts +42 -0
- package/node_modules/@mrclrchtr/supi-code-runtime/src/types.ts +15 -10
- package/node_modules/@mrclrchtr/supi-core/package.json +2 -4
- package/node_modules/@mrclrchtr/supi-core/src/api.ts +0 -4
- package/node_modules/@mrclrchtr/supi-core/src/evidence-badge.ts +3 -2
- package/node_modules/@mrclrchtr/supi-core/src/index.ts +0 -4
- package/node_modules/@mrclrchtr/supi-core/src/llm.ts +0 -10
- package/node_modules/@mrclrchtr/supi-core/src/path-utils.ts +19 -15
- package/node_modules/@mrclrchtr/supi-core/src/settings/settings-action-menu.ts +1 -0
- package/node_modules/@mrclrchtr/supi-core/src/settings/settings-schema.ts +9 -0
- package/node_modules/@mrclrchtr/supi-core/src/settings.ts +1 -0
- package/package.json +4 -5
- package/src/api.ts +9 -9
- package/src/client/client.ts +70 -41
- package/src/client/transport.ts +16 -13
- package/src/config/config.ts +2 -2
- package/src/config/lsp-settings.ts +0 -2
- package/src/index.ts +6 -6
- package/src/manager/manager-diagnostics.ts +5 -95
- package/src/manager/manager-workspace-recovery.ts +4 -3
- package/src/manager/manager-workspace-symbol.ts +44 -6
- package/src/manager/manager.ts +47 -65
- package/src/provider/lsp-semantic-provider.ts +132 -79
- package/src/provider/refactor-planning.ts +6 -14
- package/src/session/readiness.ts +38 -0
- package/src/session/runtime-controller.ts +87 -75
- package/src/session/runtime-registration.ts +5 -5
- package/src/session/{service-registry.ts → runtime-registry.ts} +163 -71
- package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/abort-utils.ts +0 -31
- package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/substrate-types.ts +0 -11
- package/node_modules/@mrclrchtr/supi-code-runtime/node_modules/@mrclrchtr/supi-core/src/types.ts +0 -2
- package/node_modules/@mrclrchtr/supi-core/src/abort-utils.ts +0 -31
- package/node_modules/@mrclrchtr/supi-core/src/substrate-types.ts +0 -11
- package/node_modules/@mrclrchtr/supi-core/src/types.ts +0 -2
- package/src/diagnostics/diagnostic-augmentation.ts +0 -82
- package/src/diagnostics/diagnostic-context.ts +0 -116
- package/src/diagnostics/diagnostic-display.ts +0 -69
- package/src/manager/capability-index.ts +0 -24
- package/src/manager/client-pool.ts +0 -33
- package/src/manager/diagnostic-store.ts +0 -51
- package/src/manager/manager-stale-resync.ts +0 -47
- package/src/manager/recovery-coordinator.ts +0 -37
- package/src/manager/workspace-router.ts +0 -44
|
@@ -3,108 +3,18 @@ import type { LspClient } from "../client/client.ts";
|
|
|
3
3
|
import type { Diagnostic } from "../config/types.ts";
|
|
4
4
|
import { relativeFilePathFromUri } from "../diagnostics/diagnostic-summary.ts";
|
|
5
5
|
import { shouldIgnoreLspPath } from "../summary.ts";
|
|
6
|
-
import { fileToUri, uriToFile } from "../utils.ts";
|
|
7
6
|
import { isExcludedByPattern } from "./manager-helpers.ts";
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export interface CascadeDiagnosticEntry {
|
|
15
|
-
uri: string;
|
|
16
|
-
diagnostics: Diagnostic[];
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export interface CascadingDiagnosticsResult {
|
|
20
|
-
primary: Diagnostic[];
|
|
21
|
-
cascade: CascadeDiagnosticEntry[];
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Find diagnostics for open files updated during a sync of another file.
|
|
26
|
-
*
|
|
27
|
-
* Files are considered cascade-affected when their diagnostic cache entry is
|
|
28
|
-
* new or has a newer `receivedAt` timestamp than the pre-sync snapshot.
|
|
29
|
-
*/
|
|
30
|
-
export function findCascadeDiagnosticEntries(
|
|
31
|
-
preSnapshot: Map<string, DiagnosticSnapshotEntry>,
|
|
32
|
-
postEntries: Map<string, DiagnosticSnapshotEntry>,
|
|
33
|
-
editedUri: string,
|
|
34
|
-
maxSeverity: number,
|
|
35
|
-
): CascadeDiagnosticEntry[] {
|
|
36
|
-
const result: CascadeDiagnosticEntry[] = [];
|
|
37
|
-
|
|
38
|
-
for (const [uri, entry] of postEntries) {
|
|
39
|
-
if (uri === editedUri) continue;
|
|
40
|
-
|
|
41
|
-
const previous = preSnapshot.get(uri);
|
|
42
|
-
if (previous && entry.receivedAt <= previous.receivedAt) continue;
|
|
43
|
-
|
|
44
|
-
const diagnostics = filterDiagnosticsBySeverity(entry.diagnostics, maxSeverity);
|
|
45
|
-
if (diagnostics.length === 0) continue;
|
|
46
|
-
|
|
47
|
-
result.push({ uri, diagnostics });
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
return result.sort((a, b) => a.uri.localeCompare(b.uri));
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/** Snapshot current diagnostic cache entries for the client's open URIs. */
|
|
54
|
-
export function snapshotOpenClientDiagnostics(
|
|
55
|
-
client: Pick<LspClient, "openUris" | "getDiagnosticCacheEntry">,
|
|
56
|
-
): Map<string, DiagnosticSnapshotEntry> {
|
|
57
|
-
const snapshot = new Map<string, DiagnosticSnapshotEntry>();
|
|
58
|
-
|
|
59
|
-
for (const uri of client.openUris) {
|
|
60
|
-
const entry = client.getDiagnosticCacheEntry(uri);
|
|
61
|
-
if (!entry) continue;
|
|
62
|
-
snapshot.set(uri, {
|
|
63
|
-
receivedAt: entry.receivedAt,
|
|
64
|
-
diagnostics: entry.diagnostics,
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
return snapshot;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/** Build post-sync entries map for the client's open URIs. */
|
|
72
|
-
export function collectOpenClientDiagnosticEntries(
|
|
73
|
-
client: Pick<LspClient, "openUris" | "getDiagnosticCacheEntry">,
|
|
74
|
-
): Map<string, DiagnosticSnapshotEntry> {
|
|
75
|
-
return snapshotOpenClientDiagnostics(client);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/** Sync a file and return its diagnostics plus cascade-affected open files. */
|
|
79
|
-
export async function syncClientFileAndGetCascadingDiagnostics(
|
|
80
|
-
client: Pick<
|
|
81
|
-
LspClient,
|
|
82
|
-
"openUris" | "getDiagnosticCacheEntry" | "syncAndWaitForDiagnostics" | "clearPullResultIds"
|
|
83
|
-
>,
|
|
8
|
+
/** Sync one file and return diagnostics up to the supplied severity threshold. */
|
|
9
|
+
export async function syncClientFileAndGetDiagnostics(
|
|
10
|
+
client: Pick<LspClient, "syncAndWaitForDiagnostics">,
|
|
84
11
|
filePath: string,
|
|
85
12
|
maxSeverity: number,
|
|
86
|
-
): Promise<
|
|
87
|
-
|
|
88
|
-
const primary = filterDiagnosticsBySeverity(
|
|
13
|
+
): Promise<Diagnostic[]> {
|
|
14
|
+
return filterDiagnosticsBySeverity(
|
|
89
15
|
await client.syncAndWaitForDiagnostics(filePath, readFileSync(filePath, "utf-8")),
|
|
90
16
|
maxSeverity,
|
|
91
17
|
);
|
|
92
|
-
client.clearPullResultIds();
|
|
93
|
-
|
|
94
|
-
const cascade = findCascadeDiagnosticEntries(
|
|
95
|
-
preSnapshot,
|
|
96
|
-
collectOpenClientDiagnosticEntries(client),
|
|
97
|
-
fileToUri(filePath),
|
|
98
|
-
maxSeverity,
|
|
99
|
-
);
|
|
100
|
-
|
|
101
|
-
return { primary, cascade };
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
export function mapCascadeDiagnosticsToFiles(
|
|
105
|
-
entries: CascadeDiagnosticEntry[],
|
|
106
|
-
): Array<{ file: string; diagnostics: Diagnostic[] }> {
|
|
107
|
-
return entries.map((entry) => ({ file: uriToFile(entry.uri), diagnostics: entry.diagnostics }));
|
|
108
18
|
}
|
|
109
19
|
|
|
110
20
|
export function collectOutstandingDiagnosticsDetailed(
|
|
@@ -5,7 +5,8 @@ import {
|
|
|
5
5
|
} from "../diagnostics/stale-diagnostics.ts";
|
|
6
6
|
|
|
7
7
|
export interface WorkspaceRecoveryResult {
|
|
8
|
-
|
|
8
|
+
/** Active clients targeted by the best-effort refresh, not confirmed successful refreshes. */
|
|
9
|
+
attemptedClients: number;
|
|
9
10
|
restartedClients: number;
|
|
10
11
|
staleAssessment: StaleDiagnosticAssessment;
|
|
11
12
|
}
|
|
@@ -41,7 +42,7 @@ export async function recoverWorkspaceDiagnostics(
|
|
|
41
42
|
quietMs?: number;
|
|
42
43
|
} = {},
|
|
43
44
|
): Promise<WorkspaceRecoveryResult> {
|
|
44
|
-
const
|
|
45
|
+
const attemptedClients = softRecoverWorkspaceDiagnostics(host, options.changes ?? []);
|
|
45
46
|
|
|
46
47
|
try {
|
|
47
48
|
await host.refreshOpenDiagnostics({ maxWaitMs: options.maxWaitMs, quietMs: options.quietMs });
|
|
@@ -72,7 +73,7 @@ export async function recoverWorkspaceDiagnostics(
|
|
|
72
73
|
}
|
|
73
74
|
|
|
74
75
|
return {
|
|
75
|
-
|
|
76
|
+
attemptedClients,
|
|
76
77
|
restartedClients,
|
|
77
78
|
staleAssessment,
|
|
78
79
|
};
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
+
import {
|
|
4
|
+
type CodeQueryResult,
|
|
5
|
+
completedCodeQuery,
|
|
6
|
+
partialCodeQuery,
|
|
7
|
+
unavailableCodeQuery,
|
|
8
|
+
} from "@mrclrchtr/supi-code-runtime/api";
|
|
3
9
|
import { walkProject } from "@mrclrchtr/supi-core/project";
|
|
4
10
|
import type { LspClient } from "../client/client.ts";
|
|
5
11
|
import type {
|
|
@@ -39,30 +45,62 @@ export function getWorkspaceSymbolWarmPosition(
|
|
|
39
45
|
return null;
|
|
40
46
|
}
|
|
41
47
|
|
|
48
|
+
export interface WorkspaceSymbolCollection {
|
|
49
|
+
results: WorkspaceSymbolLike[];
|
|
50
|
+
hasSupport: boolean;
|
|
51
|
+
completedClientCount: number;
|
|
52
|
+
failures: string[];
|
|
53
|
+
}
|
|
54
|
+
|
|
42
55
|
export async function collectWorkspaceSymbols(
|
|
43
56
|
clients: Iterable<LspClient>,
|
|
44
57
|
query: string,
|
|
45
|
-
): Promise<
|
|
58
|
+
): Promise<WorkspaceSymbolCollection> {
|
|
46
59
|
const results: WorkspaceSymbolLike[] = [];
|
|
60
|
+
const failures: string[] = [];
|
|
47
61
|
let hasSupport = false;
|
|
62
|
+
let completedClientCount = 0;
|
|
48
63
|
|
|
49
64
|
for (const client of clients) {
|
|
50
65
|
if (client.status !== "running") continue;
|
|
51
66
|
if (!client.serverCapabilities?.workspaceSymbolProvider) continue;
|
|
52
67
|
hasSupport = true;
|
|
53
68
|
const result = await client.workspaceSymbol(query);
|
|
54
|
-
if (result)
|
|
69
|
+
if (result.kind === "unavailable") {
|
|
70
|
+
failures.push(result.reason);
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
completedClientCount++;
|
|
74
|
+
results.push(...(result.data ?? []));
|
|
75
|
+
if (result.kind === "partial") failures.push(result.reason);
|
|
55
76
|
}
|
|
56
77
|
|
|
57
|
-
return { results, hasSupport };
|
|
78
|
+
return { results, hasSupport, completedClientCount, failures };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Project one multi-client collection into the shared typed query contract. */
|
|
82
|
+
export function workspaceSymbolCollectionResult(
|
|
83
|
+
collection: WorkspaceSymbolCollection,
|
|
84
|
+
): CodeQueryResult<WorkspaceSymbolLike[]> {
|
|
85
|
+
if (!collection.hasSupport) {
|
|
86
|
+
return unavailableCodeQuery("No active LSP client supports workspace-symbol requests.");
|
|
87
|
+
}
|
|
88
|
+
if (collection.completedClientCount === 0) {
|
|
89
|
+
return unavailableCodeQuery(
|
|
90
|
+
collection.failures.join("; ") || "No workspace-symbol request completed.",
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
if (collection.failures.length > 0) {
|
|
94
|
+
return partialCodeQuery(collection.results, collection.failures.join("; "));
|
|
95
|
+
}
|
|
96
|
+
return completedCodeQuery(collection.results);
|
|
58
97
|
}
|
|
59
98
|
|
|
60
99
|
export async function managerWorkspaceSymbol(
|
|
61
100
|
clients: Iterable<LspClient>,
|
|
62
101
|
query: string,
|
|
63
|
-
): Promise<WorkspaceSymbolLike[]
|
|
64
|
-
|
|
65
|
-
return hasSupport ? results : null;
|
|
102
|
+
): Promise<CodeQueryResult<WorkspaceSymbolLike[]>> {
|
|
103
|
+
return workspaceSymbolCollectionResult(await collectWorkspaceSymbols(clients, query));
|
|
66
104
|
}
|
|
67
105
|
|
|
68
106
|
export function findWorkspaceSymbolWarmTargets(
|
package/src/manager/manager.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// biome-ignore-all lint/style/noExcessiveLinesPerFile: LspManager stays cohesive; recovery and sync helpers are split into manager-*.ts modules.
|
|
3
3
|
import * as fs from "node:fs";
|
|
4
4
|
import * as path from "node:path";
|
|
5
|
+
import { type CodeQueryResult, unavailableCodeQuery } from "@mrclrchtr/supi-code-runtime/api";
|
|
5
6
|
import * as projectRoots from "@mrclrchtr/supi-core/project";
|
|
6
7
|
import { LspClient } from "../client/client.ts";
|
|
7
8
|
import { getServerForFile } from "../config/config.ts";
|
|
@@ -36,8 +37,7 @@ import {
|
|
|
36
37
|
} from "./manager-client-state.ts";
|
|
37
38
|
import {
|
|
38
39
|
collectOutstandingDiagnosticsDetailed,
|
|
39
|
-
|
|
40
|
-
syncClientFileAndGetCascadingDiagnostics,
|
|
40
|
+
syncClientFileAndGetDiagnostics,
|
|
41
41
|
} from "./manager-diagnostics.ts";
|
|
42
42
|
import {
|
|
43
43
|
clientKey,
|
|
@@ -56,8 +56,11 @@ import type {
|
|
|
56
56
|
} from "./manager-types.ts";
|
|
57
57
|
import { recoverWorkspaceDiagnostics as recoverWorkspaceDiagnosticsImpl } from "./manager-workspace-recovery.ts";
|
|
58
58
|
import {
|
|
59
|
+
collectWorkspaceSymbols,
|
|
59
60
|
findWorkspaceSymbolWarmTargets,
|
|
60
61
|
getWorkspaceSymbolWarmPosition,
|
|
62
|
+
type WorkspaceSymbolCollection,
|
|
63
|
+
workspaceSymbolCollectionResult,
|
|
61
64
|
} from "./manager-workspace-symbol.ts";
|
|
62
65
|
|
|
63
66
|
type UnavailableReason = "missing-command" | "start-failed" | "runtime-error";
|
|
@@ -361,8 +364,11 @@ export class LspManager {
|
|
|
361
364
|
return client;
|
|
362
365
|
}
|
|
363
366
|
|
|
364
|
-
/**
|
|
365
|
-
|
|
367
|
+
/**
|
|
368
|
+
* Wait until all started clients are query-ready, then warm one project file per client/root.
|
|
369
|
+
* Returns the number of concrete clients that reached readiness.
|
|
370
|
+
*/
|
|
371
|
+
async waitUntilWorkspaceReady(): Promise<number> {
|
|
366
372
|
const activeClients = Array.from(this.clients.values()).filter(
|
|
367
373
|
(client) => client.status === "running",
|
|
368
374
|
);
|
|
@@ -379,38 +385,26 @@ export class LspManager {
|
|
|
379
385
|
if (!target) continue;
|
|
380
386
|
await this.warmSemanticProject(client, target.file);
|
|
381
387
|
}
|
|
388
|
+
return activeClients.length;
|
|
382
389
|
}
|
|
383
390
|
async syncFileAndGetDiagnostics(
|
|
384
391
|
filePath: string,
|
|
385
392
|
maxSeverity: number = 1,
|
|
386
|
-
): Promise<Diagnostic[]
|
|
387
|
-
const resolvedPath = resolveSessionPath(this.cwd, filePath);
|
|
388
|
-
return (
|
|
389
|
-
(await this.syncFileAndGetCascadingDiagnostics(resolvedPath, maxSeverity)).find(
|
|
390
|
-
(entry) => entry.file === resolvedPath,
|
|
391
|
-
)?.diagnostics ?? []
|
|
392
|
-
);
|
|
393
|
-
}
|
|
394
|
-
async syncFileAndGetCascadingDiagnostics(
|
|
395
|
-
filePath: string,
|
|
396
|
-
maxSeverity: number = 1,
|
|
397
|
-
): Promise<Array<{ file: string; diagnostics: Diagnostic[] }>> {
|
|
393
|
+
): Promise<CodeQueryResult<Diagnostic[]>> {
|
|
398
394
|
const resolvedPath = resolveSessionPath(this.cwd, filePath);
|
|
399
395
|
const client = await this.getClientForFile(resolvedPath);
|
|
400
|
-
if (!client)
|
|
396
|
+
if (!client) {
|
|
397
|
+
return unavailableCodeQuery(`No LSP client can collect diagnostics for ${resolvedPath}.`);
|
|
398
|
+
}
|
|
401
399
|
try {
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
resolvedPath,
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
return [
|
|
408
|
-
...(primary.length > 0 ? [{ file: resolvedPath, diagnostics: primary }] : []),
|
|
409
|
-
...mapCascadeDiagnosticsToFiles(cascade),
|
|
410
|
-
];
|
|
411
|
-
} catch {
|
|
400
|
+
return {
|
|
401
|
+
kind: "completed",
|
|
402
|
+
data: await syncClientFileAndGetDiagnostics(client, resolvedPath, maxSeverity),
|
|
403
|
+
};
|
|
404
|
+
} catch (error) {
|
|
412
405
|
this.closeFile(resolvedPath);
|
|
413
|
-
|
|
406
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
407
|
+
return unavailableCodeQuery(`Diagnostic collection failed for ${resolvedPath}: ${detail}`);
|
|
414
408
|
}
|
|
415
409
|
}
|
|
416
410
|
/** Close a file across any active LSP clients and clear its cached diagnostics. */
|
|
@@ -447,7 +441,7 @@ export class LspManager {
|
|
|
447
441
|
maxWaitMs?: number;
|
|
448
442
|
quietMs?: number;
|
|
449
443
|
}): Promise<{
|
|
450
|
-
|
|
444
|
+
attemptedClients: number;
|
|
451
445
|
restartedClients: number;
|
|
452
446
|
staleAssessment: {
|
|
453
447
|
suspected: boolean;
|
|
@@ -613,21 +607,21 @@ export class LspManager {
|
|
|
613
607
|
maxSeverity,
|
|
614
608
|
);
|
|
615
609
|
}
|
|
616
|
-
async workspaceSymbol(
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
if (initial.results.length > 0)
|
|
610
|
+
async workspaceSymbol(
|
|
611
|
+
query: string,
|
|
612
|
+
): Promise<CodeQueryResult<(SymbolInformation | WorkspaceSymbol)[]>> {
|
|
613
|
+
const initial = await collectWorkspaceSymbols(this.clients.values(), query);
|
|
614
|
+
if (!initial.hasSupport || initial.results.length > 0) {
|
|
615
|
+
return workspaceSymbolCollectionResult(initial);
|
|
616
|
+
}
|
|
621
617
|
|
|
622
618
|
const warmed = await this.warmWorkspaceSymbolProjectsUntilResult(
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
619
|
+
findWorkspaceSymbolWarmTargets,
|
|
620
|
+
getWorkspaceSymbolWarmPosition,
|
|
621
|
+
collectWorkspaceSymbols,
|
|
626
622
|
query,
|
|
627
623
|
);
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
return initial.results;
|
|
624
|
+
return workspaceSymbolCollectionResult(warmed.collection ?? initial);
|
|
631
625
|
}
|
|
632
626
|
async ensureFileOpen(filePath: string): Promise<LspClient | null> {
|
|
633
627
|
const resolvedPath = resolveSessionPath(this.cwd, filePath);
|
|
@@ -650,14 +644,11 @@ export class LspManager {
|
|
|
650
644
|
fileTypes: string[],
|
|
651
645
|
) => Array<{ projectRoot: string; file: string }>,
|
|
652
646
|
getWarmPosition: (
|
|
653
|
-
symbols:
|
|
647
|
+
symbols: import("../config/types.ts").DocumentSymbol[] | SymbolInformation[] | null,
|
|
654
648
|
) => import("../config/types.ts").Position | null,
|
|
655
|
-
collect: (
|
|
656
|
-
clients: Iterable<LspClient>,
|
|
657
|
-
query: string,
|
|
658
|
-
) => Promise<{ results: (SymbolInformation | WorkspaceSymbol)[]; hasSupport: boolean }>,
|
|
649
|
+
collect: (clients: Iterable<LspClient>, query: string) => Promise<WorkspaceSymbolCollection>,
|
|
659
650
|
query: string,
|
|
660
|
-
): Promise<{ warmedAny: boolean;
|
|
651
|
+
): Promise<{ warmedAny: boolean; collection: WorkspaceSymbolCollection | null }> {
|
|
661
652
|
let warmedAny = false;
|
|
662
653
|
|
|
663
654
|
for (const client of Array.from(this.clients.values())) {
|
|
@@ -687,24 +678,20 @@ export class LspManager {
|
|
|
687
678
|
this.warmedWorkspaceSymbolProjects.add(projectKey);
|
|
688
679
|
warmedAny = true;
|
|
689
680
|
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
const hoverPosition = getWarmPosition(symbols);
|
|
693
|
-
if (hoverPosition)
|
|
694
|
-
await openedClient.hover(target.file, hoverPosition);
|
|
695
|
-
}
|
|
696
|
-
} catch {
|
|
697
|
-
// Best-effort warm-up only.
|
|
681
|
+
const symbols = await openedClient.documentSymbols(target.file);
|
|
682
|
+
if (symbols.kind !== "unavailable") {
|
|
683
|
+
const hoverPosition = getWarmPosition(symbols.data);
|
|
684
|
+
if (hoverPosition) await openedClient.hover(target.file, hoverPosition);
|
|
698
685
|
}
|
|
699
686
|
|
|
700
687
|
const collected = await collect(this.clients.values(), query);
|
|
701
688
|
if (collected.hasSupport && collected.results.length > 0) {
|
|
702
|
-
return { warmedAny,
|
|
689
|
+
return { warmedAny, collection: collected };
|
|
703
690
|
}
|
|
704
691
|
}
|
|
705
692
|
}
|
|
706
693
|
|
|
707
|
-
return { warmedAny,
|
|
694
|
+
return { warmedAny, collection: null };
|
|
708
695
|
}
|
|
709
696
|
|
|
710
697
|
private async warmSemanticProject(
|
|
@@ -750,15 +737,10 @@ export class LspManager {
|
|
|
750
737
|
|
|
751
738
|
this.warmedSemanticProjects.add(projectKey);
|
|
752
739
|
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
await openedClient.hover(resolvedFile, hoverPosition);
|
|
758
|
-
}
|
|
759
|
-
} catch {
|
|
760
|
-
// Best-effort warm-up only.
|
|
761
|
-
}
|
|
740
|
+
const symbols = await openedClient.documentSymbols(resolvedFile);
|
|
741
|
+
if (symbols.kind === "unavailable") return;
|
|
742
|
+
const hoverPosition = getWorkspaceSymbolWarmPosition(symbols.data);
|
|
743
|
+
if (hoverPosition) await openedClient.hover(resolvedFile, hoverPosition);
|
|
762
744
|
}
|
|
763
745
|
|
|
764
746
|
private hasOpenFileInProject(client: LspClient, projectRoot: string): boolean {
|