From 99678a823e98db6e735db814a9f102ec3928930c Mon Sep 17 00:00:00 2001 From: Brooks J Rady Date: Wed, 16 Mar 2022 16:31:53 +0000 Subject: [PATCH 1/6] feat(ui): round frame corners --- default-plugins/status-bar/src/first_line.rs | 2 +- default-plugins/status-bar/src/main.rs | 25 +++--- default-plugins/status-bar/src/second_line.rs | 42 +++++----- default-plugins/tab-bar/src/main.rs | 6 +- src/tests/e2e/remote_runner.rs | 6 +- zellij-client/src/lib.rs | 17 +++-- zellij-server/src/lib.rs | 10 +-- zellij-server/src/panes/floating_panes.rs | 7 +- zellij-server/src/panes/terminal_pane.rs | 13 ++-- .../src/panes/unit/terminal_pane_tests.rs | 6 +- zellij-server/src/route.rs | 6 +- zellij-server/src/screen.rs | 15 ++-- zellij-server/src/tab/mod.rs | 21 ++--- .../src/tab/unit/tab_integration_tests.rs | 5 +- zellij-server/src/tab/unit/tab_tests.rs | 5 +- zellij-server/src/ui/boundaries.rs | 4 + zellij-server/src/ui/pane_boundaries_frame.rs | 76 ++++++++++++++----- zellij-server/src/ui/pane_contents_and_ui.rs | 23 +++--- zellij-tile/src/data.rs | 8 +- zellij-utils/src/errors.rs | 2 +- zellij-utils/src/input/mod.rs | 13 ++-- zellij-utils/src/input/theme.rs | 18 +++-- zellij-utils/src/ipc.rs | 4 +- zellij-utils/src/setup.rs | 2 +- 24 files changed, 203 insertions(+), 133 deletions(-) diff --git a/default-plugins/status-bar/src/first_line.rs b/default-plugins/status-bar/src/first_line.rs index ed67e5cc5f..7ca0b0fb66 100644 --- a/default-plugins/status-bar/src/first_line.rs +++ b/default-plugins/status-bar/src/first_line.rs @@ -247,7 +247,7 @@ pub fn superkey(palette: ColoredElements, separator: &str) -> LinePart { } pub fn ctrl_keys(help: &ModeInfo, max_len: usize, separator: &str) -> LinePart { - let colored_elements = color_elements(help.palette); + let colored_elements = color_elements(help.style.colors); match &help.mode { InputMode::Locked => key_indicators( max_len, diff --git a/default-plugins/status-bar/src/main.rs b/default-plugins/status-bar/src/main.rs index daeb30f130..471c45c764 100644 --- a/default-plugins/status-bar/src/main.rs +++ b/default-plugins/status-bar/src/main.rs @@ -175,10 +175,10 @@ impl ZellijPlugin for State { let separator = if !self.mode_info.capabilities.arrow_fonts { ARROW_SEPARATOR } else { - &"" + "" }; - let colored_elements = color_elements(self.mode_info.palette); + let colored_elements = color_elements(self.mode_info.style.colors); let superkey = superkey(colored_elements, separator); let ctrl_keys = ctrl_keys( &self.mode_info, @@ -191,7 +191,7 @@ impl ZellijPlugin for State { // [48;5;238m is gray background, [0K is so that it fills the rest of the line // [m is background reset, [0K is so that it clears the rest of the line - match self.mode_info.palette.gray { + match self.mode_info.style.colors.gray { PaletteColor::Rgb((r, g, b)) => { println!("{}\u{1b}[48;2;{};{};{}m\u{1b}[0K", first_line, r, g, b); } @@ -208,25 +208,28 @@ impl State { let active_tab = self.tabs.iter().find(|t| t.active); if let Some(copy_destination) = self.text_copy_destination { - text_copied_hint(&self.mode_info.palette, copy_destination) + text_copied_hint(&self.mode_info.style.colors, copy_destination) } else if self.display_system_clipboard_failure { - system_clipboard_error(&self.mode_info.palette) + system_clipboard_error(&self.mode_info.style.colors) } else if let Some(active_tab) = active_tab { if active_tab.is_fullscreen_active { match self.mode_info.mode { - InputMode::Normal => { - fullscreen_panes_to_hide(&self.mode_info.palette, active_tab.panes_to_hide) - } + InputMode::Normal => fullscreen_panes_to_hide( + &self.mode_info.style.colors, + active_tab.panes_to_hide, + ), InputMode::Locked => locked_fullscreen_panes_to_hide( - &self.mode_info.palette, + &self.mode_info.style.colors, active_tab.panes_to_hide, ), _ => keybinds(&self.mode_info, &self.tip_name, cols), } } else if active_tab.are_floating_panes_visible { match self.mode_info.mode { - InputMode::Normal => floating_panes_are_visible(&self.mode_info.palette), - InputMode::Locked => locked_floating_panes_are_visible(&self.mode_info.palette), + InputMode::Normal => floating_panes_are_visible(&self.mode_info.style.colors), + InputMode::Locked => { + locked_floating_panes_are_visible(&self.mode_info.style.colors) + } _ => keybinds(&self.mode_info, &self.tip_name, cols), } } else { diff --git a/default-plugins/status-bar/src/second_line.rs b/default-plugins/status-bar/src/second_line.rs index 77868a72cb..9601c4251a 100644 --- a/default-plugins/status-bar/src/second_line.rs +++ b/default-plugins/status-bar/src/second_line.rs @@ -193,11 +193,11 @@ fn full_shortcut_list_nonstandard_mode( move |help| { let mut line_part = LinePart::default(); for (i, (letter, description)) in help.keybinds.iter().enumerate() { - let shortcut = full_length_shortcut(i == 0, letter, description, help.palette); + let shortcut = full_length_shortcut(i == 0, letter, description, help.style.colors); line_part.len += shortcut.len; line_part.part = format!("{}{}", line_part.part, shortcut,); } - let select_pane_shortcut = extra_hint_producing_function(help.palette); + let select_pane_shortcut = extra_hint_producing_function(help.style.colors); line_part.len += select_pane_shortcut.len; line_part.part = format!("{}{}", line_part.part, select_pane_shortcut,); line_part @@ -206,8 +206,8 @@ fn full_shortcut_list_nonstandard_mode( fn full_shortcut_list(help: &ModeInfo, tip: TipFn) -> LinePart { match help.mode { - InputMode::Normal => tip(help.palette), - InputMode::Locked => locked_interface_indication(help.palette), + InputMode::Normal => tip(help.style.colors), + InputMode::Locked => locked_interface_indication(help.style.colors), InputMode::Tmux => full_tmux_mode_indication(help), InputMode::RenamePane => full_shortcut_list_nonstandard_mode(select_pane_shortcut)(help), _ => full_shortcut_list_nonstandard_mode(confirm_pane_selection)(help), @@ -220,11 +220,11 @@ fn shortened_shortcut_list_nonstandard_mode( move |help| { let mut line_part = LinePart::default(); for (i, (letter, description)) in help.keybinds.iter().enumerate() { - let shortcut = first_word_shortcut(i == 0, letter, description, help.palette); + let shortcut = first_word_shortcut(i == 0, letter, description, help.style.colors); line_part.len += shortcut.len; line_part.part = format!("{}{}", line_part.part, shortcut,); } - let select_pane_shortcut = extra_hint_producing_function(help.palette); + let select_pane_shortcut = extra_hint_producing_function(help.style.colors); line_part.len += select_pane_shortcut.len; line_part.part = format!("{}{}", line_part.part, select_pane_shortcut,); line_part @@ -233,8 +233,8 @@ fn shortened_shortcut_list_nonstandard_mode( fn shortened_shortcut_list(help: &ModeInfo, tip: TipFn) -> LinePart { match help.mode { - InputMode::Normal => tip(help.palette), - InputMode::Locked => locked_interface_indication(help.palette), + InputMode::Normal => tip(help.style.colors), + InputMode::Locked => locked_interface_indication(help.style.colors), InputMode::Tmux => short_tmux_mode_indication(help), InputMode::RenamePane => { shortened_shortcut_list_nonstandard_mode(select_pane_shortcut)(help) @@ -249,7 +249,7 @@ fn best_effort_shortcut_list_nonstandard_mode( move |help, max_len| { let mut line_part = LinePart::default(); for (i, (letter, description)) in help.keybinds.iter().enumerate() { - let shortcut = first_word_shortcut(i == 0, letter, description, help.palette); + let shortcut = first_word_shortcut(i == 0, letter, description, help.style.colors); if line_part.len + shortcut.len + MORE_MSG.chars().count() > max_len { // TODO: better line_part.part = format!("{}{}", line_part.part, MORE_MSG); @@ -259,7 +259,7 @@ fn best_effort_shortcut_list_nonstandard_mode( line_part.len += shortcut.len; line_part.part = format!("{}{}", line_part.part, shortcut); } - let select_pane_shortcut = extra_hint_producing_function(help.palette); + let select_pane_shortcut = extra_hint_producing_function(help.style.colors); if line_part.len + select_pane_shortcut.len <= max_len { line_part.len += select_pane_shortcut.len; line_part.part = format!("{}{}", line_part.part, select_pane_shortcut,); @@ -271,7 +271,7 @@ fn best_effort_shortcut_list_nonstandard_mode( fn best_effort_tmux_shortcut_list(help: &ModeInfo, max_len: usize) -> LinePart { let mut line_part = tmux_mode_indication(help); for (i, (letter, description)) in help.keybinds.iter().enumerate() { - let shortcut = first_word_shortcut(i == 0, letter, description, help.palette); + let shortcut = first_word_shortcut(i == 0, letter, description, help.style.colors); if line_part.len + shortcut.len + MORE_MSG.chars().count() > max_len { // TODO: better line_part.part = format!("{}{}", line_part.part, MORE_MSG); @@ -287,7 +287,7 @@ fn best_effort_tmux_shortcut_list(help: &ModeInfo, max_len: usize) -> LinePart { fn best_effort_shortcut_list(help: &ModeInfo, tip: TipFn, max_len: usize) -> LinePart { match help.mode { InputMode::Normal => { - let line_part = tip(help.palette); + let line_part = tip(help.style.colors); if line_part.len <= max_len { line_part } else { @@ -295,7 +295,7 @@ fn best_effort_shortcut_list(help: &ModeInfo, tip: TipFn, max_len: usize) -> Lin } } InputMode::Locked => { - let line_part = locked_interface_indication(help.palette); + let line_part = locked_interface_indication(help.style.colors); if line_part.len <= max_len { line_part } else { @@ -448,11 +448,11 @@ pub fn floating_panes_are_visible(palette: &Palette) -> LinePart { } pub fn tmux_mode_indication(help: &ModeInfo) -> LinePart { - let white_color = match help.palette.white { + let white_color = match help.style.colors.white { PaletteColor::Rgb((r, g, b)) => RGB(r, g, b), PaletteColor::EightBit(color) => Fixed(color), }; - let orange_color = match help.palette.orange { + let orange_color = match help.style.colors.orange { PaletteColor::Rgb((r, g, b)) => RGB(r, g, b), PaletteColor::EightBit(color) => Fixed(color), }; @@ -472,11 +472,11 @@ pub fn tmux_mode_indication(help: &ModeInfo) -> LinePart { } pub fn full_tmux_mode_indication(help: &ModeInfo) -> LinePart { - let white_color = match help.palette.white { + let white_color = match help.style.colors.white { PaletteColor::Rgb((r, g, b)) => RGB(r, g, b), PaletteColor::EightBit(color) => Fixed(color), }; - let orange_color = match help.palette.orange { + let orange_color = match help.style.colors.orange { PaletteColor::Rgb((r, g, b)) => RGB(r, g, b), PaletteColor::EightBit(color) => Fixed(color), }; @@ -494,7 +494,7 @@ pub fn full_tmux_mode_indication(help: &ModeInfo) -> LinePart { }; for (i, (letter, description)) in help.keybinds.iter().enumerate() { - let shortcut = full_length_shortcut(i == 0, letter, description, help.palette); + let shortcut = full_length_shortcut(i == 0, letter, description, help.style.colors); line_part.len += shortcut.len; line_part.part = format!("{}{}", line_part.part, shortcut,); } @@ -502,11 +502,11 @@ pub fn full_tmux_mode_indication(help: &ModeInfo) -> LinePart { } pub fn short_tmux_mode_indication(help: &ModeInfo) -> LinePart { - let white_color = match help.palette.white { + let white_color = match help.style.colors.white { PaletteColor::Rgb((r, g, b)) => RGB(r, g, b), PaletteColor::EightBit(color) => Fixed(color), }; - let orange_color = match help.palette.orange { + let orange_color = match help.style.colors.orange { PaletteColor::Rgb((r, g, b)) => RGB(r, g, b), PaletteColor::EightBit(color) => Fixed(color), }; @@ -524,7 +524,7 @@ pub fn short_tmux_mode_indication(help: &ModeInfo) -> LinePart { }; for (i, (letter, description)) in help.keybinds.iter().enumerate() { - let shortcut = first_word_shortcut(i == 0, letter, description, help.palette); + let shortcut = first_word_shortcut(i == 0, letter, description, help.style.colors); line_part.len += shortcut.len; line_part.part = format!("{}{}", line_part.part, shortcut); } diff --git a/default-plugins/tab-bar/src/main.rs b/default-plugins/tab-bar/src/main.rs index 3db531384f..05f241bbb9 100644 --- a/default-plugins/tab-bar/src/main.rs +++ b/default-plugins/tab-bar/src/main.rs @@ -83,7 +83,7 @@ impl ZellijPlugin for State { tabname, t.active, t.is_sync_panes_active, - self.mode_info.palette, + self.mode_info.style.colors, self.mode_info.capabilities, t.other_focused_clients.as_slice(), ); @@ -94,7 +94,7 @@ impl ZellijPlugin for State { all_tabs, active_tab_index, cols.saturating_sub(1), - self.mode_info.palette, + self.mode_info.style.colors, self.mode_info.capabilities, ); let mut s = String::new(); @@ -113,7 +113,7 @@ impl ZellijPlugin for State { } len_cnt += bar_part.len; } - match self.mode_info.palette.gray { + match self.mode_info.style.colors.gray { PaletteColor::Rgb((r, g, b)) => { println!("{}\u{1b}[48;2;{};{};{}m\u{1b}[0K", s, r, g, b); } diff --git a/src/tests/e2e/remote_runner.rs b/src/tests/e2e/remote_runner.rs index 4a7d7fbfd0..042ae9b6fc 100644 --- a/src/tests/e2e/remote_runner.rs +++ b/src/tests/e2e/remote_runner.rs @@ -1,10 +1,10 @@ use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, Mutex}; -use zellij_tile::data::Palette; use zellij_server::panes::{LinkHandler, TerminalPane}; use zellij_utils::pane_size::{Dimension, PaneGeom, Size}; -use zellij_utils::{vte, zellij_tile}; +use zellij_utils::vte; +use zellij_utils::zellij_tile::prelude::Style; use ssh2::Session; use std::io::prelude::*; @@ -157,7 +157,7 @@ fn read_from_channel( let mut terminal_output = TerminalPane::new( 0, pane_geom, - Palette::default(), + Style::default(), 0, String::new(), Rc::new(RefCell::new(LinkHandler::new())), diff --git a/zellij-client/src/lib.rs b/zellij-client/src/lib.rs index bd5db5cd17..569ab41adf 100644 --- a/zellij-client/src/lib.rs +++ b/zellij-client/src/lib.rs @@ -10,6 +10,7 @@ use std::io::{self, Write}; use std::path::Path; use std::process::Command; use std::thread; +use zellij_tile::prelude::Style; use crate::{ command_is_executing::CommandIsExecuting, input_handler::input_loop, @@ -135,18 +136,24 @@ pub fn start_client( envs::set_zellij("0".to_string()); config.env.set_vars(); - let palette = config.themes.clone().map_or_else( - || os_input.load_palette(), + // FIXME: This might be the place to inject round corners! + let style = config.themes.clone().map_or_else( + || Style { + colors: os_input.load_palette(), + ..Default::default() + }, |t| { - t.theme_config(&config_options) - .unwrap_or_else(|| os_input.load_palette()) + t.theme_config(&config_options).unwrap_or_else(|| Style { + colors: os_input.load_palette(), + ..Default::default() + }) }, ); let full_screen_ws = os_input.get_terminal_size_using_fd(0); let client_attributes = ClientAttributes { size: full_screen_ws, - palette, + style, }; let first_msg = match info { diff --git a/zellij-server/src/lib.rs b/zellij-server/src/lib.rs index 7880d5f9d8..13d2f5c56d 100644 --- a/zellij-server/src/lib.rs +++ b/zellij-server/src/lib.rs @@ -18,13 +18,14 @@ use std::{ sync::{Arc, Mutex, RwLock}, thread, }; +use zellij_tile::prelude::Style; use zellij_utils::envs; use zellij_utils::nix::sys::stat::{umask, Mode}; use zellij_utils::pane_size::Size; use zellij_utils::zellij_tile; use wasmer::Store; -use zellij_tile::data::{Event, Palette, PluginCapabilities}; +use zellij_tile::data::{Event, PluginCapabilities}; use crate::{ os_input_output::ServerOsApi, @@ -100,7 +101,7 @@ impl ErrorInstruction for ServerInstruction { pub(crate) struct SessionMetaData { pub senders: ThreadSenders, pub capabilities: PluginCapabilities, - pub palette: Palette, + pub style: Style, pub default_shell: Option, screen_thread: Option>, pty_thread: Option>, @@ -371,8 +372,7 @@ pub fn start_server(mut os_input: Box, socket_path: PathBuf) { .send_to_plugin(PluginInstruction::AddClient(client_id)) .unwrap(); let default_mode = options.default_mode.unwrap_or_default(); - let mode_info = - get_mode_info(default_mode, attrs.palette, session_data.capabilities); + let mode_info = get_mode_info(default_mode, attrs.style, session_data.capabilities); let mode = mode_info.mode; session_data .senders @@ -645,7 +645,7 @@ fn init_session( }, capabilities, default_shell, - palette: client_attributes.palette, + style: client_attributes.style, screen_thread: Some(screen_thread), pty_thread: Some(pty_thread), wasm_thread: Some(wasm_thread), diff --git a/zellij-server/src/panes/floating_panes.rs b/zellij-server/src/panes/floating_panes.rs index c88bcba99d..8d932c5078 100644 --- a/zellij-server/src/panes/floating_panes.rs +++ b/zellij-server/src/panes/floating_panes.rs @@ -1,3 +1,4 @@ +use zellij_tile::prelude::Style; use zellij_utils::{position::Position, zellij_tile}; use crate::tab::floating_pane_grid::FloatingPaneGrid; @@ -14,7 +15,7 @@ use std::cell::RefCell; use std::collections::{BTreeMap, HashMap, HashSet}; use std::rc::Rc; use std::time::Instant; -use zellij_tile::data::{ModeInfo, Palette}; +use zellij_tile::data::ModeInfo; use zellij_utils::pane_size::{Offset, PaneGeom, Size, Viewport}; macro_rules! resize_pty { @@ -160,7 +161,7 @@ impl FloatingPanes { default_mode_info: &ModeInfo, session_is_mirrored: bool, output: &mut Output, - colors: Palette, + style: Style, ) { let mut floating_panes: Vec<_> = self.panes.iter_mut().collect(); floating_panes.sort_by(|(a_id, _a_pane), (b_id, _b_pane)| { @@ -178,7 +179,7 @@ impl FloatingPanes { let mut pane_contents_and_ui = PaneContentsAndUi::new( pane, output, - colors, + style, &active_panes, multiple_users_exist_in_session, Some(z_index + 1), // +1 because 0 is reserved for non-floating panes diff --git a/zellij-server/src/panes/terminal_pane.rs b/zellij-server/src/panes/terminal_pane.rs index 5ac94c4f33..fb6a072216 100644 --- a/zellij-server/src/panes/terminal_pane.rs +++ b/zellij-server/src/panes/terminal_pane.rs @@ -13,13 +13,14 @@ use std::fmt::Debug; use std::os::unix::io::RawFd; use std::rc::Rc; use std::time::{self, Instant}; +use zellij_tile::prelude::Style; use zellij_utils::pane_size::Offset; use zellij_utils::{ pane_size::{Dimension, PaneGeom}, position::Position, shared::make_terminal_title, vte, - zellij_tile::data::{InputMode, Palette, PaletteColor}, + zellij_tile::data::{InputMode, PaletteColor}, }; pub const SELECTION_SCROLL_INTERVAL_MS: u64 = 10; @@ -41,7 +42,7 @@ pub struct TerminalPane { pub geom: PaneGeom, pub geom_override: Option, pub active_at: Instant, - pub colors: Palette, + pub style: Style, vte_parser: vte::Parser, selection_scrolled_at: time::Instant, content_offset: Offset, @@ -216,7 +217,7 @@ impl Pane for TerminalPane { .selection .contains_row(character_chunk.y.saturating_sub(content_y)) { - let background_color = match self.colors.bg { + let background_color = match self.style.colors.bg { PaletteColor::Rgb(rgb) => AnsiCode::RgbCode(rgb), PaletteColor::EightBit(col) => AnsiCode::ColorIndex(col), }; @@ -482,7 +483,7 @@ impl TerminalPane { pub fn new( pid: RawFd, position_and_size: PaneGeom, - palette: Palette, + style: Style, pane_index: usize, pane_name: String, link_handler: Rc>, @@ -491,7 +492,7 @@ impl TerminalPane { let grid = Grid::new( position_and_size.rows.as_usize(), position_and_size.cols.as_usize(), - palette, + style.colors, link_handler, ); TerminalPane { @@ -504,7 +505,7 @@ impl TerminalPane { geom_override: None, vte_parser: vte::Parser::new(), active_at: Instant::now(), - colors: palette, + style, selection_scrolled_at: time::Instant::now(), pane_title: initial_pane_title, pane_name, diff --git a/zellij-server/src/panes/unit/terminal_pane_tests.rs b/zellij-server/src/panes/unit/terminal_pane_tests.rs index b5f986aaeb..adcdbd08d4 100644 --- a/zellij-server/src/panes/unit/terminal_pane_tests.rs +++ b/zellij-server/src/panes/unit/terminal_pane_tests.rs @@ -4,8 +4,8 @@ use crate::tab::Pane; use ::insta::assert_snapshot; use std::cell::RefCell; use std::rc::Rc; +use zellij_tile::prelude::Style; use zellij_utils::pane_size::PaneGeom; -use zellij_utils::zellij_tile::data::Palette; use std::fmt::Write; @@ -17,11 +17,11 @@ pub fn scrolling_inside_a_pane() { fake_win_size.rows.set_inner(20); let pid = 1; - let palette = Palette::default(); + let style = Style::default(); let mut terminal_pane = TerminalPane::new( pid, fake_win_size, - palette, + style, 0, String::new(), Rc::new(RefCell::new(LinkHandler::new())), diff --git a/zellij-server/src/route.rs b/zellij-server/src/route.rs index 033a571b36..e5489818a6 100644 --- a/zellij-server/src/route.rs +++ b/zellij-server/src/route.rs @@ -66,7 +66,7 @@ fn route_action( .unwrap(); } Action::SwitchToMode(mode) => { - let palette = session.palette; + let style = session.style; // 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 @@ -75,13 +75,13 @@ fn route_action( .send_to_plugin(PluginInstruction::Update( None, Some(client_id), - Event::ModeUpdate(get_mode_info(mode, palette, session.capabilities)), + Event::ModeUpdate(get_mode_info(mode, style, session.capabilities)), )) .unwrap(); session .senders .send_to_screen(ScreenInstruction::ChangeMode( - get_mode_info(mode, palette, session.capabilities), + get_mode_info(mode, style, session.capabilities), client_id, )) .unwrap(); diff --git a/zellij-server/src/screen.rs b/zellij-server/src/screen.rs index 5a3f027939..d9f98ec6bd 100644 --- a/zellij-server/src/screen.rs +++ b/zellij-server/src/screen.rs @@ -6,6 +6,7 @@ use std::os::unix::io::RawFd; use std::rc::Rc; use std::str; +use zellij_tile::prelude::Style; use zellij_utils::input::options::Clipboard; use zellij_utils::pane_size::Size; use zellij_utils::{ @@ -22,7 +23,7 @@ use crate::{ wasm_vm::PluginInstruction, ClientId, ServerInstruction, }; -use zellij_tile::data::{Event, InputMode, ModeInfo, Palette, PluginCapabilities, TabInfo}; +use zellij_tile::data::{Event, InputMode, ModeInfo, PluginCapabilities, TabInfo}; use zellij_utils::{ errors::{ContextType, ScreenContext}, input::{get_mode_info, options::Options}, @@ -200,7 +201,7 @@ pub(crate) struct Screen { tab_history: BTreeMap>, mode_info: BTreeMap, default_mode_info: ModeInfo, // TODO: restructure ModeInfo to prevent this duplication - colors: Palette, + style: Style, draw_pane_frames: bool, session_is_mirrored: bool, copy_command: Option, @@ -224,7 +225,7 @@ impl Screen { bus, max_panes, size: client_attributes.size, - colors: client_attributes.palette, + style: client_attributes.style, connected_clients: Rc::new(RefCell::new(HashSet::new())), active_tab_indices: BTreeMap::new(), tabs: BTreeMap::new(), @@ -504,7 +505,7 @@ impl Screen { self.bus.senders.clone(), self.max_panes, client_mode_info, - self.colors, + self.style, self.draw_pane_frames, self.connected_clients.clone(), self.session_is_mirrored, @@ -655,7 +656,7 @@ impl Screen { .unwrap() .clear_active_terminal_scroll(client_id); } - self.colors = mode_info.palette; + self.style = mode_info.style; self.mode_info.insert(client_id, mode_info.clone()); for tab in self.tabs.values_mut() { tab.change_mode_info(mode_info.clone(), client_id); @@ -711,7 +712,7 @@ pub(crate) fn screen_thread_main( max_panes, get_mode_info( config_options.default_mode.unwrap_or_default(), - client_attributes.palette, + client_attributes.style, PluginCapabilities { arrow_fonts: capabilities.unwrap_or_default(), }, @@ -1291,7 +1292,7 @@ pub(crate) fn screen_thread_main( } ScreenInstruction::ConfirmPrompt(_client_id) => { let overlay = screen.get_active_overlays_mut().pop(); - let instruction = overlay.map(|o| o.prompt_confirm()).flatten(); + let instruction = overlay.and_then(|o| o.prompt_confirm()); if let Some(instruction) = instruction { screen.bus.senders.send_to_server(*instruction).unwrap(); } diff --git a/zellij-server/src/tab/mod.rs b/zellij-server/src/tab/mod.rs index e33141f618..fdc94b02de 100644 --- a/zellij-server/src/tab/mod.rs +++ b/zellij-server/src/tab/mod.rs @@ -8,6 +8,7 @@ pub mod pane_resizer; pub mod tiled_pane_grid; use copy_command::CopyCommand; +use zellij_tile::prelude::Style; use zellij_utils::input::options::Clipboard; use zellij_utils::position::{Column, Line}; use zellij_utils::{position::Position, serde, zellij_tile}; @@ -106,7 +107,7 @@ pub(crate) struct Tab { should_clear_display_before_rendering: bool, mode_info: HashMap, default_mode_info: ModeInfo, - pub colors: Palette, + pub style: Style, connected_clients_in_app: Rc>>, // TODO: combine this and connected_clients connected_clients: HashSet, draw_pane_frames: bool, @@ -304,7 +305,7 @@ impl Tab { senders: ThreadSenders, max_panes: Option, mode_info: ModeInfo, - colors: Palette, + style: Style, draw_pane_frames: bool, connected_clients_in_app: Rc>>, session_is_mirrored: bool, @@ -350,7 +351,7 @@ impl Tab { should_clear_display_before_rendering: false, mode_info: HashMap::new(), default_mode_info: mode_info, - colors, + style, draw_pane_frames, session_is_mirrored, pending_vte_events: HashMap::new(), @@ -434,7 +435,7 @@ impl Tab { let mut new_pane = TerminalPane::new( *pid, *position_and_size, - self.colors, + self.style, next_terminal_position, layout.pane_name.clone().unwrap_or_default(), self.link_handler.clone(), @@ -725,7 +726,7 @@ impl Tab { let mut new_pane = TerminalPane::new( term_pid, new_pane_geom, - self.colors, + self.style, next_terminal_position, String::new(), self.link_handler.clone(), @@ -762,7 +763,7 @@ impl Tab { let new_terminal = TerminalPane::new( term_pid, second_winsize, - self.colors, + self.style, next_terminal_position, String::new(), self.link_handler.clone(), @@ -813,7 +814,7 @@ impl Tab { let new_terminal = TerminalPane::new( term_pid, bottom_winsize, - self.colors, + self.style, next_terminal_position, String::new(), self.link_handler.clone(), @@ -857,7 +858,7 @@ impl Tab { let new_terminal = TerminalPane::new( term_pid, right_winsize, - self.colors, + self.style, next_terminal_position, String::new(), self.link_handler.clone(), @@ -1225,7 +1226,7 @@ impl Tab { let mut pane_contents_and_ui = PaneContentsAndUi::new( pane, output, - self.colors, + self.style, &active_panes, multiple_users_exist_in_session, None, @@ -1276,7 +1277,7 @@ impl Tab { &self.default_mode_info, self.session_is_mirrored, output, - self.colors, + self.style, ); } // render boundaries if needed diff --git a/zellij-server/src/tab/unit/tab_integration_tests.rs b/zellij-server/src/tab/unit/tab_integration_tests.rs index 1026685489..b6b06ebaff 100644 --- a/zellij-server/src/tab/unit/tab_integration_tests.rs +++ b/zellij-server/src/tab/unit/tab_integration_tests.rs @@ -8,6 +8,7 @@ use crate::{ }; use std::convert::TryInto; use std::path::PathBuf; +use zellij_tile::prelude::Style; use zellij_utils::envs::set_session_name; use zellij_utils::input::layout::LayoutTemplate; use zellij_utils::input::options::Clipboard; @@ -94,7 +95,7 @@ fn create_new_tab(size: Size) -> Tab { let senders = ThreadSenders::default().silently_fail_on_send(); let max_panes = None; let mode_info = ModeInfo::default(); - let colors = Palette::default(); + let style = Style::default(); let draw_pane_frames = true; let client_id = 1; let session_is_mirrored = true; @@ -112,7 +113,7 @@ fn create_new_tab(size: Size) -> Tab { senders, max_panes, mode_info, - colors, + style, draw_pane_frames, connected_clients, session_is_mirrored, diff --git a/zellij-server/src/tab/unit/tab_tests.rs b/zellij-server/src/tab/unit/tab_tests.rs index 527894aa48..258365949e 100644 --- a/zellij-server/src/tab/unit/tab_tests.rs +++ b/zellij-server/src/tab/unit/tab_tests.rs @@ -8,6 +8,7 @@ use crate::{ }; use std::convert::TryInto; use std::path::PathBuf; +use zellij_tile::prelude::Style; use zellij_utils::input::layout::LayoutTemplate; use zellij_utils::input::options::Clipboard; use zellij_utils::ipc::IpcReceiverWithContext; @@ -90,7 +91,7 @@ fn create_new_tab(size: Size) -> Tab { let senders = ThreadSenders::default().silently_fail_on_send(); let max_panes = None; let mode_info = ModeInfo::default(); - let colors = Palette::default(); + let style = Style::default(); let draw_pane_frames = true; let client_id = 1; let session_is_mirrored = true; @@ -108,7 +109,7 @@ fn create_new_tab(size: Size) -> Tab { senders, max_panes, mode_info, - colors, + style, draw_pane_frames, connected_clients, session_is_mirrored, diff --git a/zellij-server/src/ui/boundaries.rs b/zellij-server/src/ui/boundaries.rs index 6494374155..b78d631cf2 100644 --- a/zellij-server/src/ui/boundaries.rs +++ b/zellij-server/src/ui/boundaries.rs @@ -11,11 +11,15 @@ use zellij_utils::shared::colors; use std::fmt::{Display, Error, Formatter}; pub mod boundary_type { pub const TOP_RIGHT: &str = "┐"; + pub const TOP_RIGHT_ROUND: &str = "╮"; pub const VERTICAL: &str = "│"; pub const HORIZONTAL: &str = "─"; pub const TOP_LEFT: &str = "┌"; + pub const TOP_LEFT_ROUND: &str = "╭"; pub const BOTTOM_RIGHT: &str = "┘"; + pub const BOTTOM_RIGHT_ROUND: &str = "╯"; pub const BOTTOM_LEFT: &str = "└"; + pub const BOTTOM_LEFT_ROUND: &str = "╰"; pub const VERTICAL_LEFT: &str = "┤"; pub const VERTICAL_RIGHT: &str = "├"; pub const HORIZONTAL_DOWN: &str = "┬"; diff --git a/zellij-server/src/ui/pane_boundaries_frame.rs b/zellij-server/src/ui/pane_boundaries_frame.rs index 28f6112bb0..22812cb3a8 100644 --- a/zellij-server/src/ui/pane_boundaries_frame.rs +++ b/zellij-server/src/ui/pane_boundaries_frame.rs @@ -2,8 +2,9 @@ use crate::output::CharacterChunk; use crate::panes::{AnsiCode, CharacterStyles, TerminalCharacter, EMPTY_TERMINAL_CHARACTER}; use crate::ui::boundaries::boundary_type; use crate::ClientId; +use zellij_tile::prelude::Style; use zellij_utils::pane_size::Viewport; -use zellij_utils::zellij_tile::prelude::{client_id_to_colors, Palette, PaletteColor}; +use zellij_utils::zellij_tile::prelude::{client_id_to_colors, PaletteColor}; use unicode_width::{UnicodeWidthChar, UnicodeWidthStr}; @@ -65,7 +66,7 @@ pub struct FrameParams { pub focused_client: Option, pub is_main_client: bool, pub other_focused_clients: Vec, - pub colors: Palette, + pub style: Style, pub color: Option, pub other_cursors_exist_in_session: bool, } @@ -75,7 +76,7 @@ pub struct PaneFrame { pub geom: Viewport, pub title: String, pub scroll_position: (usize, usize), // (position, length) - pub colors: Palette, + pub style: Style, pub color: Option, pub focused_client: Option, pub is_main_client: bool, @@ -94,7 +95,7 @@ impl PaneFrame { geom, title: main_title, scroll_position, - colors: frame_params.colors, + style: frame_params.style, color: frame_params.color, focused_client: frame_params.focused_client, is_main_client: frame_params.is_main_client, @@ -103,9 +104,22 @@ impl PaneFrame { } } fn client_cursor(&self, client_id: ClientId) -> Vec { - let color = client_id_to_colors(client_id, self.colors); + let color = client_id_to_colors(client_id, self.style.colors); background_color(" ", color.map(|c| c.0)) } + fn get_corner(&self, corner: &'static str) -> &'static str { + if self.style.rounded_corners { + match corner { + boundary_type::TOP_RIGHT => boundary_type::TOP_RIGHT_ROUND, + boundary_type::TOP_LEFT => boundary_type::TOP_LEFT_ROUND, + boundary_type::BOTTOM_RIGHT => boundary_type::BOTTOM_RIGHT_ROUND, + boundary_type::BOTTOM_LEFT => boundary_type::BOTTOM_LEFT_ROUND, + _ => corner, + } + } else { + corner + } + } fn render_title_right_side( &self, max_length: usize, @@ -364,9 +378,15 @@ impl PaneFrame { let mut col = self.geom.x; loop { if col == self.geom.x { - title_line.append(&mut foreground_color(boundary_type::TOP_LEFT, self.color)); + title_line.append(&mut foreground_color( + self.get_corner(boundary_type::TOP_LEFT), + self.color, + )); } else if col == self.geom.x + self.geom.cols - 1 { - title_line.append(&mut foreground_color(boundary_type::TOP_RIGHT, self.color)); + title_line.append(&mut foreground_color( + self.get_corner(boundary_type::TOP_RIGHT), + self.color, + )); } else if col == left_side_start_position { title_line.append(&mut left_side); col += left_side_len; @@ -404,9 +424,15 @@ impl PaneFrame { let mut col = self.geom.x; loop { if col == self.geom.x { - title_line.append(&mut foreground_color(boundary_type::TOP_LEFT, self.color)); + title_line.append(&mut foreground_color( + self.get_corner(boundary_type::TOP_LEFT), + self.color, + )); } else if col == self.geom.x + self.geom.cols - 1 { - title_line.append(&mut foreground_color(boundary_type::TOP_RIGHT, self.color)); + title_line.append(&mut foreground_color( + self.get_corner(boundary_type::TOP_RIGHT), + self.color, + )); } else if col == left_side_start_position { title_line.append(&mut left_side); col += *left_side_len; @@ -437,9 +463,15 @@ impl PaneFrame { let mut col = self.geom.x; loop { if col == self.geom.x { - title_line.append(&mut foreground_color(boundary_type::TOP_LEFT, self.color)); + title_line.append(&mut foreground_color( + self.get_corner(boundary_type::TOP_LEFT), + self.color, + )); } else if col == self.geom.x + self.geom.cols - 1 { - title_line.append(&mut foreground_color(boundary_type::TOP_RIGHT, self.color)); + title_line.append(&mut foreground_color( + self.get_corner(boundary_type::TOP_RIGHT), + self.color, + )); } else if col == middle_start_position { title_line.append(&mut middle); col += *middle_len; @@ -461,8 +493,10 @@ impl PaneFrame { mut right_side: Vec, right_side_len: &usize, ) -> Vec { - let mut left_boundary = foreground_color(boundary_type::TOP_LEFT, self.color); - let mut right_boundary = foreground_color(boundary_type::TOP_RIGHT, self.color); + let mut left_boundary = + foreground_color(self.get_corner(boundary_type::TOP_LEFT), self.color); + let mut right_boundary = + foreground_color(self.get_corner(boundary_type::TOP_RIGHT), self.color); let total_title_length = self.geom.cols.saturating_sub(2); // 2 for the left and right corners let mut middle = String::new(); for _ in (left_side_len + right_side_len)..total_title_length { @@ -481,8 +515,10 @@ impl PaneFrame { mut left_side: Vec, left_side_len: &usize, ) -> Vec { - let mut left_boundary = foreground_color(boundary_type::TOP_LEFT, self.color); - let mut right_boundary = foreground_color(boundary_type::TOP_RIGHT, self.color); + let mut left_boundary = + foreground_color(self.get_corner(boundary_type::TOP_LEFT), self.color); + let mut right_boundary = + foreground_color(self.get_corner(boundary_type::TOP_RIGHT), self.color); let total_title_length = self.geom.cols.saturating_sub(2); // 2 for the left and right corners let mut middle_padding = String::new(); for _ in *left_side_len..total_title_length { @@ -496,8 +532,10 @@ impl PaneFrame { ret } fn empty_title_line(&self) -> Vec { - let mut left_boundary = foreground_color(boundary_type::TOP_LEFT, self.color); - let mut right_boundary = foreground_color(boundary_type::TOP_RIGHT, self.color); + let mut left_boundary = + foreground_color(self.get_corner(boundary_type::TOP_LEFT), self.color); + let mut right_boundary = + foreground_color(self.get_corner(boundary_type::TOP_RIGHT), self.color); let total_title_length = self.geom.cols.saturating_sub(2); // 2 for the left and right corners let mut middle_padding = String::new(); for _ in 0..total_title_length { @@ -575,10 +613,10 @@ impl PaneFrame { for col in 0..self.geom.cols { let boundary = if col == 0 { // bottom left corner - boundary_type::BOTTOM_LEFT + self.get_corner(boundary_type::BOTTOM_LEFT) } else if col == self.geom.cols - 1 { // bottom right corner - boundary_type::BOTTOM_RIGHT + self.get_corner(boundary_type::BOTTOM_RIGHT) } else { boundary_type::HORIZONTAL }; diff --git a/zellij-server/src/ui/pane_contents_and_ui.rs b/zellij-server/src/ui/pane_contents_and_ui.rs index 61b0e35444..4a39da8ffa 100644 --- a/zellij-server/src/ui/pane_contents_and_ui.rs +++ b/zellij-server/src/ui/pane_contents_and_ui.rs @@ -5,13 +5,14 @@ use crate::ui::boundaries::Boundaries; use crate::ui::pane_boundaries_frame::FrameParams; use crate::ClientId; use std::collections::HashMap; -use zellij_tile::data::{ - client_id_to_colors, single_client_color, InputMode, Palette, PaletteColor, +use zellij_tile::{ + data::{client_id_to_colors, single_client_color, InputMode, PaletteColor}, + prelude::Style, }; pub struct PaneContentsAndUi<'a> { pane: &'a mut Box, output: &'a mut Output, - colors: Palette, + style: Style, focused_clients: Vec, multiple_users_exist_in_session: bool, z_index: Option, @@ -21,7 +22,7 @@ impl<'a> PaneContentsAndUi<'a> { pub fn new( pane: &'a mut Box, output: &'a mut Output, - colors: Palette, + style: Style, active_panes: &HashMap, multiple_users_exist_in_session: bool, z_index: Option, @@ -34,7 +35,7 @@ impl<'a> PaneContentsAndUi<'a> { PaneContentsAndUi { pane, output, - colors, + style, focused_clients, multiple_users_exist_in_session, z_index, @@ -95,7 +96,7 @@ impl<'a> PaneContentsAndUi<'a> { .iter() .find(|&&c_id| c_id != client_id) .unwrap(); - if let Some(colors) = client_id_to_colors(*fake_cursor_client_id, self.colors) { + if let Some(colors) = client_id_to_colors(*fake_cursor_client_id, self.style.colors) { if let Some(vte_output) = self.pane.render_fake_cursor(colors.0, colors.1) { self.output.add_post_vte_instruction_to_client( client_id, @@ -146,7 +147,7 @@ impl<'a> PaneContentsAndUi<'a> { focused_client, is_main_client: pane_focused_for_client_id, other_focused_clients: vec![], - colors: self.colors, + style: self.style, color: frame_color, other_cursors_exist_in_session: false, } @@ -155,7 +156,7 @@ impl<'a> PaneContentsAndUi<'a> { focused_client, is_main_client: pane_focused_for_client_id, other_focused_clients, - colors: self.colors, + style: self.style, color: frame_color, other_cursors_exist_in_session: self.multiple_users_exist_in_session, } @@ -195,14 +196,14 @@ impl<'a> PaneContentsAndUi<'a> { match mode { InputMode::Normal | InputMode::Locked => { if session_is_mirrored || !self.multiple_users_exist_in_session { - let colors = single_client_color(self.colors); // mirrored sessions only have one focused color + let colors = single_client_color(self.style.colors); // mirrored sessions only have one focused color Some(colors.0) } else { - let colors = client_id_to_colors(client_id, self.colors); + let colors = client_id_to_colors(client_id, self.style.colors); colors.map(|colors| colors.0) } } - _ => Some(self.colors.orange), + _ => Some(self.style.colors.orange), } } else { None diff --git a/zellij-tile/src/data.rs b/zellij-tile/src/data.rs index 0676ec3e16..24ffb8cf63 100644 --- a/zellij-tile/src/data.rs +++ b/zellij-tile/src/data.rs @@ -208,6 +208,12 @@ pub struct Palette { pub brown: PaletteColor, } +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default, Serialize, Deserialize)] +pub struct Style { + pub colors: Palette, + pub rounded_corners: bool, +} + /// Represents the contents of the help message that is printed in the status bar, /// which indicates the current [`InputMode`] and what the keybinds for that mode /// are. Related to the default `status-bar` plugin. @@ -216,7 +222,7 @@ pub struct ModeInfo { pub mode: InputMode, // FIXME: This should probably return Keys and Actions, then sort out strings plugin-side pub keybinds: Vec<(String, String)>, // => - pub palette: Palette, + pub style: Style, pub capabilities: PluginCapabilities, pub session_name: Option, } diff --git a/zellij-utils/src/errors.rs b/zellij-utils/src/errors.rs index e36fa99f17..d1ab1426f9 100644 --- a/zellij-utils/src/errors.rs +++ b/zellij-utils/src/errors.rs @@ -95,7 +95,7 @@ where println!("\u{1b}[2J{}", fmt_report(report)); process::exit(1); } else { - let _ = sender.send(T::error(format!("{}", fmt_report(report)))); + let _ = sender.send(T::error(fmt_report(report))); } } diff --git a/zellij-utils/src/input/mod.rs b/zellij-utils/src/input/mod.rs index 391fea7b48..289e52cafd 100644 --- a/zellij-utils/src/input/mod.rs +++ b/zellij-utils/src/input/mod.rs @@ -12,15 +12,14 @@ pub mod theme; use crate::envs; use termion::input::TermRead; -use zellij_tile::data::{InputMode, Key, ModeInfo, Palette, PluginCapabilities}; +use zellij_tile::{ + data::{InputMode, Key, ModeInfo, PluginCapabilities}, + prelude::Style, +}; /// Creates a [`ModeInfo`] struct indicating the current [`InputMode`] and its keybinds /// (as pairs of [`String`]s). -pub fn get_mode_info( - mode: InputMode, - palette: Palette, - capabilities: PluginCapabilities, -) -> ModeInfo { +pub fn get_mode_info(mode: InputMode, style: Style, capabilities: PluginCapabilities) -> ModeInfo { let keybinds = match mode { InputMode::Normal | InputMode::Locked | InputMode::Prompt => Vec::new(), InputMode::Resize => vec![ @@ -77,7 +76,7 @@ pub fn get_mode_info( ModeInfo { mode, keybinds, - palette, + style, capabilities, session_name, } diff --git a/zellij-utils/src/input/theme.rs b/zellij-utils/src/input/theme.rs index 5bd8b92116..2916052f53 100644 --- a/zellij-utils/src/input/theme.rs +++ b/zellij-utils/src/input/theme.rs @@ -2,7 +2,10 @@ use serde::{Deserialize, Serialize}; use std::collections::HashMap; use super::options::Options; -use zellij_tile::data::{Palette, PaletteColor}; +use zellij_tile::{ + data::{Palette, PaletteColor}, + prelude::Style, +}; /// Intermediate deserialization of themes #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] @@ -10,6 +13,8 @@ pub struct ThemesFromYaml(HashMap); #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] struct Theme { + #[serde(default)] + rounded_corners: bool, #[serde(flatten)] palette: PaletteFromYaml, } @@ -47,7 +52,7 @@ impl Default for PaletteColorFromYaml { } impl ThemesFromYaml { - pub fn theme_config(self, opts: &Options) -> Option { + pub fn theme_config(self, opts: &Options) -> Option