Add color theme config

* add option `theme` that allows for setting of a theme,
the default is `default`

* under `themes` the themes can be described as follows:

either:
```
themes:
  default:
    fg: [0,0,0]
    bg: [0,0,0]
    black: [0,0,0]
    red: [0,0,0]
    green: [0,0,0]
    yellow: [0,0,0]
    blue: [0,0,0]
    magenta: [0,0,0]
    cyan: [0,0,0]
    white: [0,0,0]
    orange: [0,0,0]
```
or
```
themes:
  default:
    fg: 0
    bg: 0
    black: 0
    red: 0
    green: 0
    yellow: 0
    blue: 0
    magenta: 0
    cyan: 0
    white: 0
    orange: 0
```

If the key is different from default, it needs to either be specified on
start with `options --theme [THEME]`, or in the configuration file under
theme: [THEME].

closes #390
This commit is contained in:
a-kenji 2021-05-29 14:53:26 +02:00
parent 00bbe2b0f8
commit ce73b6cca0
9 changed files with 145 additions and 20 deletions

View file

@ -91,7 +91,14 @@ pub fn start_client(
let take_snapshot = "\u{1b}[?1049h";
let bracketed_paste = "\u{1b}[?2004h";
os_input.unset_raw_mode(0);
let palette = os_input.load_palette();
let config_options = Options::from_cli(&config.options, opts.command.clone());
let palette = config.themes.clone().map_or_else(
|| os_input.load_palette(),
|t| {
t.theme_config(&config_options)
.unwrap_or_else(|| os_input.load_palette())
},
);
let _ = os_input
.get_stdout_writer()
.write(take_snapshot.as_bytes())
@ -102,8 +109,6 @@ pub fn start_client(
.unwrap();
std::env::set_var(&"ZELLIJ", "0");
let config_options = Options::from_cli(&config.options, opts.command.clone());
let full_screen_ws = os_input.get_terminal_size_using_fd(0);
let client_attributes = ClientAttributes {
position_and_size: full_screen_ws,

View file

@ -15,7 +15,7 @@ use std::path::PathBuf;
use std::sync::{Arc, Mutex, RwLock};
use std::thread;
use wasmer::Store;
use zellij_tile::data::{Event, InputMode, PluginCapabilities};
use zellij_tile::data::{Event, InputMode,Palette, PluginCapabilities};
use crate::{
os_input_output::ServerOsApi,
@ -84,6 +84,7 @@ impl ErrorInstruction for ServerInstruction {
pub(crate) struct SessionMetaData {
pub senders: ThreadSenders,
pub capabilities: PluginCapabilities,
pub palette: Palette,
screen_thread: Option<thread::JoinHandle<()>>,
pty_thread: Option<thread::JoinHandle<()>>,
wasm_thread: Option<thread::JoinHandle<()>>,
@ -400,6 +401,7 @@ fn init_session(
to_server: None,
},
capabilities,
palette: client_attributes.palette,
screen_thread: Some(screen_thread),
pty_thread: Some(pty_thread),
wasm_thread: Some(wasm_thread),

View file

@ -18,7 +18,7 @@ use zellij_utils::{
fn route_action(
action: Action,
session: &SessionMetaData,
os_input: &dyn ServerOsApi,
_os_input: &dyn ServerOsApi,
to_server: &SenderWithContext<ServerInstruction>,
) -> bool {
let mut should_break = false;
@ -34,7 +34,7 @@ fn route_action(
.unwrap();
}
Action::SwitchToMode(mode) => {
let palette = os_input.load_palette();
let palette = session.palette;
// TODO: use the palette from the client and remove it from the server os api
// this is left here as a stop gap measure until we shift some code around
// to allow for this

View file

@ -71,13 +71,13 @@ impl Default for InputMode {
}
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub enum Theme {
pub enum ThemeHue {
Light,
Dark,
}
impl Default for Theme {
fn default() -> Theme {
Theme::Dark
impl Default for ThemeHue {
fn default() -> ThemeHue {
ThemeHue::Dark
}
}
@ -105,7 +105,7 @@ impl Default for PaletteSource {
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, Hash, Default)]
pub struct Palette {
pub source: PaletteSource,
pub theme: Theme,
pub theme_hue: ThemeHue,
pub fg: PaletteColor,
pub bg: PaletteColor,
pub black: PaletteColor,

View file

@ -7,6 +7,7 @@ use std::path::{Path, PathBuf};
use super::keybinds::{Keybinds, KeybindsFromYaml};
use super::options::Options;
use super::theme::ThemesFromYaml;
use crate::cli::{CliArgs, Command};
use crate::setup;
@ -23,6 +24,7 @@ pub struct ConfigFromYaml {
#[serde(flatten)]
pub options: Option<Options>,
pub keybinds: Option<KeybindsFromYaml>,
pub themes: Option<ThemesFromYaml>,
}
/// Main configuration.
@ -30,6 +32,7 @@ pub struct ConfigFromYaml {
pub struct Config {
pub keybinds: Keybinds,
pub options: Options,
pub themes: Option<ThemesFromYaml>,
}
#[derive(Debug)]
@ -48,7 +51,13 @@ impl Default for Config {
fn default() -> Self {
let keybinds = Keybinds::default();
let options = Options::default();
Config { keybinds, options }
let themes = None;
Config {
keybinds,
options,
themes,
}
}
}
@ -90,7 +99,13 @@ impl Config {
let config_from_yaml: ConfigFromYaml = serde_yaml::from_str(&yaml_config)?;
let keybinds = Keybinds::get_default_keybinds_with_config(config_from_yaml.keybinds);
let options = Options::from_yaml(config_from_yaml.options);
Ok(Config { keybinds, options })
let themes = config_from_yaml.themes;
Ok(Config {
keybinds,
options,
themes,
})
}
/// Deserializes from given path.

View file

@ -4,6 +4,7 @@ pub mod actions;
pub mod config;
pub mod keybinds;
pub mod options;
pub mod theme;
use termion::input::TermRead;
use zellij_tile::data::{InputMode, Key, ModeInfo, Palette, PluginCapabilities};

View file

@ -11,6 +11,9 @@ pub struct Options {
/// that is compatible with more fonts
#[structopt(long)]
pub simplified_ui: bool,
/// Set the default theme
#[structopt(long)]
pub theme: Option<String>,
}
impl Options {
@ -32,7 +35,12 @@ impl Options {
self.simplified_ui
};
Options { simplified_ui }
let theme = None;
Options {
simplified_ui,
theme,
}
}
pub fn from_cli(&self, other: Option<Command>) -> Options {

View file

@ -0,0 +1,94 @@
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use super::options::Options;
use zellij_tile::data::{Palette, PaletteColor};
/// Intermediate deserialization of themes
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct ThemesFromYaml(HashMap<String, Theme>);
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
struct Theme {
#[serde(flatten)]
palette: PaletteFromYaml,
}
/// Intermediate deserialization struct
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, Hash, Default)]
pub struct PaletteFromYaml {
pub fg: PaletteColorFromYaml,
pub bg: PaletteColorFromYaml,
pub black: PaletteColorFromYaml,
pub red: PaletteColorFromYaml,
pub green: PaletteColorFromYaml,
pub yellow: PaletteColorFromYaml,
pub blue: PaletteColorFromYaml,
pub magenta: PaletteColorFromYaml,
pub cyan: PaletteColorFromYaml,
pub white: PaletteColorFromYaml,
pub orange: PaletteColorFromYaml,
}
/// Intermediate deserialization enum
// This is here in order to make the untagged enum work
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
#[serde(untagged)]
pub enum PaletteColorFromYaml {
Rgb((u8, u8, u8)),
EightBit(u8),
}
impl Default for PaletteColorFromYaml {
fn default() -> Self {
PaletteColorFromYaml::EightBit(0)
}
}
impl ThemesFromYaml {
pub fn theme_config(self, opts: &Options) -> Option<Palette> {
let mut from_yaml = self;
match &opts.theme {
Some(theme) => from_yaml.from_default_theme(theme.to_owned()),
None => from_yaml.from_default_theme("default".into()),
}
}
fn get_theme(&mut self, theme: String) -> Option<Theme> {
self.0.remove(&theme)
}
fn from_default_theme(&mut self, theme: String) -> Option<Palette> {
self.clone()
.get_theme(theme)
.map(|t| Palette::from(t.palette))
}
}
impl From<PaletteFromYaml> for Palette {
fn from(yaml: PaletteFromYaml) -> Self {
Palette {
fg: yaml.fg.into(),
bg: yaml.fg.into(),
black: yaml.black.into(),
red: yaml.red.into(),
green: yaml.green.into(),
yellow: yaml.yellow.into(),
blue: yaml.blue.into(),
magenta: yaml.magenta.into(),
cyan: yaml.cyan.into(),
white: yaml.white.into(),
orange: yaml.orange.into(),
..Palette::default()
}
}
}
impl From<PaletteColorFromYaml> for PaletteColor {
fn from(yaml: PaletteColorFromYaml) -> Self {
match yaml {
PaletteColorFromYaml::Rgb(color) => PaletteColor::Rgb(color),
PaletteColorFromYaml::EightBit(color) => PaletteColor::EightBit(color),
}
}
}

View file

@ -8,7 +8,7 @@ use colors_transform::{Color, Rgb};
use std::os::unix::fs::PermissionsExt;
use std::path::Path;
use std::{fs, io};
use zellij_tile::data::{Palette, PaletteColor, PaletteSource, Theme};
use zellij_tile::data::{Palette, PaletteColor, PaletteSource, ThemeHue};
const UNIX_PERMISSIONS: u32 = 0o700;
@ -64,7 +64,7 @@ pub fn _hex_to_rgb(hex: &str) -> (u8, u8, u8) {
pub fn default_palette() -> Palette {
Palette {
source: PaletteSource::Default,
theme: Theme::Dark,
theme_hue: ThemeHue::Dark,
fg: PaletteColor::EightBit(colors::BRIGHT_GRAY),
bg: PaletteColor::EightBit(colors::GRAY),
black: PaletteColor::EightBit(colors::BLACK),
@ -80,7 +80,7 @@ pub fn default_palette() -> Palette {
}
// Dark magic
pub fn _detect_theme(bg: PaletteColor) -> Theme {
pub fn _detect_theme_hue(bg: PaletteColor) -> ThemeHue {
match bg {
PaletteColor::Rgb((r, g, b)) => {
// HSP, P stands for perceived brightness
@ -89,11 +89,11 @@ pub fn _detect_theme(bg: PaletteColor) -> Theme {
+ 0.114 * (b as f64 * b as f64))
.sqrt();
match hsp > 127.5 {
true => Theme::Light,
false => Theme::Dark,
true => ThemeHue::Light,
false => ThemeHue::Dark,
}
}
_ => Theme::Dark,
_ => ThemeHue::Dark,
}
}