PranitInitial commit439f83c3 months agoHistory
165 lines · 5.9 KB · Zig
RawDownload
const std = @import("std");const user_message_card = @import("../assistant/user_message_card.zig"); pub const Rgb = user_message_card.Rgb; pub const Background = struct {    light: bool,    rgb: Rgb,}; pub fn parseOsc11Response(bytes: []const u8) ?Background {    const prefix = "\x1b]11;rgb:";    if (!std.mem.startsWith(u8, bytes, prefix)) return null;     const rgb_end = if (std.mem.endsWith(u8, bytes, "\x1b\\"))        bytes.len - 2    else if (std.mem.endsWith(u8, bytes, "\x07"))        bytes.len - 1    else        return null;    if (rgb_end <= prefix.len) return null;     var components: [3]u32 = undefined;    var it = std.mem.splitScalar(u8, bytes[prefix.len..rgb_end], '/');    for (&components) |*component| {        const part = it.next() orelse return null;        component.* = normalizeOsc11Component(part) orelse return null;    }    if (it.next() != null) return null;     const luminance = (components[0] * 299 + components[1] * 587 + components[2] * 114) / 1000;    return .{        .light = luminance > 32768,        .rgb = .{            .r = @intCast(components[0] >> 8),            .g = @intCast(components[1] >> 8),            .b = @intCast(components[2] >> 8),        },    };} // Terminal.app is the one mainstream terminal that quantizes 38;2 colors// itself; every other target either sets COLORTERM or renders RGB exactly.pub fn truecolorSupportedForValues(colorterm: ?[]const u8, term_program: ?[]const u8) bool {    if (colorterm) |value| {        if (std.mem.find(u8, value, "truecolor") != null) return true;        if (std.mem.find(u8, value, "24bit") != null) return true;    }    if (term_program) |value| {        if (std.mem.eql(u8, value, "Apple_Terminal")) return false;    }    return true;} test "truecolorSupportedForValues honors COLORTERM over program name" {    try std.testing.expect(truecolorSupportedForValues("truecolor", "Apple_Terminal"));} test "truecolorSupportedForValues degrades Apple Terminal without COLORTERM" {    try std.testing.expect(!truecolorSupportedForValues(null, "Apple_Terminal"));} test "truecolorSupportedForValues defaults to truecolor for unknown terminals" {    try std.testing.expect(truecolorSupportedForValues(null, null));    try std.testing.expect(truecolorSupportedForValues(null, "ghostty"));} pub fn parseColorFgBgLight(colorfgbg: []const u8) bool {    var last_semi: ?usize = null;    for (colorfgbg, 0..) |byte, i| {        if (byte == ';') last_semi = i;    }    const bg_str = if (last_semi) |pos| colorfgbg[pos + 1 ..] else return false;    const bg = std.fmt.parseUnsigned(u8, bg_str, 10) catch return false;    return bg >= 8;} fn normalizeOsc11Component(part: []const u8) ?u32 {    if (part.len == 0 or part.len > 4) return null;    const value = std.fmt.parseUnsigned(u32, part, 16) catch return null;    const bits: u5 = @intCast(part.len * 4);    const maximum = (@as(u32, 1) << bits) - 1;    return @divTrunc(value * 0xffff, maximum);} test "COLORFGBG parser detects light terminal" {    try std.testing.expect(parseColorFgBgLight("0;15"));    try std.testing.expect(parseColorFgBgLight("0;8"));    try std.testing.expect(parseColorFgBgLight("1;3;15"));    try std.testing.expect(!parseColorFgBgLight("15;0"));    try std.testing.expect(!parseColorFgBgLight("0;7"));    try std.testing.expect(!parseColorFgBgLight(""));    try std.testing.expect(!parseColorFgBgLight("garbage"));} test "OSC 11 parser detects light background and extracts RGB" {    const white = parseOsc11Response("\x1b]11;rgb:ffff/ffff/ffff\x1b\\").?;    try std.testing.expect(white.light);    try std.testing.expectEqual(@as(u8, 0xff), white.rgb.r);     const near_white = parseOsc11Response("\x1b]11;rgb:f0f0/f0f0/f0f0\x07").?;    try std.testing.expect(near_white.light);     const black = parseOsc11Response("\x1b]11;rgb:0000/0000/0000\x1b\\").?;    try std.testing.expect(!black.light);    try std.testing.expectEqual(@as(u8, 0x00), black.rgb.r);     const dark = parseOsc11Response("\x1b]11;rgb:1c1c/1c1c/1c1c\x1b\\").?;    try std.testing.expect(!dark.light);    try std.testing.expectEqual(@as(u8, 0x1c), dark.rgb.r);     try std.testing.expect(parseOsc11Response("garbage") == null);} test "OSC 11 parser normalizes one-digit RGB channels" {    const white = parseOsc11Response("\x1b]11;rgb:f/f/f\x07").?;     try std.testing.expect(white.light);    try std.testing.expectEqual(@as(u8, 0xff), white.rgb.r);    try std.testing.expectEqual(@as(u8, 0xff), white.rgb.g);    try std.testing.expectEqual(@as(u8, 0xff), white.rgb.b);} test "OSC 11 parser supports every RGB component width" {    const white_samples = [_][]const u8{        "\x1b]11;rgb:f/f/f\x07",        "\x1b]11;rgb:ff/ff/ff\x07",        "\x1b]11;rgb:fff/fff/fff\x07",        "\x1b]11;rgb:ffff/ffff/ffff\x07",    };    const dark_samples = [_][]const u8{        "\x1b]11;rgb:4/4/4\x07",        "\x1b]11;rgb:44/44/44\x07",        "\x1b]11;rgb:444/444/444\x07",        "\x1b]11;rgb:4444/4444/4444\x07",    };     for (white_samples) |sample| {        const parsed = parseOsc11Response(sample).?;        try std.testing.expect(parsed.light);        try std.testing.expectEqual(@as(u8, 0xff), parsed.rgb.r);    }    for (dark_samples) |sample| {        const parsed = parseOsc11Response(sample).?;        try std.testing.expect(!parsed.light);        try std.testing.expectEqual(@as(u8, 0x44), parsed.rgb.r);    }} test "OSC 11 parser rejects non-OSC-11 envelopes" {    const invalid = [_][]const u8{        "rgb:ffff/ffff/ffff",        "\x1b]10;rgb:ffff/ffff/ffff\x07",        "\x1b]11;rgb:ffff/ffff/ffff",        "\x1b]11;rgb:ffff/ffff/ffff/ffff\x07",        "\x1b]11;rgb:ffff/ffff\x07",        "\x1b]11;rgb:ffff/ffff/zzzz\x07",        "\x1b]11;rgb:fffff/ffff/ffff\x07",        "\x1b]11;rgb:ffff/ffff/ffff\x07tail",    };     for (invalid) |sample| {        try std.testing.expect(parseOsc11Response(sample) == null);    }}