diff options
| author | Denis Maximov <denismaximov98@gmail.com> | 2021-05-02 13:53:36 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-05-02 13:53:36 +0300 |
| commit | 98d9eacd2221162c60f71b73ea7f40ff7256e225 (patch) | |
| tree | bad162ac3c59a16723f75fcd32d6d0cc724be09e /src | |
| parent | docs(changelog): Improved Config Loading #423 (diff) | |
| parent | chore: remove unused dependency from zellij-tile (diff) | |
| download | sl0ppij-98d9eacd2221162c60f71b73ea7f40ff7256e225.tar.gz sl0ppij-98d9eacd2221162c60f71b73ea7f40ff7256e225.tar.xz sl0ppij-98d9eacd2221162c60f71b73ea7f40ff7256e225.zip | |
Merge pull request #239 from zellij-org/x-colors
X colors
Diffstat (limited to 'src')
| -rw-r--r-- | src/client/boundaries.rs | 36 | ||||
| -rw-r--r-- | src/client/tab.rs | 13 | ||||
| -rw-r--r-- | src/common/input/handler.rs | 17 | ||||
| -rw-r--r-- | src/common/mod.rs | 11 | ||||
| -rw-r--r-- | src/common/os_input_output.rs | 46 | ||||
| -rw-r--r-- | src/common/screen.rs | 12 | ||||
| -rw-r--r-- | src/common/utils/shared.rs | 36 | ||||
| -rw-r--r-- | src/tests/fakes.rs | 37 |
8 files changed, 180 insertions, 28 deletions
diff --git a/src/client/boundaries.rs b/src/client/boundaries.rs index 28e01a11..4708ed6a 100644 --- a/src/client/boundaries.rs +++ b/src/client/boundaries.rs @@ -1,10 +1,10 @@ use crate::tab::Pane; -use ansi_term::Colour; +use crate::utils::shared::colors; +use ansi_term::Colour::RGB; use std::collections::HashMap; -use zellij_tile::data::InputMode; +use zellij_tile::data::{InputMode, Palette}; use std::fmt::{Display, Error, Formatter}; - pub mod boundary_type { pub const TOP_RIGHT: &str = "┐"; pub const VERTICAL: &str = "│"; @@ -19,12 +19,12 @@ pub mod boundary_type { pub const CROSS: &str = "┼"; } -pub mod colors { - use ansi_term::Colour::{self, Fixed}; - pub const GREEN: Colour = Fixed(154); - pub const GRAY: Colour = Fixed(238); - pub const ORANGE: Colour = Fixed(166); -} +// pub mod colors { +// use ansi_term::Colour::{self, Fixed}; +// pub const GREEN: Colour = Fixed(154); +// pub const GRAY: Colour = Fixed(238); +// pub const ORANGE: Colour = Fixed(166); +// } pub type BoundaryType = &'static str; // easy way to refer to boundary_type above @@ -32,7 +32,7 @@ pub type BoundaryType = &'static str; // easy way to refer to boundary_type abov pub struct BoundarySymbol { boundary_type: BoundaryType, invisible: bool, - color: Option<Colour>, + color: Option<(u8, u8, u8)>, } impl BoundarySymbol { @@ -47,7 +47,7 @@ impl BoundarySymbol { self.invisible = true; self } - pub fn color(&mut self, color: Option<Colour>) -> Self { + pub fn color(&mut self, color: Option<(u8, u8, u8)>) -> Self { self.color = color; *self } @@ -58,7 +58,11 @@ impl Display for BoundarySymbol { match self.invisible { true => write!(f, " "), false => match self.color { - Some(color) => write!(f, "{}", color.paint(self.boundary_type)), + Some(color) => write!( + f, + "{}", + RGB(color.0, color.1, color.2).paint(self.boundary_type) + ), None => write!(f, "{}", self.boundary_type), }, } @@ -764,11 +768,11 @@ impl Boundaries { boundary_characters: HashMap::new(), } } - pub fn add_rect(&mut self, rect: &dyn Pane, input_mode: InputMode, color: Option<Colour>) { - let color = match color.is_some() { + pub fn add_rect(&mut self, rect: &dyn Pane, input_mode: InputMode, palette: Option<Palette>) { + let color = match palette.is_some() { true => match input_mode { - InputMode::Normal | InputMode::Locked => Some(colors::GREEN), - _ => Some(colors::ORANGE), + InputMode::Normal | InputMode::Locked => Some(palette.unwrap().green), + _ => Some(palette.unwrap().orange), }, false => None, }; diff --git a/src/client/tab.rs b/src/client/tab.rs index f9bf7b57..b01e04e5 100644 --- a/src/client/tab.rs +++ b/src/client/tab.rs @@ -1,7 +1,6 @@ //! `Tab`s holds multiple panes. It tracks their coordinates (x/y) and size, //! as well as how they should be resized -use crate::boundaries::colors; use crate::client::pane_resizer::PaneResizer; use crate::common::{input::handler::parse_keys, AppInstruction, SenderWithContext}; use crate::layout::Layout; @@ -19,7 +18,7 @@ use std::{ collections::{BTreeMap, HashSet}, }; use std::{io::Write, sync::mpsc::channel}; -use zellij_tile::data::{Event, ModeInfo}; +use zellij_tile::data::{Event, InputMode, ModeInfo, Palette}; const CURSOR_HEIGHT_WIDTH_RATIO: usize = 4; // this is not accurate and kind of a magic number, TODO: look into this @@ -75,6 +74,8 @@ pub struct Tab { pub send_app_instructions: SenderWithContext<AppInstruction>, should_clear_display_before_rendering: bool, pub mode_info: ModeInfo, + pub input_mode: InputMode, + pub colors: Palette, } #[derive(Clone, Debug, Default, Serialize, Deserialize)] @@ -84,6 +85,8 @@ pub struct TabData { pub name: String, pub active: bool, pub mode_info: ModeInfo, + pub input_mode: InputMode, + pub colors: Palette, } // FIXME: Use a struct that has a pane_type enum, to reduce all of the duplication @@ -229,6 +232,8 @@ impl Tab { max_panes: Option<usize>, pane_id: Option<PaneId>, mode_info: ModeInfo, + input_mode: InputMode, + colors: Palette, ) -> Self { let panes = if let Some(PaneId::Terminal(pid)) = pane_id { let new_terminal = TerminalPane::new(pid, *full_screen_ws); @@ -260,6 +265,8 @@ impl Tab { send_plugin_instructions, should_clear_display_before_rendering: false, mode_info, + input_mode, + colors, } } @@ -743,7 +750,7 @@ impl Tab { match self.active_terminal.unwrap() == pane.pid() { true => { pane.set_active_at(Instant::now()); - boundaries.add_rect(pane.as_ref(), self.mode_info.mode, Some(colors::GREEN)) + boundaries.add_rect(pane.as_ref(), self.mode_info.mode, Some(self.colors)) } false => boundaries.add_rect(pane.as_ref(), self.mode_info.mode, None), } diff --git a/src/common/input/handler.rs b/src/common/input/handler.rs index 62118722..7304225c 100644 --- a/src/common/input/handler.rs +++ b/src/common/input/handler.rs @@ -12,7 +12,7 @@ use crate::wasm_vm::PluginInstruction; use crate::CommandIsExecuting; use termion::input::{TermRead, TermReadEventsAndRaw}; -use zellij_tile::data::{Event, InputMode, Key, ModeInfo}; +use zellij_tile::data::{Event, InputMode, Key, ModeInfo, Palette}; /// Handles the dispatching of [`Action`]s according to the current /// [`InputMode`], and keep tracks of the current [`InputMode`]. @@ -131,11 +131,14 @@ impl InputHandler { self.send_plugin_instructions .send(PluginInstruction::Update( None, - Event::ModeUpdate(get_mode_info(mode)), + Event::ModeUpdate(get_mode_info(mode, self.os_input.load_palette())), )) .unwrap(); self.send_screen_instructions - .send(ScreenInstruction::ChangeMode(get_mode_info(mode))) + .send(ScreenInstruction::ChangeMode(get_mode_info( + mode, + self.os_input.load_palette(), + ))) .unwrap(); self.send_screen_instructions .send(ScreenInstruction::Render) @@ -284,7 +287,7 @@ impl InputHandler { /// Creates a [`Help`] struct indicating the current [`InputMode`] and its keybinds /// (as pairs of [`String`]s). // TODO this should probably be automatically generated in some way -pub fn get_mode_info(mode: InputMode) -> ModeInfo { +pub fn get_mode_info(mode: InputMode, palette: Palette) -> ModeInfo { let mut keybinds: Vec<(String, String)> = vec![]; match mode { InputMode::Normal | InputMode::Locked => {} @@ -315,7 +318,11 @@ pub fn get_mode_info(mode: InputMode) -> ModeInfo { keybinds.push(("Enter".to_string(), "when done".to_string())); } } - ModeInfo { mode, keybinds } + ModeInfo { + mode, + keybinds, + palette, + } } /// Entry point to the module. Instantiates an [`InputHandler`] and starts diff --git a/src/common/mod.rs b/src/common/mod.rs index 0afc6ef2..28446d2e 100644 --- a/src/common/mod.rs +++ b/src/common/mod.rs @@ -43,7 +43,7 @@ use utils::consts::ZELLIJ_IPC_PIPE; use wasm_vm::{wasi_read_string, wasi_write_object, zellij_exports, PluginEnv, PluginInstruction}; use wasmer::{ChainableNamedResolver, Instance, Module, Store, Value}; use wasmer_wasi::{Pipe, WasiState}; -use zellij_tile::data::{EventType, ModeInfo}; +use zellij_tile::data::{EventType, InputMode, ModeInfo}; #[derive(Serialize, Deserialize, Debug)] pub enum ApiCommand { @@ -258,7 +258,7 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs, config: Config) { let send_plugin_instructions = send_plugin_instructions.clone(); let send_app_instructions = send_app_instructions.clone(); let max_panes = opts.max_panes; - + let colors = os_input.load_palette(); move || { let mut screen = Screen::new( receive_screen_instructions, @@ -268,7 +268,12 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs, config: Config) { &full_screen_ws, os_input, max_panes, - ModeInfo::default(), + ModeInfo { + palette: colors, + ..ModeInfo::default() + }, + InputMode::Normal, + colors, ); loop { let (event, mut err_ctx) = screen diff --git a/src/common/os_input_output.rs b/src/common/os_input_output.rs index 35d77fdd..41a4bfe4 100644 --- a/src/common/os_input_output.rs +++ b/src/common/os_input_output.rs @@ -1,4 +1,5 @@ use crate::panes::PositionAndSize; +use crate::utils::shared::{colors, detect_theme, hex_to_rgb}; use nix::fcntl::{fcntl, FcntlArg, OFlag}; use nix::pty::{forkpty, Winsize}; use nix::sys::signal::{kill, Signal}; @@ -12,6 +13,8 @@ use std::os::unix::io::RawFd; use std::path::PathBuf; use std::process::{Child, Command}; use std::sync::{Arc, Mutex}; +use xrdb::Colors; +use zellij_tile::data::{Palette, PaletteSource, Theme}; use signal_hook::{consts::signal::*, iterator::Signals}; @@ -191,6 +194,7 @@ pub trait OsApi: Send + Sync { /// Returns a [`Box`] pointer to this [`OsApi`] struct. fn box_clone(&self) -> Box<dyn OsApi>; fn receive_sigwinch(&self, cb: Box<dyn Fn()>); + fn load_palette(&self) -> Palette; } impl OsApi for OsInputOutput { @@ -261,6 +265,48 @@ impl OsApi for OsInputOutput { } } } + fn load_palette(&self) -> Palette { + let palette = match Colors::new("xresources") { + Some(palette) => { + let fg = hex_to_rgb(&palette.fg); + let bg = hex_to_rgb(&palette.bg); + let colors: Vec<(u8, u8, u8)> = + palette.colors.iter().map(|c| hex_to_rgb(c)).collect(); + let theme = detect_theme(bg); + Palette { + source: PaletteSource::Xresources, + theme, + fg, + bg, + black: colors[0], + red: colors[1], + green: colors[2], + yellow: colors[3], + blue: colors[4], + magenta: colors[5], + cyan: colors[6], + white: colors[7], + orange: colors[9], + } + } + None => Palette { + source: PaletteSource::Default, + theme: Theme::Dark, + fg: colors::BRIGHT_GRAY, + bg: colors::GRAY, + black: colors::BLACK, + red: colors::RED, + green: colors::GREEN, + yellow: colors::GRAY, + blue: colors::GRAY, + magenta: colors::GRAY, + cyan: colors::GRAY, + white: colors::WHITE, + orange: colors::ORANGE, + }, + }; + palette + } } impl Clone for Box<dyn OsApi> { diff --git a/src/common/screen.rs b/src/common/screen.rs index eee1166f..e6cf73f5 100644 --- a/src/common/screen.rs +++ b/src/common/screen.rs @@ -13,7 +13,7 @@ use crate::tab::Tab; use crate::{errors::ErrorContext, wasm_vm::PluginInstruction}; use crate::{layout::Layout, panes::PaneId}; -use zellij_tile::data::{Event, ModeInfo, TabInfo}; +use zellij_tile::data::{Event, InputMode, ModeInfo, Palette, TabInfo}; /// Instructions that can be sent to the [`Screen`]. #[derive(Debug, Clone)] @@ -81,6 +81,8 @@ pub struct Screen { /// The [`OsApi`] this [`Screen`] uses. os_api: Box<dyn OsApi>, mode_info: ModeInfo, + input_mode: InputMode, + colors: Palette, } impl Screen { @@ -96,6 +98,8 @@ impl Screen { os_api: Box<dyn OsApi>, max_panes: Option<usize>, mode_info: ModeInfo, + input_mode: InputMode, + colors: Palette, ) -> Self { Screen { receiver: receive_screen_instructions, @@ -108,6 +112,8 @@ impl Screen { tabs: BTreeMap::new(), os_api, mode_info, + input_mode, + colors, } } @@ -128,6 +134,8 @@ impl Screen { self.max_panes, Some(PaneId::Terminal(pane_id)), self.mode_info.clone(), + self.input_mode, + self.colors, ); self.active_tab_index = Some(tab_index); self.tabs.insert(tab_index, tab); @@ -283,6 +291,8 @@ impl Screen { self.max_panes, None, self.mode_info.clone(), + self.input_mode, + self.colors, ); tab.apply_layout(layout, new_pids); self.active_tab_index = Some(tab_index); diff --git a/src/common/utils/shared.rs b/src/common/utils/shared.rs index d5ba943b..3f336f7b 100644 --- a/src/common/utils/shared.rs +++ b/src/common/utils/shared.rs @@ -4,6 +4,9 @@ use std::{iter, str::from_utf8}; use strip_ansi_escapes::strip; +use colors_transform::{Color, Rgb}; +use zellij_tile::data::Theme; + fn ansi_len(s: &str) -> usize { from_utf8(&strip(s.as_bytes()).unwrap()) .unwrap() @@ -28,3 +31,36 @@ pub fn adjust_to_size(s: &str, rows: usize, columns: usize) -> String { .collect::<Vec<_>>() .join("\n\r") } + +// Colors +pub mod colors { + pub const WHITE: (u8, u8, u8) = (238, 238, 238); + pub const GREEN: (u8, u8, u8) = (175, 255, 0); + pub const GRAY: (u8, u8, u8) = (68, 68, 68); + pub const BRIGHT_GRAY: (u8, u8, u8) = (138, 138, 138); + pub const RED: (u8, u8, u8) = (135, 0, 0); + pub const ORANGE: (u8, u8, u8) = (215, 95, 0); + pub const BLACK: (u8, u8, u8) = (0, 0, 0); +} + +pub fn hex_to_rgb(hex: &Option<String>) -> (u8, u8, u8) { + let c = hex.clone(); + let imm_str = &c.unwrap(); + let hex_str: &str = &imm_str; + let rgb = Rgb::from_hex_str(hex_str).unwrap().as_tuple(); + (rgb.0 as u8, rgb.1 as u8, rgb.2 as u8) +} + +// Dark magic +pub fn detect_theme(bg: (u8, u8, u8)) -> Theme { + let (r, g, b) = bg; + // HSP, P stands for perceived brightness + let hsp: f64 = (0.299 * (r as f64 * r as f64) + + 0.587 * (g as f64 * g as f64) + + 0.114 * (b as f64 * b as f64)) + .sqrt(); + match hsp > 127.5 { + true => Theme::Light, + false => Theme::Dark, + } +} diff --git a/src/tests/fakes.rs b/src/tests/fakes.rs index c9504a98..e00de017 100644 --- a/src/tests/fakes.rs +++ b/src/tests/fakes.rs @@ -8,6 +8,8 @@ use std::time::{Duration, Instant}; use crate::os_input_output::OsApi; use crate::tests::possible_tty_inputs::{get_possible_tty_inputs, Bytes}; +use crate::utils::shared::colors; +use zellij_tile::data::{Palette, PaletteSource, Theme}; use crate::tests::utils::commands::{QUIT, SLEEP}; @@ -73,6 +75,7 @@ pub struct FakeInputOutput { last_snapshot_time: Arc<Mutex<Instant>>, should_trigger_sigwinch: Arc<(Mutex<bool>, Condvar)>, sigwinch_event: Option<PositionAndSize>, + palette: Arc<Mutex<Palette>>, } impl FakeInputOutput { @@ -81,6 +84,21 @@ impl FakeInputOutput { let last_snapshot_time = Arc::new(Mutex::new(Instant::now())); let stdout_writer = FakeStdoutWriter::new(last_snapshot_time.clone()); win_sizes.insert(0, winsize); // 0 is the current terminal + let palette: Palette = Palette { + source: PaletteSource::Default, + theme: Theme::Dark, + fg: colors::BRIGHT_GRAY, + bg: colors::GRAY, + black: colors::BLACK, + red: colors::RED, + green: colors::GREEN, + yellow: colors::GRAY, + blue: colors::GRAY, + magenta: colors::GRAY, + cyan: colors::GRAY, + white: colors::WHITE, + orange: colors::ORANGE, + }; FakeInputOutput { read_buffers: Arc::new(Mutex::new(HashMap::new())), stdin_writes: Arc::new(Mutex::new(HashMap::new())), @@ -93,6 +111,7 @@ impl FakeInputOutput { possible_tty_inputs: get_possible_tty_inputs(), should_trigger_sigwinch: Arc::new((Mutex::new(false), Condvar::new())), sigwinch_event: None, + palette: Arc::new(Mutex::new(palette)), } } pub fn with_tty_inputs(mut self, tty_inputs: HashMap<u16, Bytes>) -> Self { @@ -235,4 +254,22 @@ impl OsApi for FakeInputOutput { cb(); } } + fn load_palette(&self) -> Palette { + let palette: Palette = Palette { + source: PaletteSource::Default, + theme: Theme::Dark, + fg: colors::BRIGHT_GRAY, + bg: colors::GRAY, + black: colors::BLACK, + red: colors::RED, + green: colors::GREEN, + yellow: colors::GRAY, + blue: colors::GRAY, + magenta: colors::GRAY, + cyan: colors::GRAY, + white: colors::WHITE, + orange: colors::ORANGE, + }; + palette + } } |
