diff --git a/CHANGELOG.md b/CHANGELOG.md index 1da973b..cecc9ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ and adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ### Fixes +- `codegraph node -f ` now prints the symbol's source body. Pinning an ambiguous name to a specific file (the whole point of `-f` when many files define the same function) returned only the location and caller trail with no code. (#1284) - Deleting a whole directory is now picked up by watch mode: the files inside it are removed from the index on the next auto-sync instead of lingering as stale records until an unrelated edit happened to trigger one. Operating systems often report a directory deletion as a single event on the directory itself (with no per-file events for its contents), which the watcher previously discarded. (#1285) - `codegraph sync` now gets the same slow-disk fix that made full indexing fast in 1.4.0: database checkpointing is deferred for the whole incremental run instead of firing every few megabytes of writes. On mechanical drives and other high-latency storage, a small sync on a large index no longer stalls for minutes at near-zero CPU — the cost of a sync scales with what changed, not with the size of the existing index. The same `CODEGRAPH_NO_WAL_DEFER=1` switch turns it off. (#1248) - C functions declared with a project-specific attribute macro in front of a typedef'd return type (`SEC_ATTR UINT32 MyFunc(VOID)` — common in embedded and kernel code) are now indexed under their real names. Previously the parser tripped over the unknown macro and stored the parameter list as the function name, leaving entries like `"(VOID)"` in the graph and making the real function unfindable. (#1211) diff --git a/__tests__/cli-node-command.test.ts b/__tests__/cli-node-command.test.ts index 4d34850..dfd28ac 100644 --- a/__tests__/cli-node-command.test.ts +++ b/__tests__/cli-node-command.test.ts @@ -78,3 +78,42 @@ describe('codegraph node — argument handling (#1044)', () => { expect(stderr).not.toMatch(/missing required argument/); }); }); + +describe('codegraph node — symbol pinned to a file includes the body (#1284)', () => { + let tempDir: string; + + beforeEach(async () => { + tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'codegraph-node-pin-')); + fs.mkdirSync(path.join(tempDir, 'a')); + fs.mkdirSync(path.join(tempDir, 'b')); + // Two same-named definitions, so `-f` is genuinely disambiguating. + fs.writeFileSync( + path.join(tempDir, 'a', 'state.ts'), + 'export function setState(x: number): void {\n console.log("A", x);\n}\n' + ); + fs.writeFileSync( + path.join(tempDir, 'b', 'state.ts'), + 'export function setState(y: string): void {\n console.log("B", y);\n}\n' + ); + const cg = CodeGraph.initSync(tempDir); + await cg.indexAll(); + cg.close(); + }); + + afterEach(() => { + fs.rmSync(tempDir, { recursive: true, force: true }); + }); + + it('`node -f ` prints the pinned definition WITH its source body', () => { + // The exact #1284 shape: `-f` narrowed the overload correctly but printed + // only Location + trail — no code fence — so the user had nothing to read. + const { stdout, code } = runNode(tempDir, ['setState', '-f', 'a/state.ts']); + expect(code).toBe(0); + expect(stdout).toContain('a/state.ts'); + // The body is present (line-numbered fence), and it's the pinned overload. + expect(stdout).toMatch(/1\s+export function setState\(x: number\)/); + expect(stdout).toContain('console.log("A", x)'); + // The other file's overload is not what was pinned. + expect(stdout).not.toContain('console.log("B", y)'); + }); +}); diff --git a/src/bin/codegraph.ts b/src/bin/codegraph.ts index dd1fe8a..eefb5d9 100644 --- a/src/bin/codegraph.ts +++ b/src/bin/codegraph.ts @@ -1414,7 +1414,14 @@ program const args: Record = {}; if (options.file) { args.file = options.file; - if (name && name !== options.file) args.symbol = name; + if (name && name !== options.file) { + args.symbol = name; + // Symbol mode pinned to a file is still symbol mode — the CLI + // always wants the body, exactly like the bare-symbol branch + // below. Omitting this printed location + trail with no source + // (#1284). + args.includeCode = true; + } } else if (name && (name.includes('/') || name.includes('\\'))) { args.file = name.replace(/\\/g, '/'); } else if (name) {