diff --git a/src/agent/Terminal.zig b/src/agent/Terminal.zig index c3e11f15..fefeb323 100644 --- a/src/agent/Terminal.zig +++ b/src/agent/Terminal.zig @@ -5,7 +5,6 @@ const Config = lp.Config; const Command = lp.script.Command; const SlashCommand = @import("SlashCommand.zig"); const Spinner = @import("Spinner.zig"); -const string = @import("../string.zig"); const c = @cImport({ @cInclude("isocline.h"); }); @@ -428,7 +427,7 @@ fn highlighterCallback(henv: ?*c.ic_highlight_env_t, input: [*c]const u8, _: ?*a // ALL CAPS but unknown → typo (red); lowercase/mixed → natural language (unstyled). const style: ?[*:0]const u8 = if (isKnownCommand(cmd)) style_cmd - else if (string.isAllUpper(cmd)) + else if (looksLikeKeyword(cmd)) style_err else null; @@ -437,6 +436,14 @@ fn highlighterCallback(henv: ?*c.ic_highlight_env_t, input: [*c]const u8, _: ?*a } } +fn looksLikeKeyword(s: []const u8) bool { + if (s.len == 0) return false; + for (s) |ch| { + if (!std.ascii.isUpper(ch) and !std.ascii.isDigit(ch) and ch != '_') return false; + } + return true; +} + fn isKnownCommand(name: []const u8) bool { for (Command.keywords) |kw| { if (std.mem.eql(u8, kw.name, name)) return true; diff --git a/src/script/Command.zig b/src/script/Command.zig index dca46572..34ba1aa1 100644 --- a/src/script/Command.zig +++ b/src/script/Command.zig @@ -599,6 +599,11 @@ fn getJsonI32(o: std.json.ObjectMap, key: []const u8, default: i32) i32 { // --- Tests --- +fn testUpcase(ar: std.mem.Allocator, input: []const u8) []const u8 { + const out = ar.alloc(u8, input.len) catch return input; + return std.ascii.upperString(out, input); +} + test "parse GOTO" { const cmd = parse("GOTO https://example.com"); try std.testing.expectEqualStrings("https://example.com", cmd.goto); @@ -1188,15 +1193,7 @@ test "toToolCall: substitute callback applied to selector fields" { defer arena.deinit(); const a = arena.allocator(); - const upcase = struct { - fn f(ar: std.mem.Allocator, input: []const u8) []const u8 { - const out = ar.alloc(u8, input.len) catch return input; - for (input, 0..) |c, i| out[i] = std.ascii.toUpper(c); - return out; - } - }.f; - - const tc = toToolCall(a, .{ .click = "abc" }, upcase).?; + const tc = toToolCall(a, .{ .click = "abc" }, testUpcase).?; try std.testing.expectEqualStrings("click", tc.name); try std.testing.expectEqualStrings("{\"selector\":\"ABC\"}", tc.args_json); } @@ -1206,15 +1203,7 @@ test "toToolCall: type_cmd value is NOT substituted" { defer arena.deinit(); const a = arena.allocator(); - const upcase = struct { - fn f(ar: std.mem.Allocator, input: []const u8) []const u8 { - const out = ar.alloc(u8, input.len) catch return input; - for (input, 0..) |c, i| out[i] = std.ascii.toUpper(c); - return out; - } - }.f; - - const tc = toToolCall(a, .{ .type_cmd = .{ .selector = "abc", .value = "$LP_PASSWORD" } }, upcase).?; + const tc = toToolCall(a, .{ .type_cmd = .{ .selector = "abc", .value = "$LP_PASSWORD" } }, testUpcase).?; try std.testing.expectEqualStrings("fill", tc.name); // selector substituted, value preserved as $LP_* reference try std.testing.expectEqualStrings("{\"selector\":\"ABC\",\"value\":\"$LP_PASSWORD\"}", tc.args_json); diff --git a/src/string.zig b/src/string.zig index 03c35bc9..c91b75d9 100644 --- a/src/string.zig +++ b/src/string.zig @@ -311,14 +311,6 @@ pub fn isAllWhitespace(text: []const u8) bool { } else true; } -pub fn isAllUpper(s: []const u8) bool { - if (s.len == 0) return false; - for (s) |ch| { - if (!std.ascii.isUpper(ch) and !std.ascii.isDigit(ch) and ch != '_') return false; - } - return true; -} - // Discriminatory type that signals the bridge to use arena instead of call_arena // Use this for strings that need to persist beyond the current call // The caller can unwrap and store just the underlying .str field @@ -341,17 +333,6 @@ fn asUint(comptime string: anytype) std.meta.Int( const testing = @import("testing.zig"); -test "isAllUpper" { - try testing.expectEqual(false, isAllUpper("")); - try testing.expectEqual(true, isAllUpper("GOTO")); - try testing.expectEqual(true, isAllUpper("ACCEPT_COOKIES")); - try testing.expectEqual(true, isAllUpper("X1")); - try testing.expectEqual(true, isAllUpper("_")); - try testing.expectEqual(false, isAllUpper("Goto")); - try testing.expectEqual(false, isAllUpper("goto")); - try testing.expectEqual(false, isAllUpper("GO TO")); -} - test "String" { const other_short = try String.init(undefined, "other_short", .{}); const other_long = try String.init(testing.allocator, "other_long" ** 100, .{});