lib/tracy/src/cli/args/find.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const std = @import("std");
2 const tracy = @import("../../root.zig");
3 const scalar = @import("scalar.zig");
4 const types = @import("types.zig");
5
6 pub fn parse(args: []const []const u8) !types.FindArgs {
7 if (args.len < 2) return error.InvalidArguments;
8 var parsed = types.FindArgs{
9 .path = args[0],
10 .options = .{ .pattern = args[1] },
11 };
12 var around_ns: ?u64 = null;
13 var window_ns: ?u64 = null;
14 var index: usize = 2;
15 while (index < args.len) : (index += 1) {
16 if (std.mem.eql(u8, args[index], "--format")) {
17 index += 1;
18 if (index >= args.len) return error.InvalidArguments;
19 if (std.mem.eql(u8, args[index], "text")) {
20 parsed.format = .text;
21 } else if (std.mem.eql(u8, args[index], "jsonl")) {
22 parsed.format = .jsonl;
23 } else {
24 return error.UnsupportedFormat;
25 }
26 } else if (std.mem.eql(u8, args[index], "--top")) {
27 index += 1;
28 if (index >= args.len) return error.InvalidArguments;
29 parsed.options.top = try scalar.parsePositiveUsize(args[index]);
30 } else if (std.mem.eql(u8, args[index], "--occurrences")) {
31 index += 1;
32 if (index >= args.len) return error.InvalidArguments;
33 parsed.options.occurrences = try scalar.parseUsize(args[index]);
34 } else if (std.mem.eql(u8, args[index], "--group")) {
35 index += 1;
36 if (index >= args.len) return error.InvalidArguments;
37 parsed.options.group = tracy.find.Group.fromName(args[index]) orelse return error.UnsupportedGroup;
38 } else if (std.mem.eql(u8, args[index], "--sort")) {
39 index += 1;
40 if (index >= args.len) return error.InvalidArguments;
41 parsed.options.sort = tracy.find.Sort.fromName(args[index]) orelse return error.UnsupportedSort;
42 } else if (std.mem.eql(u8, args[index], "--thread")) {
43 index += 1;
44 if (index >= args.len) return error.InvalidArguments;
45 parsed.options.thread = try scalar.parseU64(args[index]);
46 } else if (std.mem.eql(u8, args[index], "--since-ns")) {
47 index += 1;
48 if (index >= args.len) return error.InvalidArguments;
49 parsed.options.since_ns = try scalar.parseU64(args[index]);
50 } else if (std.mem.eql(u8, args[index], "--until-ns")) {
51 index += 1;
52 if (index >= args.len) return error.InvalidArguments;
53 parsed.options.until_ns = try scalar.parseU64(args[index]);
54 } else if (std.mem.eql(u8, args[index], "--around-ns")) {
55 index += 1;
56 if (index >= args.len) return error.InvalidArguments;
57 around_ns = try scalar.parseU64(args[index]);
58 } else if (std.mem.eql(u8, args[index], "--window-ns")) {
59 index += 1;
60 if (index >= args.len) return error.InvalidArguments;
61 window_ns = try scalar.parseU64(args[index]);
62 } else if (std.mem.eql(u8, args[index], "--min-duration-ns")) {
63 index += 1;
64 if (index >= args.len) return error.InvalidArguments;
65 parsed.options.min_duration_ns = try scalar.parseU64(args[index]);
66 } else if (std.mem.eql(u8, args[index], "--ignore-case")) {
67 parsed.options.ignore_case = true;
68 } else {
69 return error.UnknownArgument;
70 }
71 }
72 if (around_ns) |center| {
73 if (parsed.options.since_ns != null or parsed.options.until_ns != null) return error.InvalidArguments;
74 const width = window_ns orelse 1_000_000;
75 const half = width / 2;
76 parsed.options.since_ns = if (center > half) center - half else 0;
77 parsed.options.until_ns = center +| (width - half);
78 } else if (window_ns != null) {
79 return error.InvalidArguments;
80 }
81 if (parsed.options.since_ns != null and parsed.options.until_ns != null and parsed.options.since_ns.? > parsed.options.until_ns.?) {
82 return error.InvalidArguments;
83 }
84 return parsed;
85 }
86
87 test "find args parse filters window and grouping" {
88 const parsed = try parse(&.{
89 "events.jsonl",
90 "phase",
91 "--format",
92 "jsonl",
93 "--top",
94 "12",
95 "--occurrences",
96 "4",
97 "--group",
98 "parent",
99 "--sort",
100 "self",
101 "--thread",
102 "7",
103 "--around-ns",
104 "1000",
105 "--window-ns",
106 "200",
107 "--min-duration-ns",
108 "50",
109 "--ignore-case",
110 });
111 try std.testing.expectEqualStrings("events.jsonl", parsed.path);
112 try std.testing.expectEqualStrings("phase", parsed.options.pattern);
113 try std.testing.expectEqual(types.Format.jsonl, parsed.format);
114 try std.testing.expectEqual(@as(usize, 12), parsed.options.top);
115 try std.testing.expectEqual(@as(usize, 4), parsed.options.occurrences);
116 try std.testing.expectEqual(tracy.find.Group.parent, parsed.options.group);
117 try std.testing.expectEqual(tracy.find.Sort.self, parsed.options.sort);
118 try std.testing.expectEqual(@as(?u64, 7), parsed.options.thread);
119 try std.testing.expectEqual(@as(?u64, 900), parsed.options.since_ns);
120 try std.testing.expectEqual(@as(?u64, 1100), parsed.options.until_ns);
121 try std.testing.expectEqual(@as(u64, 50), parsed.options.min_duration_ns);
122 try std.testing.expect(parsed.options.ignore_case);
123 }