use crate::options::SkimOptions;
use tuikit::prelude::*;
#[rustfmt::skip]
lazy_static! {
pub static ref DEFAULT_THEME: ColorTheme = ColorTheme::dark256();
}
#[rustfmt::skip]
#[derive(Copy, Clone, Debug)]
pub struct ColorTheme {
fg: Color,
bg: Color,
normal_effect: Effect,
matched: Color,
matched_bg: Color,
matched_effect: Effect,
current: Color,
current_bg: Color,
current_effect: Effect,
current_match: Color,
current_match_bg: Color,
current_match_effect: Effect,
query_fg: Color,
query_bg: Color,
query_effect: Effect,
spinner: Color,
info: Color,
prompt: Color,
cursor: Color,
selected: Color,
header: Color,
border: Color,
}
#[rustfmt::skip]
#[allow(dead_code)]
impl ColorTheme {
pub fn init_from_options(options: &SkimOptions) -> ColorTheme {
if let Some(color) = options.color {
ColorTheme::from_options(color)
} else {
ColorTheme::dark256()
}
}
fn empty() -> Self {
ColorTheme {
fg: Color::Default,
bg: Color::Default,
normal_effect: Effect::empty(),
matched: Color::Default,
matched_bg: Color::Default,
matched_effect: Effect::empty(),
current: Color::Default,
current_bg: Color::Default,
current_effect: Effect::empty(),
current_match: Color::Default,
current_match_bg: Color::Default,
current_match_effect: Effect::empty(),
query_fg: Color::Default,
query_bg: Color::Default,
query_effect: Effect::empty(),
spinner: Color::Default,
info: Color::Default,
prompt: Color::Default,
cursor: Color::Default,
selected: Color::Default,
header: Color::Default,
border: Color::Default,
}
}
fn bw() -> Self {
ColorTheme {
matched_effect: Effect::UNDERLINE,
current_effect: Effect::REVERSE,
current_match_effect: Effect::UNDERLINE | Effect::REVERSE,
..ColorTheme::empty()
}
}
fn default16() -> Self {
ColorTheme {
matched: Color::GREEN,
matched_bg: Color::BLACK,
current: Color::YELLOW,
current_bg: Color::BLACK,
current_match: Color::GREEN,
current_match_bg: Color::BLACK,
spinner: Color::GREEN,
info: Color::WHITE,
prompt: Color::BLUE,
cursor: Color::RED,
selected: Color::MAGENTA,
header: Color::CYAN,
border: Color::LIGHT_BLACK,
..ColorTheme::empty()
}
}
fn dark256() -> Self {
ColorTheme {
matched: Color::AnsiValue(108),
matched_bg: Color::AnsiValue(0),
current: Color::AnsiValue(254),
current_bg: Color::AnsiValue(236),
current_match: Color::AnsiValue(151),
current_match_bg: Color::AnsiValue(236),
spinner: Color::AnsiValue(148),
info: Color::AnsiValue(144),
prompt: Color::AnsiValue(110),
cursor: Color::AnsiValue(161),
selected: Color::AnsiValue(168),
header: Color::AnsiValue(109),
border: Color::AnsiValue(59),
..ColorTheme::empty()
}
}
fn molokai256() -> Self {
ColorTheme {
matched: Color::AnsiValue(234),
matched_bg: Color::AnsiValue(186),
current: Color::AnsiValue(254),
current_bg: Color::AnsiValue(236),
current_match: Color::AnsiValue(234),
current_match_bg: Color::AnsiValue(186),
spinner: Color::AnsiValue(148),
info: Color::AnsiValue(144),
prompt: Color::AnsiValue(110),
cursor: Color::AnsiValue(161),
selected: Color::AnsiValue(168),
header: Color::AnsiValue(109),
border: Color::AnsiValue(59),
..ColorTheme::empty()
}
}
fn light256() -> Self {
ColorTheme {
matched: Color::AnsiValue(0),
matched_bg: Color::AnsiValue(220),
current: Color::AnsiValue(237),
current_bg: Color::AnsiValue(251),
current_match: Color::AnsiValue(66),
current_match_bg: Color::AnsiValue(251),
spinner: Color::AnsiValue(65),
info: Color::AnsiValue(101),
prompt: Color::AnsiValue(25),
cursor: Color::AnsiValue(161),
selected: Color::AnsiValue(168),
header: Color::AnsiValue(31),
border: Color::AnsiValue(145),
..ColorTheme::empty()
}
}
#[allow(clippy::wildcard_in_or_patterns)]
fn from_options(color: &str) -> Self {
let mut theme = ColorTheme::dark256();
for pair in color.split(',') {
let color: Vec<&str> = pair.split(':').collect();
if color.len() < 2 {
theme = match color[0] {
"molokai" => ColorTheme::molokai256(),
"light" => ColorTheme::light256(),
"16" => ColorTheme::default16(),
"bw" => ColorTheme::bw(),
"empty" => ColorTheme::empty(),
"dark" | "default" | _ => ColorTheme::dark256(),
};
continue;
}
let new_color = if color[1].len() == 7 {
let r = u8::from_str_radix(&color[1][1..3], 16).unwrap_or(255);
let g = u8::from_str_radix(&color[1][3..5], 16).unwrap_or(255);
let b = u8::from_str_radix(&color[1][5..7], 16).unwrap_or(255);
Color::Rgb(r, g, b)
} else {
color[1].parse::<u8>()
.map(Color::AnsiValue)
.unwrap_or(Color::Default)
};
match color[0] {
"fg" => theme.fg = new_color,
"bg" => theme.bg = new_color,
"matched" | "hl" => theme.matched = new_color,
"matched_bg" => theme.matched_bg = new_color,
"current" | "fg+" => theme.current = new_color,
"current_bg" | "bg+" => theme.current_bg = new_color,
"current_match" | "hl+" => theme.current_match = new_color,
"current_match_bg" => theme.current_match_bg = new_color,
"query" => theme.query_fg = new_color,
"query_bg" => theme.query_bg = new_color,
"spinner" => theme.spinner = new_color,
"info" => theme.info = new_color,
"prompt" => theme.prompt = new_color,
"cursor" | "pointer" => theme.cursor = new_color,
"selected" | "marker" => theme.selected = new_color,
"header" => theme.header = new_color,
"border" => theme.border = new_color,
_ => {}
}
}
theme
}
pub fn normal(&self) -> Attr {
Attr {
fg: self.fg,
bg: self.bg,
effect: self.normal_effect,
}
}
pub fn matched(&self) -> Attr {
Attr {
fg: self.matched,
bg: self.matched_bg,
effect: self.matched_effect,
}
}
pub fn current(&self) -> Attr {
Attr {
fg: self.current,
bg: self.current_bg,
effect: self.current_effect,
}
}
pub fn current_match(&self) -> Attr {
Attr {
fg: self.current_match,
bg: self.current_match_bg,
effect: self.current_match_effect,
}
}
pub fn query(&self) -> Attr {
Attr {
fg: self.query_fg,
bg: self.query_bg,
effect: self.query_effect,
}
}
pub fn spinner(&self) -> Attr {
Attr {
fg: self.spinner,
bg: self.bg,
effect: Effect::BOLD,
}
}
pub fn info(&self) -> Attr {
Attr {
fg: self.info,
bg: self.bg,
effect: Effect::empty(),
}
}
pub fn prompt(&self) -> Attr {
Attr {
fg: self.prompt,
bg: self.bg,
effect: Effect::empty(),
}
}
pub fn cursor(&self) -> Attr {
Attr {
fg: self.cursor,
bg: self.current_bg,
effect: Effect::empty(),
}
}
pub fn selected(&self) -> Attr {
Attr {
fg: self.selected,
bg: self.current_bg,
effect: Effect::empty(),
}
}
pub fn header(&self) -> Attr {
Attr {
fg: self.header,
bg: self.bg,
effect: Effect::empty(),
}
}
pub fn border(&self) -> Attr {
Attr {
fg: self.border,
bg: self.bg,
effect: Effect::empty(),
}
}
}