this repo has no description
13
fork

Configure Feed

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

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