mirror of
https://github.com/alexpasmantier/television.git
synced 2025-06-06 19:45:23 +00:00
feat(ui): add support for standard ANSI colors theming and update default theme (#221)
Fixes #211 <img width="2554" alt="Screenshot 2025-01-06 at 13 01 57" src="https://github.com/user-attachments/assets/3706b93a-4be1-4a88-8c3e-bfb71a36db50" />
This commit is contained in:
parent
53bd4a3815
commit
d7e6c35735
@ -56,7 +56,7 @@ input_bar_position = "top"
|
||||
# A list of builtin themes can be found in the `themes` directory of the television
|
||||
# repository. You may also create your own theme by creating a new file in a `themes`
|
||||
# directory in your configuration directory (see the `config.toml` location above).
|
||||
theme = "catppuccin"
|
||||
theme = "default"
|
||||
|
||||
# Previewers settings
|
||||
# ----------------------------------------------------------------------------
|
||||
@ -65,7 +65,7 @@ theme = "catppuccin"
|
||||
# Bulitin syntax highlighting uses the same syntax highlighting engine as bat.
|
||||
# To get a list of your currently available themes, run `bat --list-themes`
|
||||
# Note that setting the BAT_THEME environment variable will override this setting.
|
||||
theme = "Coldark-Dark"
|
||||
theme = "TwoDark"
|
||||
|
||||
# Keybindings
|
||||
# ----------------------------------------------------------------------------
|
||||
|
@ -12,14 +12,68 @@ use super::get_config_dir;
|
||||
|
||||
pub mod builtin;
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct Color {
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Color {
|
||||
Ansi(ANSIColor),
|
||||
Rgb(RGBColor),
|
||||
}
|
||||
|
||||
impl Color {
|
||||
pub fn from_str(s: &str) -> Option<Self> {
|
||||
if s.starts_with('#') {
|
||||
RGBColor::from_str(s).map(Self::Rgb)
|
||||
} else {
|
||||
match s.to_lowercase().as_str() {
|
||||
"black" => Some(Self::Ansi(ANSIColor::Black)),
|
||||
"red" => Some(Self::Ansi(ANSIColor::Red)),
|
||||
"green" => Some(Self::Ansi(ANSIColor::Green)),
|
||||
"yellow" => Some(Self::Ansi(ANSIColor::Yellow)),
|
||||
"blue" => Some(Self::Ansi(ANSIColor::Blue)),
|
||||
"magenta" => Some(Self::Ansi(ANSIColor::Magenta)),
|
||||
"cyan" => Some(Self::Ansi(ANSIColor::Cyan)),
|
||||
"white" => Some(Self::Ansi(ANSIColor::White)),
|
||||
"bright-black" => Some(Self::Ansi(ANSIColor::BrightBlack)),
|
||||
"bright-red" => Some(Self::Ansi(ANSIColor::BrightRed)),
|
||||
"bright-green" => Some(Self::Ansi(ANSIColor::BrightGreen)),
|
||||
"bright-yellow" => Some(Self::Ansi(ANSIColor::BrightYellow)),
|
||||
"bright-blue" => Some(Self::Ansi(ANSIColor::BrightBlue)),
|
||||
"bright-magenta" => Some(Self::Ansi(ANSIColor::BrightMagenta)),
|
||||
"bright-cyan" => Some(Self::Ansi(ANSIColor::BrightCyan)),
|
||||
"bright-white" => Some(Self::Ansi(ANSIColor::BrightWhite)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum ANSIColor {
|
||||
Black,
|
||||
Red,
|
||||
Green,
|
||||
Yellow,
|
||||
Blue,
|
||||
Magenta,
|
||||
Cyan,
|
||||
White,
|
||||
BrightBlack,
|
||||
BrightRed,
|
||||
BrightGreen,
|
||||
BrightYellow,
|
||||
BrightBlue,
|
||||
BrightMagenta,
|
||||
BrightCyan,
|
||||
BrightWhite,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
pub struct RGBColor {
|
||||
pub r: u8,
|
||||
pub g: u8,
|
||||
pub b: u8,
|
||||
}
|
||||
|
||||
impl Color {
|
||||
impl RGBColor {
|
||||
pub fn new(r: u8, g: u8, b: u8) -> Self {
|
||||
Self { r, g, b }
|
||||
}
|
||||
@ -90,11 +144,11 @@ impl Theme {
|
||||
}
|
||||
}
|
||||
|
||||
pub const DEFAULT_THEME: &str = "gruvbox-dark";
|
||||
pub const DEFAULT_THEME: &str = "default";
|
||||
|
||||
impl Default for Theme {
|
||||
fn default() -> Self {
|
||||
let theme_content = include_str!("../../../themes/gruvbox-dark.toml");
|
||||
let theme_content = include_str!("../../../themes/default.toml");
|
||||
toml::from_str(theme_content).unwrap()
|
||||
}
|
||||
}
|
||||
@ -179,12 +233,46 @@ impl<'de> Deserialize<'de> for Theme {
|
||||
}
|
||||
|
||||
#[allow(clippy::from_over_into)]
|
||||
impl Into<RatatuiColor> for &Color {
|
||||
impl Into<RatatuiColor> for &RGBColor {
|
||||
fn into(self) -> RatatuiColor {
|
||||
RatatuiColor::Rgb(self.r, self.g, self.b)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::from_over_into)]
|
||||
impl Into<RatatuiColor> for &ANSIColor {
|
||||
fn into(self) -> RatatuiColor {
|
||||
match self {
|
||||
ANSIColor::Black => RatatuiColor::Black,
|
||||
ANSIColor::Red => RatatuiColor::Red,
|
||||
ANSIColor::Green => RatatuiColor::Green,
|
||||
ANSIColor::Yellow => RatatuiColor::Yellow,
|
||||
ANSIColor::Blue => RatatuiColor::Blue,
|
||||
ANSIColor::Magenta => RatatuiColor::Magenta,
|
||||
ANSIColor::Cyan => RatatuiColor::Cyan,
|
||||
ANSIColor::White => RatatuiColor::Gray,
|
||||
ANSIColor::BrightBlack => RatatuiColor::DarkGray,
|
||||
ANSIColor::BrightRed => RatatuiColor::LightRed,
|
||||
ANSIColor::BrightGreen => RatatuiColor::LightGreen,
|
||||
ANSIColor::BrightYellow => RatatuiColor::LightYellow,
|
||||
ANSIColor::BrightBlue => RatatuiColor::LightBlue,
|
||||
ANSIColor::BrightMagenta => RatatuiColor::LightMagenta,
|
||||
ANSIColor::BrightCyan => RatatuiColor::LightCyan,
|
||||
ANSIColor::BrightWhite => RatatuiColor::White,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::from_over_into)]
|
||||
impl Into<RatatuiColor> for &Color {
|
||||
fn into(self) -> RatatuiColor {
|
||||
match self {
|
||||
Color::Ansi(ansi) => ansi.into(),
|
||||
Color::Rgb(rgb) => rgb.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::from_over_into)]
|
||||
impl Into<Colorscheme> for &Theme {
|
||||
fn into(self) -> Colorscheme {
|
||||
@ -265,3 +353,111 @@ impl Into<ModeColorscheme> for &Theme {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_theme_deserialization() {
|
||||
let theme_content = r##"
|
||||
background = "#000000"
|
||||
border_fg = "black"
|
||||
text_fg = "white"
|
||||
dimmed_text_fg = "bright-black"
|
||||
input_text_fg = "bright-white"
|
||||
result_count_fg = "bright-white"
|
||||
result_name_fg = "bright-white"
|
||||
result_line_number_fg = "bright-white"
|
||||
result_value_fg = "bright-white"
|
||||
selection_bg = "bright-white"
|
||||
match_fg = "bright-white"
|
||||
preview_title_fg = "bright-white"
|
||||
channel_mode_fg = "bright-white"
|
||||
remote_control_mode_fg = "bright-white"
|
||||
send_to_channel_mode_fg = "bright-white"
|
||||
"##;
|
||||
let theme: Theme = toml::from_str(theme_content).unwrap();
|
||||
assert_eq!(
|
||||
theme.background,
|
||||
Some(Color::Rgb(RGBColor::from_str("000000").unwrap()))
|
||||
);
|
||||
assert_eq!(theme.border_fg, Color::Ansi(ANSIColor::Black));
|
||||
assert_eq!(theme.text_fg, Color::Ansi(ANSIColor::White));
|
||||
assert_eq!(theme.dimmed_text_fg, Color::Ansi(ANSIColor::BrightBlack));
|
||||
assert_eq!(theme.input_text_fg, Color::Ansi(ANSIColor::BrightWhite));
|
||||
assert_eq!(theme.result_count_fg, Color::Ansi(ANSIColor::BrightWhite));
|
||||
assert_eq!(theme.result_name_fg, Color::Ansi(ANSIColor::BrightWhite));
|
||||
assert_eq!(
|
||||
theme.result_line_number_fg,
|
||||
Color::Ansi(ANSIColor::BrightWhite)
|
||||
);
|
||||
assert_eq!(theme.result_value_fg, Color::Ansi(ANSIColor::BrightWhite));
|
||||
assert_eq!(theme.selection_bg, Color::Ansi(ANSIColor::BrightWhite));
|
||||
assert_eq!(theme.match_fg, Color::Ansi(ANSIColor::BrightWhite));
|
||||
assert_eq!(
|
||||
theme.preview_title_fg,
|
||||
Color::Ansi(ANSIColor::BrightWhite)
|
||||
);
|
||||
assert_eq!(theme.channel_mode_fg, Color::Ansi(ANSIColor::BrightWhite));
|
||||
assert_eq!(
|
||||
theme.remote_control_mode_fg,
|
||||
Color::Ansi(ANSIColor::BrightWhite)
|
||||
);
|
||||
assert_eq!(
|
||||
theme.send_to_channel_mode_fg,
|
||||
Color::Ansi(ANSIColor::BrightWhite)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_theme_deserialization_no_background() {
|
||||
let theme_content = r##"
|
||||
border_fg = "black"
|
||||
text_fg = "white"
|
||||
dimmed_text_fg = "bright-black"
|
||||
input_text_fg = "bright-white"
|
||||
result_count_fg = "#ffffff"
|
||||
result_name_fg = "bright-white"
|
||||
result_line_number_fg = "#ffffff"
|
||||
result_value_fg = "bright-white"
|
||||
selection_bg = "bright-white"
|
||||
match_fg = "bright-white"
|
||||
preview_title_fg = "bright-white"
|
||||
channel_mode_fg = "bright-white"
|
||||
remote_control_mode_fg = "bright-white"
|
||||
send_to_channel_mode_fg = "bright-white"
|
||||
"##;
|
||||
let theme: Theme = toml::from_str(theme_content).unwrap();
|
||||
assert_eq!(theme.background, None);
|
||||
assert_eq!(theme.border_fg, Color::Ansi(ANSIColor::Black));
|
||||
assert_eq!(theme.text_fg, Color::Ansi(ANSIColor::White));
|
||||
assert_eq!(theme.dimmed_text_fg, Color::Ansi(ANSIColor::BrightBlack));
|
||||
assert_eq!(theme.input_text_fg, Color::Ansi(ANSIColor::BrightWhite));
|
||||
assert_eq!(
|
||||
theme.result_count_fg,
|
||||
Color::Rgb(RGBColor::from_str("ffffff").unwrap())
|
||||
);
|
||||
assert_eq!(theme.result_name_fg, Color::Ansi(ANSIColor::BrightWhite));
|
||||
assert_eq!(
|
||||
theme.result_line_number_fg,
|
||||
Color::Rgb(RGBColor::from_str("ffffff").unwrap())
|
||||
);
|
||||
assert_eq!(theme.result_value_fg, Color::Ansi(ANSIColor::BrightWhite));
|
||||
assert_eq!(theme.selection_bg, Color::Ansi(ANSIColor::BrightWhite));
|
||||
assert_eq!(theme.match_fg, Color::Ansi(ANSIColor::BrightWhite));
|
||||
assert_eq!(
|
||||
theme.preview_title_fg,
|
||||
Color::Ansi(ANSIColor::BrightWhite)
|
||||
);
|
||||
assert_eq!(theme.channel_mode_fg, Color::Ansi(ANSIColor::BrightWhite));
|
||||
assert_eq!(
|
||||
theme.remote_control_mode_fg,
|
||||
Color::Ansi(ANSIColor::BrightWhite)
|
||||
);
|
||||
assert_eq!(
|
||||
theme.send_to_channel_mode_fg,
|
||||
Color::Ansi(ANSIColor::BrightWhite)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ use lazy_static::lazy_static;
|
||||
lazy_static! {
|
||||
pub static ref BUILTIN_THEMES: HashMap<&'static str, &'static str> = {
|
||||
let mut m = HashMap::new();
|
||||
m.insert("default", include_str!("../../../../themes/default.toml"));
|
||||
m.insert(
|
||||
"television",
|
||||
include_str!("../../../../themes/television.toml"),
|
||||
|
20
themes/default.toml
Normal file
20
themes/default.toml
Normal file
@ -0,0 +1,20 @@
|
||||
# general
|
||||
# background = 'black'
|
||||
border_fg = 'bright-black'
|
||||
text_fg = 'bright-blue'
|
||||
dimmed_text_fg = 'white'
|
||||
# input
|
||||
input_text_fg = 'bright-red'
|
||||
result_count_fg = 'bright-red'
|
||||
# results
|
||||
result_name_fg = 'bright-blue'
|
||||
result_line_number_fg = 'bright-yellow'
|
||||
result_value_fg = 'white'
|
||||
selection_bg = 'bright-black'
|
||||
match_fg = 'bright-red'
|
||||
# preview
|
||||
preview_title_fg = 'bright-magenta'
|
||||
# modes
|
||||
channel_mode_fg = 'green'
|
||||
remote_control_mode_fg = 'yellow'
|
||||
send_to_channel_mode_fg = 'cyan'
|
Loading…
x
Reference in New Issue
Block a user