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`.
pull/126/head
Arijit Basu 3 years ago committed by Arijit Basu
parent 59b55ee192
commit fd92d8ee01

@ -68,8 +68,8 @@ Table of content
<img height=240 width=360 src="https://s3.gifyu.com/images/xplr-serve.gif" />
</a>
<a href="https://github.com/sayanarijit/xplr/wiki/Hacks#disk-usage-dua-cli" target="_blank">
<img height=240 width=360 src="https://s4.gifyu.com/images/xplr-dua.gif" />
<a href="https://github.com/sayanarijit/xplr/wiki/Themes#material-landscape" target="_blank">
<img height=240 width=360 src="https://s3.gifyu.com/images/theaming.gif" />
</a>
<a href="https://github.com/sayanarijit/xplr/wiki/Hacks#sendreceive-files-via-qr-code-on-lan" target="_blank">

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

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

@ -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<Color>,
bg: Option<Color>,
add_modifier: Option<Modifier>,
sub_modifier: Option<Modifier>,
add_modifiers: Option<IndexSet<Modifier>>,
sub_modifiers: Option<IndexSet<Modifier>>,
}
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<TuiStyle> 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<TuiStyle> for Style {
fn into(self) -> TuiStyle {
if *NO_COLOR {
@ -60,8 +109,23 @@ impl Into<TuiStyle> 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<B: Backend>(
@ -266,7 +330,7 @@ fn draw_table<B: Backend>(
(
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<B: Backend>(
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<B: Backend>(
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<B: Backend>(
.collect::<Vec<Cell>>(),
)
.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<B: Backend>(
.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<B: Backend>(
.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<B: Backend>(
.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<B: Backend>(
.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<B: Backend>(
.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<B: Backend>(
.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<B: Backend>(
}))
.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<B: Backend>(
&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<B: Backend>(
.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::<Vec<ListItem>>();
@ -714,29 +792,34 @@ mod test {
use super::*;
use crate::config;
use tui::style::Color;
use tui::style::Modifier;
fn modifier(m: Modifier) -> Option<IndexSet<Modifier>> {
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),
},
}
);

Loading…
Cancel
Save