diff --git a/Cargo.toml b/Cargo.toml index 9cb8b828..01ee2d4f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,6 +50,7 @@ rmp = "^0.8" rmpv = { version = "^0.4.2", features=["with-serde",] } rmp-serde = "^0.14.0" smallvec = { version = "1.1.0", features = ["serde", ] } +bitflags = "1.0" [profile.release] diff --git a/meli-themes.5 b/meli-themes.5 index 740b5cee..cbe74658 100644 --- a/meli-themes.5 +++ b/meli-themes.5 @@ -104,17 +104,19 @@ Case-sensitive. .It "Bold" .It +"Dim" +.It +"Italics" +.It "Underline" .It -"BoldUnderline" +"Blink" .It "Reverse" .It -"BoldReverse" +"Hidden" .It -"UnderlineReverse" -.It -"BoldReverseUnderline" +Any combo of the above separated by a bitwise XOR "\&|" eg "Dim | Italics" .El .Sh VALID COLOR VALUES Color values are of type String with the following valid contents: diff --git a/src/bin.rs b/src/bin.rs index d0ddf2d9..1d4ff1fc 100644 --- a/src/bin.rs +++ b/src/bin.rs @@ -45,6 +45,8 @@ extern crate nom; extern crate serde_json; extern crate smallvec; +#[macro_use] +extern crate bitflags; #[global_allocator] static GLOBAL: System = System; diff --git a/src/components/contacts/contact_list.rs b/src/components/contacts/contact_list.rs index 5bec1f0d..6f34a8cc 100644 --- a/src/components/contacts/contact_list.rs +++ b/src/components/contacts/contact_list.rs @@ -287,13 +287,13 @@ impl ContactList { if a.name.grapheme_len() + s.len() > width + 1 { /* Print account name */ let (x, y) = - write_string_to_grid(&a.name, grid, fg_color, bg_color, Attr::Bold, area, None); + write_string_to_grid(&a.name, grid, fg_color, bg_color, Attr::BOLD, area, None); write_string_to_grid( &s, grid, fg_color, bg_color, - Attr::Bold, + Attr::BOLD, ( pos_dec( (get_x(bottom_right!(area)), get_y(upper_left!(area))), @@ -308,7 +308,7 @@ impl ContactList { grid, fg_color, bg_color, - Attr::Bold, + Attr::BOLD, ( pos_dec( (get_x(bottom_right!(area)), get_y(upper_left!(area))), @@ -327,13 +327,13 @@ impl ContactList { /* Print account name */ let (x, y) = - write_string_to_grid(&a.name, grid, fg_color, bg_color, Attr::Bold, area, None); + write_string_to_grid(&a.name, grid, fg_color, bg_color, Attr::BOLD, area, None); write_string_to_grid( &s, grid, fg_color, bg_color, - Attr::Bold, + Attr::BOLD, ( pos_dec( (get_x(bottom_right!(area)), get_y(upper_left!(area))), diff --git a/src/components/mail/compose.rs b/src/components/mail/compose.rs index 9ce5a462..d6eeff46 100644 --- a/src/components/mail/compose.rs +++ b/src/components/mail/compose.rs @@ -457,7 +457,7 @@ impl Component for Composer { grid, Color::Byte(189), Color::Byte(167), - Attr::Default, + Attr::DEFAULT, ( pos_dec(upper_left!(header_area), (0, 1)), bottom_right!(header_area), diff --git a/src/components/mail/listing.rs b/src/components/mail/listing.rs index 6820b453..5b3d2f0a 100644 --- a/src/components/mail/listing.rs +++ b/src/components/mail/listing.rs @@ -1226,7 +1226,7 @@ impl Listing { grid, self.theme_default.fg, self.theme_default.bg, - Attr::Bold, + Attr::BOLD, area, None, ); @@ -1262,9 +1262,9 @@ impl Listing { ); if !context.settings.terminal.use_color() { - ret.0.attrs |= Attr::Reverse; - ret.1.attrs |= Attr::Reverse; - ret.2.attrs |= Attr::Reverse; + ret.0.attrs |= Attr::REVERSE; + ret.1.attrs |= Attr::REVERSE; + ret.2.attrs |= Attr::REVERSE; } ret } else { @@ -1349,9 +1349,9 @@ impl Listing { unread_count_att.bg, unread_count_att.attrs | if count.unwrap_or(0) > 0 { - Attr::Bold + Attr::BOLD } else { - Attr::Default + Attr::DEFAULT }, ( ( diff --git a/src/components/mail/listing/compact.rs b/src/components/mail/listing/compact.rs index 33828d28..ad5927a0 100644 --- a/src/components/mail/listing/compact.rs +++ b/src/components/mail/listing/compact.rs @@ -127,7 +127,7 @@ impl MailListingTrait for CompactListing { ..self.color_cache }; if !context.settings.terminal.use_color() { - self.color_cache.highlighted.attrs |= Attr::Reverse; + self.color_cache.highlighted.attrs |= Attr::REVERSE; } // Get mailbox as a reference. @@ -1040,7 +1040,7 @@ impl CompactListing { &mut columns[0], fg_color, bg_color, - Attr::Default, + Attr::DEFAULT, ((0, idx), (min_width.0, idx)), None, ); @@ -1052,7 +1052,7 @@ impl CompactListing { &mut columns[1], fg_color, bg_color, - Attr::Default, + Attr::DEFAULT, ((0, idx), (min_width.1.saturating_sub(1), idx)), None, ); @@ -1064,7 +1064,7 @@ impl CompactListing { &mut columns[2], fg_color, bg_color, - Attr::Default, + Attr::DEFAULT, ((0, idx), (min_width.2, idx)), None, ); @@ -1076,7 +1076,7 @@ impl CompactListing { &mut columns[3], fg_color, bg_color, - Attr::Default, + Attr::DEFAULT, ((0, idx), (min_width.3, idx)), None, ); @@ -1088,7 +1088,7 @@ impl CompactListing { &mut columns[4], fg_color, bg_color, - Attr::Default, + Attr::DEFAULT, ((0, idx), (min_width.4, idx)), None, ); diff --git a/src/components/mail/listing/conversations.rs b/src/components/mail/listing/conversations.rs index 6dca759e..363cc718 100644 --- a/src/components/mail/listing/conversations.rs +++ b/src/components/mail/listing/conversations.rs @@ -114,7 +114,7 @@ impl MailListingTrait for ConversationsListing { }; if !context.settings.terminal.use_color() { - self.color_cache.highlighted.attrs |= Attr::Reverse; + self.color_cache.highlighted.attrs |= Attr::REVERSE; } // Get mailbox as a reference. // @@ -765,7 +765,7 @@ impl ConversationsListing { &mut self.content, fg_color, bg_color, - Attr::Default, + Attr::DEFAULT, ((0, 3 * idx), (width - 1, 3 * idx)), None, ); @@ -778,7 +778,7 @@ impl ConversationsListing { &mut self.content, fg_color, bg_color, - Attr::Bold, + Attr::BOLD, ((x, 3 * idx), (width - 1, 3 * idx)), None, ); @@ -817,7 +817,7 @@ impl ConversationsListing { &mut self.content, fg_color, bg_color, - Attr::Default, + Attr::DEFAULT, ((0, 3 * idx + 1), (width - 1, 3 * idx + 1)), None, ); @@ -833,7 +833,7 @@ impl ConversationsListing { &mut self.content, fg_color, bg_color, - Attr::Default, + Attr::DEFAULT, ((x + 4, 3 * idx + 1), (width - 1, 3 * idx + 1)), None, ); @@ -971,7 +971,7 @@ impl ConversationsListing { &mut self.content, fg_color, bg_color, - Attr::Default, + Attr::DEFAULT, ((0, 3 * idx), (width - 1, 3 * idx)), None, ); @@ -984,7 +984,7 @@ impl ConversationsListing { &mut self.content, fg_color, bg_color, - Attr::Bold, + Attr::BOLD, ((x, 3 * idx), (width - 1, 3 * idx)), None, ); @@ -1029,7 +1029,7 @@ impl ConversationsListing { &mut self.content, fg_color, bg_color, - Attr::Default, + Attr::DEFAULT, ((0, 3 * idx + 1), (width - 1, 3 * idx + 1)), None, ); @@ -1043,7 +1043,7 @@ impl ConversationsListing { &mut self.content, fg_color, bg_color, - Attr::Default, + Attr::DEFAULT, ((x + 4, 3 * idx + 1), (width - 1, 3 * idx + 1)), None, ); diff --git a/src/components/mail/listing/plain.rs b/src/components/mail/listing/plain.rs index a1f0b48e..8a88b6b9 100644 --- a/src/components/mail/listing/plain.rs +++ b/src/components/mail/listing/plain.rs @@ -127,7 +127,7 @@ impl MailListingTrait for PlainListing { ..self.color_cache }; if !context.settings.terminal.use_color() { - self.color_cache.highlighted.attrs |= Attr::Reverse; + self.color_cache.highlighted.attrs |= Attr::REVERSE; } // Get mailbox as a reference. @@ -982,7 +982,7 @@ impl Component for PlainListing { grid, Color::Default, Color::Default, - Attr::Default, + Attr::DEFAULT, area, Some(get_x(upper_left)), ); diff --git a/src/components/mail/listing/thread.rs b/src/components/mail/listing/thread.rs index d88d4c77..53cb486a 100644 --- a/src/components/mail/listing/thread.rs +++ b/src/components/mail/listing/thread.rs @@ -83,7 +83,7 @@ impl MailListingTrait for ThreadListing { ..self.color_cache }; if !context.settings.terminal.use_color() { - self.color_cache.highlighted.attrs |= Attr::Reverse; + self.color_cache.highlighted.attrs |= Attr::REVERSE; } // Get mailbox as a reference. @@ -191,7 +191,7 @@ impl MailListingTrait for ThreadListing { &mut self.content, fg_color, bg_color, - Attr::Default, + Attr::DEFAULT, ((0, idx), (MAX_COLS - 1, idx)), None, ); diff --git a/src/components/mail/status.rs b/src/components/mail/status.rs index 5a8c3e65..6829ba2e 100644 --- a/src/components/mail/status.rs +++ b/src/components/mail/status.rs @@ -53,7 +53,7 @@ impl Component for StatusPanel { &mut self.content, self.theme_default.fg, self.theme_default.bg, - Attr::Bold, + Attr::BOLD, ((1, 1), (width - 1, height - 1)), Some(1), ); @@ -91,7 +91,7 @@ impl Component for StatusPanel { &mut self.content, self.theme_default.fg, self.theme_default.bg, - Attr::Bold, + Attr::BOLD, ((1, y + 1), (width - 1, height - 1)), Some(1), ); @@ -276,7 +276,7 @@ impl StatusPanel { &mut self.content, self.theme_default.fg, self.theme_default.bg, - Attr::Bold, + Attr::BOLD, ((3, 12 + i * 10), (120 - 2, 12 + i * 10)), Some(3), ); @@ -356,7 +356,7 @@ impl StatusPanel { &mut self.content, self.theme_default.fg, self.theme_default.bg, - Attr::Bold, + Attr::BOLD, ((5 + column_width, y + 2), (120 - 2, y + 2)), None, ); @@ -395,7 +395,7 @@ impl Component for AccountStatus { &mut self.content, self.theme_default.fg, self.theme_default.bg, - Attr::Bold, + Attr::BOLD, ((1, 0), (width - 1, height - 1)), None, ); @@ -406,7 +406,7 @@ impl Component for AccountStatus { &mut self.content, self.theme_default.fg, self.theme_default.bg, - Attr::Bold, + Attr::BOLD, ((1, line), (width - 1, height - 1)), None, ); @@ -429,7 +429,7 @@ impl Component for AccountStatus { &mut self.content, self.theme_default.fg, self.theme_default.bg, - Attr::Bold, + Attr::BOLD, ((1, line), (width - 1, height - 1)), None, ); @@ -474,7 +474,7 @@ impl Component for AccountStatus { &mut self.content, self.theme_default.fg, self.theme_default.bg, - Attr::Bold, + Attr::BOLD, ((1, line), (width - 1, height - 1)), None, ); @@ -501,7 +501,7 @@ impl Component for AccountStatus { &mut self.content, self.theme_default.fg, self.theme_default.bg, - Attr::Bold, + Attr::BOLD, ((1, line), (width - 1, height - 1)), None, ); @@ -531,7 +531,7 @@ impl Component for AccountStatus { &mut self.content, self.theme_default.fg, self.theme_default.bg, - Attr::Bold, + Attr::BOLD, ((1, line), (width - 1, height - 1)), None, ); diff --git a/src/components/mail/view.rs b/src/components/mail/view.rs index 0b5e1a95..c3a0b633 100644 --- a/src/components/mail/view.rs +++ b/src/components/mail/view.rs @@ -492,7 +492,7 @@ impl Component for MailView { grid, Color::Default, Color::Default, - Attr::Default, + Attr::DEFAULT, ((_x, y), bottom_right), None, ); @@ -524,7 +524,7 @@ impl Component for MailView { grid, Color::Default, Color::Default, - Attr::Default, + Attr::DEFAULT, ((x, y), bottom_right), Some(get_x(upper_left)), ); @@ -537,7 +537,7 @@ impl Component for MailView { grid, Color::Default, Color::Default, - Attr::Default, + Attr::DEFAULT, ((x, y), bottom_right), Some(get_x(upper_left)), ); @@ -550,7 +550,7 @@ impl Component for MailView { grid, Color::Default, Color::Default, - Attr::Default, + Attr::DEFAULT, ((x, y), bottom_right), Some(get_x(upper_left)), ); @@ -743,7 +743,7 @@ impl Component for MailView { grid, Color::Default, Color::Default, - Attr::Default, + Attr::DEFAULT, (set_y(upper_left, y), bottom_right), Some(get_x(upper_left)), ); diff --git a/src/components/mail/view/envelope.rs b/src/components/mail/view/envelope.rs index 1b5130cb..77c7e01d 100644 --- a/src/components/mail/view/envelope.rs +++ b/src/components/mail/view/envelope.rs @@ -241,7 +241,7 @@ impl Component for EnvelopeView { grid, Color::Byte(33), Color::Default, - Attr::Default, + Attr::DEFAULT, area, Some(get_x(upper_left)), ); @@ -255,7 +255,7 @@ impl Component for EnvelopeView { grid, Color::Byte(33), Color::Default, - Attr::Default, + Attr::DEFAULT, (set_y(upper_left, y + 1), bottom_right), Some(get_x(upper_left)), ); @@ -269,7 +269,7 @@ impl Component for EnvelopeView { grid, Color::Byte(33), Color::Default, - Attr::Default, + Attr::DEFAULT, (set_y(upper_left, y + 1), bottom_right), Some(get_x(upper_left)), ); @@ -283,7 +283,7 @@ impl Component for EnvelopeView { grid, Color::Byte(33), Color::Default, - Attr::Default, + Attr::DEFAULT, (set_y(upper_left, y + 1), bottom_right), Some(get_x(upper_left)), ); @@ -297,7 +297,7 @@ impl Component for EnvelopeView { grid, Color::Byte(33), Color::Default, - Attr::Default, + Attr::DEFAULT, (set_y(upper_left, y + 1), bottom_right), Some(get_x(upper_left)), ); diff --git a/src/components/mail/view/thread.rs b/src/components/mail/view/thread.rs index f795a433..35d08863 100644 --- a/src/components/mail/view/thread.rs +++ b/src/components/mail/view/thread.rs @@ -266,7 +266,7 @@ impl ThreadView { } else { Color::Byte(251) }, - Attr::Default, + Attr::DEFAULT, ( (e.index.0 * 4 + 1, 2 * y), (e.index.0 * 4 + e.heading.grapheme_width() + 1, height - 1), @@ -348,7 +348,7 @@ impl ThreadView { } else { Color::Byte(251) }, - Attr::Default, + Attr::DEFAULT, ( (e.index.0 * 4 + 1, 2 * y), (e.index.0 * 4 + e.heading.grapheme_width() + 1, height - 1), @@ -668,7 +668,7 @@ impl ThreadView { grid, Color::Byte(33), Color::Default, - Attr::Default, + Attr::DEFAULT, area, Some(get_x(upper_left)), ); @@ -771,7 +771,7 @@ impl ThreadView { grid, Color::Byte(33), Color::Default, - Attr::Default, + Attr::DEFAULT, area, Some(get_x(upper_left)), ); diff --git a/src/components/utilities.rs b/src/components/utilities.rs index e99c2196..9afab637 100644 --- a/src/components/utilities.rs +++ b/src/components/utilities.rs @@ -495,13 +495,13 @@ impl Pager { content, colors.fg, colors.bg, - Attr::Default, + Attr::DEFAULT, ((0, i), (width.saturating_sub(1), i)), None, ); if l.starts_with("⤷") { content[(0, i)].set_fg(Color::Byte(240)); - content[(0, i)].set_attrs(Attr::Bold); + content[(0, i)].set_attrs(Attr::BOLD); } } } @@ -874,7 +874,7 @@ impl StatusBar { fn draw_status_bar(&mut self, grid: &mut CellBuffer, area: Area, context: &mut Context) { let mut attribute = crate::conf::value(context, "status.bar"); if !context.settings.terminal.use_color() { - attribute.attrs |= Attr::Reverse; + attribute.attrs |= Attr::REVERSE; } let (x, y) = write_string_to_grid( &self.status, @@ -900,7 +900,7 @@ impl StatusBar { get_x(bottom_right!(area)), ) { - grid[(x, y)].set_attrs(attribute.attrs | Attr::Bold); + grid[(x, y)].set_attrs(attribute.attrs | Attr::BOLD); } } @@ -923,7 +923,7 @@ impl StatusBar { grid, Color::Byte(219), Color::Byte(88), - Attr::Default, + Attr::DEFAULT, area, None, ); @@ -931,7 +931,7 @@ impl StatusBar { pos_inc(upper_left!(area), (self.ex_buffer.cursor(), 0)).0, y, ) { - cell.set_attrs(Attr::Underline); + cell.set_attrs(Attr::UNDERLINE); } change_colors(grid, area, Color::Byte(219), Color::Byte(88)); context.dirty_areas.push_back(area); @@ -1125,7 +1125,7 @@ impl Component for StatusBar { grid, Color::Byte(88), // DarkRed, Color::Byte(174), //LightPink3 - Attr::Default, + Attr::DEFAULT, ( set_y( upper_left!(hist_area), @@ -1140,7 +1140,7 @@ impl Component for StatusBar { grid, Color::White, Color::Byte(174), - Attr::Default, + Attr::DEFAULT, ((x + 2, y), bottom_right!(hist_area)), None, ); @@ -1165,7 +1165,7 @@ impl Component for StatusBar { grid, Color::Byte(97), // MediumPurple3, Color::Byte(88), //LightPink3 - Attr::Default, + Attr::DEFAULT, ( ( get_x(upper_left) @@ -1482,7 +1482,7 @@ impl Tabbed { let tab_unfocused_attribute = crate::conf::value(context, "tab.unfocused"); let mut tab_focused_attribute = crate::conf::value(context, "tab.focused"); if !context.settings.terminal.use_color() { - tab_focused_attribute.attrs |= Attr::Reverse; + tab_focused_attribute.attrs |= Attr::REVERSE; } let mut x = get_x(upper_left); @@ -1683,7 +1683,7 @@ impl Component for Tabbed { &mut self.help_content, Color::Default, Color::Default, - Attr::Bold, + Attr::BOLD, ((2, 0), (max_width.saturating_sub(2), max_length - 1)), None, ); @@ -1692,7 +1692,7 @@ impl Component for Tabbed { &mut self.help_content, Color::Default, Color::Default, - Attr::Default, + Attr::DEFAULT, ((x + 1, y), (max_width.saturating_sub(2), max_length - 1)), None, ); @@ -1701,7 +1701,7 @@ impl Component for Tabbed { &mut self.help_content, Color::Default, Color::Default, - Attr::Default, + Attr::DEFAULT, ((2, 1), (max_width.saturating_sub(2), max_length - 1)), None, ); @@ -1712,7 +1712,7 @@ impl Component for Tabbed { &mut self.help_content, Color::Default, Color::Default, - Attr::Default, + Attr::DEFAULT, ((2, 2), (max_width.saturating_sub(2), max_length - 1)), None, ); @@ -1724,7 +1724,7 @@ impl Component for Tabbed { &mut self.help_content, Color::Default, Color::Default, - Attr::Default, + Attr::DEFAULT, ((2, 2 + idx), (max_width.saturating_sub(2), max_length - 1)), None, ); @@ -1738,7 +1738,7 @@ impl Component for Tabbed { &mut self.help_content, Color::Default, Color::Default, - Attr::Bold, + Attr::BOLD, ((2, 2 + idx), (max_width.saturating_sub(2), max_length - 1)), None, ); @@ -1747,7 +1747,7 @@ impl Component for Tabbed { &mut self.help_content, Color::Default, Color::Default, - Attr::Default, + Attr::DEFAULT, ((x + 2, y), (max_width.saturating_sub(2), max_length - 1)), None, ); @@ -2167,7 +2167,7 @@ impl Component for UIDialo let shortcuts = self.get_shortcuts(context); let mut highlighted_attrs = crate::conf::value(context, "widgets.options.highlighted"); if !context.settings.terminal.use_color() { - highlighted_attrs.attrs |= Attr::Reverse; + highlighted_attrs.attrs |= Attr::REVERSE; } match (event, self.cursor) { (UIEvent::Input(Key::Char('\n')), _) if self.single_only => { @@ -2188,7 +2188,7 @@ impl Component for UIDialo &mut self.content, Color::Default, Color::Default, - Attr::Default, + Attr::DEFAULT, ((3, c + 2), (width - 2, c + 2)), None, ); @@ -2198,7 +2198,7 @@ impl Component for UIDialo &mut self.content, Color::Default, Color::Default, - Attr::Default, + Attr::DEFAULT, ((3, c + 2), (width - 2, c + 2)), None, ); @@ -2240,7 +2240,7 @@ impl Component for UIDialo self.content[c] .set_fg(Color::Default) .set_bg(Color::Default) - .set_attrs(Attr::Default); + .set_attrs(Attr::DEFAULT); } for c in self.content.row_iter(2..(width - 2), c + 1) { self.content[c] @@ -2256,7 +2256,7 @@ impl Component for UIDialo self.content[c] .set_fg(Color::Default) .set_bg(Color::Default) - .set_attrs(Attr::Default); + .set_attrs(Attr::DEFAULT); } for c in self.content.row_iter(2..4, c + 1) { self.content[c] @@ -2280,14 +2280,14 @@ impl Component for UIDialo self.content[c] .set_fg(Color::Default) .set_bg(Color::Default) - .set_attrs(Attr::Default); + .set_attrs(Attr::DEFAULT); } let c = self.entries.len().saturating_sub(1); self.cursor = SelectorCursor::Entry(c); let mut highlighted_attrs = crate::conf::value(context, "widgets.options.highlighted"); if !context.settings.terminal.use_color() { - highlighted_attrs.attrs |= Attr::Reverse; + highlighted_attrs.attrs |= Attr::REVERSE; } for c in self.content.row_iter(2..4, c + 2) { self.content[c] @@ -2308,7 +2308,7 @@ impl Component for UIDialo self.content[c] .set_fg(Color::Default) .set_bg(Color::Default) - .set_attrs(Attr::Default); + .set_attrs(Attr::DEFAULT); } for c in self.content.row_iter(2..(width - 2), c + 3) { self.content[c] @@ -2324,7 +2324,7 @@ impl Component for UIDialo self.content[c] .set_fg(Color::Default) .set_bg(Color::Default) - .set_attrs(Attr::Default); + .set_attrs(Attr::DEFAULT); } for c in self.content.row_iter(2..4, c + 3) { self.content[c] @@ -2345,7 +2345,7 @@ impl Component for UIDialo self.content[c] .set_fg(Color::Default) .set_bg(Color::Default) - .set_attrs(Attr::Default); + .set_attrs(Attr::DEFAULT); } for c in self.content.row_iter( ((width - "OK Cancel".len()) / 2)..((width - "OK Cancel".len()) / 2 + 1), @@ -2370,7 +2370,7 @@ impl Component for UIDialo self.content[c] .set_fg(Color::Default) .set_bg(Color::Default) - .set_attrs(Attr::Default); + .set_attrs(Attr::DEFAULT); } for c in self.content.row_iter( ((width - "OK Cancel".len()) / 2 + 6) @@ -2455,7 +2455,7 @@ impl Component for UIConfirmationDialog { let shortcuts = self.get_shortcuts(context); let mut highlighted_attrs = crate::conf::value(context, "widgets.options.highlighted"); if !context.settings.terminal.use_color() { - highlighted_attrs.attrs |= Attr::Reverse; + highlighted_attrs.attrs |= Attr::REVERSE; } match (event, self.cursor) { (UIEvent::Input(Key::Char('\n')), _) if self.single_only => { @@ -2476,7 +2476,7 @@ impl Component for UIConfirmationDialog { &mut self.content, Color::Default, Color::Default, - Attr::Default, + Attr::DEFAULT, ((3, c + 2), (width - 2, c + 2)), None, ); @@ -2486,7 +2486,7 @@ impl Component for UIConfirmationDialog { &mut self.content, Color::Default, Color::Default, - Attr::Default, + Attr::DEFAULT, ((3, c + 2), (width - 2, c + 2)), None, ); @@ -2528,7 +2528,7 @@ impl Component for UIConfirmationDialog { self.content[c] .set_fg(Color::Default) .set_bg(Color::Default) - .set_attrs(Attr::Default); + .set_attrs(Attr::DEFAULT); } for c in self.content.row_iter(2..(width - 2), c + 1) { self.content[c] @@ -2544,7 +2544,7 @@ impl Component for UIConfirmationDialog { self.content[c] .set_fg(Color::Default) .set_bg(Color::Default) - .set_attrs(Attr::Default); + .set_attrs(Attr::DEFAULT); } for c in self.content.row_iter(2..4, c + 1) { self.content[c] @@ -2568,14 +2568,14 @@ impl Component for UIConfirmationDialog { self.content[c] .set_fg(Color::Default) .set_bg(Color::Default) - .set_attrs(Attr::Default); + .set_attrs(Attr::DEFAULT); } let c = self.entries.len().saturating_sub(1); self.cursor = SelectorCursor::Entry(c); let mut highlighted_attrs = crate::conf::value(context, "widgets.options.highlighted"); if !context.settings.terminal.use_color() { - highlighted_attrs.attrs |= Attr::Reverse; + highlighted_attrs.attrs |= Attr::REVERSE; } for c in self.content.row_iter(2..4, c + 2) { self.content[c] @@ -2596,7 +2596,7 @@ impl Component for UIConfirmationDialog { self.content[c] .set_fg(Color::Default) .set_bg(Color::Default) - .set_attrs(Attr::Default); + .set_attrs(Attr::DEFAULT); } for c in self.content.row_iter(2..(width - 2), c + 3) { self.content[c] @@ -2612,7 +2612,7 @@ impl Component for UIConfirmationDialog { self.content[c] .set_fg(Color::Default) .set_bg(Color::Default) - .set_attrs(Attr::Default); + .set_attrs(Attr::DEFAULT); } for c in self.content.row_iter(2..4, c + 3) { self.content[c] @@ -2633,7 +2633,7 @@ impl Component for UIConfirmationDialog { self.content[c] .set_fg(Color::Default) .set_bg(Color::Default) - .set_attrs(Attr::Default); + .set_attrs(Attr::DEFAULT); } for c in self.content.row_iter( ((width - "OK Cancel".len()) / 2)..((width - "OK Cancel".len()) / 2 + 1), @@ -2658,7 +2658,7 @@ impl Component for UIConfirmationDialog { self.content[c] .set_fg(Color::Default) .set_bg(Color::Default) - .set_attrs(Attr::Default); + .set_attrs(Attr::DEFAULT); } for c in self.content.row_iter( ((width - "OK Cancel".len()) / 2 + 6) @@ -2767,7 +2767,7 @@ impl Selec &mut content, Color::Byte(8), Color::Default, - Attr::Default, + Attr::DEFAULT, ((0, 0), (width - 1, 0)), None, ); @@ -2776,7 +2776,7 @@ impl Selec &mut content, Color::Default, Color::Default, - Attr::Default, + Attr::DEFAULT, ((2, 0), (width - 1, 0)), None, ); @@ -2786,7 +2786,7 @@ impl Selec &mut content, Color::Byte(8), Color::Default, - Attr::Default, + Attr::DEFAULT, ((x + i, 0), (width - 1, 0)), None, ); @@ -2796,7 +2796,7 @@ impl Selec &mut content, Color::Byte(8), Color::Default, - Attr::Default, + Attr::DEFAULT, ((width - 1, 0), (width - 1, 0)), None, ); @@ -2805,7 +2805,7 @@ impl Selec &mut content, Color::Byte(8), Color::Default, - Attr::Default, + Attr::DEFAULT, ((0, height - 1), (width - 1, height - 1)), None, ); @@ -2818,7 +2818,7 @@ impl Selec &mut content, Color::Byte(8), Color::Default, - Attr::Default, + Attr::DEFAULT, ((1, height - 1), (width - 2, height - 1)), None, ); @@ -2827,7 +2827,7 @@ impl Selec &mut content, Color::Byte(8), Color::Default, - Attr::Default, + Attr::DEFAULT, ((width - 1, height - 1), (width - 1, height - 1)), None, ); @@ -2837,7 +2837,7 @@ impl Selec &mut content, Color::Byte(8), Color::Default, - Attr::Default, + Attr::DEFAULT, ((0, i), (width - 1, i)), None, ); @@ -2846,14 +2846,14 @@ impl Selec &mut content, Color::Byte(8), Color::Default, - Attr::Default, + Attr::DEFAULT, ((width - 1, i), (width - 1, i)), None, ); } let mut highlighted_attrs = crate::conf::value(context, "widgets.options.highlighted"); if !context.settings.terminal.use_color() { - highlighted_attrs.attrs |= Attr::Reverse; + highlighted_attrs.attrs |= Attr::REVERSE; } if single_only { for (i, e) in entries.iter().enumerate() { @@ -2869,7 +2869,7 @@ impl Selec if i == 0 { highlighted_attrs.attrs } else { - Attr::Default + Attr::DEFAULT }, ((2, i + 2), (width - 1, i + 2)), None, @@ -2882,7 +2882,7 @@ impl Selec &mut content, Color::Default, Color::Default, - Attr::Default, + Attr::DEFAULT, ((2, i + 2), (width - 1, i + 2)), None, ); @@ -2903,7 +2903,7 @@ impl Selec &mut content, Color::Default, Color::Default, - Attr::Bold, + Attr::BOLD, ( ((width - "OK Cancel".len()) / 2, height - 3), (width - 1, height - 3), diff --git a/src/components/utilities/widgets.rs b/src/components/utilities/widgets.rs index 0eeefa0e..21e0b24f 100644 --- a/src/components/utilities/widgets.rs +++ b/src/components/utilities/widgets.rs @@ -439,7 +439,7 @@ impl Component for FormWidget { let mut field_attrs = crate::conf::value(context, "widgets.form.highlighted"); if !context.settings.terminal.use_color() { - field_attrs.attrs |= Attr::Reverse; + field_attrs.attrs |= Attr::REVERSE; } for row in grid.bounds_iter(( pos_inc(upper_left, (0, i)), @@ -670,7 +670,7 @@ where } else { theme_default.bg }, - Attr::Bold, + Attr::BOLD, ( pos_inc(upper_left, (len, 0)), pos_inc(upper_left, (cur_len + len, 0)), @@ -847,7 +847,7 @@ impl AutoComplete { .unwrap_or(0) + 1, entries.len(), - Cell::with_style(Color::Byte(23), Color::Byte(7), Attr::Default), + Cell::with_style(Color::Byte(23), Color::Byte(7), Attr::DEFAULT), ); let width = content.cols(); for (i, e) in entries.iter().enumerate() { @@ -856,7 +856,7 @@ impl AutoComplete { &mut content, Color::Byte(23), Color::Byte(7), - Attr::Default, + Attr::DEFAULT, ((0, i), (width - 1, i)), None, ); @@ -865,7 +865,7 @@ impl AutoComplete { &mut content, Color::Byte(23), Color::Byte(7), - Attr::Default, + Attr::DEFAULT, ((x + 2, i), (width - 1, i)), None, ); @@ -874,7 +874,7 @@ impl AutoComplete { &mut content, Color::Byte(23), Color::Byte(7), - Attr::Default, + Attr::DEFAULT, ((width - 1, i), (width - 1, i)), None, ); diff --git a/src/conf/themes.rs b/src/conf/themes.rs index a1b0cd70..7cdcc714 100644 --- a/src/conf/themes.rs +++ b/src/conf/themes.rs @@ -262,7 +262,7 @@ impl Default for ThemeValue { impl Default for ThemeValue { fn default() -> Self { - ThemeValue::Value(Attr::Default) + ThemeValue::Value(Attr::DEFAULT) } } @@ -272,7 +272,7 @@ impl<'de> Deserialize<'de> for ThemeValue { D: Deserializer<'de>, { if let Ok(s) = ::deserialize(deserializer) { - if let Ok(c) = Attr::from_string_de::<'de, D>(s.clone()) { + if let Ok(c) = Attr::from_string_de::<'de, D, String>(s.clone()) { Ok(ThemeValue::Value(c)) } else { Ok(ThemeValue::Link(s.into())) @@ -473,7 +473,7 @@ impl Default for Theme { dark.insert($key.into(), ThemeAttributeInner::default()); }; } - add!("theme_default", dark = { fg: Color::Default, bg: Color::Default, attrs: Attr::Default }, light = { fg: Color::Default, bg: Color::Default, attrs: Attr::Default }); + add!("theme_default", dark = { fg: Color::Default, bg: Color::Default, attrs: Attr::DEFAULT }, light = { fg: Color::Default, bg: Color::Default, attrs: Attr::DEFAULT }); add!("status.bar", dark = { fg: Color::Byte(123), bg: Color::Byte(26) }, light = { fg: Color::Byte(123), bg: Color::Byte(26) }); add!("status.notification", dark = { fg: Color::Byte(219), bg: Color::Byte(88) }, light = { fg: Color::Byte(219), bg: Color::Byte(88) }); @@ -482,13 +482,13 @@ impl Default for Theme { add!("tab.bar"); add!( "widgets.list.header", - dark = { fg: Color::Black, bg: Color::White, attrs: Attr::Bold }, - light = {fg: Color::White, bg: Color::Black, attrs: Attr::Bold } + dark = { fg: Color::Black, bg: Color::White, attrs: Attr::BOLD }, + light = {fg: Color::White, bg: Color::Black, attrs: Attr::BOLD } ); add!( "widgets.form.label", - dark = { attrs: Attr::Bold }, - light = { attrs: Attr::Bold } + dark = { attrs: Attr::BOLD }, + light = { attrs: Attr::BOLD } ); add!("widgets.form.field"); add!("widgets.form.highlighted", light = { bg: Color::Byte(246) }, dark = { bg: Color::Byte(246) }); @@ -567,7 +567,6 @@ impl Default for Theme { dark = { fg: Color::Byte(0), bg: Color::Byte(251) - }, light = { fg: Color::Byte(0), @@ -725,17 +724,17 @@ impl Default for Theme { light = { fg: Color::White, bg: Color::Byte(8), - attrs: Attr::Bold + attrs: Attr::BOLD }, dark = { fg: Color::White, bg: Color::Byte(8), - attrs: Attr::Bold + attrs: Attr::BOLD } ); - add!("pager.highlight_search", light = { fg: Color::White, bg: Color::Byte(6) /* Teal */, attrs: Attr::Bold }, dark = { fg: Color::White, bg: Color::Byte(6) /* Teal */, attrs: Attr::Bold }); - add!("pager.highlight_search_current", light = { fg: Color::White, bg: Color::Byte(17) /* NavyBlue */, attrs: Attr::Bold }, dark = { fg: Color::White, bg: Color::Byte(17) /* NavyBlue */, attrs: Attr::Bold }); + add!("pager.highlight_search", light = { fg: Color::White, bg: Color::Byte(6) /* Teal */, attrs: Attr::BOLD }, dark = { fg: Color::White, bg: Color::Byte(6) /* Teal */, attrs: Attr::BOLD }); + add!("pager.highlight_search_current", light = { fg: Color::White, bg: Color::Byte(17) /* NavyBlue */, attrs: Attr::BOLD }, dark = { fg: Color::White, bg: Color::Byte(17) /* NavyBlue */, attrs: Attr::BOLD }); Theme { light, dark, diff --git a/src/state.rs b/src/state.rs index e5a4db9b..a7e35fac 100644 --- a/src/state.rs +++ b/src/state.rs @@ -695,7 +695,7 @@ impl State { .unwrap(); let mut current_fg = Color::Default; let mut current_bg = Color::Default; - let mut current_attrs = Attr::Default; + let mut current_attrs = Attr::DEFAULT; write!(stdout, "\x1B[m").unwrap(); for x in x_start..=x_end { let c = &grid[(x, y)]; @@ -730,7 +730,7 @@ impl State { cursor::Goto(x_start as u16 + 1, (y + 1) as u16) ) .unwrap(); - let mut current_attrs = Attr::Default; + let mut current_attrs = Attr::DEFAULT; write!(stdout, "\x1B[m").unwrap(); for x in x_start..=x_end { let c = &grid[(x, y)]; diff --git a/src/terminal/cells.rs b/src/terminal/cells.rs index 2e72a3bc..109576ad 100644 --- a/src/terminal/cells.rs +++ b/src/terminal/cells.rs @@ -448,11 +448,11 @@ impl Cell { /// # Examples /// /// ```no_run - /// let cell = Cell::new('x', Color::Default, Color::Green, Attr::Default); + /// let cell = Cell::new('x', Color::Default, Color::Green, Attr::DEFAULT); /// assert_eq!(cell.ch(), 'x'); /// assert_eq!(cell.fg(), Color::Default); /// assert_eq!(cell.bg(), Color::Green); - /// assert_eq!(cell.attrs(), Attr::Default); + /// assert_eq!(cell.attrs(), Attr::DEFAULT); /// ``` pub fn new(ch: char, fg: Color, bg: Color, attrs: Attr) -> Cell { Cell { @@ -475,10 +475,10 @@ impl Cell { /// assert_eq!(cell.ch(), 'x'); /// assert_eq!(cell.fg(), Color::Default); /// assert_eq!(cell.bg(), Color::Default); - /// assert_eq!(cell.attrs(), Attr::Default); + /// assert_eq!(cell.attrs(), Attr::DEFAULT); /// ``` pub fn with_char(ch: char) -> Cell { - Cell::new(ch, Color::Default, Color::Default, Attr::Default) + Cell::new(ch, Color::Default, Color::Default, Attr::DEFAULT) } /// Creates a new `Cell` with the given style and a blank `char`. @@ -486,10 +486,10 @@ impl Cell { /// # Examples /// /// ```no_run - /// let mut cell = Cell::with_style(Color::Default, Color::Red, Attr::Bold); + /// let mut cell = Cell::with_style(Color::Default, Color::Red, Attr::BOLD); /// assert_eq!(cell.fg(), Color::Default); /// assert_eq!(cell.bg(), Color::Red); - /// assert_eq!(cell.attrs(), Attr::Bold); + /// assert_eq!(cell.attrs(), Attr::BOLD); /// assert_eq!(cell.ch(), ' '); /// ``` pub fn with_style(fg: Color, bg: Color, attr: Attr) -> Cell { @@ -531,7 +531,7 @@ impl Cell { /// # Examples /// /// ```no_run - /// let mut cell = Cell::with_style(Color::Blue, Color::Default, Attr::Default); + /// let mut cell = Cell::with_style(Color::Blue, Color::Default, Attr::DEFAULT); /// assert_eq!(cell.fg(), Color::Blue); /// ``` pub fn fg(&self) -> Color { @@ -561,7 +561,7 @@ impl Cell { /// # Examples /// /// ```no_run - /// let mut cell = Cell::with_style(Color::Default, Color::Green, Attr::Default); + /// let mut cell = Cell::with_style(Color::Default, Color::Green, Attr::DEFAULT); /// assert_eq!(cell.bg(), Color::Green); /// ``` pub fn bg(&self) -> Color { @@ -633,7 +633,7 @@ impl Default for Cell { /// assert_eq!(cell.bg(), Color::Default); /// ``` fn default() -> Cell { - Cell::new(' ', Color::Default, Color::Default, Attr::Default) + Cell::new(' ', Color::Default, Color::Default, Attr::DEFAULT) } } @@ -642,7 +642,7 @@ impl Default for Cell { /// `Color::Default` represents the default color of the underlying terminal. /// /// The eight basic colors may be used directly and correspond to 0x00..0x07 in the 8-bit (256) -/// color range; in addition, the eight basic colors coupled with `Attr::Bold` correspond to +/// color range; in addition, the eight basic colors coupled with `Attr::BOLD` correspond to /// 0x08..0x0f in the 8-bit color range. /// /// `Color::Byte(..)` may be used to specify a color in the 8-bit range. @@ -1362,83 +1362,105 @@ impl Serialize for Color { } } -/// The attributes of a `Cell`. -/// -/// `Attr` enumerates all combinations of attributes a given style may have. -/// -/// `Attr::Default` represents no attribute. -/// -/// # Examples -/// -/// ```no_run -/// // Default attribute. -/// let def = Attr::Default; -/// -/// // Base attribute. -/// let base = Attr::Bold; -/// -/// // Combination. -/// let comb = Attr::UnderlineReverse; -/// ``` -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum Attr { - /// Terminal default. - Default = 0b000, - Bold = 0b001, - Underline = 0b100, - BoldUnderline = 0b011, - Reverse = 0b010, - BoldReverse = 0b101, - UnderlineReverse = 0b110, - BoldReverseUnderline = 0b111, -} - -impl core::ops::BitOr for Attr { - type Output = Attr; - - fn bitor(self, rhs: Self) -> Self::Output { - match self as u8 | rhs as u8 { - 0b000 => Attr::Default, - 0b001 => Attr::Bold, - 0b100 => Attr::Underline, - 0b011 => Attr::BoldUnderline, - 0b010 => Attr::Reverse, - 0b101 => Attr::BoldReverse, - 0b110 => Attr::UnderlineReverse, - 0b111 => Attr::BoldReverseUnderline, - _ => unsafe { std::hint::unreachable_unchecked() }, - } - } -} - -impl core::ops::BitAnd for Attr { - type Output = bool; - - fn bitand(self, rhs: Self) -> Self::Output { - self as u8 & rhs as u8 > 0 - } -} - -impl core::ops::BitOrAssign for Attr { - fn bitor_assign(&mut self, rhs: Attr) { - use Attr::*; - *self = match *self as u8 | rhs as u8 { - 0b000 => Default, - 0b001 => Bold, - 0b100 => Underline, - 0b011 => BoldUnderline, - 0b010 => Reverse, - 0b101 => BoldReverse, - 0b110 => UnderlineReverse, - 0b111 => BoldReverseUnderline, - _ => unsafe { std::hint::unreachable_unchecked() }, - }; +bitflags::bitflags! { + /// The attributes of a `Cell`. + /// + /// `Attr` enumerates all combinations of attributes a given style may have. + /// + /// `Attr::DEFAULT` represents no attribute. + /// + /// # Examples + /// + /// ```no_run + /// // Default attribute. + /// let def = Attr::DEFAULT; + /// + /// // Base attribute. + /// let base = Attr::BOLD; + /// + /// // Combination. + /// let comb = Attr::UNDERLINE | Attr::REVERSE; + /// ``` + pub struct Attr: u8 { + /// Terminal default. + const DEFAULT = 0b000_0000; + const BOLD = 0b000_0001; + const DIM = 0b000_0010; + const ITALICS = 0b000_0100; + const UNDERLINE = 0b000_1000; + const BLINK = 0b001_0000; + const REVERSE = 0b010_0000; + const HIDDEN = 0b100_0000; } } impl Default for Attr { fn default() -> Self { - Attr::Default + Attr::DEFAULT + } +} + +impl fmt::Display for Attr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Attr::DEFAULT => write!(f, "Default"), + Attr::BOLD => write!(f, "Bold"), + Attr::DIM => write!(f, "Dim"), + Attr::ITALICS => write!(f, "Italics"), + Attr::UNDERLINE => write!(f, "Underline"), + Attr::BLINK => write!(f, "Blink"), + Attr::REVERSE => write!(f, "Reverse"), + Attr::HIDDEN => write!(f, "Hidden"), + combination => { + let mut ctr = 0; + if combination.intersects(Attr::BOLD) { + ctr += 1; + Attr::BOLD.fmt(f)?; + } + if combination.intersects(Attr::DIM) { + if ctr > 0 { + write!(f, "|")?; + } + ctr += 1; + Attr::DIM.fmt(f)?; + } + if combination.intersects(Attr::ITALICS) { + if ctr > 0 { + write!(f, "|")?; + } + ctr += 1; + Attr::ITALICS.fmt(f)?; + } + if combination.intersects(Attr::UNDERLINE) { + if ctr > 0 { + write!(f, "|")?; + } + ctr += 1; + Attr::UNDERLINE.fmt(f)?; + } + if combination.intersects(Attr::BLINK) { + if ctr > 0 { + write!(f, "|")?; + } + ctr += 1; + Attr::BLINK.fmt(f)?; + } + if combination.intersects(Attr::REVERSE) { + if ctr > 0 { + write!(f, "|")?; + } + ctr += 1; + Attr::REVERSE.fmt(f)?; + } + if combination.intersects(Attr::HIDDEN) { + if ctr > 0 { + write!(f, "|")?; + } + Attr::HIDDEN.fmt(f)?; + } + write!(f, "") + } + } } } @@ -1448,9 +1470,9 @@ impl<'de> Deserialize<'de> for Attr { D: Deserializer<'de>, { if let Ok(s) = ::deserialize(deserializer) { - Attr::from_string_de::<'de, D>(s) + Attr::from_string_de::<'de, D, String>(s) } else { - Err(de::Error::custom("invalid attr value")) + Err(de::Error::custom("Attributes value must be a string.")) } } } @@ -1460,52 +1482,93 @@ impl Serialize for Attr { where S: Serializer, { - match self { - Attr::Default => serializer.serialize_str("Default"), - Attr::Bold => serializer.serialize_str("Bold"), - Attr::Underline => serializer.serialize_str("Underline"), - Attr::BoldUnderline => serializer.serialize_str("BoldUnderline"), - Attr::Reverse => serializer.serialize_str("Reverse"), - Attr::BoldReverse => serializer.serialize_str("BoldReverse"), - Attr::UnderlineReverse => serializer.serialize_str("UnderlineReverse"), - Attr::BoldReverseUnderline => serializer.serialize_str("BoldReverseUnderline"), - } + serializer.serialize_str(&self.to_string()) } } impl Attr { - pub fn from_string_de<'de, D>(s: String) -> std::result::Result + pub fn from_string_de<'de, D, T: AsRef>(s: T) -> std::result::Result where D: Deserializer<'de>, { - match s.as_str() { - "Default" => Ok(Attr::Default), - "Bold" => Ok(Attr::Bold), - "Underline" => Ok(Attr::Underline), - "BoldUnderline" => Ok(Attr::BoldUnderline), - "Reverse" => Ok(Attr::Reverse), - "BoldReverse" => Ok(Attr::BoldReverse), - "UnderlineReverse" => Ok(Attr::UnderlineReverse), - "BoldReverseUnderline" => Ok(Attr::BoldReverseUnderline), - _ => Err(de::Error::custom("invalid attr value")), + match s.as_ref().trim() { + "Default" => Ok(Attr::DEFAULT), + "Dim" => Ok(Attr::DIM), + "Bold" => Ok(Attr::BOLD), + "Italics" => Ok(Attr::ITALICS), + "Underline" => Ok(Attr::UNDERLINE), + "Blink" => Ok(Attr::BLINK), + "Reverse" => Ok(Attr::REVERSE), + "Hidden" => Ok(Attr::HIDDEN), + combination if combination.contains("|") => { + let mut ret = Attr::DEFAULT; + for c in combination.trim().split("|") { + ret |= Self::from_string_de::<'de, D, &str>(c)?; + } + Ok(ret) + } + _ => Err(de::Error::custom( + r#"Text attribute value must either be a single attribute (eg "Bold") or a combination of attributes separated by "|" (eg "Bold|Underline"). Valid attributes are "Default", "Bold", "Italics", "Underline", "Blink", "Reverse" and "Hidden"."#, + )), } } pub fn write(self, prev: Attr, stdout: &mut crate::StateStdout) -> std::io::Result<()> { use std::io::Write; - match (self & Attr::Bold, prev & Attr::Bold) { + match (self.intersects(Attr::BOLD), prev.intersects(Attr::BOLD)) { (true, true) | (false, false) => Ok(()), (false, true) => write!(stdout, "\x1B[22m"), (true, false) => write!(stdout, "\x1B[1m"), } - .and_then(|_| match (self & Attr::Underline, prev & Attr::Underline) { - (true, true) | (false, false) => Ok(()), - (false, true) => write!(stdout, "\x1B[24m"), - (true, false) => write!(stdout, "\x1B[4m"), + .and_then( + |_| match (self.intersects(Attr::DIM), prev.intersects(Attr::DIM)) { + (true, true) | (false, false) => Ok(()), + (false, true) => write!(stdout, "\x1B[22m"), + (true, false) => write!(stdout, "\x1B[2m"), + }, + ) + .and_then(|_| { + match ( + self.intersects(Attr::ITALICS), + prev.intersects(Attr::ITALICS), + ) { + (true, true) | (false, false) => Ok(()), + (false, true) => write!(stdout, "\x1B[23m"), + (true, false) => write!(stdout, "\x1B[3m"), + } }) - .and_then(|_| match (self & Attr::Reverse, prev & Attr::Reverse) { - (true, true) | (false, false) => Ok(()), - (false, true) => write!(stdout, "\x1B[27m"), - (true, false) => write!(stdout, "\x1B[7m"), + .and_then(|_| { + match ( + self.intersects(Attr::UNDERLINE), + prev.intersects(Attr::UNDERLINE), + ) { + (true, true) | (false, false) => Ok(()), + (false, true) => write!(stdout, "\x1B[24m"), + (true, false) => write!(stdout, "\x1B[4m"), + } + }) + .and_then( + |_| match (self.intersects(Attr::BLINK), prev.intersects(Attr::BLINK)) { + (true, true) | (false, false) => Ok(()), + (false, true) => write!(stdout, "\x1B[25m"), + (true, false) => write!(stdout, "\x1B[5m"), + }, + ) + .and_then(|_| { + match ( + self.intersects(Attr::REVERSE), + prev.intersects(Attr::REVERSE), + ) { + (true, true) | (false, false) => Ok(()), + (false, true) => write!(stdout, "\x1B[27m"), + (true, false) => write!(stdout, "\x1B[7m"), + } + }) + .and_then(|_| { + match (self.intersects(Attr::HIDDEN), prev.intersects(Attr::HIDDEN)) { + (true, true) | (false, false) => Ok(()), + (false, true) => write!(stdout, "\x1B[28m"), + (true, false) => write!(stdout, "\x1B[8m"), + } }) } } @@ -2493,7 +2556,7 @@ fn test_cellbuffer_search() { &mut buf, Color::Default, Color::Default, - Attr::Default, + Attr::DEFAULT, ((0, i), (width.saturating_sub(1), i)), None, );