tiny.smg.cli.options
Defined in cli.
API (25)
Actions
Public operations.
configuredLimitscouplingOnlyValuedepthValueflagValueflagValueshasFlaghasJsoninlineOptionValueoptionNameparseByteSizepositionalsearchLimitValuesignedLimitValuesignedOptionValueslicedLenstorageLimitunsignedTraversalDepth
Types and contracts
Public types and contracts.
Values and defaults
Public values and defaults.
byte_limit_optionsmax_fragment_bytes_optionmax_git_file_list_bytes_optionmax_source_file_bytes_optionwal_recovery_limit_bytes_option
Source
Source: tools/smg/src/cli/options.zig
zig
const std = @import("std");const smg = @import("../root.zig");const text = smg.text;pub const max_source_file_bytes_option = "--max-source-file-bytes";pub const max_fragment_bytes_option = "--max-fragment-bytes";pub const max_git_file_list_bytes_option = "--max-git-file-list-bytes";pub const wal_recovery_limit_bytes_option = "--wal-recovery-limit-bytes";pub const byte_limit_options = [_][]const u8{ max_source_file_bytes_option, max_fragment_bytes_option, max_git_file_list_bytes_option, wal_recovery_limit_bytes_option,};pub const ByteLimitFailure = struct { option: []const u8, value: []const u8, reason: Reason, pub const Reason = enum { invalid_size, capacity_overflow, fragment_header, };};pub const LimitsResult = union(enum) { limits: smg.Limits, invalid: ByteLimitFailure,};pub fn positional(allocator: std.mem.Allocator, args: []const []const u8) ![]const []const u8 { var out: std.ArrayList([]const u8) = .empty; var i: usize = 0; while (i < args.len) : (i += 1) { const arg = args[i]; if (std.mem.startsWith(u8, arg, "--")) { if (takesValue(arg) and inlineOptionValue(arg) == null and i + 1 < args.len) i += 1; continue; } try out.append(allocator, arg); } return try out.toOwnedSlice(allocator);}fn takesValue(flag: []const u8) bool { const valued = [_][]const u8{ "--file", "--line", "--doc", "--meta", "--type", "--rel", "--format", "--limit", "--depth", "--top", "--module", "--kind", "--level", "--since", "--churn-days", "--deny", "--exclude-source", "--invariant", "--forall", "--assert", "--scope", "--prefix", "--sync-point", "--tokens", "--entry-points", "--baseline", "--debounce", "--exclude", max_source_file_bytes_option, max_fragment_bytes_option, max_git_file_list_bytes_option, wal_recovery_limit_bytes_option, }; const name = optionName(flag); for (valued) |item| if (std.mem.eql(u8, name, item)) return true; return false;}pub fn optionName(arg: []const u8) []const u8 { if (!std.mem.startsWith(u8, arg, "--")) return arg; const equals = std.mem.indexOfScalar(u8, arg, '=') orelse return arg; return arg[0..equals];}pub fn inlineOptionValue(arg: []const u8) ?[]const u8 { if (!std.mem.startsWith(u8, arg, "--")) return null; const equals = std.mem.indexOfScalar(u8, arg, '=') orelse return null; return arg[equals + 1 ..];}pub fn hasFlag(args: []const []const u8, flag: []const u8) bool { for (args) |arg| if (std.mem.eql(u8, arg, flag)) return true; return false;}pub fn flagValue(args: []const []const u8, flag: []const u8) ?[]const u8 { var i: usize = 0; while (i + 1 < args.len) : (i += 1) { if (std.mem.eql(u8, optionName(args[i]), flag)) { if (inlineOptionValue(args[i])) |value| return value; } if (std.mem.eql(u8, args[i], flag)) return args[i + 1]; } if (args.len != 0 and std.mem.eql(u8, optionName(args[args.len - 1]), flag)) { if (inlineOptionValue(args[args.len - 1])) |value| return value; } return null;}pub fn flagValues(allocator: std.mem.Allocator, args: []const []const u8, flag: []const u8) ![]const []const u8 { var out: std.ArrayList([]const u8) = .empty; var i: usize = 0; while (i + 1 < args.len) : (i += 1) { if (std.mem.eql(u8, optionName(args[i]), flag)) { if (inlineOptionValue(args[i])) |value| { try out.append(allocator, value); continue; } } if (std.mem.eql(u8, args[i], flag)) { try out.append(allocator, args[i + 1]); i += 1; } } if (args.len != 0 and std.mem.eql(u8, optionName(args[args.len - 1]), flag)) { if (inlineOptionValue(args[args.len - 1])) |value| try out.append(allocator, value); } return try out.toOwnedSlice(allocator);}pub fn hasJson(args: []const []const u8) bool { return hasFlag(args, "--json") or std.mem.eql(u8, flagValue(args, "--format") orelse "", "json");}pub fn signedLimitValue(args: []const []const u8) i64 { return signedOptionValue(args, "--limit", 20);}pub fn signedOptionValue(args: []const []const u8, option: []const u8, default: i64) i64 { return if (flagValue(args, option)) |raw| std.fmt.parseInt(i64, raw, 10) catch default else default;}pub fn storageLimit(limit: i64) usize { return if (limit > 0) @intCast(limit) else 0;}pub fn slicedLen(total: usize, limit: i64) usize { if (limit == 0) return total; if (limit > 0) return @min(total, @as(usize, @intCast(limit))); const magnitude = if (limit == std.math.minInt(i64)) std.math.maxInt(u64) else @as(u64, @intCast(-limit)); const total_u64 = @as(u64, @intCast(total)); if (magnitude >= total_u64) return 0; return @intCast(total_u64 - magnitude);}pub fn searchLimitValue(args: []const []const u8) i64 { return text.parseInt(flagValue(args, "--limit") orelse "10", 10);}pub fn depthValue(args: []const []const u8) ?usize { _ = flagValue(args, "--depth") orelse return null; return unsignedTraversalDepth(signedOptionValue(args, "--depth", 0));}pub fn unsignedTraversalDepth(depth: i64) usize { return if (depth > 0) @intCast(depth) else 0;}pub fn couplingOnlyValue(args: []const []const u8) bool { var value = true; for (args) |arg| { if (std.mem.eql(u8, arg, "--coupling-only")) value = true; if (std.mem.eql(u8, arg, "--all-rels")) value = false; } return value;}pub fn parseByteSize(raw: []const u8) error{ InvalidByteSize, CapacityOverflow }!usize { const Unit = struct { suffix: []const u8, multiplier: usize, }; const units = [_]Unit{ .{ .suffix = "GiB", .multiplier = 1024 * 1024 * 1024 }, .{ .suffix = "MiB", .multiplier = 1024 * 1024 }, .{ .suffix = "KiB", .multiplier = 1024 }, .{ .suffix = "B", .multiplier = 1 }, }; var digits = raw; var multiplier: usize = 1; for (units) |unit| { if (!std.mem.endsWith(u8, raw, unit.suffix)) continue; digits = raw[0 .. raw.len - unit.suffix.len]; multiplier = unit.multiplier; break; } if (digits.len == 0) return error.InvalidByteSize; const value = std.fmt.parseUnsigned(usize, digits, 10) catch |err| switch (err) { error.InvalidCharacter => return error.InvalidByteSize, error.Overflow => return error.CapacityOverflow, }; if (value == 0) return error.InvalidByteSize; return std.math.mul(usize, value, multiplier) catch error.CapacityOverflow;}pub fn configuredLimits(args: []const []const u8, base: smg.Limits) LimitsResult { var limits = base; for (byte_limit_options) |option| { const raw = flagValue(args, option) orelse continue; const value = parseByteSize(raw) catch |err| return .{ .invalid = .{ .option = option, .value = raw, .reason = switch (err) { error.InvalidByteSize => .invalid_size, error.CapacityOverflow => .capacity_overflow, }, } }; if (std.mem.eql(u8, option, max_source_file_bytes_option)) { limits.scan.max_source_file_bytes = value; } else if (std.mem.eql(u8, option, max_fragment_bytes_option)) { if (value <= std.crypto.hash.sha2.Sha256.digest_length) return .{ .invalid = .{ .option = option, .value = raw, .reason = .fragment_header, } }; limits.scan.max_fragment_bytes = value; } else if (std.mem.eql(u8, option, max_git_file_list_bytes_option)) { limits.scan.max_git_file_list_bytes = value; } else if (std.mem.eql(u8, option, wal_recovery_limit_bytes_option)) { limits.storage.wal_recovery_limit_bytes = value; } else unreachable; } _ = limits.derive() catch unreachable; return .{ .limits = limits };}test "positional skips valued flags" { const args = [_][]const u8{ "name", "--limit", "3", "--json", "tail", "--top", "4", "--exclude", ".zig-cache", "--module", "app", "--baseline", "1:digest" }; const pos = try positional(std.testing.allocator, &args); defer std.testing.allocator.free(pos); try std.testing.expectEqual(@as(usize, 2), pos.len); try std.testing.expectEqualStrings("name", pos[0]); try std.testing.expectEqualStrings("tail", pos[1]);}test "signed option helpers preserve click-shaped values" { const limit = [_][]const u8{ "--limit", "-1" }; try std.testing.expectEqual(@as(i64, -1), signedLimitValue(&limit)); const inline_limit = [_][]const u8{"--limit=-2"}; try std.testing.expectEqual(@as(i64, -2), signedLimitValue(&inline_limit)); const inline_format = [_][]const u8{"--format=json"}; try std.testing.expectEqualStrings("json", flagValue(&inline_format, "--format").?);}test "slice and storage limits preserve signed semantics" { try std.testing.expectEqual(@as(usize, 7), slicedLen(7, 0)); try std.testing.expectEqual(@as(usize, 2), slicedLen(7, 2)); try std.testing.expectEqual(@as(usize, 6), slicedLen(7, -1)); try std.testing.expectEqual(@as(usize, 0), slicedLen(7, -20)); try std.testing.expectEqual(@as(usize, 0), storageLimit(-1)); try std.testing.expectEqual(@as(usize, 4), storageLimit(4));}test "depth and relationship options preserve python semantics" { const deps_depth = [_][]const u8{ "--depth", "-1" }; try std.testing.expectEqual(@as(?usize, 0), depthValue(&deps_depth)); const all_then_coupling = [_][]const u8{ "--all-rels", "--coupling-only" }; try std.testing.expect(couplingOnlyValue(&all_then_coupling)); const coupling_then_all = [_][]const u8{ "--coupling-only", "--all-rels" }; try std.testing.expect(!couplingOnlyValue(&coupling_then_all));}test "byte size parser accepts binary units and rejects invalid capacities" { try std.testing.expectEqual(@as(usize, 32 * 1024 * 1024), try parseByteSize("32MiB")); try std.testing.expectEqual(@as(usize, 4096), try parseByteSize("4KiB")); try std.testing.expectEqual(@as(usize, 17), try parseByteSize("17")); try std.testing.expectEqual(@as(usize, 17), try parseByteSize("17B")); try std.testing.expectError(error.InvalidByteSize, parseByteSize("0")); try std.testing.expectError(error.InvalidByteSize, parseByteSize("32MB")); try std.testing.expectError(error.CapacityOverflow, parseByteSize("999999999999999999999999GiB"));}test "configured limits map human options to their owners" { const args = [_][]const u8{ "--max-source-file-bytes=48MiB", "--max-fragment-bytes", "384MiB", "--max-git-file-list-bytes=96MiB", "--wal-recovery-limit-bytes", "512MiB", }; const configured = configuredLimits(&args, smg.default_limits).limits; try std.testing.expectEqual(@as(usize, 48 * 1024 * 1024), configured.scan.max_source_file_bytes); try std.testing.expectEqual(@as(usize, 384 * 1024 * 1024), configured.scan.max_fragment_bytes); try std.testing.expectEqual(@as(usize, 96 * 1024 * 1024), configured.scan.max_git_file_list_bytes); try std.testing.expectEqual(@as(usize, 512 * 1024 * 1024), configured.storage.wal_recovery_limit_bytes);}Source: tools/smg/src/cli/root.zig:7
zig
pub const options = @import("options.zig");Complete caller list for cli.options.flagValue
19 direct callers.
tiny.smg.cli.options.configuredLimits[function] attools/smg/src/cli/options.zig:216tiny.smg.cli.options.depthValue[function] attools/smg/src/cli/options.zig:170tiny.smg.cli.options.hasJson[function] attools/smg/src/cli/options.zig:141tiny.smg.cli.options.searchLimitValue[function] attools/smg/src/cli/options.zig:166tiny.smg.cli.options.signedOptionValue[function] attools/smg/src/cli/options.zig:149tools.smg.src.cli.options.test_signed_option_helpers_preserve_click-shaped_values[function] — test; no exact target attools/smg/src/cli/options.zig:256in nearest public ownertiny.smg.cli.optionstiny.smg.cli.validation.rejectInvalidChoiceOption[function] attools/smg/src/cli/validation/value.zig:43tiny.smg.cli.validation.rejectInvalidFloatOption[function] attools/smg/src/cli/validation/value.zig:68tiny.smg.cli.validation.rejectInvalidIntegerOption[function] attools/smg/src/cli/validation/value.zig:59tiny.smg.cli.validation.rejectInvalidIntegerRangeOption[function] attools/smg/src/cli/validation/value.zig:119tiny.smg.cli.validation.rejectInvalidLine[function] attools/smg/src/cli/validation/value.zig:130tiny.smg.command.node.list[function] attools/smg/src/command/node.zig:17tools.smg.src.command.rules.add.addKind[function] — private; no exact target attools/smg/src/command/rules/add.zig:29in nearest public ownertiny.smg.command.rules.addtools.smg.src.command.rules.add.denyRule[function] — private; no exact target attools/smg/src/command/rules/add.zig:77in nearest public ownertiny.smg.command.rules.addtools.smg.src.command.rules.add.invariantRule[function] — private; no exact target attools/smg/src/command/rules/add.zig:98in nearest public ownertiny.smg.command.rules.addtools.smg.src.command.rules.add.ruleParams[function] — private; no exact target attools/smg/src/command/rules/add.zig:147in nearest public ownertiny.smg.command.rules.addtools.smg.src.command.rules.add.ruleScope[function] — private; no exact target attools/smg/src/command/rules/add.zig:143in nearest public ownertiny.smg.command.rules.addtiny.smg.command.search.run[function] attools/smg/src/command/search.zig:13tiny.smg.command.usages.run[function] attools/smg/src/command/usages.zig:24
Complete caller list for cli.options.hasFlag
7 direct callers.
tiny.smg.cli.options.hasJson[function] attools/smg/src/cli/options.zig:141tiny.smg.command.check.run[function] attools/smg/src/command/check/run.zig:13tiny.smg.command.inspection.run[function] attools/smg/src/command/inspection.zig:5tiny.smg.command.node.show[function] attools/smg/src/command/node.zig:49tools.smg.src.command.rules.add.addKind[function] — private; no exact target attools/smg/src/command/rules/add.zig:29in nearest public ownertiny.smg.command.rules.addtools.smg.src.command.rules.add.denyRule[function] — private; no exact target attools/smg/src/command/rules/add.zig:77in nearest public ownertiny.smg.command.rules.addtiny.smg.command.search.run[function] attools/smg/src/command/search.zig:13
Complete caller list for cli.options.optionName
8 direct callers.
tiny.smg.cli.options.flagValue[function] attools/smg/src/cli/options.zig:106tiny.smg.cli.options.flagValues[function] attools/smg/src/cli/options.zig:120tools.smg.src.cli.options.takesValue[function] — private; no exact target attools/smg/src/cli/options.zig:49in nearest public ownertiny.smg.cli.optionstiny.smg.cli.validation.rejectUnexpectedOptions[function] attools/smg/src/cli/validation/unexpected.zig:9tiny.smg.cli.validation.rejectUnexpectedOptionsPlain[function] attools/smg/src/cli/validation/unexpected.zig:20tiny.smg.cli.validation.rejectUnexpectedScanOptions[function] attools/smg/src/cli/validation/unexpected.zig:31tiny.smg.cli.validation.optionWithForbiddenValue[function] attools/smg/src/cli/validation/value.zig:34tiny.smg.cli.validation.rejectMissingOptionValues[function] attools/smg/src/cli/validation/value.zig:11
Complete caller list for cli.options.positional
9 direct callers.
tools.smg.src.cli.options.test_positional_skips_valued_flags[function] — test; no exact target attools/smg/src/cli/options.zig:247in nearest public ownertiny.smg.cli.optionstiny.smg.cli.validation.validateQueryNameCommand[function] attools/smg/src/cli/validation/query.zig:11tiny.smg.command.check.run[function] attools/smg/src/command/check/run.zig:13tiny.smg.command.node.list[function] attools/smg/src/command/node.zig:17tiny.smg.command.node.show[function] attools/smg/src/command/node.zig:49tiny.smg.command.search.index[function] attools/smg/src/command/search.zig:47tiny.smg.command.search.run[function] attools/smg/src/command/search.zig:13tiny.smg.command.status.run[function] attools/smg/src/command/status.zig:12tiny.smg.command.usages.run[function] attools/smg/src/command/usages.zig:24
Audit
| Definitions | 26 |
|---|---|
| Public names | 26 |
| Members | 8 |
| Version | 26.7.0 |
| Revision | daab053ee433 |