From b25f10f92a299309a8319c22c3ca0c7da8b6689f Mon Sep 17 00:00:00 2001 From: Manos Pitsidianakis Date: Sun, 6 Oct 2019 10:58:47 +0300 Subject: [PATCH] conf: add a light theme option --- meli.1 | 6 ++ meli.conf.5 | 11 +++- sample-config | 3 + ui/src/components/mail/listing/compact.rs | 46 +++++++++---- .../components/mail/listing/conversations.rs | 33 ++++++++-- ui/src/components/mail/listing/plain.rs | 64 ++++++++++++++----- ui/src/components/mail/view.rs | 26 +++++--- ui/src/conf.rs | 6 ++ ui/src/conf/terminal.rs | 36 +++++++++++ 9 files changed, 186 insertions(+), 45 deletions(-) create mode 100644 ui/src/conf/terminal.rs diff --git a/meli.1 b/meli.1 index d9c22865..12bed547 100644 --- a/meli.1 +++ b/meli.1 @@ -62,6 +62,12 @@ The main visual navigation tool is the left-side sidebar. The menu's visibility ). .Pp The view into each folder has 4 modes: plain, threaded, conversations and compact. Plain views each mail indvidually, threaded shows their thread relationship visually, and conversations includes one entry per thread of emails (compact is one row per thread). +.Pp +If you're using a light color palette in your terminal, you can set +.Em theme = "light" +in the +.Em terminal +section of your configuration. .Bd -literal ^^ .-=-=-=-. ^^ ^^ (`-=-=-=-=-`) ^^ diff --git a/meli.conf.5 b/meli.conf.5 index 1cc82cce..0c24bd5e 100644 --- a/meli.conf.5 +++ b/meli.conf.5 @@ -41,7 +41,7 @@ Newline means LF (0x0A) or CRLF (0x0D 0x0A). .Pp Refer to TOML documentation for valid TOML syntax. .Sh SECTIONS -The top level sections of the config are accounts, shortcuts, notifications, pager, composing, pgp. +The top level sections of the config are accounts, shortcuts, notifications, pager, composing, pgp, terminal. .Pp .Sy example configuration .Bd -literal @@ -85,6 +85,9 @@ scroll_up = 'k' scroll_down = 'j' page_up = PageUp page_down = PageDown + +[terminal] +theme = "light" .Ed .Pp available options are listed below. @@ -308,6 +311,12 @@ auto verify signed e-mail according to RFC3156 .\" default value .Pq Em "gpg2" .El +.Sh TERMINAL +.Bl -tag -width "danger_accept_invalid_certs boolean" -offset -indent +.It Cm theme Ar String +(optional) select between these themes: light / dark +.\" default value +.Pq Em dark .Sh SEE ALSO .Xr meli 1 .Sh CONFORMING TO diff --git a/sample-config b/sample-config index 29aa62ef..0bb8ad9e 100644 --- a/sample-config +++ b/sample-config @@ -84,3 +84,6 @@ #auto_sign = false # always sign sent messages #auto_verify_signatures = true # always verify signatures when reading signed e-mails #gpg_binary = "/usr/bin/gpg2" #optional +# +#[terminal] +#theme = "dark" # or "light" diff --git a/ui/src/components/mail/listing/compact.rs b/ui/src/components/mail/listing/compact.rs index 7afd9db9..e486009d 100644 --- a/ui/src/components/mail/listing/compact.rs +++ b/ui/src/components/mail/listing/compact.rs @@ -93,14 +93,26 @@ impl ListingTrait for CompactListing { let thread_node = &threads.thread_nodes[&i]; let fg_color = self.data_columns.columns[0][(0, idx)].fg(); - let bg_color = if self.cursor_pos.2 == idx { - Color::Byte(246) - } else if self.selection[&i] { - Color::Byte(210) - } else if thread_node.has_unseen() { - Color::Byte(251) + let bg_color = if context.settings.terminal.theme == "light" { + if self.cursor_pos.2 == idx { + Color::Byte(244) + } else if self.selection[&i] { + Color::Byte(210) + } else if thread_node.has_unseen() { + Color::Byte(251) + } else { + self.data_columns.columns[0][(0, idx)].bg() + } } else { - self.data_columns.columns[0][(0, idx)].bg() + if self.cursor_pos.2 == idx { + Color::Byte(246) + } else if self.selection[&i] { + Color::Byte(210) + } else if thread_node.has_unseen() { + Color::Byte(251) + } else { + self.data_columns.columns[0][(0, idx)].bg() + } }; let (upper_left, bottom_right) = area; @@ -639,12 +651,22 @@ impl CompactListing { } else { Color::Default }; - let bg_color = if thread_node.has_unseen() { - Color::Byte(251) - } else if idx % 2 == 0 { - Color::Byte(236) + let bg_color = if context.settings.terminal.theme == "light" { + if thread_node.has_unseen() { + Color::Byte(251) + } else if idx % 2 == 0 { + Color::Byte(252) + } else { + Color::Default + } } else { - Color::Default + if thread_node.has_unseen() { + Color::Byte(253) + } else if idx % 2 == 0 { + Color::Byte(236) + } else { + Color::Default + } }; let (x, _) = write_string_to_grid( &idx.to_string(), diff --git a/ui/src/components/mail/listing/conversations.rs b/ui/src/components/mail/listing/conversations.rs index 2fc8dd66..7289f081 100644 --- a/ui/src/components/mail/listing/conversations.rs +++ b/ui/src/components/mail/listing/conversations.rs @@ -146,6 +146,12 @@ impl ListingTrait for ConversationsListing { ((0, 3 * idx), pos_dec(self.content.size(), (1, 1))), ); + let padding_fg = if context.settings.terminal.theme == "light" { + Color::Byte(254) + } else { + Color::Byte(235) + }; + let (upper_left, bottom_right) = area; let width = self.content.size().0; let (x, y) = upper_left; @@ -157,7 +163,7 @@ impl ListingTrait for ConversationsListing { grid[(x, y + 1)].set_fg(fg_color); grid[(x, y + 1)].set_bg(bg_color); - grid[(x, y + 2)].set_fg(Color::Byte(235)); + grid[(x, y + 2)].set_fg(padding_fg); grid[(x, y + 2)].set_bg(bg_color); } } else if width < width!(area) { @@ -169,7 +175,7 @@ impl ListingTrait for ConversationsListing { grid[(x, y + 1)].set_fg(fg_color); grid[(x, y + 1)].set_bg(bg_color); - grid[(x, y + 2)].set_fg(Color::Byte(235)); + grid[(x, y + 2)].set_fg(padding_fg); grid[(x, y + 2)].set_bg(bg_color); } } @@ -362,6 +368,12 @@ impl ListingTrait for ConversationsListing { /* fill any remaining columns, if our view is wider than self.content */ let width = self.content.size().0; + let padding_fg = if context.settings.terminal.theme == "light" { + Color::Byte(254) + } else { + Color::Byte(235) + }; + if width < width!(area) { let y_offset = get_y(upper_left); for y in 0..rows { @@ -372,7 +384,7 @@ impl ListingTrait for ConversationsListing { grid[(x, y_offset + 3 * y + 2)].set_fg(Color::Default); grid[(x, y_offset + 3 * y + 1)].set_bg(bg_color); grid[(x, y_offset + 3 * y + 2)].set_ch('▓'); - grid[(x, y_offset + 3 * y + 2)].set_fg(Color::Byte(235)); + grid[(x, y_offset + 3 * y + 2)].set_fg(padding_fg); grid[(x, y_offset + 3 * y + 2)].set_bg(bg_color); } } @@ -643,6 +655,12 @@ impl ConversationsListing { let width = std::cmp::min(MAX_COLS, max_entry_columns); self.content = CellBuffer::new(width, 4 * rows.len(), Cell::with_char(' ')); + let padding_fg = if context.settings.terminal.theme == "light" { + Color::Byte(254) + } else { + Color::Byte(235) + }; + for ((idx, root_idx), strings) in threads.root_iter().enumerate().zip(rows) { let thread_node = &threads.thread_nodes()[&root_idx]; let i = if let Some(i) = thread_node.message() { @@ -724,7 +742,7 @@ impl ConversationsListing { } for x in 0..width { self.content[(x, 3 * idx + 2)].set_ch('▓'); - self.content[(x, 3 * idx + 2)].set_fg(Color::Byte(235)); + self.content[(x, 3 * idx + 2)].set_fg(padding_fg); self.content[(x, 3 * idx + 2)].set_bg(bg_color); } } @@ -1074,10 +1092,15 @@ impl Component for ConversationsListing { fg_color, bg_color, ); + let padding_fg = if context.settings.terminal.theme == "light" { + Color::Byte(254) + } else { + Color::Byte(235) + }; change_colors( &mut self.content, ((0, 3 * row + 2), (width - 1, 3 * row + 2)), - Color::Byte(235), + padding_fg, bg_color, ); let rows = (get_y(bottom_right) - get_y(upper_left) + 1) / 3; diff --git a/ui/src/components/mail/listing/plain.rs b/ui/src/components/mail/listing/plain.rs index 5667774c..be31814e 100644 --- a/ui/src/components/mail/listing/plain.rs +++ b/ui/src/components/mail/listing/plain.rs @@ -102,14 +102,26 @@ impl ListingTrait for PlainListing { } else { Color::Default }; - let bg_color = if self.cursor_pos.2 == idx { - Color::Byte(246) - } else if !envelope.is_seen() { - Color::Byte(251) - } else if idx % 2 == 0 { - Color::Byte(236) + let bg_color = if context.settings.terminal.theme == "light" { + if self.cursor_pos.2 == idx { + Color::Byte(246) + } else if !envelope.is_seen() { + Color::Byte(251) + } else if idx % 2 == 0 { + Color::Byte(252) + } else { + Color::Default + } } else { - Color::Default + if self.cursor_pos.2 == idx { + Color::Byte(246) + } else if !envelope.is_seen() { + Color::Byte(251) + } else if idx % 2 == 0 { + Color::Byte(236) + } else { + Color::Default + } }; change_colors(grid, area, fg_color, bg_color); } @@ -369,12 +381,22 @@ impl PlainListing { } else { Color::Default }; - let bg_color = if !envelope.is_seen() { - Color::Byte(251) - } else if idx % 2 == 0 { - Color::Byte(236) + let bg_color = if context.settings.terminal.theme == "light" { + if !envelope.is_seen() { + Color::Byte(251) + } else if idx % 2 == 0 { + Color::Byte(252) + } else { + Color::Default + } } else { - Color::Default + if !envelope.is_seen() { + Color::Byte(251) + } else if idx % 2 == 0 { + Color::Byte(236) + } else { + Color::Default + } }; let (x, _) = write_string_to_grid( &rows[idx].0, @@ -432,12 +454,20 @@ impl PlainListing { } } - fn unhighlight_line(&mut self, idx: usize) { + fn unhighlight_line(&mut self, idx: usize, context: &Context) { let fg_color = Color::Default; - let bg_color = if idx % 2 == 0 { - Color::Byte(236) + let bg_color = if context.settings.terminal.theme == "light" { + if idx % 2 == 0 { + Color::Byte(252) + } else { + Color::Default + } } else { - Color::Default + if idx % 2 == 0 { + Color::Byte(236) + } else { + Color::Default + } }; change_colors( &mut self.content, @@ -503,7 +533,7 @@ impl Component for PlainListing { } }; if must_unhighlight { - self.unhighlight_line(idx); + self.unhighlight_line(idx, context); } let mid = get_y(upper_left) + total_rows - bottom_entity_rows; self.draw_list( diff --git a/ui/src/components/mail/view.rs b/ui/src/components/mail/view.rs index 92a11cb9..6845e28a 100644 --- a/ui/src/components/mail/view.rs +++ b/ui/src/components/mail/view.rs @@ -334,6 +334,12 @@ impl Component for MailView { } let envelope: &Envelope = &account.get_env(&self.coordinates.2); + let header_fg = if context.settings.terminal.theme == "light" { + Color::Black + } else { + Color::Byte(33) + }; + if self.mode == ViewMode::Raw { clear_area(grid, area); context.dirty_areas.push_back(area); @@ -342,7 +348,7 @@ impl Component for MailView { let (x, y) = write_string_to_grid( &format!("Date: {}", envelope.date_as_str()), grid, - Color::Byte(33), + header_fg, Color::Default, Attr::Default, area, @@ -356,7 +362,7 @@ impl Component for MailView { let (x, y) = write_string_to_grid( &format!("From: {}", envelope.field_from_to_string()), grid, - Color::Byte(33), + header_fg, Color::Default, Attr::Default, (set_y(upper_left, y + 1), bottom_right), @@ -370,7 +376,7 @@ impl Component for MailView { let (x, y) = write_string_to_grid( &format!("To: {}", envelope.field_to_to_string()), grid, - Color::Byte(33), + header_fg, Color::Default, Attr::Default, (set_y(upper_left, y + 1), bottom_right), @@ -384,7 +390,7 @@ impl Component for MailView { let (x, y) = write_string_to_grid( &format!("Subject: {}", envelope.subject()), grid, - Color::Byte(33), + header_fg, Color::Default, Attr::Default, (set_y(upper_left, y + 1), bottom_right), @@ -398,7 +404,7 @@ impl Component for MailView { let (x, mut y) = write_string_to_grid( &format!("Message-ID: <{}>", envelope.message_id_raw()), grid, - Color::Byte(33), + header_fg, Color::Default, Attr::Default, (set_y(upper_left, y + 1), bottom_right), @@ -413,7 +419,7 @@ impl Component for MailView { let (x, _y) = write_string_to_grid( &format!("In-Reply-To: {}", envelope.in_reply_to_display().unwrap()), grid, - Color::Byte(33), + header_fg, Color::Default, Attr::Default, (set_y(upper_left, y + 1), bottom_right), @@ -435,7 +441,7 @@ impl Component for MailView { .join(", ") ), grid, - Color::Byte(33), + header_fg, Color::Default, Attr::Default, (set_y(upper_left, _y + 1), bottom_right), @@ -461,7 +467,7 @@ impl Component for MailView { let (_x, _) = write_string_to_grid( "List-ID: ", grid, - Color::Byte(33), + header_fg, Color::Default, Attr::Default, (set_y(upper_left, y), bottom_right), @@ -482,7 +488,7 @@ impl Component for MailView { let (_x, _) = write_string_to_grid( " Available actions: [ ", grid, - Color::Byte(33), + header_fg, Color::Default, Attr::Default, ((x, y), bottom_right), @@ -528,7 +534,7 @@ impl Component for MailView { } if archive.is_some() || post.is_some() || unsubscribe.is_some() { grid[(x - 2, y)].set_ch(' '); - grid[(x - 1, y)].set_fg(Color::Byte(33)); + grid[(x - 1, y)].set_fg(header_fg); grid[(x - 1, y)].set_bg(Color::Default); grid[(x - 1, y)].set_ch(']'); } diff --git a/ui/src/conf.rs b/ui/src/conf.rs index 46e9d09c..f4e2498e 100644 --- a/ui/src/conf.rs +++ b/ui/src/conf.rs @@ -29,6 +29,7 @@ pub mod notifications; pub mod pager; pub mod pgp; pub mod shortcuts; +pub mod terminal; pub mod accounts; pub use self::accounts::Account; @@ -38,6 +39,7 @@ pub use self::shortcuts::*; use self::default_vals::*; use self::notifications::NotificationsSettings; +use self::terminal::TerminalSettings; use crate::pager::PagerSettings; use melib::backends::SpecialUseMailbox; use melib::conf::AccountSettings; @@ -277,6 +279,8 @@ struct FileSettings { composing: ComposingSettings, #[serde(default)] pgp: PGPSettings, + #[serde(default)] + terminal: TerminalSettings, } #[derive(Debug, Clone, Default)] @@ -306,6 +310,7 @@ pub struct Settings { pub shortcuts: Shortcuts, pub composing: ComposingSettings, pub pgp: PGPSettings, + pub terminal: TerminalSettings, } impl FileSettings { @@ -394,6 +399,7 @@ impl Settings { shortcuts: fs.shortcuts, composing: fs.composing, pgp: fs.pgp, + terminal: fs.terminal, } } } diff --git a/ui/src/conf/terminal.rs b/ui/src/conf/terminal.rs new file mode 100644 index 00000000..2861cb50 --- /dev/null +++ b/ui/src/conf/terminal.rs @@ -0,0 +1,36 @@ +/* + * meli - configuration module. + * + * Copyright 2019 Manos Pitsidianakis + * + * This file is part of meli. + * + * meli is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * meli is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with meli. If not, see . + */ + +/// Settings for terminal display +#[derive(Debug, Deserialize, Clone, Serialize)] +pub struct TerminalSettings { + #[serde(default)] + /// light, dark + pub theme: String, +} + +impl Default for TerminalSettings { + fn default() -> Self { + TerminalSettings { + theme: "dark".to_string(), + } + } +}