From fd92d8ee010cd60ce2312feb2609c637fc398c71 Mon Sep 17 00:00:00 2001 From: Arijit Basu Date: Sat, 8 May 2021 09:17:13 +0530 Subject: [PATCH] Make modifiers more intuitive It's difficult to calculate the bits for adding and removing modifiers. With this commit, we be will use words `Bold`, `Italic` instead of `bits: x`. --- README.md | 4 +- src/config.rs | 46 +++-------- src/config.yml | 88 +++------------------ src/ui.rs | 211 ++++++++++++++++++++++++++++++++++--------------- 4 files changed, 172 insertions(+), 177 deletions(-) diff --git a/README.md b/README.md index d7a8f37..4b60828 100644 --- a/README.md +++ b/README.md @@ -68,8 +68,8 @@ Table of content - - + + diff --git a/src/config.rs b/src/config.rs index f36ded7..017c7dd 100644 --- a/src/config.rs +++ b/src/config.rs @@ -4,6 +4,7 @@ use crate::app::NodeFilter; use crate::app::NodeSorter; use crate::app::NodeSorterApplicable; use crate::default_config; +use crate::ui::Border; use crate::ui::Style; use anyhow::Result; use indexmap::IndexSet; @@ -12,7 +13,6 @@ use std::collections::BTreeMap; use std::collections::HashMap; use tui::layout::Constraint as TuiConstraint; use tui::layout::Rect; -use tui::widgets::Borders as TuiBorders; #[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)] #[serde(deny_unknown_fields)] @@ -74,8 +74,8 @@ impl NodeTypeConfig { } /// Get a reference to the node type config's style. - pub fn style(&self) -> Style { - self.style + pub fn style(&self) -> &Style { + &self.style } /// Get a reference to the node type config's meta. @@ -180,8 +180,8 @@ impl UiConfig { } /// Get a reference to the ui config's style. - pub fn style(&self) -> Style { - self.style + pub fn style(&self) -> &Style { + &self.style } } @@ -208,8 +208,8 @@ impl UiElement { } /// Get a reference to the ui element's style. - pub fn style(&self) -> Style { - self.style + pub fn style(&self) -> &Style { + &self.style } } @@ -240,8 +240,8 @@ impl TableRowConfig { } /// Get a reference to the table row config's style. - pub fn style(&self) -> Style { - self.style + pub fn style(&self) -> &Style { + &self.style } /// Get a reference to the table row config's height. @@ -348,8 +348,8 @@ impl TableConfig { } /// Get a reference to the table config's style. - pub fn style(&self) -> Style { - self.style + pub fn style(&self) -> &Style { + &self.style } /// Get a reference to the table config's tree. @@ -1027,26 +1027,6 @@ impl ModesConfig { } } -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub enum Border { - Top, - Right, - Bottom, - Left, -} - -impl Border { - pub fn bits(self) -> u32 { - match self { - Self::Top => TuiBorders::TOP.bits(), - Self::Right => TuiBorders::RIGHT.bits(), - Self::Bottom => TuiBorders::BOTTOM.bits(), - Self::Left => TuiBorders::LEFT.bits(), - } - } -} - #[derive(Debug, Clone, Default, Serialize, Deserialize)] #[serde(deny_unknown_fields)] pub struct LayoutOptions { @@ -1115,8 +1095,8 @@ impl BlockConfig { } /// Get a reference to the block config's style. - pub fn style(&self) -> Style { - self.style + pub fn style(&self) -> &Style { + &self.style } } diff --git a/src/config.yml b/src/config.yml index 5c58c3e..32a2343 100644 --- a/src/config.yml +++ b/src/config.yml @@ -22,9 +22,6 @@ layouts: - SortAndFilter: borders: [Top, Right, Bottom, Left] - Table: - title: - style: - fg: Red borders: [Top, Right, Bottom, Left] - InputAndLogs: borders: [Top, Right, Bottom, Left] @@ -110,7 +107,7 @@ general: - sorter: ByIRelativePath reverse: false prompt: - format: "> " + format: "❯ " cursor: format: █ logs: @@ -133,20 +130,13 @@ general: style: fg: null bg: null - add_modifier: - bits: 0 - sub_modifier: - bits: 0 + add_modifiers: null + sub_modifiers: null - format: '╭──── path' - format: size - format: type style: - fg: null - bg: null - add_modifier: - bits: 1 - sub_modifier: - bits: 0 + add_modifiers: [Bold] height: 1 row: cols: @@ -154,78 +144,35 @@ general: - format: > {{{tree}}}{{{prefix}}}{{{meta.icon}}}{{#if (ne meta.icon "")}} {{/if}}{{{relativePath}}}{{#if isDir}}/{{/if}}{{{suffix}}} {{#if isSymlink}}-> {{#if isBroken}}×{{else}}{{{symlink.absolutePath}}}{{/if}}{{#if symlink.isDir}}/{{/if}}{{/if}} - style: - fg: null - bg: null - add_modifier: - bits: 0 - sub_modifier: - bits: 0 - format: '{{#unless isDir}}{{humansize size}}{{/unless}}' - format: '{{#if isSymlink}}{{{symlink.mimeEssence}}}{{else}}{{{mimeEssence}}}{{/if}}' - style: - fg: null - bg: null - add_modifier: - bits: 0 - sub_modifier: - bits: 0 height: 0 - style: - fg: null - bg: null - add_modifier: - bits: 0 - sub_modifier: - bits: 0 tree: - format: ├─ - style: - fg: null - bg: null - add_modifier: - bits: 0 - sub_modifier: - bits: 0 - format: ├─ - format: ╰─ - col_spacing: 1 + col_spacing: 0 col_widths: - Percentage: 10 - Percentage: 50 - Percentage: 20 - Percentage: 20 + default_ui: prefix: ' ' suffix: '' - style: - fg: null - bg: null - add_modifier: - bits: 0 - sub_modifier: - bits: 0 focus_ui: prefix: ▸[ suffix: ']' style: fg: Blue - bg: null - add_modifier: - bits: 1 - sub_modifier: - bits: 0 + add_modifiers: [Bold] selection_ui: prefix: ' {' suffix: '}' style: fg: LightGreen - bg: null - add_modifier: - bits: 1 - sub_modifier: - bits: 0 - + add_modifiers: [Bold] sort_and_filter_ui: separator: format: " › " @@ -359,31 +306,16 @@ node_types: directory: style: fg: Cyan - bg: null - add_modifier: - bits: 1 - sub_modifier: - bits: 0 + add_modifiers: [Bold] meta: icon: ð file: - style: - fg: null - bg: null - add_modifier: - bits: 0 - sub_modifier: - bits: 0 meta: icon: ƒ symlink: style: fg: Magenta - bg: null - add_modifier: - bits: 4 - sub_modifier: - bits: 0 + add_modifiers: [Italic] meta: icon: § mime_essence: {} diff --git a/src/ui.rs b/src/ui.rs index fe399c7..8996c26 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -4,6 +4,7 @@ use crate::app::{Node, ResolvedNode}; use crate::config::BlockConfig; use crate::config::Layout; use handlebars::Handlebars; +use indexmap::IndexSet; use lazy_static::lazy_static; use serde::{Deserialize, Serialize}; use std::cmp::Ordering; @@ -12,7 +13,7 @@ use std::env; use tui::backend::Backend; use tui::layout::Rect; use tui::layout::{Constraint as TuiConstraint, Direction, Layout as TuiLayout}; -use tui::style::{Color, Modifier, Style as TuiStyle}; +use tui::style::{Color, Modifier as TuiModifier, Style as TuiStyle}; use tui::text::{Span, Spans}; use tui::widgets::{Block, Borders as TuiBorders, Cell, List, ListItem, Paragraph, Row, Table}; use tui::Frame; @@ -22,36 +23,84 @@ lazy_static! { pub static ref DEFAULT_STYLE: TuiStyle = TuiStyle::default(); } -#[derive(Debug, Copy, Clone, Default, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub enum Border { + Top, + Right, + Bottom, + Left, +} + +impl Border { + pub fn bits(self) -> u32 { + match self { + Self::Top => TuiBorders::TOP.bits(), + Self::Right => TuiBorders::RIGHT.bits(), + Self::Bottom => TuiBorders::BOTTOM.bits(), + Self::Left => TuiBorders::LEFT.bits(), + } + } +} + +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub enum Modifier { + Bold, + Dim, + Italic, + Underlined, + SlowBlink, + RapidBlink, + Reversed, + Hidden, + CrossedOut, +} + +impl Modifier { + pub fn bits(self) -> u16 { + match self { + Self::Bold => TuiModifier::BOLD.bits(), + Self::Dim => TuiModifier::DIM.bits(), + Self::Italic => TuiModifier::ITALIC.bits(), + Self::Underlined => TuiModifier::UNDERLINED.bits(), + Self::SlowBlink => TuiModifier::SLOW_BLINK.bits(), + Self::RapidBlink => TuiModifier::RAPID_BLINK.bits(), + Self::Reversed => TuiModifier::REVERSED.bits(), + Self::Hidden => TuiModifier::HIDDEN.bits(), + Self::CrossedOut => TuiModifier::CROSSED_OUT.bits(), + } + } +} + +#[derive(Debug, Clone, Default, Serialize, Deserialize)] #[serde(deny_unknown_fields)] pub struct Style { fg: Option, bg: Option, - add_modifier: Option, - sub_modifier: Option, + add_modifiers: Option>, + sub_modifiers: Option>, +} + +impl PartialEq for Style { + fn eq(&self, other: &Self) -> bool { + self.fg == other.fg + && self.bg == other.bg + && self.add_modifiers == other.add_modifiers + && self.sub_modifiers == other.sub_modifiers + } } impl Style { pub fn extend(mut self, other: Self) -> Self { self.fg = other.fg.or(self.fg); self.bg = other.bg.or(self.bg); - self.add_modifier = other.add_modifier.or(self.add_modifier); - self.sub_modifier = other.sub_modifier.or(self.sub_modifier); + self.add_modifiers = other.add_modifiers.or(self.add_modifiers); + self.sub_modifiers = other.sub_modifiers.or(self.sub_modifiers); self } } -impl From for Style { - fn from(s: TuiStyle) -> Self { - Self { - fg: s.fg, - bg: s.bg, - add_modifier: Some(s.add_modifier), - sub_modifier: Some(s.sub_modifier), - } - } -} - impl Into for Style { fn into(self) -> TuiStyle { if *NO_COLOR { @@ -60,8 +109,23 @@ impl Into for Style { TuiStyle { fg: self.fg, bg: self.bg, - add_modifier: self.add_modifier.unwrap_or_else(Modifier::empty), - sub_modifier: self.sub_modifier.unwrap_or_else(Modifier::empty), + add_modifier: TuiModifier::from_bits_truncate( + self.add_modifiers + .unwrap_or_default() + .into_iter() + .map(|m| m.bits()) + .reduce(|a, b| (a ^ b)) + .unwrap_or_else(|| TuiModifier::empty().bits()), + ), + + sub_modifier: TuiModifier::from_bits_truncate( + self.sub_modifiers + .unwrap_or_default() + .into_iter() + .map(|m| m.bits()) + .reduce(|a, b| (a ^ b)) + .unwrap_or_else(|| TuiModifier::empty().bits()), + ), } } } @@ -183,9 +247,9 @@ fn block<'a>(config: BlockConfig, default_title: String) -> Block<'a> { )) .title(Span::styled( config.title().format().clone().unwrap_or(default_title), - config.title().style().into(), + config.title().style().clone().into(), )) - .style(config.style().into()) + .style(config.style().clone().into()) } fn draw_table( @@ -266,7 +330,7 @@ fn draw_table( ( ui.prefix().clone(), ui.suffix().clone(), - ui.style().extend(node_type.style()), + ui.style().clone().extend(node_type.style().clone()), ) }; @@ -274,14 +338,14 @@ fn draw_table( let ui = app_config.general().selection_ui().clone(); prefix = ui.prefix().clone().or(prefix); suffix = ui.suffix().clone().or(suffix); - style = style.extend(ui.style()); + style = style.extend(ui.style().clone()); }; if is_focused { let ui = app_config.general().focus_ui().clone(); prefix = ui.prefix().clone().or(prefix); suffix = ui.suffix().clone().or(suffix); - style = style.extend(ui.style()); + style = style.extend(ui.style().clone()); }; let meta = NodeUiMetadata::new( @@ -325,8 +389,8 @@ fn draw_table( let table = Table::new(rows) .widths(&table_constraints) - .style(app_config.general().table().style().into()) - .highlight_style(app_config.general().focus_ui().style().into()) + .style(app_config.general().table().style().clone().into()) + .highlight_style(app_config.general().focus_ui().style().clone().into()) .column_spacing( app_config .general() @@ -359,7 +423,7 @@ fn draw_table( .collect::>(), ) .height(header_height) - .style(app_config.general().table().header().style().into()), + .style(app_config.general().table().header().style().clone().into()), ); f.render_widget(table, layout_size); @@ -456,7 +520,7 @@ fn draw_input_buffer( .format() .clone() .unwrap_or_default(), - app.config().general().prompt().style().into(), + app.config().general().prompt().style().clone().into(), ), Span::raw(app.input_buffer().unwrap_or_else(|| "".into())), Span::styled( @@ -466,7 +530,7 @@ fn draw_input_buffer( .format() .clone() .unwrap_or_default(), - app.config().general().cursor().style().into(), + app.config().general().cursor().style().clone().into(), ), ])) .block(block(config, " Input ".into())); @@ -490,7 +554,11 @@ fn draw_sort_n_filter( .format() .to_owned() .unwrap_or_default(), - ui.sort_direction_identifiers().forward().style().into(), + ui.sort_direction_identifiers() + .forward() + .style() + .clone() + .into(), ); let reverse = Span::styled( @@ -499,7 +567,11 @@ fn draw_sort_n_filter( .format() .to_owned() .unwrap_or_default(), - ui.sort_direction_identifiers().reverse().style().into(), + ui.sort_direction_identifiers() + .reverse() + .style() + .clone() + .into(), ); let mut spans = filter_by @@ -509,7 +581,10 @@ fn draw_sort_n_filter( .get(&f.filter()) .map(|u| { ( - Span::styled(u.format().to_owned().unwrap_or_default(), u.style().into()), + Span::styled( + u.format().to_owned().unwrap_or_default(), + u.style().clone().into(), + ), Span::raw(f.input().clone()), ) }) @@ -526,7 +601,10 @@ fn draw_sort_n_filter( .get(&s.sorter()) .map(|u| { ( - Span::styled(u.format().to_owned().unwrap_or_default(), u.style().into()), + Span::styled( + u.format().to_owned().unwrap_or_default(), + u.style().clone().into(), + ), direction.clone(), ) }) @@ -534,7 +612,7 @@ fn draw_sort_n_filter( })) .zip(std::iter::repeat(Span::styled( ui.separator().format().to_owned().unwrap_or_default(), - ui.separator().style().into(), + ui.separator().style().clone().into(), ))) .map(|((a, b), c)| vec![a, b, c]) .flatten() @@ -573,7 +651,7 @@ fn draw_logs( &logs_config.info().format().to_owned().unwrap_or_default(), l.message() )) - .style(logs_config.info().style().into()), + .style(logs_config.info().style().clone().into()), app::LogLevel::Success => ListItem::new(format!( "{} | {} | {}", &time, @@ -584,14 +662,14 @@ fn draw_logs( .unwrap_or_default(), l.message() )) - .style(logs_config.success().style().into()), + .style(logs_config.success().style().clone().into()), app::LogLevel::Error => ListItem::new(format!( "{} | {} | {}", &time, &logs_config.error().format().to_owned().unwrap_or_default(), l.message() )) - .style(logs_config.error().style().into()), + .style(logs_config.error().style().clone().into()), } }) .collect::>(); @@ -714,29 +792,34 @@ mod test { use super::*; use crate::config; use tui::style::Color; - use tui::style::Modifier; + + fn modifier(m: Modifier) -> Option> { + let mut x = IndexSet::new(); + x.insert(m); + Some(x) + } #[test] fn test_extend_style() { let a = Style { fg: Some(Color::Red), bg: None, - add_modifier: Some(Modifier::BOLD), - sub_modifier: None, + add_modifiers: modifier(Modifier::Bold), + sub_modifiers: None, }; let b = Style { fg: None, bg: Some(Color::Blue), - add_modifier: None, - sub_modifier: Some(Modifier::DIM), + add_modifiers: None, + sub_modifiers: modifier(Modifier::Dim), }; let c = Style { fg: Some(Color::Cyan), bg: Some(Color::Magenta), - add_modifier: Some(Modifier::CROSSED_OUT), - sub_modifier: Some(Modifier::ITALIC), + add_modifiers: modifier(Modifier::CrossedOut), + sub_modifiers: modifier(Modifier::Italic), }; assert_eq!( @@ -744,8 +827,8 @@ mod test { Style { fg: Some(Color::Red), bg: Some(Color::Blue), - add_modifier: Some(Modifier::BOLD), - sub_modifier: Some(Modifier::DIM), + add_modifiers: modifier(Modifier::Bold), + sub_modifiers: modifier(Modifier::Dim), } ); @@ -754,8 +837,8 @@ mod test { Style { fg: Some(Color::Red), bg: Some(Color::Blue), - add_modifier: Some(Modifier::BOLD), - sub_modifier: Some(Modifier::DIM), + add_modifiers: modifier(Modifier::Bold), + sub_modifiers: modifier(Modifier::Dim), } ); @@ -764,8 +847,8 @@ mod test { Style { fg: Some(Color::Cyan), bg: Some(Color::Magenta), - add_modifier: Some(Modifier::CROSSED_OUT), - sub_modifier: Some(Modifier::ITALIC), + add_modifiers: modifier(Modifier::CrossedOut), + sub_modifiers: modifier(Modifier::Italic), } ); @@ -774,8 +857,8 @@ mod test { Style { fg: Some(Color::Red), bg: Some(Color::Magenta), - add_modifier: Some(Modifier::BOLD), - sub_modifier: Some(Modifier::ITALIC), + add_modifiers: modifier(Modifier::Bold), + sub_modifiers: modifier(Modifier::Italic), } ); } @@ -788,8 +871,8 @@ mod test { style: Style { fg: Some(Color::Red), bg: None, - add_modifier: Some(Modifier::BOLD), - sub_modifier: None, + add_modifiers: modifier(Modifier::Bold), + sub_modifiers: None, }, }; @@ -799,8 +882,8 @@ mod test { style: Style { fg: None, bg: Some(Color::Blue), - add_modifier: None, - sub_modifier: Some(Modifier::DIM), + add_modifiers: None, + sub_modifiers: modifier(Modifier::Dim), }, }; @@ -810,8 +893,8 @@ mod test { style: Style { fg: Some(Color::Cyan), bg: Some(Color::Magenta), - add_modifier: Some(Modifier::CROSSED_OUT), - sub_modifier: Some(Modifier::ITALIC), + add_modifiers: modifier(Modifier::CrossedOut), + sub_modifiers: modifier(Modifier::Italic), }, }; @@ -823,8 +906,8 @@ mod test { style: Style { fg: Some(Color::Red), bg: Some(Color::Blue), - add_modifier: Some(Modifier::BOLD), - sub_modifier: Some(Modifier::DIM), + add_modifiers: modifier(Modifier::Bold), + sub_modifiers: modifier(Modifier::Dim), }, } ); @@ -837,8 +920,8 @@ mod test { style: Style { fg: Some(Color::Red), bg: Some(Color::Blue), - add_modifier: Some(Modifier::BOLD), - sub_modifier: Some(Modifier::DIM), + add_modifiers: modifier(Modifier::Bold), + sub_modifiers: modifier(Modifier::Dim), }, } ); @@ -851,8 +934,8 @@ mod test { style: Style { fg: Some(Color::Cyan), bg: Some(Color::Magenta), - add_modifier: Some(Modifier::CROSSED_OUT), - sub_modifier: Some(Modifier::ITALIC), + add_modifiers: modifier(Modifier::CrossedOut), + sub_modifiers: modifier(Modifier::Italic), }, } );