tiny.smg.command.search
Defined in command.
API (5)
Actions
Public operations.
Source
Source: tools/smg/src/command/root.zig:20
zig
pub const search = @import("search.zig");Source: tools/smg/src/command/search.zig
zig
const std = @import("std");const pretty_json = @import("pretty").json;const smg = @import("../root.zig");const options = smg.cli.options;const output = smg.cli.output;const search_mod = smg.search;const session = smg.command.session;const storage = smg.storage;const table = smg.cli.table;const validation = smg.cli.validation;pub fn run(allocator: std.mem.Allocator, _: std.mem.Allocator, args: []const []const u8, limits: smg.Limits, boundary: session.PhaseBoundary) !u8 { const pos = try options.positional(allocator, args); if (pos.len < 1) return error.MissingArgument; const root = try storage.requireRoot(allocator); try session.noteGraphAge(allocator, root); const kind = options.flagValue(args, "--kind"); const limit = options.searchLimitValue(args); const result = search_mod.searchStored( allocator, root, pos[0], kind, limit, limits.storage, ) catch |err| switch (err) { search_mod.Error.InvalidSearchQuery => { try output.writeErrFmt(allocator, "Error: invalid search query: '{s}'\n", .{pos[0]}); return 2; }, else => return err, }; boundary.seal(); defer boundary.beginTeardown(); if (options.hasJson(args)) return try writeJson(allocator, result, limit); if (result.hits.len == 0) return try output.writeOut("No results.\n"); var out: std.Io.Writer.Allocating = .init(allocator); if (options.hasFlag(args, "--full")) { try writeFull(allocator, &out.writer, result); } else { try writeTable(allocator, &out.writer, result); } return try output.writeOut(out.written());}pub fn index(allocator: std.mem.Allocator, phases: std.mem.Allocator, args: []const []const u8, limits: smg.Limits) !u8 { if (try validation.rejectUnexpectedOptionsPlain(allocator, "index", "[OPTIONS]", args, &.{})) return 2; const pos = try options.positional(allocator, args); if (pos.len != 0) { try output.writeClickUsageError(allocator, "index", "[OPTIONS]", try validation.unexpectedArgumentMessage(allocator, pos)); return 2; } const root = try storage.requireRoot(allocator); const count = try search_mod.rebuildStored(phases, root, limits); return try output.writeOutFmt(allocator, "Indexed {d} nodes into search cache\n", .{count});}pub fn writeJson(allocator: std.mem.Allocator, result: search_mod.Result, limit: i64) !u8 { var out: std.Io.Writer.Allocating = .init(allocator); var writer = pretty_json.Writer.init(&out.writer, .minified); try writer.beginObject(); try writer.objectField("rows"); try writer.beginArray(); for (result.hits) |hit| { try writer.beginObject(); try writer.objectField("rank"); try writer.write(hit.rank); try writer.objectField("kind"); try writer.write(hit.kind); try writer.objectField("name"); try writer.write(hit.name); try writer.objectField("location"); try writer.write(try search_mod.location(allocator, hit)); try writer.objectField("snippet"); try writer.write(search_mod.snippet(hit)); try writer.endObject(); } try writer.endArray(); try writer.objectField("total"); try writer.write(result.total); try writer.objectField("displayed"); try writer.write(result.hits.len); try writer.objectField("truncated"); try writer.write(result.total > @as(i64, @intCast(result.hits.len))); try writer.objectField("limit"); try writer.write(limit); try writer.endObject(); try out.writer.writeByte('\n'); return try output.writeOut(out.written());}pub fn writeTable(allocator: std.mem.Allocator, writer: *std.Io.Writer, result: search_mod.Result) !void { const columns = [_]table.Column{ .{ .header = "rank", .alignment = .right, .max_width = 6 }, .{ .header = "kind", .max_width = 12 }, .{ .header = "name", .max_width = 40 }, .{ .header = "location", .max_width = 30 }, .{ .header = "snippet", .max_width = 40 }, }; var scratch_state = std.heap.ArenaAllocator.init(allocator); defer scratch_state.deinit(); const scratch = scratch_state.allocator(); var rows: std.ArrayList([]const []const u8) = .empty; for (result.hits) |hit| { try table.appendRow(scratch, &rows, &.{ try std.fmt.allocPrint(scratch, "{d}", .{hit.rank}), hit.kind, hit.name, try search_mod.location(scratch, hit), search_mod.snippet(hit), }); } const total = if (result.total > 0) @as(usize, @intCast(result.total)) else result.hits.len; try table.write(allocator, writer, &columns, rows.items, total);}pub fn writeFull(allocator: std.mem.Allocator, writer: *std.Io.Writer, result: search_mod.Result) !void { for (result.hits) |hit| { try writer.print("{d}. [{s}] {s}\n", .{ hit.rank, hit.kind, hit.name }); try writer.print(" {s}\n", .{try search_mod.location(allocator, hit)}); if (hit.docstring) |doc| { if (doc.len != 0) { var lines = std.mem.splitScalar(u8, doc, '\n'); var count: usize = 0; while (count < 5) : (count += 1) { const line = lines.next() orelse break; try writer.print(" {s}\n", .{line}); } } } try writer.writeByte('\n'); } if (result.total > @as(i64, @intCast(result.hits.len))) try writer.print("(showing {d} of {d} -- use --limit 0 for all, --json for exact records)\n", .{ result.hits.len, result.total });}test "search renders table and full text" { var arena = std.heap.ArenaAllocator.init(std.testing.allocator); defer arena.deinit(); const allocator = arena.allocator(); const hits = [_]search_mod.Hit{ .{ .rank = 1, .name = "app.handler", .kind = "function", .file = "src/app.py", .line_start = 12, .line_end = 14, .docstring = "first line\nsecond line", .score = 10, }, .{ .rank = 2, .name = "app.module", .kind = "module", .file = null, .line_start = null, .line_end = null, .docstring = null, .score = 5, }, }; const result: search_mod.Result = .{ .hits = &hits, .total = 3 }; var table_out: std.Io.Writer.Allocating = .init(allocator); try writeTable(allocator, &table_out.writer, result); try std.testing.expect(std.mem.indexOf(u8, table_out.written(), "rank") != null); try std.testing.expect(std.mem.indexOf(u8, table_out.written(), "app.handler") != null); try std.testing.expect(std.mem.indexOf(u8, table_out.written(), "src/app.py:12") != null); try std.testing.expect(std.mem.indexOf(u8, table_out.written(), "first line") != null); try std.testing.expect(std.mem.indexOf(u8, table_out.written(), "showing 2 of 3") != null); var full_out: std.Io.Writer.Allocating = .init(allocator); try writeFull(allocator, &full_out.writer, result); try std.testing.expect(std.mem.indexOf(u8, full_out.written(), "1. [function] app.handler\n") != null); try std.testing.expect(std.mem.indexOf(u8, full_out.written(), " src/app.py:12\n") != null); try std.testing.expect(std.mem.indexOf(u8, full_out.written(), " first line\n") != null); try std.testing.expect(std.mem.indexOf(u8, full_out.written(), "(showing 2 of 3 -- use --limit 0 for all, --json for exact records)\n") != null);}Complete call list for command.search.run
11 direct calls.
tiny.smg.cli.options.flagValue[function] attools/smg/src/cli/options.zig:106tiny.smg.cli.options.hasFlag[function] attools/smg/src/cli/options.zig:101tiny.smg.cli.options.hasJson[function] attools/smg/src/cli/options.zig:141tiny.smg.cli.options.positional[function] attools/smg/src/cli/options.zig:35tiny.smg.cli.options.searchLimitValue[function] attools/smg/src/cli/options.zig:166tiny.smg.cli.output.writeErrFmt[function] attools/smg/src/cli/output.zig:27tiny.smg.cli.output.writeOut[function] attools/smg/src/cli/output.zig:8tiny.smg.command.search.writeFull[function] attools/smg/src/command/search.zig:118tiny.smg.command.search.writeJson[function] attools/smg/src/command/search.zig:59tiny.smg.command.search.writeTable[function] attools/smg/src/command/search.zig:93tiny.smg.command.session.noteGraphAge[function] attools/smg/src/command/session.zig:104
Audit
| Definitions | 6 |
|---|---|
| Public names | 6 |
| Members | 0 |
| Version | 26.7.0 |
| Revision | daab053ee433 |