diff --git a/drift.lock b/drift.lock index 854ea9d..3726b0f 100644 --- a/drift.lock +++ b/drift.lock @@ -4,7 +4,7 @@ version = 1 doc = ".claude/skills/drift/SKILL.md" target = "src/main.zig" origin = "github:fiberplane/drift" -sig = "0e63465cf6539ff3" +sig = "3faa73e2bb344a79" [[bindings]] doc = ".claude/skills/drift/SKILL.md" @@ -20,12 +20,12 @@ sig = "2dccb33f6b790afa" [[bindings]] doc = "CLAUDE.md" target = "src/main.zig" -sig = "0e63465cf6539ff3" +sig = "3faa73e2bb344a79" [[bindings]] doc = "docs/CLI.md" target = "src/commands/link.zig" -sig = "7bd7f824afc30e0b" +sig = "3ae8f4ee2c85d8d8" [[bindings]] doc = "docs/CLI.md" @@ -60,18 +60,28 @@ sig = "55bc77a2853cb654" [[bindings]] doc = "docs/DESIGN.md" target = "src/main.zig" -sig = "0e63465cf6539ff3" +sig = "3faa73e2bb344a79" [[bindings]] doc = "docs/DESIGN.md" target = "src/symbols.zig" -sig = "bbe250d43609daa1" +sig = "772dd9e7e974468e" [[bindings]] doc = "docs/DESIGN.md" target = "src/vcs.zig" sig = "84da70be235ca9d4" +[[bindings]] +doc = "docs/DESIGN.md" +target = "src/vcs.zig#GitCatFile" +sig = "c61b49f799a878de" + +[[bindings]] +doc = "docs/DESIGN.md" +target = "src/vcs.zig#getRepoIdentity" +sig = "7d0fe37e5eff5e30" + [[bindings]] doc = "docs/RELEASING.md" target = ".github/workflows/ci.yml" diff --git a/src/commands/link.zig b/src/commands/link.zig index a0d909d..a6a7979 100644 --- a/src/commands/link.zig +++ b/src/commands/link.zig @@ -49,7 +49,13 @@ pub fn run( const existing_binding = findBinding(lf.bindings.items, normalized_doc_path, normalized_target); const old_sig = if (existing_binding) |b| b.fieldValue("sig") else null; - try upsertBinding(ctx, &lf, cwd_path, normalized_doc_path, normalized_target); + upsertBinding(ctx, &lf, cwd_path, normalized_doc_path, normalized_target) catch |err| switch (err) { + error.CannotComputeFingerprint => { + stderr_w.print("error: cannot compute fingerprint for target: {s}\n", .{raw_anchor}) catch {}; + return err; + }, + else => return err, + }; const binding = findBinding(lf.bindings.items, normalized_doc_path, normalized_target).?; if (isDocGateBlocked(binding, old_sig, doc_is_still_accurate)) { @@ -73,7 +79,13 @@ pub fn run( for (lf.bindings.items) |*binding| { if (!std.mem.eql(u8, binding.doc_path, normalized_doc_path)) continue; const old_sig = binding.fieldValue("sig"); - try refreshBindingSig(ctx, cwd_path, lf.root_path, binding); + refreshBindingSig(ctx, cwd_path, lf.root_path, binding) catch |err| switch (err) { + error.CannotComputeFingerprint => { + stderr_w.print("error: cannot compute fingerprint for target: {s}\n", .{binding.target}) catch {}; + return err; + }, + else => return err, + }; if (isDocGateBlocked(binding, old_sig, doc_is_still_accurate)) { refused_count += 1; diff --git a/src/main.zig b/src/main.zig index 838c6e4..273dfb2 100644 --- a/src/main.zig +++ b/src/main.zig @@ -250,7 +250,7 @@ pub fn main(init: std.process.Init) !void { fatal(&stderr_w.interface, "", .{}); }, error.CannotComputeFingerprint => { - fatal(&stderr_w.interface, "error: cannot compute fingerprint for anchor in '{s}'\n", .{doc_path}); + fatal(&stderr_w.interface, "", .{}); }, error.DocUnchanged => { fatal(&stderr_w.interface, "", .{}); diff --git a/src/queries/zig.scm b/src/queries/zig.scm index 94a0d87..773ca19 100644 --- a/src/queries/zig.scm +++ b/src/queries/zig.scm @@ -1,8 +1,7 @@ -; Symbol declarations in Zig +; Symbol declarations in Zig (tree-sitter-grammars/tree-sitter-zig node names) [ - (TopLevelDecl - (FnDecl - (IDENTIFIER) @name)) @definition - (VarDecl - (IDENTIFIER) @name) @definition + (function_declaration + name: (identifier) @name) @definition + (variable_declaration + . (identifier) @name) @definition ] diff --git a/src/symbols.zig b/src/symbols.zig index 0ba14db..ff77db5 100644 --- a/src/symbols.zig +++ b/src/symbols.zig @@ -217,6 +217,48 @@ test "fingerprintFileSyntax works for zig source" { try std.testing.expect(fp != null); } +test "symbol queries compile for every supported language" { + const extensions = [_][]const u8{ ".ts", ".py", ".rs", ".go", ".zig", ".java" }; + for (extensions) |ext| { + const lang_query = languageForExtension(ext) orelse return error.TestUnexpectedResult; + var error_offset: u32 = 0; + const query = ts.Query.create(lang_query.language, lang_query.query_source, &error_offset) catch { + std.debug.print("symbol query for '{s}' failed to compile at byte offset {d}\n", .{ ext, error_offset }); + return error.TestUnexpectedResult; + }; + query.destroy(); + } +} + +test "fingerprintSymbolSyntax resolves zig fn and const declarations" { + const source = + \\const std = @import("std"); + \\ + \\pub const RepoMap = struct { + \\ entries: u32, + \\}; + \\ + \\pub fn parseSpec(spec: []const u8) void { + \\ _ = spec; + \\} + \\ + ; + const lang_query = languageForExtension(".zig") orelse return error.TestUnexpectedResult; + try std.testing.expect(fingerprintSymbolSyntax(source, lang_query, "parseSpec") != null); + try std.testing.expect(fingerprintSymbolSyntax(source, lang_query, "RepoMap") != null); + try std.testing.expect(fingerprintSymbolSyntax(source, lang_query, "missing") == null); +} + +test "zig variable_declaration query matches only the declared name, not the initializer" { + const source = + \\const alias = imported_name; + \\ + ; + const lang_query = languageForExtension(".zig") orelse return error.TestUnexpectedResult; + try std.testing.expect(fingerprintSymbolSyntax(source, lang_query, "alias") != null); + try std.testing.expect(fingerprintSymbolSyntax(source, lang_query, "imported_name") == null); +} + test "computeFingerprint matches for real zig files" { const allocator = std.testing.allocator;