this repo has no description
13
fork

Configure Feed

Select the types of activity you want to include in your feed.

at 01605eebf65be21caa85ee9d840047f864553308 203 lines 5.9 kB view raw
1const std = @import("std"); 2const Image = @import("Image.zig"); 3 4char: Character = .{}, 5style: Style = .{}, 6link: Hyperlink = .{}, 7image: ?Image.Placement = null, 8default: bool = false, 9/// Set to true if this cell is the last cell printed in a row before wrap. Vaxis will determine if 10/// it should rely on the terminal's autowrap feature which can help with primary screen resizes 11wrapped: bool = false, 12 13/// Segment is a contiguous run of text that has a constant style 14pub const Segment = struct { 15 text: []const u8, 16 style: Style = .{}, 17 link: Hyperlink = .{}, 18}; 19 20pub const Character = struct { 21 grapheme: []const u8 = " ", 22 /// width should only be provided when the application is sure the terminal 23 /// will measure the same width. This can be ensure by using the gwidth method 24 /// included in libvaxis. If width is 0, libvaxis will measure the glyph at 25 /// render time 26 width: u8 = 1, 27}; 28 29pub const CursorShape = enum { 30 default, 31 block_blink, 32 block, 33 underline_blink, 34 underline, 35 beam_blink, 36 beam, 37}; 38 39pub const Hyperlink = struct { 40 uri: []const u8 = "", 41 /// ie "id=app-1234" 42 params: []const u8 = "", 43}; 44 45pub const Style = struct { 46 pub const Underline = enum { 47 off, 48 single, 49 double, 50 curly, 51 dotted, 52 dashed, 53 }; 54 55 fg: Color = .default, 56 bg: Color = .default, 57 ul: Color = .default, 58 ul_style: Underline = .off, 59 60 bold: bool = false, 61 dim: bool = false, 62 italic: bool = false, 63 blink: bool = false, 64 reverse: bool = false, 65 invisible: bool = false, 66 strikethrough: bool = false, 67 68 pub fn eql(a: Style, b: Style) bool { 69 const SGRBits = packed struct { 70 bold: bool, 71 dim: bool, 72 italic: bool, 73 blink: bool, 74 reverse: bool, 75 invisible: bool, 76 strikethrough: bool, 77 }; 78 const a_sgr: SGRBits = .{ 79 .bold = a.bold, 80 .dim = a.dim, 81 .italic = a.italic, 82 .blink = a.blink, 83 .reverse = a.reverse, 84 .invisible = a.invisible, 85 .strikethrough = a.strikethrough, 86 }; 87 const b_sgr: SGRBits = .{ 88 .bold = b.bold, 89 .dim = b.dim, 90 .italic = b.italic, 91 .blink = b.blink, 92 .reverse = b.reverse, 93 .invisible = b.invisible, 94 .strikethrough = b.strikethrough, 95 }; 96 const a_cast: u7 = @bitCast(a_sgr); 97 const b_cast: u7 = @bitCast(b_sgr); 98 return a_cast == b_cast and 99 Color.eql(a.fg, b.fg) and 100 Color.eql(a.bg, b.bg) and 101 Color.eql(a.ul, b.ul) and 102 a.ul_style == b.ul_style; 103 } 104}; 105 106pub const Color = union(enum) { 107 default, 108 index: u8, 109 rgb: [3]u8, 110 111 pub const Kind = union(enum) { 112 fg, 113 bg, 114 cursor, 115 index: u8, 116 }; 117 118 /// Returned when querying a color from the terminal 119 pub const Report = struct { 120 kind: Kind, 121 value: [3]u8, 122 }; 123 124 pub const Scheme = enum { 125 dark, 126 light, 127 }; 128 129 pub fn eql(a: Color, b: Color) bool { 130 switch (a) { 131 .default => return b == .default, 132 .index => |a_idx| { 133 switch (b) { 134 .index => |b_idx| return a_idx == b_idx, 135 else => return false, 136 } 137 }, 138 .rgb => |a_rgb| { 139 switch (b) { 140 .rgb => |b_rgb| return a_rgb[0] == b_rgb[0] and 141 a_rgb[1] == b_rgb[1] and 142 a_rgb[2] == b_rgb[2], 143 else => return false, 144 } 145 }, 146 } 147 } 148 149 pub fn rgbFromUint(val: u24) Color { 150 const r_bits = val & 0b11111111_00000000_00000000; 151 const g_bits = val & 0b00000000_11111111_00000000; 152 const b_bits = val & 0b00000000_00000000_11111111; 153 const rgb = [_]u8{ 154 @truncate(r_bits >> 16), 155 @truncate(g_bits >> 8), 156 @truncate(b_bits), 157 }; 158 return .{ .rgb = rgb }; 159 } 160 161 /// parse an XParseColor-style rgb specification into an rgb Color. The spec 162 /// is of the form: rgb:rrrr/gggg/bbbb. Generally, the high two bits will always 163 /// be the same as the low two bits. 164 pub fn rgbFromSpec(spec: []const u8) !Color { 165 var iter = std.mem.splitScalar(u8, spec, ':'); 166 const prefix = iter.next() orelse return error.InvalidColorSpec; 167 if (!std.mem.eql(u8, "rgb", prefix)) return error.InvalidColorSpec; 168 169 const spec_str = iter.next() orelse return error.InvalidColorSpec; 170 171 var spec_iter = std.mem.splitScalar(u8, spec_str, '/'); 172 173 const r_raw = spec_iter.next() orelse return error.InvalidColorSpec; 174 if (r_raw.len != 4) return error.InvalidColorSpec; 175 176 const g_raw = spec_iter.next() orelse return error.InvalidColorSpec; 177 if (g_raw.len != 4) return error.InvalidColorSpec; 178 179 const b_raw = spec_iter.next() orelse return error.InvalidColorSpec; 180 if (b_raw.len != 4) return error.InvalidColorSpec; 181 182 const r = try std.fmt.parseUnsigned(u8, r_raw[2..], 16); 183 const g = try std.fmt.parseUnsigned(u8, g_raw[2..], 16); 184 const b = try std.fmt.parseUnsigned(u8, b_raw[2..], 16); 185 186 return .{ 187 .rgb = [_]u8{ r, g, b }, 188 }; 189 } 190 191 test "rgbFromSpec" { 192 const spec = "rgb:aaaa/bbbb/cccc"; 193 const actual = try rgbFromSpec(spec); 194 switch (actual) { 195 .rgb => |rgb| { 196 try std.testing.expectEqual(0xAA, rgb[0]); 197 try std.testing.expectEqual(0xBB, rgb[1]); 198 try std.testing.expectEqual(0xCC, rgb[2]); 199 }, 200 else => try std.testing.expect(false), 201 } 202 } 203};