@shanepadgett/tau-agent 0.33.1 → 0.35.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/docs/context.md +29 -20
- package/docs/extending-tau-agent.md +63 -24
- package/extensions/appshot/index.ts +112 -111
- package/extensions/aside/README.md +7 -0
- package/extensions/aside/index.ts +168 -0
- package/extensions/aside/panel.ts +83 -0
- package/extensions/bash-approval/README.md +20 -0
- package/extensions/bash-approval/index.ts +235 -0
- package/extensions/bash-approval/settings.ts +24 -0
- package/extensions/branch/index.ts +38 -21
- package/extensions/cache-diagnostics/index.ts +70 -58
- package/extensions/checkpoint/README.md +9 -0
- package/extensions/checkpoint/checkpoint-budget.ts +66 -0
- package/extensions/checkpoint/checkpoint.ts +279 -0
- package/extensions/checkpoint/index.ts +102 -0
- package/extensions/checkpoint/messages.ts +170 -0
- package/extensions/checkpoint/prompt.ts +24 -0
- package/extensions/checkpoint/settings.ts +27 -0
- package/extensions/commit/commit-effort.ts +3 -3
- package/extensions/commit/commit-plan.ts +2 -2
- package/extensions/context/README.md +12 -8
- package/extensions/context/definitions.ts +178 -55
- package/extensions/context/index.ts +192 -160
- package/extensions/context/panel.ts +57 -37
- package/extensions/context/sync.ts +139 -89
- package/extensions/context/validation.ts +37 -25
- package/extensions/effort/README.md +1 -1
- package/extensions/effort/index.ts +3 -3
- package/extensions/effort/state.ts +3 -18
- package/extensions/explore/guidance.ts +6 -47
- package/extensions/explore/index.ts +38 -53
- package/extensions/explore/{ast/read → read}/hook.ts +12 -7
- package/extensions/explore/{ast/tools → tools}/ast-search.ts +15 -19
- package/extensions/explore/{ast/tools → tools}/context.ts +16 -23
- package/extensions/explore/{ast/tools → tools}/deps.ts +11 -15
- package/extensions/explore/{ast/tools → tools}/discover.ts +15 -17
- package/extensions/explore/{ast/tools → tools}/impact.ts +20 -23
- package/extensions/explore/{ast/tools → tools}/outline.ts +21 -24
- package/extensions/explore/{ast/tools → tools}/relationships.ts +23 -32
- package/extensions/explore/{ast/tools → tools}/render.ts +1 -1
- package/extensions/explore/{ast/tools → tools}/reverse-deps.ts +11 -15
- package/extensions/explore/{ast/tools → tools}/show.ts +16 -19
- package/extensions/explore/tools/target-params.ts +9 -0
- package/extensions/footer/index.ts +75 -56
- package/extensions/handoff/index.ts +8 -30
- package/extensions/image-gen/index.ts +46 -40
- package/extensions/patch/executor.ts +190 -135
- package/extensions/patch/matcher.ts +82 -48
- package/extensions/patch/parser.ts +149 -105
- package/extensions/patch/render.ts +32 -39
- package/extensions/patch/summary.ts +30 -26
- package/extensions/ready/README.md +7 -0
- package/extensions/ready/index.ts +58 -0
- package/extensions/ready/model.ts +128 -0
- package/extensions/ready/packs.ts +272 -0
- package/extensions/ready/render.ts +445 -0
- package/extensions/ready/scan.ts +760 -0
- package/extensions/reference/index.ts +2 -0
- package/extensions/reference/panel.ts +94 -31
- package/extensions/review/README.md +14 -6
- package/extensions/review/index.ts +58 -99
- package/extensions/review/model.ts +13 -33
- package/extensions/review/session.ts +9 -23
- package/extensions/runtime-context/context.ts +30 -26
- package/extensions/script-runner/README.md +2 -2
- package/extensions/script-runner/index.ts +122 -82
- package/extensions/silent-command-runner/index.ts +38 -23
- package/extensions/soul/README.md +2 -2
- package/extensions/soul/index.ts +4 -4
- package/extensions/soul/prompt.ts +6 -10
- package/extensions/soul/settings.ts +6 -3
- package/extensions/subagent/agents/context-sync.md +185 -33
- package/extensions/subagent/agents/scout.md +2 -2
- package/extensions/subagent/agents/web-research.md +2 -2
- package/extensions/subagent/agents.ts +137 -84
- package/extensions/subagent/cmux-dashboard.ts +39 -30
- package/extensions/subagent/index.ts +79 -59
- package/extensions/subagent/resume.ts +1 -1
- package/extensions/subagent/run.ts +308 -193
- package/extensions/subagent/runtime.ts +781 -343
- package/extensions/tau/index.ts +47 -38
- package/extensions/tau-help/help.md +20 -8
- package/extensions/tool-loader/README.md +4 -2
- package/extensions/tool-loader/index.ts +77 -52
- package/extensions/web/index.ts +6 -3
- package/extensions/web/webfetch.ts +114 -86
- package/package.json +3 -3
- package/schemas/tau.schema.json +38 -35
- package/shared/bounded-text-result.ts +1 -0
- package/shared/checkpoint-visibility.ts +9 -0
- package/shared/events.ts +28 -10
- package/shared/isolated-session.ts +72 -30
- package/shared/model-effort.ts +23 -22
- package/shared/model-fallback/index.ts +66 -41
- package/shared/settings/load.ts +45 -38
- package/shared/temporary-output-store.ts +16 -10
- package/{extensions/explore → src}/ast/adapter.ts +11 -2
- package/{extensions/explore → src}/ast/engine.ts +54 -38
- package/{extensions/explore → src}/ast/format/ast-search.ts +15 -6
- package/{extensions/explore → src}/ast/format/context.ts +3 -6
- package/src/ast/format/deps.ts +94 -0
- package/{extensions/explore → src}/ast/format/discover.ts +2 -2
- package/{extensions/explore → src}/ast/format/impact.ts +9 -11
- package/{extensions/explore → src}/ast/format/outline.ts +2 -2
- package/{extensions/explore → src}/ast/format/relationships.ts +11 -7
- package/{extensions/explore → src}/ast/format/show.ts +1 -1
- package/src/ast/format/targeted-result.ts +20 -0
- package/src/ast/grammars/c_sharp.wasm +0 -0
- package/{extensions/explore → src}/ast/grammars/manifest.json +9 -12
- package/{extensions/explore → src}/ast/grammars/manifest.ts +0 -4
- package/{extensions/explore → src}/ast/graph/file-graph.ts +210 -98
- package/{extensions/explore → src}/ast/graph/relationships.ts +285 -72
- package/{extensions/explore → src}/ast/ir.ts +6 -0
- package/src/ast/languages/csharp-file-deps.ts +90 -0
- package/{extensions/explore → src}/ast/languages/csharp.ts +9 -40
- package/src/ast/languages/dotted-index.ts +131 -0
- package/{extensions/explore → src}/ast/languages/file-dep-util.ts +22 -13
- package/src/ast/languages/fixtures/sample.cs +53 -0
- package/src/ast/languages/fixtures/sample.cs.expected.json +156 -0
- package/src/ast/languages/fixtures/sample.go +37 -0
- package/src/ast/languages/fixtures/sample.go.expected.json +96 -0
- package/src/ast/languages/fixtures/sample.java +40 -0
- package/src/ast/languages/fixtures/sample.java.expected.json +126 -0
- package/src/ast/languages/fixtures/sample.kt +31 -0
- package/src/ast/languages/fixtures/sample.kt.expected.json +134 -0
- package/src/ast/languages/fixtures/sample.md +23 -0
- package/src/ast/languages/fixtures/sample.md.expected.json +44 -0
- package/src/ast/languages/fixtures/sample.rs +54 -0
- package/src/ast/languages/fixtures/sample.rs.expected.json +178 -0
- package/src/ast/languages/fixtures/sample.swift +45 -0
- package/src/ast/languages/fixtures/sample.swift.expected.json +147 -0
- package/src/ast/languages/fixtures/sample.ts +45 -0
- package/src/ast/languages/fixtures/sample.ts.expected.json +141 -0
- package/src/ast/languages/fixtures/sample.tsx +36 -0
- package/src/ast/languages/fixtures/sample.tsx.expected.json +59 -0
- package/{extensions/explore → src}/ast/languages/go-file-deps.ts +6 -0
- package/{extensions/explore → src}/ast/languages/go.ts +21 -3
- package/{extensions/explore → src}/ast/languages/java.ts +5 -38
- package/src/ast/languages/jvm-file-deps.ts +135 -0
- package/{extensions/explore → src}/ast/languages/kotlin.ts +5 -39
- package/{extensions/explore → src}/ast/languages/rust-file-deps.ts +3 -3
- package/{extensions/explore → src}/ast/languages/rust.ts +21 -13
- package/{extensions/explore → src}/ast/languages/swift-file-deps.ts +22 -15
- package/{extensions/explore → src}/ast/languages/swift.ts +9 -39
- package/{extensions/explore → src}/ast/languages/tree.ts +47 -0
- package/{extensions/explore → src}/ast/languages/typescript-file-deps.ts +108 -0
- package/{extensions/explore → src}/ast/languages/typescript-package-surface.ts +4 -3
- package/{extensions/explore → src}/ast/languages/typescript.ts +3 -5
- package/{extensions/explore → src}/ast/markdown.ts +72 -47
- package/{extensions/explore → src}/ast/queries/ast-search.ts +164 -146
- package/{extensions/explore → src}/ast/queries/composite-target.ts +1 -1
- package/{extensions/explore → src}/ast/queries/context.ts +116 -80
- package/{extensions/explore → src}/ast/queries/discover.ts +154 -105
- package/src/ast/queries/impact.ts +291 -0
- package/{extensions/explore → src}/ast/queries/outline.ts +4 -2
- package/{extensions/explore → src}/ast/queries/show.ts +46 -42
- package/{extensions/explore → src}/ast/query.ts +1 -1
- package/{extensions/explore → src}/ast/registry.ts +1 -2
- package/{extensions/explore → src}/ast/scan.ts +1 -1
- package/src/ast/session.ts +50 -0
- package/{extensions/explore → src}/ast/slice.ts +8 -0
- package/{extensions/explore → src/ast}/traverse.ts +32 -20
- package/src/file-injection/index.ts +547 -0
- package/src/image-generation/client.ts +50 -31
- package/src/image-generation/index.ts +177 -134
- package/src/index.ts +2 -0
- package/src/tool-loading/index.ts +58 -0
- package/extensions/context/evidence.ts +0 -517
- package/extensions/context/projection.ts +0 -141
- package/extensions/context/state.ts +0 -30
- package/extensions/context/write-scope.ts +0 -109
- package/extensions/explore/ast/format/deps.ts +0 -86
- package/extensions/explore/ast/grammars/odin.wasm +0 -0
- package/extensions/explore/ast/languages/csharp-file-deps.ts +0 -189
- package/extensions/explore/ast/languages/fixtures/sample.cs +0 -17
- package/extensions/explore/ast/languages/fixtures/sample.java +0 -21
- package/extensions/explore/ast/languages/fixtures/sample.kt +0 -15
- package/extensions/explore/ast/languages/fixtures/sample.odin +0 -28
- package/extensions/explore/ast/languages/fixtures/sample.rs +0 -31
- package/extensions/explore/ast/languages/fixtures/sample.swift +0 -25
- package/extensions/explore/ast/languages/jvm-file-deps.ts +0 -217
- package/extensions/explore/ast/languages/odin-file-deps.ts +0 -175
- package/extensions/explore/ast/languages/odin.ts +0 -407
- package/extensions/explore/ast/queries/impact.ts +0 -250
- package/extensions/explore/outline-injection.ts +0 -151
- package/extensions/explore/read/autoread.ts +0 -118
- package/extensions/review/panel.ts +0 -128
- package/extensions/working-memory/README.md +0 -17
- package/extensions/working-memory/checkpoint.ts +0 -242
- package/extensions/working-memory/index.ts +0 -341
- package/extensions/working-memory/memory.ts +0 -235
- package/extensions/working-memory/render.ts +0 -185
- package/extensions/working-memory/settings.ts +0 -38
- package/extensions/working-memory/state.ts +0 -158
- package/shared/autoread.ts +0 -234
- package/shared/context-messages.ts +0 -19
- package/shared/outline-injection.ts +0 -56
- /package/{extensions/explore → src}/ast/format/composite.ts +0 -0
- /package/{extensions/explore → src}/ast/grammars/kotlin.wasm +0 -0
- /package/{extensions/explore → src}/ast/grammars/swift.wasm +0 -0
- /package/{extensions/explore → src}/ast/identity.ts +0 -0
- /package/{extensions/explore → src}/ast/package-surface.ts +0 -0
- /package/{extensions/explore/ast/read/policy.ts → src/ast/read-policy.ts} +0 -0
package/shared/settings/load.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
2
|
-
import { IsObject, type TSchema } from "typebox";
|
|
2
|
+
import { IsObject, type TObject, type TSchema } from "typebox";
|
|
3
3
|
import { Value } from "typebox/value";
|
|
4
4
|
import type { JsonObject, TauExtensionSettingsSpec } from "./define.ts";
|
|
5
5
|
import { asObject, readJsonStatus, writeJsonObject } from "./json.ts";
|
|
@@ -63,6 +63,47 @@ function extensionSection(root: JsonObject, key: string): JsonObject | undefined
|
|
|
63
63
|
|
|
64
64
|
const NO_DEFAULT = Symbol("no-default");
|
|
65
65
|
|
|
66
|
+
function repairKnownProperties(
|
|
67
|
+
schema: TObject,
|
|
68
|
+
valueObject: JsonObject,
|
|
69
|
+
defaultObject: JsonObject | undefined,
|
|
70
|
+
): JsonObject | typeof NO_DEFAULT {
|
|
71
|
+
const repaired: JsonObject = {};
|
|
72
|
+
const required = new Set(Array.isArray(schema.required) ? schema.required : []);
|
|
73
|
+
for (const [key, propertySchema] of Object.entries(schema.properties)) {
|
|
74
|
+
if (!Object.hasOwn(valueObject, key)) {
|
|
75
|
+
if (!required.has(key)) continue;
|
|
76
|
+
const requiredDefault = propertyDefault(propertySchema, defaultObject, key);
|
|
77
|
+
if (requiredDefault === NO_DEFAULT) return NO_DEFAULT;
|
|
78
|
+
repaired[key] = Value.Clone(requiredDefault);
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const propertyValue = replaceInvalidProperties(
|
|
83
|
+
propertySchema,
|
|
84
|
+
valueObject[key],
|
|
85
|
+
propertyDefault(propertySchema, defaultObject, key),
|
|
86
|
+
);
|
|
87
|
+
if (propertyValue !== NO_DEFAULT) repaired[key] = propertyValue;
|
|
88
|
+
else if (required.has(key)) return NO_DEFAULT;
|
|
89
|
+
}
|
|
90
|
+
return repaired;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function repairAdditionalProperties(schema: TObject, valueObject: JsonObject, repaired: JsonObject): void {
|
|
94
|
+
const additionalProperties = asObject(schema)?.additionalProperties;
|
|
95
|
+
if (additionalProperties === false) return;
|
|
96
|
+
for (const [key, additionalValue] of Object.entries(valueObject)) {
|
|
97
|
+
if (Object.hasOwn(schema.properties, key)) continue;
|
|
98
|
+
if (additionalProperties === undefined || additionalProperties === true) {
|
|
99
|
+
repaired[key] = additionalValue;
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
const repairedAdditional = replaceInvalidProperties(additionalProperties as TSchema, additionalValue, NO_DEFAULT);
|
|
103
|
+
if (repairedAdditional !== NO_DEFAULT) repaired[key] = repairedAdditional;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
66
107
|
function replaceInvalidProperties(
|
|
67
108
|
schema: TSchema,
|
|
68
109
|
value: unknown,
|
|
@@ -73,43 +114,9 @@ function replaceInvalidProperties(
|
|
|
73
114
|
const valueObject = asObject(value);
|
|
74
115
|
if (IsObject(schema) && valueObject) {
|
|
75
116
|
const defaultObject = documentedDefault === NO_DEFAULT ? undefined : asObject(documentedDefault);
|
|
76
|
-
const repaired
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
if (!Object.hasOwn(valueObject, key)) {
|
|
80
|
-
if (!required.has(key)) continue;
|
|
81
|
-
const requiredDefault = propertyDefault(propertySchema, defaultObject, key);
|
|
82
|
-
if (requiredDefault === NO_DEFAULT) return validatedDefault(schema, documentedDefault);
|
|
83
|
-
repaired[key] = Value.Clone(requiredDefault);
|
|
84
|
-
continue;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const propertyValue = replaceInvalidProperties(
|
|
88
|
-
propertySchema,
|
|
89
|
-
valueObject[key],
|
|
90
|
-
propertyDefault(propertySchema, defaultObject, key),
|
|
91
|
-
);
|
|
92
|
-
if (propertyValue !== NO_DEFAULT) repaired[key] = propertyValue;
|
|
93
|
-
else if (required.has(key)) return validatedDefault(schema, documentedDefault);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const schemaObject = asObject(schema);
|
|
97
|
-
const additionalProperties = schemaObject?.additionalProperties;
|
|
98
|
-
if (additionalProperties !== false) {
|
|
99
|
-
for (const [key, additionalValue] of Object.entries(valueObject)) {
|
|
100
|
-
if (Object.hasOwn(schema.properties, key)) continue;
|
|
101
|
-
if (additionalProperties === undefined || additionalProperties === true) repaired[key] = additionalValue;
|
|
102
|
-
else {
|
|
103
|
-
const repairedAdditional = replaceInvalidProperties(
|
|
104
|
-
additionalProperties as TSchema,
|
|
105
|
-
additionalValue,
|
|
106
|
-
NO_DEFAULT,
|
|
107
|
-
);
|
|
108
|
-
if (repairedAdditional !== NO_DEFAULT) repaired[key] = repairedAdditional;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
117
|
+
const repaired = repairKnownProperties(schema, valueObject, defaultObject);
|
|
118
|
+
if (repaired === NO_DEFAULT) return validatedDefault(schema, documentedDefault);
|
|
119
|
+
repairAdditionalProperties(schema, valueObject, repaired);
|
|
113
120
|
if (Value.Check(schema, repaired)) return repaired;
|
|
114
121
|
}
|
|
115
122
|
|
|
@@ -126,6 +126,7 @@ export class TemporaryOutputStore {
|
|
|
126
126
|
return writer;
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
+
// fallow-ignore-next-line unused-class-member -- called via createTemporaryOutputStore() from explore session lifecycle
|
|
129
130
|
async shutdown(): Promise<void> {
|
|
130
131
|
if (this.shutdownPromise) return this.shutdownPromise;
|
|
131
132
|
this.shutdownPromise = this.performShutdown();
|
|
@@ -177,6 +178,20 @@ export class TemporaryOutputStore {
|
|
|
177
178
|
this.active.delete(writer);
|
|
178
179
|
}
|
|
179
180
|
|
|
181
|
+
private async isRemovableOrphan(path: string): Promise<boolean> {
|
|
182
|
+
const metadata = await stat(path);
|
|
183
|
+
if (Date.now() - metadata.mtimeMs < this.orphanLifetimeMs) return false;
|
|
184
|
+
const marker = JSON.parse(await readFile(join(path, OWNER_FILE), "utf8")) as Partial<OwnerMarker>;
|
|
185
|
+
if (marker.kind !== "tau-tool-output" || marker.version !== 1 || typeof marker.pid !== "number") return false;
|
|
186
|
+
try {
|
|
187
|
+
process.kill(marker.pid, 0);
|
|
188
|
+
return false;
|
|
189
|
+
} catch (error) {
|
|
190
|
+
if (!isErrorCode(error, "ESRCH")) return false;
|
|
191
|
+
}
|
|
192
|
+
return true;
|
|
193
|
+
}
|
|
194
|
+
|
|
180
195
|
private async removeStaleOrphans(): Promise<void> {
|
|
181
196
|
let directory;
|
|
182
197
|
try {
|
|
@@ -188,16 +203,7 @@ export class TemporaryOutputStore {
|
|
|
188
203
|
if (!entry.isDirectory() || !entry.name.startsWith(DIRECTORY_PREFIX)) continue;
|
|
189
204
|
const path = join(this.baseDirectory, entry.name);
|
|
190
205
|
try {
|
|
191
|
-
|
|
192
|
-
if (Date.now() - metadata.mtimeMs < this.orphanLifetimeMs) continue;
|
|
193
|
-
const marker = JSON.parse(await readFile(join(path, OWNER_FILE), "utf8")) as Partial<OwnerMarker>;
|
|
194
|
-
if (marker.kind !== "tau-tool-output" || marker.version !== 1 || typeof marker.pid !== "number") continue;
|
|
195
|
-
try {
|
|
196
|
-
process.kill(marker.pid, 0);
|
|
197
|
-
continue;
|
|
198
|
-
} catch (error) {
|
|
199
|
-
if (!isErrorCode(error, "ESRCH")) continue;
|
|
200
|
-
}
|
|
206
|
+
if (!(await this.isRemovableOrphan(path))) continue;
|
|
201
207
|
await rm(path, { recursive: true, force: true });
|
|
202
208
|
} catch {
|
|
203
209
|
// An untrusted or concurrently changing directory is not ours to remove.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Tree } from "web-tree-sitter";
|
|
2
|
-
import type { Decl, ImportRef } from "./ir.ts";
|
|
2
|
+
import type { CallSite, Decl, ImportRef } from "./ir.ts";
|
|
3
3
|
import type { PackageSurfaceResolver } from "./package-surface.ts";
|
|
4
4
|
|
|
5
5
|
export type LanguageCapabilities = {
|
|
@@ -8,6 +8,8 @@ export type LanguageCapabilities = {
|
|
|
8
8
|
fileDeps: boolean;
|
|
9
9
|
callEdges: boolean;
|
|
10
10
|
packageSurface: boolean;
|
|
11
|
+
/** Interfaces are satisfied by method set, not by naming them (Go). */
|
|
12
|
+
structuralImplements: boolean;
|
|
11
13
|
};
|
|
12
14
|
|
|
13
15
|
/**
|
|
@@ -25,11 +27,18 @@ export type AstSearchPatternContext = {
|
|
|
25
27
|
export type ExtractResult = {
|
|
26
28
|
decls: Decl[];
|
|
27
29
|
imports: ImportRef[];
|
|
30
|
+
/** Call sites in top-level statements — outside any declaration body. */
|
|
31
|
+
fileCalls: CallSite[];
|
|
28
32
|
};
|
|
29
33
|
|
|
30
|
-
/**
|
|
34
|
+
/**
|
|
35
|
+
* Result of adapter-owned import specifier → file resolution.
|
|
36
|
+
* `package` is an in-repo directory too large to list file by file — distinct
|
|
37
|
+
* from `external`, which means "not in this repository".
|
|
38
|
+
*/
|
|
31
39
|
export type FileDepResolution =
|
|
32
40
|
| { kind: "internal"; paths: string[] }
|
|
41
|
+
| { kind: "package"; id: string; dir: string; fileCount: number }
|
|
33
42
|
| { kind: "external"; id: string }
|
|
34
43
|
| { kind: "unresolved" };
|
|
35
44
|
|
|
@@ -13,7 +13,7 @@ import type { AdapterRegistry } from "./registry.ts";
|
|
|
13
13
|
import { createDefaultRegistry } from "./registry.ts";
|
|
14
14
|
import type { FileIr } from "./ir.ts";
|
|
15
15
|
import { grammarWasmPath, loadGrammarManifest, runtimeWasmPath, type GrammarPin } from "./grammars/manifest.ts";
|
|
16
|
-
import { formatPathForDisplay, pathResolutionError, resolveExplorePath } from "
|
|
16
|
+
import { formatPathForDisplay, pathResolutionError, resolveExplorePath } from "./traverse.ts";
|
|
17
17
|
|
|
18
18
|
export type FileSource = {
|
|
19
19
|
ir: FileIr;
|
|
@@ -95,6 +95,40 @@ function pinById(id: string): GrammarPin {
|
|
|
95
95
|
return pin;
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
+
function isMetaVarStart(c: string): boolean {
|
|
99
|
+
return (c >= "A" && c <= "Z") || c === "_";
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function isMetaVarContinue(c: string): boolean {
|
|
103
|
+
return isMetaVarStart(c) || (c >= "0" && c <= "9");
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function pushUniqueName(list: string[], name: string): void {
|
|
107
|
+
if (!list.includes(name)) list.push(name);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** Read `$NAME` / `$$$NAME` starting at `start` (must point at `$`). */
|
|
111
|
+
function readMetaVarAt(pattern: string, start: number): { dollars: number; name: string; next: number } {
|
|
112
|
+
let i = start;
|
|
113
|
+
let dollars = 0;
|
|
114
|
+
while (i < pattern.length && pattern[i] === "$") {
|
|
115
|
+
dollars += 1;
|
|
116
|
+
i += 1;
|
|
117
|
+
}
|
|
118
|
+
let name = "";
|
|
119
|
+
while (i < pattern.length) {
|
|
120
|
+
const c = pattern[i];
|
|
121
|
+
if (c === undefined) break;
|
|
122
|
+
if ((name.length === 0 && isMetaVarStart(c)) || (name.length > 0 && isMetaVarContinue(c))) {
|
|
123
|
+
name += c;
|
|
124
|
+
i += 1;
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
break;
|
|
128
|
+
}
|
|
129
|
+
return { dollars, name, next: i };
|
|
130
|
+
}
|
|
131
|
+
|
|
98
132
|
/** ast-grep metavars: `$NAME` one node, `$$$NAME` sibling sequence. Skip `$_`. */
|
|
99
133
|
function metaVarNames(pattern: string): { singles: string[]; multis: string[] } {
|
|
100
134
|
const singles: string[] = [];
|
|
@@ -105,30 +139,11 @@ function metaVarNames(pattern: string): { singles: string[]; multis: string[] }
|
|
|
105
139
|
i += 1;
|
|
106
140
|
continue;
|
|
107
141
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
dollars += 1;
|
|
111
|
-
i += 1;
|
|
112
|
-
}
|
|
113
|
-
let name = "";
|
|
114
|
-
while (i < pattern.length) {
|
|
115
|
-
const c = pattern[i];
|
|
116
|
-
if (c === undefined) break;
|
|
117
|
-
const isAlpha = (c >= "A" && c <= "Z") || c === "_";
|
|
118
|
-
const isAlnum = isAlpha || (c >= "0" && c <= "9");
|
|
119
|
-
if ((name.length === 0 && isAlpha) || (name.length > 0 && isAlnum)) {
|
|
120
|
-
name += c;
|
|
121
|
-
i += 1;
|
|
122
|
-
continue;
|
|
123
|
-
}
|
|
124
|
-
break;
|
|
125
|
-
}
|
|
142
|
+
const { dollars, name, next } = readMetaVarAt(pattern, i);
|
|
143
|
+
i = next;
|
|
126
144
|
if (name.length === 0 || name === "_") continue;
|
|
127
|
-
if (dollars >= 3)
|
|
128
|
-
|
|
129
|
-
} else if (dollars === 1) {
|
|
130
|
-
if (!singles.includes(name)) singles.push(name);
|
|
131
|
-
}
|
|
145
|
+
if (dollars >= 3) pushUniqueName(multis, name);
|
|
146
|
+
else if (dollars === 1) pushUniqueName(singles, name);
|
|
132
147
|
}
|
|
133
148
|
return { singles, multis };
|
|
134
149
|
}
|
|
@@ -228,6 +243,17 @@ export function createExploreEngine(options: ExploreEngineOptions): ExploreEngin
|
|
|
228
243
|
}
|
|
229
244
|
};
|
|
230
245
|
|
|
246
|
+
const requireSearchableAdapter = (languageId: string) => {
|
|
247
|
+
const adapter = registry.adapterForId(languageId);
|
|
248
|
+
if (adapter === undefined) {
|
|
249
|
+
throw new Error(`Unregistered language: ${languageId}`);
|
|
250
|
+
}
|
|
251
|
+
if (adapter.mode !== "grammar" || !adapter.capabilities.search) {
|
|
252
|
+
throw new Error(`Language does not support structural search: ${languageId}`);
|
|
253
|
+
}
|
|
254
|
+
return adapter;
|
|
255
|
+
};
|
|
256
|
+
|
|
231
257
|
const ensureReady = async (): Promise<Parser> => {
|
|
232
258
|
assertLive();
|
|
233
259
|
if (parser !== undefined) return parser;
|
|
@@ -257,13 +283,7 @@ export function createExploreEngine(options: ExploreEngineOptions): ExploreEngin
|
|
|
257
283
|
const ensureSearchLanguage = async (languageId: string): Promise<void> => {
|
|
258
284
|
assertLive();
|
|
259
285
|
if (searchLangReady.has(languageId)) return;
|
|
260
|
-
|
|
261
|
-
if (adapter === undefined) {
|
|
262
|
-
throw new Error(`Unregistered language: ${languageId}`);
|
|
263
|
-
}
|
|
264
|
-
if (adapter.mode !== "grammar" || !adapter.capabilities.search) {
|
|
265
|
-
throw new Error(`Language does not support structural search: ${languageId}`);
|
|
266
|
-
}
|
|
286
|
+
requireSearchableAdapter(languageId);
|
|
267
287
|
await ensureSearchReady();
|
|
268
288
|
assertLive();
|
|
269
289
|
await registerDynamicLanguage({
|
|
@@ -320,6 +340,7 @@ export function createExploreEngine(options: ExploreEngineOptions): ExploreEngin
|
|
|
320
340
|
lineCount,
|
|
321
341
|
decls: extracted.decls,
|
|
322
342
|
imports: extracted.imports,
|
|
343
|
+
fileCalls: extracted.fileCalls,
|
|
323
344
|
parseDegraded: false,
|
|
324
345
|
};
|
|
325
346
|
}
|
|
@@ -342,6 +363,7 @@ export function createExploreEngine(options: ExploreEngineOptions): ExploreEngin
|
|
|
342
363
|
lineCount,
|
|
343
364
|
decls: extracted.decls,
|
|
344
365
|
imports: extracted.imports,
|
|
366
|
+
fileCalls: extracted.fileCalls,
|
|
345
367
|
parseDegraded: tree.rootNode.hasError,
|
|
346
368
|
};
|
|
347
369
|
} finally {
|
|
@@ -386,13 +408,7 @@ export function createExploreEngine(options: ExploreEngineOptions): ExploreEngin
|
|
|
386
408
|
|
|
387
409
|
async searchInSource(languageId: string, source: string, pattern: string): Promise<AstSearchHit[]> {
|
|
388
410
|
assertLive();
|
|
389
|
-
const adapter =
|
|
390
|
-
if (adapter === undefined) {
|
|
391
|
-
throw new Error(`Unregistered language: ${languageId}`);
|
|
392
|
-
}
|
|
393
|
-
if (adapter.mode !== "grammar" || !adapter.capabilities.search) {
|
|
394
|
-
throw new Error(`Language does not support structural search: ${languageId}`);
|
|
395
|
-
}
|
|
411
|
+
const adapter = requireSearchableAdapter(languageId);
|
|
396
412
|
await ensureSearchLanguage(languageId);
|
|
397
413
|
assertLive();
|
|
398
414
|
|
|
@@ -1,27 +1,36 @@
|
|
|
1
1
|
import type { AstSearchMatch, AstSearchResult } from "../queries/ast-search.ts";
|
|
2
2
|
import type { ScanOutcome } from "../scan.ts";
|
|
3
|
-
import type { TraversalLimit } from "
|
|
4
|
-
import { formatPathForDisplay } from "
|
|
3
|
+
import type { TraversalLimit } from "../traverse.ts";
|
|
4
|
+
import { formatPathForDisplay } from "../traverse.ts";
|
|
5
5
|
|
|
6
6
|
function lineRange(startLine: number, endLine: number): string {
|
|
7
7
|
return startLine === endLine ? `L${startLine}` : `L${startLine}-${endLine}`;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
/** Head-retained line budget per match. resultLimit caps match count, not match size. */
|
|
11
|
+
const MATCH_MAX_LINES = 12;
|
|
12
|
+
|
|
10
13
|
function formatMatchRows(match: AstSearchMatch): string[] {
|
|
11
14
|
const lines: string[] = [];
|
|
12
15
|
const preview = match.text.length > 0 ? match.text : "(empty)";
|
|
13
16
|
const previewLines = preview.split("\n");
|
|
14
17
|
const first = previewLines[0] ?? "(empty)";
|
|
15
18
|
lines.push(`${lineRange(match.startLine, match.endLine)} ${first}`);
|
|
16
|
-
|
|
19
|
+
const shown = Math.min(previewLines.length, MATCH_MAX_LINES);
|
|
20
|
+
for (let i = 1; i < shown; i += 1) {
|
|
17
21
|
lines.push(` ${previewLines[i] ?? ""}`);
|
|
18
22
|
}
|
|
23
|
+
if (previewLines.length > shown) {
|
|
24
|
+
lines.push(` ... +${previewLines.length - shown} lines`);
|
|
25
|
+
}
|
|
19
26
|
for (const binding of match.bindings) {
|
|
20
27
|
const bindLines = binding.text.split("\n");
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
lines.push(`
|
|
28
|
+
// A multi-line capture is a span, not a value — report its size.
|
|
29
|
+
if (bindLines.length > 1) {
|
|
30
|
+
lines.push(` $${binding.name} = <${bindLines.length} lines>`);
|
|
31
|
+
continue;
|
|
24
32
|
}
|
|
33
|
+
lines.push(` $${binding.name} = ${bindLines[0] ?? ""}`);
|
|
25
34
|
}
|
|
26
35
|
if (match.enclosing !== undefined) {
|
|
27
36
|
lines.push(` in ${match.enclosing.kind} ${match.enclosing.name} L${match.enclosing.startLine}`);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { formatPathForDisplay } from "
|
|
1
|
+
import { formatPathForDisplay } from "../traverse.ts";
|
|
2
2
|
import type { ContextEntry, ContextGroup, ContextResult, ContextTarget } from "../queries/context.ts";
|
|
3
3
|
import { compositeSectionBlocks, type CompositeBlock } from "./composite.ts";
|
|
4
|
-
import {
|
|
4
|
+
import { formatTargetedResult } from "./targeted-result.ts";
|
|
5
5
|
|
|
6
6
|
function formatTargetHeader(target: ContextTarget, budget: number, used: number, cwd: string): string {
|
|
7
7
|
const path = formatPathForDisplay(target.path, cwd);
|
|
@@ -43,10 +43,7 @@ function formatResolved(result: Extract<ContextResult, { kind: "resolved" }>, cw
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
export function formatContextResult(result: ContextResult, cwd: string): string {
|
|
46
|
-
|
|
47
|
-
if (result.kind === "notFound") return "No matching declaration.";
|
|
48
|
-
if (result.kind === "candidates") return formatCandidateList(result.candidates, cwd);
|
|
49
|
-
return formatResolved(result, cwd);
|
|
46
|
+
return formatTargetedResult(result, cwd, formatResolved);
|
|
50
47
|
}
|
|
51
48
|
|
|
52
49
|
export function contextSectionBlocks(
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import type { FileDepQueryResult } from "../graph/file-graph.ts";
|
|
2
|
+
import { formatPathForDisplay } from "../traverse.ts";
|
|
3
|
+
|
|
4
|
+
function depthPrefix(depth: number, showDepth: boolean): string {
|
|
5
|
+
return showDepth ? `d${depth} ` : "";
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function commonDirPrefixLength(split: readonly string[][]): number {
|
|
9
|
+
const first = split[0];
|
|
10
|
+
if (first === undefined || split.length <= 1) return 0;
|
|
11
|
+
let common = 0;
|
|
12
|
+
while (common < first.length - 1) {
|
|
13
|
+
const part = first[common];
|
|
14
|
+
if (part === undefined) break;
|
|
15
|
+
if (!split.every((parts) => parts[common] === part)) break;
|
|
16
|
+
common += 1;
|
|
17
|
+
}
|
|
18
|
+
return common;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Factor shared directory prefixes into a small indent tree. */
|
|
22
|
+
function formatInternalTree(rows: readonly { depth: number; display: string }[], showDepth: boolean): string[] {
|
|
23
|
+
if (rows.length === 0) return [];
|
|
24
|
+
|
|
25
|
+
const split = rows.map((row) => row.display.split("/"));
|
|
26
|
+
const common = commonDirPrefixLength(split);
|
|
27
|
+
const first = split[0];
|
|
28
|
+
const lines: string[] = [];
|
|
29
|
+
if (common > 0 && first !== undefined) {
|
|
30
|
+
lines.push(first.slice(0, common).join("/"));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
for (let i = 0; i < rows.length; i += 1) {
|
|
34
|
+
const row = rows[i];
|
|
35
|
+
const parts = split[i];
|
|
36
|
+
if (row === undefined || parts === undefined) continue;
|
|
37
|
+
const leaf = common > 0 ? parts.slice(common).join("/") : row.display;
|
|
38
|
+
const indent = common > 0 ? " " : "";
|
|
39
|
+
lines.push(`${indent}${depthPrefix(row.depth, showDepth)}${leaf}`);
|
|
40
|
+
}
|
|
41
|
+
return lines;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function formatDepsResult(result: FileDepQueryResult, cwd: string, emptyLabel: string): string {
|
|
45
|
+
const showDepth = result.depth > 1;
|
|
46
|
+
const inRepo: { depth: number; display: string }[] = [];
|
|
47
|
+
const external: { depth: number; id: string }[] = [];
|
|
48
|
+
for (const hit of result.hits) {
|
|
49
|
+
if (hit.kind === "internal") {
|
|
50
|
+
inRepo.push({ depth: hit.depth, display: formatPathForDisplay(hit.path, cwd) });
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (hit.kind === "package") {
|
|
54
|
+
// In-repo directory, listed as a package because file-by-file would flood.
|
|
55
|
+
inRepo.push({
|
|
56
|
+
depth: hit.depth,
|
|
57
|
+
display: `${formatPathForDisplay(hit.dir, cwd)}/ (${hit.fileCount} files)`,
|
|
58
|
+
});
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
external.push({ depth: hit.depth, id: hit.id });
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (inRepo.length === 0 && external.length === 0) {
|
|
65
|
+
return emptyLabel;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const lines: string[] = [];
|
|
69
|
+
lines.push(...formatInternalTree(inRepo, showDepth));
|
|
70
|
+
|
|
71
|
+
if (external.length > 0) {
|
|
72
|
+
lines.push("external:");
|
|
73
|
+
for (const hit of external) {
|
|
74
|
+
lines.push(` ${depthPrefix(hit.depth, showDepth)}${hit.id}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (result.externalOmitted > 0) {
|
|
78
|
+
lines.push(` +${result.externalOmitted} more external`);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (result.resultLimitReached) {
|
|
82
|
+
lines.push(`omitted (result limit ${result.resultLimit})`);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return lines.join("\n");
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function formatDepsEmpty(): string {
|
|
89
|
+
return "No file dependencies";
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function formatReverseDepsEmpty(): string {
|
|
93
|
+
return "No reverse file dependencies";
|
|
94
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { DiscoverCandidate, DiscoverResult } from "../queries/discover.ts";
|
|
2
2
|
import type { ScanOutcome } from "../scan.ts";
|
|
3
|
-
import type { TraversalLimit } from "
|
|
4
|
-
import { formatPathForDisplay } from "
|
|
3
|
+
import type { TraversalLimit } from "../traverse.ts";
|
|
4
|
+
import { formatPathForDisplay } from "../traverse.ts";
|
|
5
5
|
|
|
6
6
|
function lineRange(startLine: number, endLine: number): string {
|
|
7
7
|
return startLine === endLine ? `L${startLine}` : `L${startLine}-${endLine}`;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { formatPathForDisplay } from "
|
|
1
|
+
import { formatPathForDisplay } from "../traverse.ts";
|
|
2
2
|
import type { ImpactFileRow, ImpactResult, ImpactSection, ImpactSiteRow, ImpactTarget } from "../queries/impact.ts";
|
|
3
3
|
import { compositeSectionBlocks, type CompositeBlock } from "./composite.ts";
|
|
4
|
-
import {
|
|
4
|
+
import { formatTargetedResult } from "./targeted-result.ts";
|
|
5
5
|
|
|
6
6
|
function formatTargetHeader(target: ImpactTarget, cwd: string): string {
|
|
7
7
|
const path = formatPathForDisplay(target.path, cwd);
|
|
@@ -17,10 +17,11 @@ function formatSiteRow(row: ImpactSiteRow): string {
|
|
|
17
17
|
|
|
18
18
|
function formatFileRow(row: ImpactFileRow, cwd: string, showDepth: boolean): string {
|
|
19
19
|
const depth = showDepth ? `d${row.depth} ` : "";
|
|
20
|
-
if (row.
|
|
21
|
-
|
|
20
|
+
if (row.target.kind === "internal") return ` ${depth}${formatPathForDisplay(row.target.path, cwd)}`;
|
|
21
|
+
if (row.target.kind === "package") {
|
|
22
|
+
return ` ${depth}${formatPathForDisplay(row.target.dir, cwd)}/ (${row.target.fileCount} files)`;
|
|
22
23
|
}
|
|
23
|
-
return ` ${depth}${row.
|
|
24
|
+
return ` ${depth}${row.target.id}`;
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
function formatSection(section: ImpactSection, cwd: string): string[] {
|
|
@@ -41,8 +42,8 @@ function formatSection(section: ImpactSection, cwd: string): string[] {
|
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
if (fileRows.length > 0) {
|
|
44
|
-
const internal = fileRows.filter((row) => row.
|
|
45
|
-
const external = fileRows.filter((row) => row.
|
|
45
|
+
const internal = fileRows.filter((row) => row.target.kind !== "external");
|
|
46
|
+
const external = fileRows.filter((row) => row.target.kind === "external");
|
|
46
47
|
for (const row of internal) {
|
|
47
48
|
lines.push(formatFileRow(row, cwd, showDepth));
|
|
48
49
|
}
|
|
@@ -80,10 +81,7 @@ function formatResolved(result: Extract<ImpactResult, { kind: "resolved" }>, cwd
|
|
|
80
81
|
}
|
|
81
82
|
|
|
82
83
|
export function formatImpactResult(result: ImpactResult, cwd: string): string {
|
|
83
|
-
|
|
84
|
-
if (result.kind === "notFound") return "No matching declaration.";
|
|
85
|
-
if (result.kind === "candidates") return formatCandidateList(result.candidates, cwd);
|
|
86
|
-
return formatResolved(result, cwd);
|
|
84
|
+
return formatTargetedResult(result, cwd, formatResolved);
|
|
87
85
|
}
|
|
88
86
|
|
|
89
87
|
export function impactSectionBlocks(
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { OutlineFileView, OutlineRow } from "../queries/outline.ts";
|
|
2
2
|
import type { ScanOutcome } from "../scan.ts";
|
|
3
|
-
import type { TraversalLimit } from "
|
|
4
|
-
import { formatPathForDisplay } from "
|
|
3
|
+
import type { TraversalLimit } from "../traverse.ts";
|
|
4
|
+
import { formatPathForDisplay } from "../traverse.ts";
|
|
5
5
|
|
|
6
6
|
function lineRange(startLine: number, endLine: number): string {
|
|
7
7
|
return startLine === endLine ? `L${startLine}` : `L${startLine}-${endLine}`;
|
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
import type { Candidate } from "../identity.ts";
|
|
2
2
|
import type { RelationshipQueryResult, RelationshipSite, RelationshipTarget } from "../graph/relationships.ts";
|
|
3
|
-
import {
|
|
3
|
+
import { compactSignature } from "../slice.ts";
|
|
4
|
+
import { formatPathForDisplay } from "../traverse.ts";
|
|
5
|
+
|
|
6
|
+
function candidateParts(candidate: Candidate, cwd: string): { path: string; signature: string } {
|
|
7
|
+
return {
|
|
8
|
+
path: formatPathForDisplay(candidate.path, cwd),
|
|
9
|
+
signature: compactSignature(candidate.signature),
|
|
10
|
+
};
|
|
11
|
+
}
|
|
4
12
|
|
|
5
13
|
function formatCompetitors(competitors: readonly Candidate[], cwd: string): string[] {
|
|
6
14
|
const lines: string[] = [];
|
|
7
15
|
for (const c of competitors) {
|
|
8
|
-
const path =
|
|
9
|
-
const sig = c.signature.replace(/\s+/gu, " ").trim();
|
|
10
|
-
const short = sig.length > 80 ? `${sig.slice(0, 77)}...` : sig;
|
|
16
|
+
const { path, signature: short } = candidateParts(c, cwd);
|
|
11
17
|
lines.push(` - ${path}:${c.startLine} ${c.kind} ${c.qualifiedName || c.name} ${short}`);
|
|
12
18
|
}
|
|
13
19
|
return lines;
|
|
@@ -57,9 +63,7 @@ function formatResolved(
|
|
|
57
63
|
export function formatCandidateList(candidates: readonly Candidate[], cwd: string): string {
|
|
58
64
|
const lines = ["Ambiguous target — disambiguate with targetPath or line:", ""];
|
|
59
65
|
for (const c of candidates) {
|
|
60
|
-
const path =
|
|
61
|
-
const sig = c.signature.replace(/\s+/gu, " ").trim();
|
|
62
|
-
const short = sig.length > 80 ? `${sig.slice(0, 77)}...` : sig;
|
|
66
|
+
const { path, signature: short } = candidateParts(c, cwd);
|
|
63
67
|
lines.push(`${path}:${c.startLine} ${c.kind} ${c.qualifiedName || c.name}`);
|
|
64
68
|
if (short.length > 0) lines.push(` ${short}`);
|
|
65
69
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ShowBatch, ShowBlock } from "../queries/show.ts";
|
|
2
|
-
import { formatPathForDisplay } from "
|
|
2
|
+
import { formatPathForDisplay } from "../traverse.ts";
|
|
3
3
|
|
|
4
4
|
function lineRange(startLine: number, endLine: number): string {
|
|
5
5
|
return startLine === endLine ? `L${startLine}` : `L${startLine}-${endLine}`;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Candidate } from "../identity.ts";
|
|
2
|
+
import { formatCandidateList } from "./relationships.ts";
|
|
3
|
+
|
|
4
|
+
type TargetedResult<Resolved extends { kind: "resolved" }> =
|
|
5
|
+
| Resolved
|
|
6
|
+
| { kind: "candidates"; candidates: Candidate[] }
|
|
7
|
+
| { kind: "notFound" }
|
|
8
|
+
| { kind: "error"; message: string };
|
|
9
|
+
|
|
10
|
+
/** Shared dispatch for query results that resolve one declaration target. */
|
|
11
|
+
export function formatTargetedResult<Resolved extends { kind: "resolved" }>(
|
|
12
|
+
result: TargetedResult<Resolved>,
|
|
13
|
+
cwd: string,
|
|
14
|
+
formatResolved: (resolved: Resolved, cwd: string) => string,
|
|
15
|
+
): string {
|
|
16
|
+
if (result.kind === "error") return result.message;
|
|
17
|
+
if (result.kind === "notFound") return "No matching declaration.";
|
|
18
|
+
if (result.kind === "candidates") return formatCandidateList(result.candidates, cwd);
|
|
19
|
+
return formatResolved(result, cwd);
|
|
20
|
+
}
|
|
Binary file
|
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"webTreeSitter": "0.26.11",
|
|
3
3
|
"vscodeTreeSitterWasm": "0.3.1",
|
|
4
|
-
"treeSitterCli": "0.26.11",
|
|
5
|
-
"wasiSdk": "wasi-sdk-29",
|
|
6
4
|
"grammars": [
|
|
7
5
|
{ "id": "typescript", "source": "vscode", "file": "tree-sitter-typescript.wasm" },
|
|
8
6
|
{ "id": "tsx", "source": "vscode", "file": "tree-sitter-tsx.wasm" },
|
|
9
7
|
{ "id": "go", "source": "vscode", "file": "tree-sitter-go.wasm" },
|
|
10
8
|
{ "id": "rust", "source": "vscode", "file": "tree-sitter-rust.wasm" },
|
|
11
|
-
{
|
|
9
|
+
{
|
|
10
|
+
"id": "c_sharp",
|
|
11
|
+
"source": "release",
|
|
12
|
+
"file": "c_sharp.wasm",
|
|
13
|
+
"repo": "https://github.com/tree-sitter/tree-sitter-c-sharp",
|
|
14
|
+
"tag": "v0.23.5",
|
|
15
|
+
"rev": "cac6d5fb595f5811a076336682d5d595ac1c9e85",
|
|
16
|
+
"url": "https://github.com/tree-sitter/tree-sitter-c-sharp/releases/download/v0.23.5/tree-sitter-c_sharp.wasm"
|
|
17
|
+
},
|
|
12
18
|
{ "id": "java", "source": "vscode", "file": "tree-sitter-java.wasm" },
|
|
13
19
|
{
|
|
14
20
|
"id": "kotlin",
|
|
@@ -27,15 +33,6 @@
|
|
|
27
33
|
"tag": "0.7.3",
|
|
28
34
|
"rev": "b8b22bffbb3441780e6471665bacfb263741c86a",
|
|
29
35
|
"url": "https://github.com/alex-pinkus/tree-sitter-swift/releases/download/0.7.3/tree-sitter-swift.wasm"
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
"id": "odin",
|
|
33
|
-
"source": "built",
|
|
34
|
-
"file": "odin.wasm",
|
|
35
|
-
"repo": "https://github.com/tree-sitter-grammars/tree-sitter-odin",
|
|
36
|
-
"tag": "v1.3.0",
|
|
37
|
-
"rev": "e8adc739b78409a99f8c31313f0bb54cc538cf73",
|
|
38
|
-
"subdir": "."
|
|
39
36
|
}
|
|
40
37
|
]
|
|
41
38
|
}
|