use {
super::*,
crate::errors::ProgramError,
crokey::crossterm::{
QueueableCommand,
style::{
Attribute::*,
Attributes,
Color::*,
SetBackgroundColor,
},
},
rustc_hash::FxHashMap,
std::{
fmt,
io::Write,
},
termimad::CompoundStyle,
};
macro_rules! StyleMap {
(
$(
$name:ident: $fg:expr, $bg:expr, [$($attr:expr)*] $( / $fgu:expr, $bgu:expr , [$($attru:expr)*] )*
)*
) => {
pub struct StyleMap {
styled: bool,
$(pub $name: CompoundStyle,)*
}
pub struct StyleMaps {
pub focused: StyleMap,
pub unfocused: StyleMap,
}
impl StyleMap {
pub fn no_term() -> Self {
Self {
styled: false,
$($name: CompoundStyle::default(),)*
}
}
fn diffuse_default(&mut self) {
$(
let mut base = self.default.clone();
base.overwrite_with(&self.$name);
self.$name = base;
)*
}
}
impl StyleMaps {
pub fn create(skin_conf: &FxHashMap<String, SkinEntry>) -> Self {
let mut focused = StyleMap {
styled: true,
$($name: skin_conf
.get(stringify!($name))
.map(|sec| sec.get_focused().clone())
.unwrap_or(
CompoundStyle::new(
$fg,
$bg,
Attributes::from(vec![$($attr),*].as_slice()),
)
)
,)*
};
focused.diffuse_default();
let mut unfocused = StyleMap {
styled: true,
$($name: CompoundStyle::default(),)*
};
$(
unfocused.$name = CompoundStyle::new(
$fg,
$bg,
Attributes::from(vec![$($attr),*].as_slice()),
);
$(
unfocused.$name = CompoundStyle::new(
$fgu,
$bgu,
Attributes::from(vec![$($attru),*].as_slice()),
);
)*
if let Some(sec) = skin_conf.get(stringify!($name)) {
unfocused.$name = sec.get_unfocused().clone();
}
)*
unfocused.diffuse_default();
Self {
focused,
unfocused,
}
}
}
impl Clone for StyleMap {
fn clone(&self) -> Self {
Self {
styled: self.styled,
$($name: self.$name.clone(),)*
}
}
}
}
}
impl StyleMap {
pub fn queue_reset<W: Write>(
&self,
f: &mut W,
) -> Result<(), ProgramError> {
if self.styled {
f.queue(SetBackgroundColor(Color::Reset))?;
}
Ok(())
}
pub fn good_to_bad_color(
&self,
value: f64,
) -> Color {
debug_assert!((0.0..=1.0).contains(&value));
const N: usize = 10;
let idx = (value * N as f64) as usize;
let cs = match idx {
0 => &self.good_to_bad_0,
1 => &self.good_to_bad_1,
2 => &self.good_to_bad_2,
3 => &self.good_to_bad_3,
4 => &self.good_to_bad_4,
5 => &self.good_to_bad_5,
6 => &self.good_to_bad_6,
7 => &self.good_to_bad_7,
8 => &self.good_to_bad_8,
_ => &self.good_to_bad_9,
};
cs.object_style.foreground_color.unwrap_or(Color::Blue)
}
}
StyleMap! {
default: gray(22), gray(2), [] / gray(20), gray(2), []
tree: gray(8), None, [] / gray(4), None, []
parent: gray(18), None, [] / gray(13), None, []
file: gray(22), None, [] / gray(15), None, []
directory: ansi(110), None, [Bold] / ansi(110), None, []
exe: Some(Cyan), None, []
link: Some(Magenta), None, []
pruning: gray(12), None, [Italic]
perm__: gray(5), None, []
perm_r: ansi(94), None, []
perm_w: ansi(132), None, []
perm_x: ansi(65), None, []
owner: ansi(138), None, []
group: ansi(131), None, []
count: ansi(138), gray(4), []
dates: ansi(66), None, []
sparse: ansi(214), None, []
content_extract: ansi(29), None, []
content_match: ansi(34), None, []
device_id_major: ansi(138), None, []
device_id_sep: ansi(102), None, []
device_id_minor: ansi(138), None, []
git_branch: ansi(178), None, []
git_insertions: ansi(28), None, []
git_deletions: ansi(160), None, []
git_status_current: gray(5), None, []
git_status_modified: ansi(28), None, []
git_status_new: ansi(94), None, [Bold]
git_status_ignored: gray(17), None, []
git_status_conflicted: ansi(88), None, []
git_status_other: ansi(88), None, []
selected_line: None, gray(6), [] / None, gray(4), []
char_match: Some(Green), None, []
file_error: Some(Red), None, []
flag_label: gray(15), gray(2), []
flag_value: ansi(178), gray(2), [Bold]
input: Some(White), gray(2), [] / gray(15), None, []
status_error: gray(22), ansi(124), []
status_job: ansi(220), gray(5), []
status_normal: gray(20), gray(4), [] / gray(2), gray(2), []
status_italic: ansi(178), gray(4), [] / gray(2), gray(2), []
status_bold: ansi(178), gray(4), [Bold] / gray(2), gray(2), []
status_code: ansi(229), gray(4), [] / gray(2), gray(2), []
status_ellipsis: gray(19), gray(1), [] / gray(2), gray(2), []
purpose_normal: gray(20), gray(2), []
purpose_italic: ansi(178), gray(2), []
purpose_bold: ansi(178), gray(2), [Bold]
purpose_ellipsis: gray(20), gray(2), []
scrollbar_track: gray(7), None, [] / gray(4), None, []
scrollbar_thumb: gray(22), None, [] / gray(14), None, []
help_paragraph: gray(20), None, []
help_bold: ansi(178), None, [Bold]
help_italic: ansi(229), None, []
help_code: gray(21), gray(3), []
help_headers: ansi(178), None, []
help_table_border: ansi(239), None, []
preview: gray(20), gray(1), [] / gray(18), gray(2), []
preview_title: gray(23), gray(2), [] / gray(21), gray(2), []
preview_line_number: gray(12), gray(3), []
preview_separator: gray(7), None, []
preview_match: None, ansi(29), []
hex_null: gray(8), None, []
hex_ascii_graphic: gray(18), None, []
hex_ascii_whitespace: ansi(143), None, []
hex_ascii_other: ansi(215), None, []
hex_non_ascii: ansi(167), None, []
staging_area_title: gray(22), gray(2), [] / gray(20), gray(3), []
mode_command_mark: gray(5), ansi(204), [Bold]
good_to_bad_0: ansi(28), None, []
good_to_bad_1: ansi(29), None, []
good_to_bad_2: ansi(29), None, []
good_to_bad_3: ansi(29), None, []
good_to_bad_4: ansi(29), None, []
good_to_bad_5: ansi(100), None, []
good_to_bad_6: ansi(136), None, []
good_to_bad_7: ansi(172), None, []
good_to_bad_8: ansi(166), None, []
good_to_bad_9: ansi(196), None, []
}
impl fmt::Debug for StyleMap {
fn fmt(
&self,
f: &mut fmt::Formatter<'_>,
) -> fmt::Result {
write!(f, "Skin")
}
}