Add Italics, Blink, Dim and Hidden text attributes

Text attributes have been rewritten as bit flags, so for example instead of
"BoldUnderline" you'd have to define "Bold | Underline" in your theme
settings.

Requested in #21
master
Manos Pitsidianakis 2020-04-05 12:04:25 +03:00
parent e9a935dbf7
commit 4930d1b46c
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
19 changed files with 314 additions and 247 deletions

View File

@ -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]

View File

@ -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:

View File

@ -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;

View File

@ -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))),

View File

@ -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),

View File

@ -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
},
(
(

View File

@ -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,
);

View File

@ -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,
);

View File

@ -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)),
);

View File

@ -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,
);

View File

@ -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,
);

View File

@ -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)),
);

View File

@ -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)),
);

View File

@ -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)),
);

View File

@ -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<T: 'static + PartialEq + Debug + Clone + Sync + Send> 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<T: 'static + PartialEq + Debug + Clone + Sync + Send> 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<T: 'static + PartialEq + Debug + Clone + Sync + Send> 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<T: 'static + PartialEq + Debug + Clone + Sync + Send> 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<T: 'static + PartialEq + Debug + Clone + Sync + Send> 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<T: 'static + PartialEq + Debug + Clone + Sync + Send> 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<T: 'static + PartialEq + Debug + Clone + Sync + Send> 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<T: 'static + PartialEq + Debug + Clone + Sync + Send> 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<T: 'static + PartialEq + Debug + Clone + Sync + Send> 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<T: 'static + PartialEq + Debug + Clone + Sync + Send> 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<T: PartialEq + Debug + Clone + Sync + Send, F: 'static + Sync + Send> Selec
&mut content,
Color::Byte(8),
Color::Default,
Attr::Default,
Attr::DEFAULT,
((0, 0), (width - 1, 0)),
None,
);
@ -2776,7 +2776,7 @@ impl<T: PartialEq + Debug + Clone + Sync + Send, F: 'static + Sync + Send> Selec
&mut content,
Color::Default,
Color::Default,
Attr::Default,
Attr::DEFAULT,
((2, 0), (width - 1, 0)),
None,
);
@ -2786,7 +2786,7 @@ impl<T: PartialEq + Debug + Clone + Sync + Send, F: 'static + Sync + Send> Selec
&mut content,
Color::Byte(8),
Color::Default,
Attr::Default,
Attr::DEFAULT,
((x + i, 0), (width - 1, 0)),
None,
);
@ -2796,7 +2796,7 @@ impl<T: PartialEq + Debug + Clone + Sync + Send, F: 'static + Sync + Send> Selec
&mut content,
Color::Byte(8),
Color::Default,
Attr::Default,
Attr::DEFAULT,
((width - 1, 0), (width - 1, 0)),
None,
);
@ -2805,7 +2805,7 @@ impl<T: PartialEq + Debug + Clone + Sync + Send, F: 'static + Sync + Send> 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<T: PartialEq + Debug + Clone + Sync + Send, F: 'static + Sync + Send> 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<T: PartialEq + Debug + Clone + Sync + Send, F: 'static + Sync + Send> 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<T: PartialEq + Debug + Clone + Sync + Send, F: 'static + Sync + Send> Selec
&mut content,
Color::Byte(8),
Color::Default,
Attr::Default,
Attr::DEFAULT,
((0, i), (width - 1, i)),
None,
);
@ -2846,14 +2846,14 @@ impl<T: PartialEq + Debug + Clone + Sync + Send, F: 'static + Sync + Send> 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<T: PartialEq + Debug + Clone + Sync + Send, F: 'static + Sync + Send> 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<T: PartialEq + Debug + Clone + Sync + Send, F: 'static + Sync + Send> Selec
&mut content,
Color::Default,
Color::Default,
Attr::Default,
Attr::DEFAULT,
((2, i + 2), (width - 1, i + 2)),
None,
);
@ -2903,7 +2903,7 @@ impl<T: PartialEq + Debug + Clone + Sync + Send, F: 'static + Sync + Send> Selec
&mut content,
Color::Default,
Color::Default,
Attr::Bold,
Attr::BOLD,
(
((width - "OK Cancel".len()) / 2, height - 3),
(width - 1, height - 3),

View File

@ -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,
);

View File

@ -262,7 +262,7 @@ impl Default for ThemeValue<Color> {
impl Default for ThemeValue<Attr> {
fn default() -> Self {
ThemeValue::Value(Attr::Default)
ThemeValue::Value(Attr::DEFAULT)
}
}
@ -272,7 +272,7 @@ impl<'de> Deserialize<'de> for ThemeValue<Attr> {
D: Deserializer<'de>,
{
if let Ok(s) = <String>::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,

View File

@ -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)];

View File

@ -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 {
}
}
bitflags::bitflags! {
/// The attributes of a `Cell`.
///
/// `Attr` enumerates all combinations of attributes a given style may have.
///
/// `Attr::Default` represents no attribute.
/// `Attr::DEFAULT` represents no attribute.
///
/// # Examples
///
/// ```no_run
/// // Default attribute.
/// let def = Attr::Default;
/// let def = Attr::DEFAULT;
///
/// // Base attribute.
/// let base = Attr::Bold;
/// let base = Attr::BOLD;
///
/// // Combination.
/// let comb = Attr::UnderlineReverse;
/// let comb = Attr::UNDERLINE | Attr::REVERSE;
/// ```
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Attr {
pub struct Attr: u8 {
/// 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() },
};
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) = <String>::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<Self, D::Error>
pub fn from_string_de<'de, D, T: AsRef<str>>(s: T) -> std::result::Result<Self, D::Error>
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) {
.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.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 & Attr::Reverse, prev & Attr::Reverse) {
.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,
);