diff --git a/meli/src/conf/themes.rs b/meli/src/conf/themes.rs index 606a50bd..49df172a 100644 --- a/meli/src/conf/themes.rs +++ b/meli/src/conf/themes.rs @@ -358,10 +358,16 @@ pub struct ThemeAttributeInner { impl Default for ThemeAttributeInner { fn default() -> Self { + Self::inherited("theme_default") + } +} + +impl ThemeAttributeInner { + pub fn inherited(key: &'static str) -> Self { Self { - fg: "theme_default".into(), - bg: "theme_default".into(), - attrs: "theme_default".into(), + fg: key.into(), + bg: key.into(), + attrs: key.into(), } } } @@ -399,8 +405,14 @@ enum ThemeValue { } impl From<&'static str> for ThemeValue { - fn from(from: &'static str) -> Self { - Self::Link(from.into(), ColorField::LikeSelf) + fn from(s: &'static str) -> Self { + if let Some(stripped) = s.strip_suffix(".fg") { + Self::Link(Cow::Borrowed(stripped), ColorField::Fg) + } else if let Some(stripped) = s.strip_suffix(".bg") { + Self::Link(Cow::Borrowed(stripped), ColorField::Bg) + } else { + Self::Link(s.into(), ColorField::LikeSelf) + } } } @@ -703,6 +715,8 @@ impl<'de> Deserialize<'de> for Themes { #[derive(Default, Deserialize)] #[serde(deny_unknown_fields)] struct ThemeAttributeInnerOptions { + #[serde(default)] + from: Option>, #[serde(default)] fg: Option>, #[serde(default)] @@ -712,133 +726,59 @@ impl<'de> Deserialize<'de> for Themes { } let mut ret = Self::default(); - let mut s = ::deserialize(deserializer)?; - for tk in s.other_themes.keys() { - ret.other_themes.insert(tk.clone(), ret.dark.clone()); - } - - for (k, v) in ret.light.iter_mut() { - if let Some(mut att) = s.light.keys.shift_remove(k) { - if let Some(att) = att.fg.take() { - v.fg = att; - } - if let Some(att) = att.bg.take() { - v.bg = att; - } - if let Some(att) = att.attrs.take() { - v.attrs = att; - } - } - } - if !s.light.keys.is_empty() { - return Err(de::Error::custom(format!( - "light theme contains unrecognized theme keywords: {}", - s.light - .keys - .keys() - .map(|k| k.as_ref()) - .collect::>() - .join(", ") - ))); - } - ret.light.color_aliases = s.light.color_aliases; - ret.light.attr_aliases = s.light.attr_aliases; - for (k, v) in s.light.text_format_regexps { - let mut acc = SmallVec::new(); - for (rs, v) in v { - match RegexValue::new_with_options(&rs, v.o) { - Ok(regexp) => { - acc.push(TextFormatterSetting { - regexp, - fg: v.rest.fg, - bg: v.rest.bg, - attrs: v.rest.attrs, - priority: v.priority, - }); - } - Err(err) => { - return Err(de::Error::custom(err.to_string())); - } - } - } - ret.light.text_format_regexps.insert(k, acc); - } - for (k, v) in ret.dark.iter_mut() { - if let Some(mut att) = s.dark.keys.shift_remove(k) { - if let Some(att) = att.fg.take() { - v.fg = att; - } - if let Some(att) = att.bg.take() { - v.bg = att; - } - if let Some(att) = att.attrs.take() { - v.attrs = att; - } - } - } - if !s.dark.keys.is_empty() { - return Err(de::Error::custom(format!( - "dark theme contains unrecognized theme keywords: {}", - s.dark - .keys - .keys() - .map(|k| k.as_ref()) - .collect::>() - .join(", ") - ))); - } - ret.dark.color_aliases = s.dark.color_aliases; - ret.dark.attr_aliases = s.dark.attr_aliases; - for (k, v) in s.dark.text_format_regexps { - let mut acc = SmallVec::new(); - for (rs, v) in v { - match RegexValue::new_with_options(&rs, v.o) { - Ok(regexp) => { - acc.push(TextFormatterSetting { - regexp, - fg: v.rest.fg, - bg: v.rest.bg, - attrs: v.rest.attrs, - priority: v.priority, - }); - } - Err(err) => { - return Err(de::Error::custom(err.to_string())); - } - } - } - ret.dark.text_format_regexps.insert(k, acc); - } - for (tk, t) in ret.other_themes.iter_mut() { - let mut theme = s.other_themes.shift_remove(tk).unwrap(); - for (k, v) in t.iter_mut() { - if let Some(mut att) = theme.keys.shift_remove(k) { - if let Some(att) = att.fg.take() { + let ThemesOptions { + light, + dark, + other_themes, + } = ::deserialize(deserializer)?; + + fn construct_theme<'de, D>( + name: Cow<'_, str>, + theme: &mut Theme, + mut s: ThemeOptions, + ) -> std::result::Result<(), D::Error> + where + D: Deserializer<'de>, + { + for (k, v) in theme.iter_mut() { + if let Some(ThemeAttributeInnerOptions { + from, + fg, + bg, + attrs, + }) = s.keys.shift_remove(k) + { + if let Some(att) = fg { v.fg = att; + } else if let Some(ref parent) = from { + v.fg = ThemeValue::Link(parent.clone(), ColorField::LikeSelf); } - if let Some(att) = att.bg.take() { + if let Some(att) = bg { v.bg = att; + } else if let Some(ref parent) = from { + v.bg = ThemeValue::Link(parent.clone(), ColorField::LikeSelf); } - if let Some(att) = att.attrs.take() { + if let Some(att) = attrs { v.attrs = att; + } else if let Some(parent) = from { + v.attrs = ThemeValue::Link(parent, ()); } } } - if !theme.keys.is_empty() { + if !s.keys.is_empty() { return Err(de::Error::custom(format!( "{} theme contains unrecognized theme keywords: {}", - tk, - theme - .keys + name, + s.keys .keys() .map(|k| k.as_ref()) .collect::>() .join(", ") ))); } - t.color_aliases = theme.color_aliases; - t.attr_aliases = theme.attr_aliases; - for (k, v) in theme.text_format_regexps { + theme.color_aliases = s.color_aliases; + theme.attr_aliases = s.attr_aliases; + for (k, v) in s.text_format_regexps { let mut acc = SmallVec::new(); for (rs, v) in v { match RegexValue::new_with_options(&rs, v.o) { @@ -856,8 +796,17 @@ impl<'de> Deserialize<'de> for Themes { } } } - t.text_format_regexps.insert(k, acc); + theme.text_format_regexps.insert(k, acc); } + Ok(()) + } + + construct_theme::(Cow::Borrowed(self::DARK), &mut ret.dark, dark)?; + construct_theme::(Cow::Borrowed(self::LIGHT), &mut ret.light, light)?; + for (name, theme_opts) in other_themes { + let mut theme = ret.dark.clone(); + construct_theme::(Cow::Borrowed(&name), &mut theme, theme_opts)?; + ret.other_themes.insert(name, theme); } Ok(ret) } @@ -1153,6 +1102,12 @@ impl Default for Themes { let other_themes = IndexMap::default(); macro_rules! add { + ($key:literal from $parent_key:literal, $($theme:ident={ $($name:ident : $val:expr),*$(,)? }),*$(,)?) => { + add!($key); + $($theme.insert($key.into(), ThemeAttributeInner { + $($name: $val.into()),* + ,..ThemeAttributeInner::inherited($parent_key) }));* + }; ($key:literal, $($theme:ident={ $($name:ident : $val:expr),*$(,)? }),*$(,)?) => { add!($key); $($theme.insert($key.into(), ThemeAttributeInner { @@ -1179,7 +1134,7 @@ impl Default for Themes { add!("text.highlight", dark = { fg: Color::Blue, bg: "theme_default", attrs: Attr::REVERSE }, light = { fg: Color::Blue, bg: "theme_default", attrs: Attr::REVERSE }); /* rest */ - add!("highlight", dark = { fg: Color::Byte(240), bg: Color::Byte(237), attrs: Attr::BOLD }, light = { fg: Color::Byte(240), bg: Color::Byte(237), attrs: Attr::BOLD }); + add!("highlight", dark = { fg: "theme_default.bg", bg: "theme_default.fg", attrs: Attr::BOLD }, light = { fg: Color::Byte(240), bg: Color::Byte(237), attrs: Attr::BOLD }); add!("status.bar", dark = { fg: Color::Byte(123), bg: Color::Byte(26) }, light = { fg: Color::Byte(123), bg: Color::Byte(26) }); add!("status.command_bar", dark = { fg: Color::Byte(219), bg: Color::Byte(88) }, light = { fg: Color::Byte(219), bg: Color::Byte(88) }); @@ -1221,11 +1176,11 @@ impl Default for Themes { attrs: Attr::BOLD, } ); - add!("mail.sidebar_unread_count", dark = { fg: Color::Byte(243) }); - add!("mail.sidebar_index", dark = { fg: Color::Byte(243) }); - add!("mail.sidebar_highlighted", dark = { fg: Color::Byte(233), bg: Color::Byte(15) }); + add!("mail.sidebar_unread_count" from "mail.sidebar", dark = { fg: Color::Byte(243) }); + add!("mail.sidebar_index" from "mail.sidebar", dark = { fg: Color::Byte(243) }); + add!("mail.sidebar_highlighted" from "mail.sidebar", dark = { fg: Color::Byte(233), bg: Color::Byte(15) }); add!( - "mail.sidebar_highlighted_unread_count", + "mail.sidebar_highlighted_unread_count" from "mail.sidebar_highlighted", light = { fg: "mail.sidebar_highlighted", bg: "mail.sidebar_highlighted" @@ -1236,7 +1191,7 @@ impl Default for Themes { } ); add!( - "mail.sidebar_highlighted_index", + "mail.sidebar_highlighted_index" from "mail.sidebar_highlighted", light = { fg: "mail.sidebar_index", bg: "mail.sidebar_highlighted", @@ -1247,14 +1202,14 @@ impl Default for Themes { }, ); add!( - "mail.sidebar_highlighted_account", + "mail.sidebar_highlighted_account" from "mail.sidebar_highlighted", dark = { fg: Color::Byte(15), bg: Color::Byte(233), } ); add!( - "mail.sidebar_highlighted_account_name", + "mail.sidebar_highlighted_account_name" from "mail.sidebar_highlighted", dark = { fg: "mail.sidebar_highlighted_account", bg: "mail.sidebar_highlighted_account", @@ -1267,7 +1222,7 @@ impl Default for Themes { } ); add!( - "mail.sidebar_highlighted_account_unread_count", + "mail.sidebar_highlighted_account_unread_count" from "mail.sidebar_highlighted", light = { fg: "mail.sidebar_unread_count", bg: "mail.sidebar_highlighted_account", @@ -1278,7 +1233,7 @@ impl Default for Themes { } ); add!( - "mail.sidebar_highlighted_account_index", + "mail.sidebar_highlighted_account_index" from "mail.sidebar_highlighted", light = { fg: "mail.sidebar_index", bg: "mail.sidebar_highlighted_account" diff --git a/meli/src/contacts/editor.rs b/meli/src/contacts/editor.rs index d5f9a402..dd6818e8 100644 --- a/meli/src/contacts/editor.rs +++ b/meli/src/contacts/editor.rs @@ -65,7 +65,7 @@ impl ContactManager { mode: ViewMode::Edit, form: FormWidget::default(), account_pos: 0, - content: Screen::::new(), + content: Screen::::new(theme_default), theme_default, dirty: true, has_changes: false, diff --git a/meli/src/contacts/list.rs b/meli/src/contacts/list.rs index abfb583b..71871c0a 100644 --- a/meli/src/contacts/list.rs +++ b/meli/src/contacts/list.rs @@ -88,6 +88,7 @@ impl ContactList { index: i, }) .collect(); + let theme_default = crate::conf::value(context, "theme_default"); Self { accounts, cursor_pos: 0, @@ -96,8 +97,8 @@ impl ContactList { account_pos: 0, id_positions: Vec::new(), mode: ViewMode::List, - data_columns: DataColumns::default(), - theme_default: crate::conf::value(context, "theme_default"), + data_columns: DataColumns::new(theme_default), + theme_default, highlight_theme: crate::conf::value(context, "highlight"), initialized: false, dirty: true, @@ -251,7 +252,6 @@ impl ContactList { } else { self.theme_default }; - theme.fg = self.theme_default.fg; if !grid.use_color { theme.attrs |= Attr::REVERSE; } diff --git a/meli/src/jobs_view.rs b/meli/src/jobs_view.rs index cf81367b..2f6020ca 100644 --- a/meli/src/jobs_view.rs +++ b/meli/src/jobs_view.rs @@ -90,7 +90,7 @@ impl JobManager { ..ThemeAttribute::default() } }; - let mut data_columns = DataColumns::default(); + let mut data_columns = DataColumns::new(theme_default); data_columns.theme_config.set_single_theme(theme_default); Self { cursor_pos: 0, diff --git a/meli/src/mail/listing.rs b/meli/src/mail/listing.rs index edcd2885..46fdf06b 100644 --- a/meli/src/mail/listing.rs +++ b/meli/src/mail/listing.rs @@ -20,6 +20,7 @@ */ use std::{ + borrow::Cow, collections::{BTreeMap, BTreeSet, HashMap, HashSet}, convert::TryFrom, fs::File, @@ -2812,7 +2813,7 @@ impl Listing { account: 0, menu: MenuEntryCursor::Mailbox(0), }, - menu: Screen::::new(), + menu: Screen::::new(crate::conf::value(context, "mail.sidebar")), menu_scrollbar_show_timer: context.main_loop_handler.job_executor.clone().create_timer( std::time::Duration::from_secs(0), std::time::Duration::from_millis(1200), @@ -3028,7 +3029,6 @@ impl Listing { } else { crate::conf::value(context, "mail.sidebar_account_name") }; - // Print account name first self.menu.grid_mut().write_string( &self.accounts[aidx].name, @@ -3053,7 +3053,6 @@ impl Listing { ); return 0; } - area = self.menu.area().skip_rows(account_y); let lines_len = lines.len(); let mut idx = 0; @@ -3131,6 +3130,7 @@ impl Listing { crate::conf::value(context, "mail.sidebar_unread_count"), ) }; + self.menu.grid_mut().change_theme(area.nth_row(y + 1), att); // Calculate how many columns the mailbox index tags should occupy with right // alignment, eg. @@ -3257,19 +3257,21 @@ impl Listing { None, ) .0 - + x; + + x + + 1; area = self.menu.area().skip_rows(account_y); // Unread message count - let count_string = match (l.count, l.collapsed_count) { - (None, None) => " ...".to_string(), - (Some(0), None) => String::new(), - (Some(0), Some(0)) | (None, Some(0)) => " v".to_string(), - (Some(0), Some(coll)) => format!(" ({}) v", coll), - (Some(c), Some(0)) => format!(" {} v", c), - (Some(c), Some(coll)) => format!(" {} ({}) v", c, coll), - (Some(c), None) => format!(" {}", c), - (None, Some(coll)) => format!(" ({}) v", coll), + let count_string: Cow<'static, str> = match (l.count, l.collapsed_count) { + (None, None) if context.settings.terminal.ascii_drawing => "...".into(), + (None, None) => "…".into(), + (Some(0), None) => "".into(), + (Some(0), Some(0)) | (None, Some(0)) => "v".into(), + (Some(0), Some(coll)) => format!("({}) v", coll).into(), + (Some(c), Some(0)) => format!("{} v", c).into(), + (Some(c), Some(coll)) => format!("{} ({}) v", c, coll).into(), + (Some(c), None) => format!("{}", c).into(), + (None, Some(coll)) => format!("({}) v", coll).into(), }; let skip_cols = { @@ -3282,7 +3284,7 @@ impl Listing { } }; let (x, _) = self.menu.grid_mut().write_string( - &count_string, + count_string.as_ref(), unread_count_att.fg, unread_count_att.bg, unread_count_att.attrs @@ -3462,7 +3464,7 @@ impl Listing { let coordinates = self.component.coordinates(); std::mem::replace( &mut self.component, - Plain(PlainListing::new(self.id, coordinates)), + Plain(PlainListing::new(self.id, coordinates, context)), ) } IndexStyle::Threaded => { @@ -3482,7 +3484,7 @@ impl Listing { let coordinates = self.component.coordinates(); std::mem::replace( &mut self.component, - Compact(CompactListing::new(self.id, coordinates)), + Compact(CompactListing::new(self.id, coordinates, context)), ) } IndexStyle::Conversations => { diff --git a/meli/src/mail/listing/compact.rs b/meli/src/mail/listing/compact.rs index 5c5be5ff..80a5bcf9 100644 --- a/meli/src/mail/listing/compact.rs +++ b/meli/src/mail/listing/compact.rs @@ -877,7 +877,12 @@ impl std::fmt::Display for CompactListing { } impl CompactListing { - pub fn new(parent: ComponentId, coordinates: (AccountHash, MailboxHash)) -> Box { + pub fn new( + parent: ComponentId, + coordinates: (AccountHash, MailboxHash), + context: &Context, + ) -> Box { + let color_cache = ColorCache::new(context, IndexStyle::Compact); Box::new(Self { cursor_pos: (AccountHash::default(), MailboxHash::default(), 0), new_cursor_pos: (coordinates.0, coordinates.1, 0), @@ -891,12 +896,12 @@ impl CompactListing { filtered_selection: Vec::new(), filtered_order: HashMap::default(), focus: Focus::None, - data_columns: DataColumns::default(), + data_columns: DataColumns::new(color_cache.theme_default), rows_drawn: SegmentTree::default(), rows: RowsState::default(), dirty: true, force_draw: true, - color_cache: ColorCache::default(), + color_cache, movement: None, modifier_active: false, modifier_command: None, diff --git a/meli/src/mail/listing/plain.rs b/meli/src/mail/listing/plain.rs index 8dffae82..3cdbb28c 100644 --- a/meli/src/mail/listing/plain.rs +++ b/meli/src/mail/listing/plain.rs @@ -623,7 +623,12 @@ impl std::fmt::Display for PlainListing { } impl PlainListing { - pub fn new(parent: ComponentId, coordinates: (AccountHash, MailboxHash)) -> Box { + pub fn new( + parent: ComponentId, + coordinates: (AccountHash, MailboxHash), + context: &Context, + ) -> Box { + let color_cache = ColorCache::new(context, IndexStyle::Plain); Box::new(Self { cursor_pos: (AccountHash::default(), MailboxHash::default(), 0), new_cursor_pos: (coordinates.0, coordinates.1, 0), @@ -637,11 +642,11 @@ impl PlainListing { select_job: None, filtered_selection: Vec::new(), filtered_order: HashMap::default(), - data_columns: DataColumns::default(), + data_columns: DataColumns::new(color_cache.theme_default), dirty: true, force_draw: true, focus: Focus::None, - color_cache: ColorCache::default(), + color_cache, movement: None, modifier_active: false, modifier_command: None, diff --git a/meli/src/mail/listing/thread.rs b/meli/src/mail/listing/thread.rs index 862f4e33..f6a694c1 100644 --- a/meli/src/mail/listing/thread.rs +++ b/meli/src/mail/listing/thread.rs @@ -757,14 +757,15 @@ impl ThreadListing { coordinates: (AccountHash, MailboxHash), context: &Context, ) -> Box { + let color_cache = ColorCache::new(context, IndexStyle::Threaded); Box::new(Self { cursor_pos: (coordinates.0, MailboxHash::default(), 0), new_cursor_pos: (coordinates.0, coordinates.1, 0), length: 0, sort: (Default::default(), Default::default()), subsort: (Default::default(), Default::default()), - color_cache: ColorCache::new(context, IndexStyle::Threaded), - data_columns: DataColumns::default(), + data_columns: DataColumns::new(color_cache.theme_default), + color_cache, rows_drawn: SegmentTree::default(), rows: RowsState::default(), seen_cache: IndexMap::default(), diff --git a/meli/src/mail/status.rs b/meli/src/mail/status.rs index e0e9a1bb..707c8918 100644 --- a/meli/src/mail/status.rs +++ b/meli/src/mail/status.rs @@ -44,15 +44,7 @@ impl std::fmt::Display for AccountStatus { impl AccountStatus { pub fn new(account_pos: usize, theme_default: ThemeAttribute) -> Self { - let default_cell = { - let mut ret = Cell::with_char(' '); - ret.set_fg(theme_default.fg) - .set_bg(theme_default.bg) - .set_attrs(theme_default.attrs); - ret - }; - let mut content = Screen::::new(); - content.grid_mut().default_cell = default_cell; + let mut content = Screen::::new(theme_default); content.grid_mut().set_growable(true); _ = content.resize(80, 20); diff --git a/meli/src/mail/view/envelope.rs b/meli/src/mail/view/envelope.rs index 00ab3397..6a4b84ba 100644 --- a/meli/src/mail/view/envelope.rs +++ b/meli/src/mail/view/envelope.rs @@ -751,7 +751,7 @@ impl Component for EnvelopeView { if sticky || skip_header_ctr == 0 { if y <= area.height() { grid.clear_area( - area.skip_rows(y), + area.skip_rows(y).take_rows(1), hdr_area_theme, ); let (_x, _y) = @@ -993,19 +993,12 @@ impl Component for EnvelopeView { } } } - for c in grid.row_iter(area, (x + 1)..area.width(), y) { - grid[c] - .set_ch(' ') - .set_fg(hdr_area_theme.fg) - .set_bg(hdr_area_theme.bg); - } y += 1; } } self.force_draw_headers = false; - grid.clear_area(area.nth_row(y), hdr_area_theme); context.dirty_areas.push_back(area.take_rows(y + 3)); if !self.view_settings.sticky_headers { let height_p = self.pager.size().1; diff --git a/meli/src/mail/view/thread.rs b/meli/src/mail/view/thread.rs index 29fd87cc..02d56176 100644 --- a/meli/src/mail/view/thread.rs +++ b/meli/src/mail/view/thread.rs @@ -86,6 +86,7 @@ impl ThreadView { focus: Option, context: &mut Context, ) -> Self { + let theme_default = crate::conf::value(context, "theme_default"); let mut view = Self { reversed: false, coordinates, @@ -110,7 +111,7 @@ impl ThreadView { new_expanded_pos: 0, visible_entries: vec![], movement: None, - content: Screen::::default(), + content: Screen::::new(theme_default), }; view.initiate(expanded_hash, go_to_first_unread, context); view.new_cursor_pos = view.new_expanded_pos; diff --git a/meli/src/mailbox_management.rs b/meli/src/mailbox_management.rs index cca2b64c..8370fdc5 100644 --- a/meli/src/mailbox_management.rs +++ b/meli/src/mailbox_management.rs @@ -94,7 +94,7 @@ impl MailboxManager { pub fn new(context: &Context, account_pos: usize) -> Self { let account_hash = context.accounts[account_pos].hash(); let theme_default = crate::conf::value(context, "theme_default"); - let mut data_columns = DataColumns::default(); + let mut data_columns = DataColumns::new(theme_default); data_columns.theme_config.set_single_theme(theme_default); Self { cursor_pos: 0, diff --git a/meli/src/state.rs b/meli/src/state.rs index 5838ce93..b860e689 100644 --- a/meli/src/state.rs +++ b/meli/src/state.rs @@ -427,7 +427,8 @@ impl State { let working = Arc::new(()); let control = Arc::downgrade(&working); - let mut screen = Box::new(Screen::::new().with_cols_and_rows(cols, rows)); + let mut screen = + Box::new(Screen::::new(Default::default()).with_cols_and_rows(cols, rows)); screen .tty_mut() .set_mouse(settings.terminal.use_mouse.is_true()) diff --git a/meli/src/terminal/cells.rs b/meli/src/terminal/cells.rs index bffe3b95..fd2a0f87 100644 --- a/meli/src/terminal/cells.rs +++ b/meli/src/terminal/cells.rs @@ -1155,6 +1155,17 @@ impl Default for Cell { } } +impl From for Cell { + fn from(ThemeAttribute { fg, bg, attrs, .. }: ThemeAttribute) -> Self { + Self { + fg, + bg, + attrs, + ..Self::default() + } + } +} + bitflags::bitflags! { /// The attributes of a `Cell`. /// @@ -1407,7 +1418,7 @@ impl Attr { /// /// ```rust,no_run /// # use meli::terminal::{Screen, Virtual, Area}; -/// # let mut screen = Screen::::new(); +/// # let mut screen = Screen::::new(Default::default()); /// # assert!(screen.resize(120, 20)); /// # let area = screen.area(); /// for c in screen.grid().row_iter(area, 0..area.width(), 2) { @@ -1425,7 +1436,7 @@ pub struct RowIterator { /// /// ```rust,no_run /// # use meli::terminal::{Screen, Virtual, Area}; -/// # let mut screen = Screen::::new(); +/// # let mut screen = Screen::::new(Default::default()); /// # assert!(screen.resize(120, 20)); /// # let area = screen.area(); /// for row in screen.grid().bounds_iter(area) { @@ -1991,7 +2002,7 @@ mod tests { #[test] fn test_bounds_iter() { - let mut screen = Screen::::new(); + let mut screen = Screen::::new(Default::default()); assert!(screen.resize(120, 20)); let area = screen.area(); assert_eq!(area.width(), 120); diff --git a/meli/src/terminal/embedded/terminal.rs b/meli/src/terminal/embedded/terminal.rs index 9adb5345..c6b56592 100644 --- a/meli/src/terminal/embedded/terminal.rs +++ b/meli/src/terminal/embedded/terminal.rs @@ -225,7 +225,7 @@ impl Default for EmbeddedGrid { impl EmbeddedGrid { #[inline] pub fn new() -> Self { - let normal_screen = Box::new(Screen::::new()); + let normal_screen = Box::new(Screen::::new(Default::default())); Self { cursor: (0, 0), scroll_region: ScrollRegion { @@ -236,7 +236,7 @@ impl EmbeddedGrid { }, terminal_size: (0, 0), initialized: false, - alternate_screen: Box::new(Screen::::new()), + alternate_screen: Box::new(Screen::::new(Default::default())), state: State::Normal, fg_color: Color::Default, bg_color: Color::Default, diff --git a/meli/src/terminal/screen.rs b/meli/src/terminal/screen.rs index db9fe6d1..d2d04935 100644 --- a/meli/src/terminal/screen.rs +++ b/meli/src/terminal/screen.rs @@ -32,7 +32,7 @@ use crate::{ EnableMouse, EnableSGRMouse, Pos, RestoreWindowTitleIconFromStack, SaveWindowTitleIconToStack, }, - Attr, Context, + Attr, Context, ThemeAttribute, }; pub type StateStdout = termion::screen::AlternateScreen< @@ -168,7 +168,7 @@ impl std::fmt::Debug for Screen { impl Screen { #[inline] - pub fn init(display: D) -> Self { + pub fn init(display: D, theme_default: ThemeAttribute) -> Self { let area = Area { offset: (0, 0), upper_left: (0, 0), @@ -178,14 +178,17 @@ impl Screen { canvas_rows: 0, generation: ScreenGeneration::NIL, }; - Self { + let mut retval = Self { cols: 0, rows: 0, grid: CellBuffer::nil(area), overlay_grid: CellBuffer::nil(area), display, generation: ScreenGeneration::NIL, - } + }; + retval.grid_mut().default_cell = theme_default.into(); + retval.overlay_grid_mut().default_cell = theme_default.into(); + retval } #[inline] @@ -269,12 +272,15 @@ impl Clone for Screen { impl Screen { #[inline] - pub fn new() -> Self { - Self::init(Tty { - stdout: None, - mouse: false, - draw_horizontal_segment_fn: Self::draw_horizontal_segment, - }) + pub fn new(theme_default: ThemeAttribute) -> Self { + Self::init( + Tty { + stdout: None, + mouse: false, + draw_horizontal_segment_fn: Self::draw_horizontal_segment, + }, + theme_default, + ) } #[inline] @@ -484,16 +490,10 @@ impl Screen { } } -impl Default for Screen { - fn default() -> Self { - Self::new() - } -} - impl Screen { #[inline] - pub fn new() -> Self { - Self::init(Virtual) + pub fn new(theme_default: ThemeAttribute) -> Self { + Self::init(Virtual, theme_default) } #[must_use] @@ -772,7 +772,7 @@ impl Area { /// /// ```rust /// # use meli::terminal::{Screen, Virtual, Area}; - /// # let mut screen = Screen::::new(); + /// # let mut screen = Screen::::new(Default::default()); /// # assert!(screen.resize(120, 20)); /// # let area = screen.area(); /// assert_eq!(area.width(), 120); @@ -803,7 +803,7 @@ impl Area { /// /// ```rust /// # use meli::terminal::{Screen, Virtual, Area}; - /// # let mut screen = Screen::::new(); + /// # let mut screen = Screen::::new(Default::default()); /// # assert!(screen.resize(120, 20)); /// # let area = screen.area(); /// assert_eq!(area.width(), 120); @@ -849,7 +849,7 @@ impl Area { /// /// ```rust /// # use meli::terminal::{Screen, Virtual, Area}; - /// # let mut screen = Screen::::new(); + /// # let mut screen = Screen::::new(Default::default()); /// # assert!(screen.resize(120, 20)); /// # let area = screen.area(); /// assert_eq!(area.width(), 120); @@ -872,7 +872,7 @@ impl Area { /// /// ```rust /// # use meli::terminal::{Screen, Virtual, Area}; - /// # let mut screen = Screen::::new(); + /// # let mut screen = Screen::::new(Default::default()); /// # assert!(screen.resize(120, 20)); /// # let area = screen.area(); /// assert_eq!(area.width(), 120); @@ -909,7 +909,7 @@ impl Area { /// /// ```rust /// # use meli::terminal::{Screen, Virtual, Area}; - /// # let mut screen = Screen::::new(); + /// # let mut screen = Screen::::new(Default::default()); /// # assert!(screen.resize(120, 20)); /// # let area = screen.area(); /// assert_eq!(area.width(), 120); @@ -942,7 +942,7 @@ impl Area { /// /// ```rust /// # use meli::terminal::{Screen, Virtual, Area}; - /// # let mut screen = Screen::::new(); + /// # let mut screen = Screen::::new(Default::default()); /// # assert!(screen.resize(120, 20)); /// # let area = screen.area(); /// assert_eq!(area.width(), 120); @@ -1081,7 +1081,7 @@ mod tests { #[test] fn test_skip_rows() { - let mut screen = Screen::::new(); + let mut screen = Screen::::new(Default::default()); assert!(screen.resize(120, 20)); let area = screen.area(); assert_eq!(area.width(), 120); @@ -1103,7 +1103,7 @@ mod tests { #[test] fn test_skip_rows_from_end() { - let mut screen = Screen::::new(); + let mut screen = Screen::::new(Default::default()); assert!(screen.resize(120, 20)); let area = screen.area(); assert_eq!(area.width(), 120); @@ -1120,7 +1120,7 @@ mod tests { #[test] fn test_skip_cols() { - let mut screen = Screen::::new(); + let mut screen = Screen::::new(Default::default()); assert!(screen.resize(120, 20)); let area = screen.area(); assert_eq!(area.width(), 120); @@ -1142,7 +1142,7 @@ mod tests { #[test] fn test_skip_cols_from_end() { - let mut screen = Screen::::new(); + let mut screen = Screen::::new(Default::default()); assert!(screen.resize(120, 20)); let area = screen.area(); assert_eq!(area.width(), 120); @@ -1159,7 +1159,7 @@ mod tests { #[test] fn test_take_rows() { - let mut screen = Screen::::new(); + let mut screen = Screen::::new(Default::default()); assert!(screen.resize(120, 20)); let area = screen.area(); assert_eq!(area.width(), 120); @@ -1176,7 +1176,7 @@ mod tests { #[test] fn test_take_cols() { - let mut screen = Screen::::new(); + let mut screen = Screen::::new(Default::default()); assert!(screen.resize(120, 20)); let area = screen.area(); assert_eq!(area.width(), 120); @@ -1193,7 +1193,7 @@ mod tests { #[test] fn test_nth_area() { - let mut screen = Screen::::new(); + let mut screen = Screen::::new(Default::default()); assert!(screen.resize(120, 20)); let area = screen.area(); assert_eq!(area.width(), 120); @@ -1222,7 +1222,7 @@ mod tests { #[test] fn test_place_inside_area() { - let mut screen = Screen::::new(); + let mut screen = Screen::::new(Default::default()); assert!(screen.resize(120, 20)); let area = screen.area(); assert_eq!(area.width(), 120); @@ -1251,7 +1251,7 @@ mod tests { const ALIGNMENTS: [Alignment; 4] = [Fill, Start, End, Center]; - let mut screen = Screen::::new(); + let mut screen = Screen::::new(Default::default()); assert!(screen.resize(120, 20)); let area = screen.area(); assert_eq!(area.width(), 120); diff --git a/meli/src/utilities.rs b/meli/src/utilities.rs index a261fcaa..01065cad 100644 --- a/meli/src/utilities.rs +++ b/meli/src/utilities.rs @@ -864,9 +864,10 @@ pub struct Tabbed { impl Tabbed { pub fn new(children: Vec>, context: &Context) -> Self { let pinned = children.len(); + let theme_default = crate::conf::value(context, "theme_default"); let mut ret = Self { help_view: HelpView { - content: Screen::::new(), + content: Screen::::new(theme_default), curr_views: children .first() .map(|c| c.shortcuts(context)) @@ -874,7 +875,7 @@ impl Tabbed { cursor: (0, 0), search: None, }, - theme_default: crate::conf::value(context, "theme_default"), + theme_default, pinned, children, cursor_pos: 0, diff --git a/meli/src/utilities/dialogs.rs b/meli/src/utilities/dialogs.rs index f6a89006..920299cd 100644 --- a/meli/src/utilities/dialogs.rs +++ b/meli/src/utilities/dialogs.rs @@ -521,6 +521,7 @@ impl::new(), + content: Screen::::new(theme_default), initialized: false, done: false, done_fn, dirty: true, - theme_default: Default::default(), + theme_default, id: ComponentId::default(), }; ret.initialise(context); diff --git a/meli/src/utilities/tables.rs b/meli/src/utilities/tables.rs index 8c90a3f6..256aeb1a 100644 --- a/meli/src/utilities/tables.rs +++ b/meli/src/utilities/tables.rs @@ -65,13 +65,19 @@ impl TableRowFormat { } */ -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug)] pub struct TableThemeConfig { pub theme: TableTheme, //pub row_formats: HashMap>, } impl TableThemeConfig { + pub fn new(theme_default: ThemeAttribute) -> Self { + Self { + theme: TableTheme::Single(theme_default), + } + } + pub fn set_single_theme(&mut self, value: ThemeAttribute) -> &mut Self { self.theme = TableTheme::Single(value); self @@ -92,19 +98,20 @@ pub enum TableTheme { }, } -impl Default for TableTheme { - fn default() -> Self { - Self::Single(ThemeAttribute::default()) - } -} - -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug)] pub struct TableCursorConfig { pub handle: bool, pub theme: TableTheme, } impl TableCursorConfig { + pub fn new(theme_default: ThemeAttribute) -> Self { + Self { + handle: false, + theme: TableTheme::Single(theme_default), + } + } + pub fn set_handle(&mut self, value: bool) -> &mut Self { self.handle = value; self @@ -136,8 +143,8 @@ pub struct DataColumns { // Workaround because Default derive doesn't work for const generic array // lengths yet. -impl Default for DataColumns { - fn default() -> Self { +impl DataColumns { + pub fn new(theme_default: ThemeAttribute) -> Self { fn init_array(cl: impl Fn() -> T) -> [T; N] { // https://doc.rust-lang.org/std/mem/union.MaybeUninit.html#initializing-an-array-element-by-element let mut data: [MaybeUninit; N] = unsafe { MaybeUninit::uninit().assume_init() }; @@ -149,9 +156,9 @@ impl Default for DataColumns { } Self { - cursor_config: TableCursorConfig::default(), - theme_config: TableThemeConfig::default(), - columns: Box::new(init_array(|| Screen::init(Virtual))), + cursor_config: TableCursorConfig::new(theme_default), + theme_config: TableThemeConfig::new(theme_default), + columns: Box::new(init_array(|| Screen::init(Virtual, theme_default))), widths: [0_usize; N], elasticities: [ColumnElasticity::default(); N], x_offset: 0,