aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDenis Maximov <denismaximov98@gmail.com>2021-05-02 13:53:36 +0300
committerGitHub <noreply@github.com>2021-05-02 13:53:36 +0300
commit98d9eacd2221162c60f71b73ea7f40ff7256e225 (patch)
treebad162ac3c59a16723f75fcd32d6d0cc724be09e /src
parentdocs(changelog): Improved Config Loading #423 (diff)
parentchore: remove unused dependency from zellij-tile (diff)
downloadsl0ppij-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.rs36
-rw-r--r--src/client/tab.rs13
-rw-r--r--src/common/input/handler.rs17
-rw-r--r--src/common/mod.rs11
-rw-r--r--src/common/os_input_output.rs46
-rw-r--r--src/common/screen.rs12
-rw-r--r--src/common/utils/shared.rs36
-rw-r--r--src/tests/fakes.rs37
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
+ }
}