const std = @import("std"); const meta = std.meta; const expect = std.testing.expect; const expectEqual = std.testing.expectEqual; pub const ColorRGB = struct { r: u8, g: u8, b: u8, const Self = @This(); pub fn eql(self: Self, other: Self) bool { return meta.eql(self, other); } }; pub const Color = union(enum) { Default, Black, Red, Green, Yellow, Blue, Magenta, Cyan, White, Fixed: u8, Grey: u8, RGB: ColorRGB, const Self = @This(); pub fn eql(self: Self, other: Self) bool { return meta.eql(self, other); } }; pub const FontStyle = packed struct { bold: bool = false, dim: bool = false, italic: bool = false, underline: bool = false, slowblink: bool = false, rapidblink: bool = false, reverse: bool = false, hidden: bool = false, crossedout: bool = false, fraktur: bool = false, overline: bool = false, const Self = @This(); pub const bold = Self{ .bold = true, }; pub const dim = Self{ .dim = true, }; pub const italic = Self{ .italic = true, }; pub const underline = Self{ .underline = true, }; pub const slowblink = Self{ .slowblink = true, }; pub const rapidblink = Self{ .rapidblink = true, }; pub const reverse = Self{ .reverse = true, }; pub const hidden = Self{ .hidden = true, }; pub const crossedout = Self{ .crossedout = true, }; pub const fraktur = Self{ .fraktur = true, }; pub const overline = Self{ .overline = true, }; pub fn toU11(self: Self) u11 { return @bitCast(self); } pub fn fromU11(bits: u11) Self { return @bitCast(bits); } /// Returns true iff this font style contains no attributes pub fn isDefault(self: Self) bool { return self.toU11() == 0; } /// Returns true iff these font styles contain exactly the same /// attributes pub fn eql(self: Self, other: Self) bool { return self.toU11() == other.toU11(); } /// Returns true iff self is a subset of the attributes of /// other, i.e. all attributes of self are at least present in /// other as well pub fn subsetOf(self: Self, other: Self) bool { return self.toU11() & other.toU11() == self.toU11(); } /// Returns this font style with all attributes removed that are /// contained in other pub fn without(self: Self, other: Self) Self { return fromU11(self.toU11() & ~other.toU11()); } }; test "FontStyle bits" { try expectEqual(@as(u11, 0), (FontStyle{}).toU11()); try expectEqual(@as(u11, 1), (FontStyle.bold).toU11()); try expectEqual(@as(u11, 1 << 2), (FontStyle.italic).toU11()); try expectEqual(@as(u11, 1 << 2) | 1, (FontStyle{ .bold = true, .italic = true }).toU11()); try expectEqual(FontStyle{}, FontStyle.fromU11((FontStyle{}).toU11())); try expectEqual(FontStyle.bold, FontStyle.fromU11((FontStyle.bold).toU11())); } test "FontStyle subsetOf" { const default = FontStyle{}; const bold = FontStyle.bold; const italic = FontStyle.italic; const bold_and_italic = FontStyle{ .bold = true, .italic = true }; try expect(default.subsetOf(default)); try expect(default.subsetOf(bold)); try expect(bold.subsetOf(bold)); try expect(!bold.subsetOf(default)); try expect(!bold.subsetOf(italic)); try expect(default.subsetOf(bold_and_italic)); try expect(bold.subsetOf(bold_and_italic)); try expect(italic.subsetOf(bold_and_italic)); try expect(bold_and_italic.subsetOf(bold_and_italic)); try expect(!bold_and_italic.subsetOf(bold)); try expect(!bold_and_italic.subsetOf(italic)); try expect(!bold_and_italic.subsetOf(default)); } test "FontStyle without" { const default = FontStyle{}; const bold = FontStyle.bold; const italic = FontStyle.italic; const bold_and_italic = FontStyle{ .bold = true, .italic = true }; try expectEqual(default, default.without(default)); try expectEqual(bold, bold.without(default)); try expectEqual(default, bold.without(bold)); try expectEqual(bold, bold.without(italic)); try expectEqual(bold, bold_and_italic.without(italic)); try expectEqual(italic, bold_and_italic.without(bold)); try expectEqual(default, bold_and_italic.without(bold_and_italic)); } pub const Style = struct { foreground: Color = .Default, background: Color = .Default, font_style: FontStyle = FontStyle{}, const Self = @This(); /// Returns true iff this style equals the other style in /// foreground color, background color and font style pub fn eql(self: Self, other: Self) bool { if (!self.font_style.eql(other.font_style)) return false; if (!meta.eql(self.foreground, other.foreground)) return false; return meta.eql(self.background, other.background); } /// Returns true iff this style equals the default set of styles pub fn isDefault(self: Self) bool { return eql(self, Self{}); } // pub const parse = @import("parse_style.zig").parseStyle; }; test "style equality" { const a = Style{}; const b = Style{ .font_style = FontStyle.bold, }; const c = Style{ .foreground = Color.Red, }; try expect(a.isDefault()); try expect(a.eql(a)); try expect(b.eql(b)); try expect(c.eql(c)); try expect(!a.eql(b)); try expect(!b.eql(a)); try expect(!a.eql(c)); }