feat(config): new theme definition spec (#3242)

* Implement initial structs from spec

* kdl configuration unmarshalling

* typo text styling

* remove is_selected toggle

* incorporate new status bar ui into theming

* improve test coverage of config behavior

* tab bar correction

* correct also compact bar

* remove spacing between table columns

* refactor table styling

* use text_unselected.emphasis_1 for keygroup sep

* fix tab bar more text

* repair field flattening for theme

* remove extra styling KDL node

* update tests

* updated selected text conversion

* padding for header bar

* minor corrections for existing themes

* background handling

* compact bar corrections

* properly handle opaque method to activate background

* update newer plugins to use styling struct

* correct omission of selected state

* fix: bold typeface for text elements

* fix: fg -> white for list_unselected conversion

* fix: emphasis and opacity handling for nested_list

* correct stylings in the session-manager

* fix emphases translation for table component

* correct emphasis for run instructions

* correct frame_highlight translation for old themes

* provide missing implementation of frame_highlight

* fencepost emphasis color names

* Set a pseudo-None for frame_unselected in old theme conversion

* correct alternating bg for simplified-ui

* update snapshots

* fix inner text padding and errorneous snapshots

* suppress warning about deprecated usage of palette

* remove unused import

* feat(plugins): API to change floating pane coordinates (#3958)

* basic functionality through the cli

* added to plugin api

* add display area and viewport size to TabInfo

* fix tests and add new one

* some cleanups

* refactor: extract pane_id parsing logic

* style(fmt): rustfmt

* docs(changelog): floating pane coordinate chagne API

* fix(tiled-panes): opening panes from the cli (#3963)

* feat(plugins): add `PastedText` Event (#3962)

* working with text paste

* handle utf8 conversion error

* feat(plugins): add PastedText Event

* docs(changelog): plugins pasted text event

* black for table opaque background

* properly apply opacity to table

* correct padding for explicit width ribbons

* feat(plugins): Allow opening panes near plugin (#3966)

* added command + terminal variants

* added editor variant

* style(fmt): rustfmt

* docs(changelog): plugin apis to open panes near plugin

* feat(plugins): send info about $EDITOR and $SHELL (#3971)

* feat(plugins): send info about $EDITOR and $SHELL

* fix(e2e): snapshot update

* docs(changelog): plugin editor and shell info

* fix(floating-panes): when changing coordinates, if a pane is not floating - make it floating (#3972)

* fix(panes): when changing floating pane coordinates, if the pane is not floating, float it

* style(fmt): rustfmt

* docs(changelog): floating pane coordinate fix

* fix(break-pane): strip logical position when inserting pane to new tab (#3973)

* docs(changelog): logical position fix

* Optional frame_unselected theme

* fixture with correct width to account for arrow padding

* update snapshot and rustfmt

---------

Co-authored-by: Aram Drevekenin <aram@poor.dev>
This commit is contained in:
Mark Grey 2025-02-07 05:59:54 -05:00 committed by GitHub
parent 834f1e68f2
commit 26b99eac63
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
59 changed files with 5117 additions and 1265 deletions

View file

@ -16,7 +16,7 @@ fn populate_tabs_in_tab_line(
tabs_after_active: &mut Vec<LinePart>, tabs_after_active: &mut Vec<LinePart>,
tabs_to_render: &mut Vec<LinePart>, tabs_to_render: &mut Vec<LinePart>,
cols: usize, cols: usize,
palette: Palette, palette: Styling,
capabilities: PluginCapabilities, capabilities: PluginCapabilities,
) { ) {
let mut middle_size = get_current_title_len(tabs_to_render); let mut middle_size = get_current_title_len(tabs_to_render);
@ -107,7 +107,7 @@ fn populate_tabs_in_tab_line(
fn left_more_message( fn left_more_message(
tab_count_to_the_left: usize, tab_count_to_the_left: usize,
palette: Palette, palette: Styling,
separator: &str, separator: &str,
tab_index: usize, tab_index: usize,
) -> LinePart { ) -> LinePart {
@ -122,13 +122,14 @@ fn left_more_message(
// 238 // 238
// chars length plus separator length on both sides // chars length plus separator length on both sides
let more_text_len = more_text.width() + 2 * separator.width(); let more_text_len = more_text.width() + 2 * separator.width();
let (text_color, sep_color) = match palette.theme_hue { let (text_color, sep_color) = (
ThemeHue::Dark => (palette.white, palette.black), palette.ribbon_unselected.base,
ThemeHue::Light => (palette.black, palette.white), palette.text_unselected.background,
}; );
let left_separator = style!(sep_color, palette.orange).paint(separator); let plus_ribbon_bg = palette.text_selected.emphasis_0;
let more_styled_text = style!(text_color, palette.orange).bold().paint(more_text); let left_separator = style!(sep_color, plus_ribbon_bg).paint(separator);
let right_separator = style!(palette.orange, sep_color).paint(separator); let more_styled_text = style!(text_color, plus_ribbon_bg).bold().paint(more_text);
let right_separator = style!(plus_ribbon_bg, sep_color).paint(separator);
let more_styled_text = let more_styled_text =
ANSIStrings(&[left_separator, more_styled_text, right_separator]).to_string(); ANSIStrings(&[left_separator, more_styled_text, right_separator]).to_string();
LinePart { LinePart {
@ -140,7 +141,7 @@ fn left_more_message(
fn right_more_message( fn right_more_message(
tab_count_to_the_right: usize, tab_count_to_the_right: usize,
palette: Palette, palette: Styling,
separator: &str, separator: &str,
tab_index: usize, tab_index: usize,
) -> LinePart { ) -> LinePart {
@ -154,13 +155,15 @@ fn right_more_message(
}; };
// chars length plus separator length on both sides // chars length plus separator length on both sides
let more_text_len = more_text.width() + 2 * separator.width(); let more_text_len = more_text.width() + 2 * separator.width();
let (text_color, sep_color) = match palette.theme_hue {
ThemeHue::Dark => (palette.white, palette.black), let (text_color, sep_color) = (
ThemeHue::Light => (palette.black, palette.white), palette.ribbon_unselected.base,
}; palette.text_unselected.background,
let left_separator = style!(sep_color, palette.orange).paint(separator); );
let more_styled_text = style!(text_color, palette.orange).bold().paint(more_text); let plus_ribbon_bg = palette.text_selected.emphasis_0;
let right_separator = style!(palette.orange, sep_color).paint(separator); let left_separator = style!(sep_color, plus_ribbon_bg).paint(separator);
let more_styled_text = style!(text_color, plus_ribbon_bg).bold().paint(more_text);
let right_separator = style!(plus_ribbon_bg, sep_color).paint(separator);
let more_styled_text = let more_styled_text =
ANSIStrings(&[left_separator, more_styled_text, right_separator]).to_string(); ANSIStrings(&[left_separator, more_styled_text, right_separator]).to_string();
LinePart { LinePart {
@ -173,24 +176,17 @@ fn right_more_message(
fn tab_line_prefix( fn tab_line_prefix(
session_name: Option<&str>, session_name: Option<&str>,
mode: InputMode, mode: InputMode,
palette: Palette, palette: Styling,
cols: usize, cols: usize,
) -> Vec<LinePart> { ) -> Vec<LinePart> {
let prefix_text = " Zellij ".to_string(); let prefix_text = " Zellij ".to_string();
let prefix_text_len = prefix_text.chars().count(); let prefix_text_len = prefix_text.chars().count();
let text_color = match palette.theme_hue { let text_color = palette.text_unselected.base;
ThemeHue::Dark => palette.white, let bg_color = palette.text_unselected.background;
ThemeHue::Light => palette.black, let locked_mode_color = palette.text_unselected.emphasis_3;
}; let normal_mode_color = palette.text_unselected.emphasis_2;
let bg_color = match palette.theme_hue { let other_modes_color = palette.text_unselected.emphasis_0;
ThemeHue::Dark => palette.black,
ThemeHue::Light => palette.white,
};
let locked_mode_color = palette.magenta;
let normal_mode_color = palette.green;
let other_modes_color = palette.orange;
let prefix_styled_text = style!(text_color, bg_color).bold().paint(prefix_text); let prefix_styled_text = style!(text_color, bg_color).bold().paint(prefix_text);
let mut parts = vec![LinePart { let mut parts = vec![LinePart {
@ -201,10 +197,6 @@ fn tab_line_prefix(
if let Some(name) = session_name { if let Some(name) = session_name {
let name_part = format!("({})", name); let name_part = format!("({})", name);
let name_part_len = name_part.width(); let name_part_len = name_part.width();
let text_color = match palette.theme_hue {
ThemeHue::Dark => palette.white,
ThemeHue::Light => palette.black,
};
let name_part_styled_text = style!(text_color, bg_color).bold().paint(name_part); let name_part_styled_text = style!(text_color, bg_color).bold().paint(name_part);
if cols.saturating_sub(prefix_text_len) >= name_part_len { if cols.saturating_sub(prefix_text_len) >= name_part_len {
parts.push(LinePart { parts.push(LinePart {
@ -253,7 +245,7 @@ pub fn tab_line(
mut all_tabs: Vec<LinePart>, mut all_tabs: Vec<LinePart>,
active_tab_index: usize, active_tab_index: usize,
cols: usize, cols: usize,
palette: Palette, palette: Styling,
capabilities: PluginCapabilities, capabilities: PluginCapabilities,
hide_session_name: bool, hide_session_name: bool,
mode: InputMode, mode: InputMode,
@ -293,6 +285,7 @@ pub fn tab_line(
let current_title_len = get_current_title_len(&prefix); let current_title_len = get_current_title_len(&prefix);
if current_title_len < cols { if current_title_len < cols {
let mut remaining_space = cols - current_title_len; let mut remaining_space = cols - current_title_len;
let remaining_bg = palette.text_unselected.background;
if let Some(swap_layout_status) = swap_layout_status( if let Some(swap_layout_status) = swap_layout_status(
remaining_space, remaining_space,
active_swap_layout_name, active_swap_layout_name,
@ -304,7 +297,7 @@ pub fn tab_line(
remaining_space -= swap_layout_status.len; remaining_space -= swap_layout_status.len;
let mut buffer = String::new(); let mut buffer = String::new();
for _ in 0..remaining_space { for _ in 0..remaining_space {
buffer.push_str(&style!(palette.black, palette.black).paint(" ").to_string()); buffer.push_str(&style!(remaining_bg, remaining_bg).paint(" ").to_string());
} }
prefix.push(LinePart { prefix.push(LinePart {
part: buffer, part: buffer,
@ -323,7 +316,7 @@ fn swap_layout_status(
swap_layout_name: &Option<String>, swap_layout_name: &Option<String>,
is_swap_layout_damaged: bool, is_swap_layout_damaged: bool,
input_mode: InputMode, input_mode: InputMode,
palette: &Palette, palette: &Styling,
separator: &str, separator: &str,
) -> Option<LinePart> { ) -> Option<LinePart> {
match swap_layout_name { match swap_layout_name {
@ -331,31 +324,28 @@ fn swap_layout_status(
let mut swap_layout_name = format!(" {} ", swap_layout_name); let mut swap_layout_name = format!(" {} ", swap_layout_name);
swap_layout_name.make_ascii_uppercase(); swap_layout_name.make_ascii_uppercase();
let swap_layout_name_len = swap_layout_name.len() + 3; let swap_layout_name_len = swap_layout_name.len() + 3;
let bg = palette.text_unselected.background;
let fg = palette.ribbon_unselected.background;
let green = palette.ribbon_selected.background;
let (prefix_separator, swap_layout_name, suffix_separator) = let (prefix_separator, swap_layout_name, suffix_separator) =
if input_mode == InputMode::Locked { if input_mode == InputMode::Locked {
( (
style!(palette.black, palette.fg).paint(separator), style!(bg, fg).paint(separator),
style!(palette.black, palette.fg) style!(bg, fg).italic().paint(&swap_layout_name),
.italic() style!(fg, bg).paint(separator),
.paint(&swap_layout_name),
style!(palette.fg, palette.black).paint(separator),
) )
} else if is_swap_layout_damaged { } else if is_swap_layout_damaged {
( (
style!(palette.black, palette.fg).paint(separator), style!(bg, fg).paint(separator),
style!(palette.black, palette.fg) style!(bg, fg).bold().paint(&swap_layout_name),
.bold() style!(fg, bg).paint(separator),
.paint(&swap_layout_name),
style!(palette.fg, palette.black).paint(separator),
) )
} else { } else {
( (
style!(palette.black, palette.green).paint(separator), style!(bg, green).paint(separator),
style!(palette.black, palette.green) style!(bg, green).bold().paint(&swap_layout_name),
.bold() style!(green, bg).paint(separator),
.paint(&swap_layout_name),
style!(palette.green, palette.black).paint(separator),
) )
}; };
let swap_layout_indicator = format!( let swap_layout_indicator = format!(

View file

@ -131,10 +131,7 @@ impl ZellijPlugin for State {
.tab_line .tab_line
.iter() .iter()
.fold(String::new(), |output, part| output + &part.part); .fold(String::new(), |output, part| output + &part.part);
let background = match self.mode_info.style.colors.theme_hue { let background = self.mode_info.style.colors.text_unselected.background;
ThemeHue::Dark => self.mode_info.style.colors.black,
ThemeHue::Light => self.mode_info.style.colors.white,
};
match background { match background {
PaletteColor::Rgb((r, g, b)) => { PaletteColor::Rgb((r, g, b)) => {
print!("{}\u{1b}[48;2;{};{};{}m\u{1b}[0K", output, r, g, b); print!("{}\u{1b}[48;2;{};{};{}m\u{1b}[0K", output, r, g, b);

View file

@ -4,12 +4,12 @@ use unicode_width::UnicodeWidthStr;
use zellij_tile::prelude::*; use zellij_tile::prelude::*;
use zellij_tile_utils::style; use zellij_tile_utils::style;
fn cursors(focused_clients: &[ClientId], palette: Palette) -> (Vec<ANSIString>, usize) { fn cursors(focused_clients: &[ClientId], colors: MultiplayerColors) -> (Vec<ANSIString>, usize) {
// cursor section, text length // cursor section, text length
let mut len = 0; let mut len = 0;
let mut cursors = vec![]; let mut cursors = vec![];
for client_id in focused_clients.iter() { for client_id in focused_clients.iter() {
if let Some(color) = client_id_to_colors(*client_id, palette) { if let Some(color) = client_id_to_colors(*client_id, colors) {
cursors.push(style!(color.1, color.0).paint(" ")); cursors.push(style!(color.1, color.0).paint(" "));
len += 1; len += 1;
} }
@ -21,37 +21,40 @@ pub fn render_tab(
text: String, text: String,
tab: &TabInfo, tab: &TabInfo,
is_alternate_tab: bool, is_alternate_tab: bool,
palette: Palette, palette: Styling,
separator: &str, separator: &str,
) -> LinePart { ) -> LinePart {
let focused_clients = tab.other_focused_clients.as_slice(); let focused_clients = tab.other_focused_clients.as_slice();
let separator_width = separator.width(); let separator_width = separator.width();
let alternate_tab_color = match palette.theme_hue { let alternate_tab_color = if is_alternate_tab {
// TODO: only do this if we don't have the arrow capabilities palette.ribbon_unselected.emphasis_1
ThemeHue::Dark => palette.white, } else {
ThemeHue::Light => palette.black, palette.ribbon_unselected.background
}; };
let background_color = if tab.active { let background_color = if tab.active {
palette.green palette.ribbon_selected.background
} else if is_alternate_tab { } else if is_alternate_tab {
alternate_tab_color alternate_tab_color
} else { } else {
palette.fg palette.ribbon_unselected.background
}; };
let foreground_color = match palette.theme_hue { let foreground_color = if tab.active {
ThemeHue::Dark => palette.black, palette.ribbon_selected.base
ThemeHue::Light => palette.white, } else {
palette.ribbon_unselected.base
}; };
let left_separator = style!(foreground_color, background_color).paint(separator); let separator_fill_color = palette.text_unselected.background;
let left_separator = style!(separator_fill_color, background_color).paint(separator);
let mut tab_text_len = text.width() + (separator_width * 2) + 2; // + 2 for padding let mut tab_text_len = text.width() + (separator_width * 2) + 2; // + 2 for padding
let tab_styled_text = style!(foreground_color, background_color) let tab_styled_text = style!(foreground_color, background_color)
.bold() .bold()
.paint(format!(" {} ", text)); .paint(format!(" {} ", text));
let right_separator = style!(background_color, foreground_color).paint(separator); let right_separator = style!(background_color, separator_fill_color).paint(separator);
let tab_styled_text = if !focused_clients.is_empty() { let tab_styled_text = if !focused_clients.is_empty() {
let (cursor_section, extra_length) = cursors(focused_clients, palette); let (cursor_section, extra_length) =
cursors(focused_clients, palette.multiplayer_user_colors);
tab_text_len += extra_length; tab_text_len += extra_length;
let mut s = String::new(); let mut s = String::new();
let cursor_beginning = style!(foreground_color, background_color) let cursor_beginning = style!(foreground_color, background_color)
@ -85,7 +88,7 @@ pub fn tab_style(
mut tabname: String, mut tabname: String,
tab: &TabInfo, tab: &TabInfo,
mut is_alternate_tab: bool, mut is_alternate_tab: bool,
palette: Palette, palette: Styling,
capabilities: PluginCapabilities, capabilities: PluginCapabilities,
) -> LinePart { ) -> LinePart {
let separator = tab_separator(capabilities); let separator = tab_separator(capabilities);

View file

@ -71,7 +71,7 @@ struct State {
ui_size: usize, ui_size: usize,
current_screen: Screen, current_screen: Screen,
latest_mode_info: Option<ModeInfo>, latest_mode_info: Option<ModeInfo>,
colors: Palette, colors: Styling,
} }
impl Default for State { impl Default for State {
@ -82,7 +82,7 @@ impl Default for State {
ui_size: UI_SIZE, ui_size: UI_SIZE,
current_screen: Screen::default(), current_screen: Screen::default(),
latest_mode_info: None, latest_mode_info: None,
colors: Palette::default(), colors: Palette::default().into(),
} }
} }
} }

View file

@ -1,11 +1,8 @@
use crate::{Screen, WIDTH_BREAKPOINTS}; use crate::{Screen, WIDTH_BREAKPOINTS};
use zellij_tile::prelude::*; use zellij_tile::prelude::*;
pub fn top_tab_menu(cols: usize, current_screen: &Screen, colors: &Palette) { pub fn top_tab_menu(cols: usize, current_screen: &Screen, colors: &Styling) {
let background = match colors.theme_hue { let background = colors.text_unselected.background;
ThemeHue::Dark => colors.black,
ThemeHue::Light => colors.white,
};
let bg_color = match background { let bg_color = match background {
PaletteColor::Rgb((r, g, b)) => format!("\u{1b}[48;2;{};{};{}m\u{1b}[0K", r, g, b), PaletteColor::Rgb((r, g, b)) => format!("\u{1b}[48;2;{};{};{}m\u{1b}[0K", r, g, b),
PaletteColor::EightBit(color) => format!("\u{1b}[48;5;{}m\u{1b}[0K", color), PaletteColor::EightBit(color) => format!("\u{1b}[48;5;{}m\u{1b}[0K", color),

View file

@ -34,7 +34,7 @@ pub struct NewPluginScreen {
selected_config_index: Option<usize>, selected_config_index: Option<usize>,
request_ids: Vec<String>, request_ids: Vec<String>,
load_in_background: bool, load_in_background: bool,
colors: Palette, colors: Styling,
} }
impl Default for NewPluginScreen { impl Default for NewPluginScreen {
@ -50,13 +50,13 @@ impl Default for NewPluginScreen {
selected_config_index: None, selected_config_index: None,
request_ids: vec![], request_ids: vec![],
load_in_background: false, load_in_background: false,
colors: Palette::default(), colors: Palette::default().into(),
} }
} }
} }
impl NewPluginScreen { impl NewPluginScreen {
pub fn new(colors: Palette) -> Self { pub fn new(colors: Styling) -> Self {
Self { Self {
colors, colors,
..Default::default() ..Default::default()
@ -261,10 +261,7 @@ impl NewPluginScreen {
None, None,
None, None,
); );
let background = match self.colors.theme_hue { let background = self.colors.text_unselected.background;
ThemeHue::Dark => self.colors.black,
ThemeHue::Light => self.colors.white,
};
let bg_color = match background { let bg_color = match background {
PaletteColor::Rgb((r, g, b)) => format!("\u{1b}[48;2;{};{};{}m\u{1b}[0K", r, g, b), PaletteColor::Rgb((r, g, b)) => format!("\u{1b}[48;2;{};{};{}m\u{1b}[0K", r, g, b),
PaletteColor::EightBit(color) => format!("\u{1b}[48;5;{}m\u{1b}[0K", color), PaletteColor::EightBit(color) => format!("\u{1b}[48;5;{}m\u{1b}[0K", color),
@ -496,7 +493,7 @@ struct State {
plugin_id_to_tab_position: HashMap<u32, usize>, plugin_id_to_tab_position: HashMap<u32, usize>,
search_term: String, search_term: String,
new_plugin_screen: Option<NewPluginScreen>, new_plugin_screen: Option<NewPluginScreen>,
colors: Palette, colors: Styling,
} }
register_plugin!(State); register_plugin!(State);

View file

@ -122,10 +122,7 @@ impl ZellijPlugin for State {
fn render(&mut self, rows: usize, cols: usize) { fn render(&mut self, rows: usize, cols: usize) {
let (x, y, width, height) = self.main_menu_size(rows, cols); let (x, y, width, height) = self.main_menu_size(rows, cols);
let background = match self.colors.palette.theme_hue { let background = self.colors.palette.text_unselected.background;
ThemeHue::Dark => self.colors.palette.black,
ThemeHue::Light => self.colors.palette.white,
};
if self.is_welcome_screen { if self.is_welcome_screen {
render_banner(x, 0, rows.saturating_sub(height), width); render_banner(x, 0, rows.saturating_sub(height), width);

View file

@ -83,9 +83,14 @@ impl ListItem {
let mut remaining_cols = max_cols; let mut remaining_cols = max_cols;
for span in session_name { for span in session_name {
span.render( span.render(
indices indices.clone().map(|i| {
.clone() (
.map(|i| (SpanStyle::ForegroundBold(self.colors.palette.magenta), i)), SpanStyle::ForegroundBold(
self.colors.palette.text_unselected.emphasis_3,
),
i,
)
}),
&mut line_to_render, &mut line_to_render,
&mut remaining_cols, &mut remaining_cols,
); );
@ -102,9 +107,14 @@ impl ListItem {
let mut remaining_cols = max_cols; let mut remaining_cols = max_cols;
for span in tab_name { for span in tab_name {
span.render( span.render(
indices indices.clone().map(|i| {
.clone() (
.map(|i| (SpanStyle::ForegroundBold(self.colors.palette.magenta), i)), SpanStyle::ForegroundBold(
self.colors.palette.text_unselected.emphasis_3,
),
i,
)
}),
&mut line_to_render, &mut line_to_render,
&mut remaining_cols, &mut remaining_cols,
); );
@ -116,9 +126,14 @@ impl ListItem {
let mut remaining_cols = max_cols; let mut remaining_cols = max_cols;
for span in pane_name { for span in pane_name {
span.render( span.render(
indices indices.clone().map(|i| {
.clone() (
.map(|i| (SpanStyle::ForegroundBold(self.colors.palette.magenta), i)), SpanStyle::ForegroundBold(
self.colors.palette.text_unselected.emphasis_3,
),
i,
)
}),
&mut line_to_render, &mut line_to_render,
&mut remaining_cols, &mut remaining_cols,
); );
@ -297,11 +312,11 @@ impl LineToRender {
pub fn make_selected_as_search(&mut self, add_arrows: bool) { pub fn make_selected_as_search(&mut self, add_arrows: bool) {
self.is_selected = true; self.is_selected = true;
let arrows = if add_arrows { let arrows = if add_arrows {
self.colors.magenta(" <↓↑> ") self.colors.shortcuts(" <↓↑> ")
} else { } else {
" ".to_owned() " ".to_owned()
}; };
match self.colors.palette.bg { match self.colors.palette.list_selected.background {
PaletteColor::EightBit(byte) => { PaletteColor::EightBit(byte) => {
self.line = format!( self.line = format!(
"\u{1b}[48;5;{byte}m\u{1b}[K\u{1b}[48;5;{byte}m{arrows}{}", "\u{1b}[48;5;{byte}m\u{1b}[K\u{1b}[48;5;{byte}m{arrows}{}",
@ -319,11 +334,11 @@ impl LineToRender {
pub fn make_selected(&mut self, add_arrows: bool) { pub fn make_selected(&mut self, add_arrows: bool) {
self.is_selected = true; self.is_selected = true;
let arrows = if add_arrows { let arrows = if add_arrows {
self.colors.magenta("<←↓↑→>") self.colors.shortcuts("<←↓↑→>")
} else { } else {
" ".to_owned() " ".to_owned()
}; };
match self.colors.palette.bg { match self.colors.palette.list_selected.background {
PaletteColor::EightBit(byte) => { PaletteColor::EightBit(byte) => {
self.line = format!( self.line = format!(
"\u{1b}[48;5;{byte}m\u{1b}[K\u{1b}[48;5;{byte}m{arrows}{}", "\u{1b}[48;5;{byte}m\u{1b}[K\u{1b}[48;5;{byte}m{arrows}{}",
@ -343,7 +358,7 @@ impl LineToRender {
let more = if self.truncated_result_count > 0 { let more = if self.truncated_result_count > 0 {
self.colors self.colors
.red(&format!(" [+{}]", self.truncated_result_count)) .exit_code_error(&format!(" [+{}]", self.truncated_result_count))
} else { } else {
String::new() String::new()
}; };
@ -368,12 +383,12 @@ pub fn build_session_ui_line(session_ui_info: &SessionUiInfo, colors: Colors) ->
.iter() .iter()
.fold(0, |acc, tab| acc + tab.panes.len()); .fold(0, |acc, tab| acc + tab.panes.len());
let tab_count = format!("{}", tab_count_text); let tab_count = format!("{}", tab_count_text);
let tab_count_styled = colors.cyan(&tab_count); let tab_count_styled = colors.tab_count(&tab_count);
let total_pane_count = format!("{}", total_pane_count_text); let total_pane_count = format!("{}", total_pane_count_text);
let total_pane_count_styled = colors.green(&total_pane_count); let total_pane_count_styled = colors.pane_count(&total_pane_count);
let session_name = &session_ui_info.name; let session_name = &session_ui_info.name;
let connected_users = format!("{}", session_ui_info.connected_users); let connected_users = format!("{}", session_ui_info.connected_users);
let connected_users_styled = colors.orange(&connected_users); let connected_users_styled = colors.connected_users(&connected_users);
let session_bullet_span = let session_bullet_span =
UiSpan::UiSpanTelescope(UiSpanTelescope::new(vec![StringAndLength::new( UiSpan::UiSpanTelescope(UiSpanTelescope::new(vec![StringAndLength::new(
format!(" > "), format!(" > "),
@ -381,7 +396,7 @@ pub fn build_session_ui_line(session_ui_info: &SessionUiInfo, colors: Colors) ->
)])); )]));
let session_name_span = UiSpan::TruncatableUiSpan(TruncatableUiSpan::new( let session_name_span = UiSpan::TruncatableUiSpan(TruncatableUiSpan::new(
session_name.clone(), session_name.clone(),
SpanStyle::ForegroundBold(colors.palette.orange), SpanStyle::ForegroundBold(colors.palette.text_unselected.emphasis_0),
)); ));
let tab_and_pane_count = UiSpan::UiSpanTelescope(UiSpanTelescope::new(vec![ let tab_and_pane_count = UiSpan::UiSpanTelescope(UiSpanTelescope::new(vec![
StringAndLength::new( StringAndLength::new(
@ -409,9 +424,12 @@ pub fn build_session_ui_line(session_ui_info: &SessionUiInfo, colors: Colors) ->
ui_spans.push(connected_users_count); ui_spans.push(connected_users_count);
if session_ui_info.is_current_session { if session_ui_info.is_current_session {
let current_session_indication = UiSpan::UiSpanTelescope(UiSpanTelescope::new(vec![ let current_session_indication = UiSpan::UiSpanTelescope(UiSpanTelescope::new(vec![
StringAndLength::new(colors.orange(&format!(" <CURRENT SESSION>")), 18), StringAndLength::new(
StringAndLength::new(colors.orange(&format!(" <CURRENT>")), 10), colors.current_session_marker(&format!(" <CURRENT SESSION>")),
StringAndLength::new(colors.orange(&format!(" <C>")), 4), 18,
),
StringAndLength::new(colors.current_session_marker(&format!(" <CURRENT>")), 10),
StringAndLength::new(colors.current_session_marker(&format!(" <C>")), 4),
])); ]));
ui_spans.push(current_session_indication); ui_spans.push(current_session_indication);
} }
@ -423,7 +441,7 @@ pub fn build_tab_ui_line(tab_ui_info: &TabUiInfo, colors: Colors) -> Vec<UiSpan>
let tab_name = &tab_ui_info.name; let tab_name = &tab_ui_info.name;
let pane_count_text = tab_ui_info.panes.len(); let pane_count_text = tab_ui_info.panes.len();
let pane_count = format!("{}", pane_count_text); let pane_count = format!("{}", pane_count_text);
let pane_count_styled = colors.green(&pane_count); let pane_count_styled = colors.pane_count(&pane_count);
let tab_bullet_span = let tab_bullet_span =
UiSpan::UiSpanTelescope(UiSpanTelescope::new(vec![StringAndLength::new( UiSpan::UiSpanTelescope(UiSpanTelescope::new(vec![StringAndLength::new(
format!(" - "), format!(" - "),
@ -431,7 +449,7 @@ pub fn build_tab_ui_line(tab_ui_info: &TabUiInfo, colors: Colors) -> Vec<UiSpan>
)])); )]));
let tab_name_span = UiSpan::TruncatableUiSpan(TruncatableUiSpan::new( let tab_name_span = UiSpan::TruncatableUiSpan(TruncatableUiSpan::new(
tab_name.clone(), tab_name.clone(),
SpanStyle::ForegroundBold(colors.palette.cyan), SpanStyle::ForegroundBold(colors.palette.text_unselected.emphasis_1),
)); ));
let connected_users_count_span = UiSpan::UiSpanTelescope(UiSpanTelescope::new(vec![ let connected_users_count_span = UiSpan::UiSpanTelescope(UiSpanTelescope::new(vec![
StringAndLength::new( StringAndLength::new(
@ -455,9 +473,9 @@ pub fn build_pane_ui_line(pane_ui_info: &PaneUiInfo, colors: Colors) -> Vec<UiSp
let exit_code = pane_ui_info.exit_code.map(|exit_code_number| { let exit_code = pane_ui_info.exit_code.map(|exit_code_number| {
let exit_code = format!("{}", exit_code_number); let exit_code = format!("{}", exit_code_number);
let exit_code = if exit_code_number == 0 { let exit_code = if exit_code_number == 0 {
colors.green(&exit_code) colors.session_and_folder_entry(&exit_code)
} else { } else {
colors.red(&exit_code) colors.exit_code_error(&exit_code)
}; };
exit_code exit_code
}); });
@ -505,7 +523,7 @@ pub fn minimize_lines(
} }
pub fn render_prompt(search_term: &str, colors: Colors, x: usize, y: usize) { pub fn render_prompt(search_term: &str, colors: Colors, x: usize, y: usize) {
let prompt = colors.green(&format!("Search:")); let prompt = colors.session_and_folder_entry(&format!("Search:"));
let search_term = colors.bold(&format!("{}_", search_term)); let search_term = colors.bold(&format!("{}_", search_term));
println!( println!(
"\u{1b}[{};{}H\u{1b}[0m{} {}\n", "\u{1b}[{};{}H\u{1b}[0m{} {}\n",
@ -581,10 +599,10 @@ fn render_new_session_folder_prompt(
let new_session_path = new_session_folder.clone(); let new_session_path = new_session_folder.clone();
let new_session_folder = new_session_folder.display().to_string(); let new_session_folder = new_session_folder.display().to_string();
let change_folder_shortcut_text = "<Ctrl f>"; let change_folder_shortcut_text = "<Ctrl f>";
let change_folder_shortcut = colors.magenta(&change_folder_shortcut_text); let change_folder_shortcut = colors.shortcuts(&change_folder_shortcut_text);
let to_change = "to change"; let to_change = "to change";
let reset_folder_shortcut_text = "<Ctrl c>"; let reset_folder_shortcut_text = "<Ctrl c>";
let reset_folder_shortcut = colors.magenta(reset_folder_shortcut_text); let reset_folder_shortcut = colors.shortcuts(reset_folder_shortcut_text);
let to_reset = "to reset"; let to_reset = "to reset";
if max_cols if max_cols
>= folder_prompt.width() >= folder_prompt.width()
@ -598,8 +616,8 @@ fn render_new_session_folder_prompt(
print!( print!(
"\u{1b}[m{}{} {} ({} {}, {} {})", "\u{1b}[m{}{} {} ({} {}, {} {})",
format!("\u{1b}[{};{}H", y + 1, x + 1), format!("\u{1b}[{};{}H", y + 1, x + 1),
colors.green(folder_prompt), colors.session_name_prompt(folder_prompt),
colors.orange(&new_session_folder), colors.session_and_folder_entry(&new_session_folder),
change_folder_shortcut, change_folder_shortcut,
to_change, to_change,
reset_folder_shortcut, reset_folder_shortcut,
@ -617,8 +635,8 @@ fn render_new_session_folder_prompt(
print!( print!(
"\u{1b}[m{}{} {} ({} {}, {} {})", "\u{1b}[m{}{} {} ({} {}, {} {})",
format!("\u{1b}[{};{}H", y + 1, x + 1), format!("\u{1b}[{};{}H", y + 1, x + 1),
colors.green(short_folder_prompt), colors.session_name_prompt(short_folder_prompt),
colors.orange(&new_session_folder), colors.session_and_folder_entry(&new_session_folder),
change_folder_shortcut, change_folder_shortcut,
to_change, to_change,
reset_folder_shortcut, reset_folder_shortcut,
@ -634,8 +652,8 @@ fn render_new_session_folder_prompt(
print!( print!(
"\u{1b}[m{}{} {} ({}/{})", "\u{1b}[m{}{} {} ({}/{})",
format!("\u{1b}[{};{}H", y + 1, x + 1), format!("\u{1b}[{};{}H", y + 1, x + 1),
colors.green(short_folder_prompt), colors.session_name_prompt(short_folder_prompt),
colors.orange(&new_session_folder), colors.session_and_folder_entry(&new_session_folder),
change_folder_shortcut, change_folder_shortcut,
reset_folder_shortcut, reset_folder_shortcut,
); );
@ -652,8 +670,8 @@ fn render_new_session_folder_prompt(
print!( print!(
"\u{1b}[m{}{} {} ({}/{})", "\u{1b}[m{}{} {} ({}/{})",
format!("\u{1b}[{};{}H", y + 1, x + 1), format!("\u{1b}[{};{}H", y + 1, x + 1),
colors.green(short_folder_prompt), colors.session_name_prompt(short_folder_prompt),
colors.orange(&truncated_path), colors.session_and_folder_entry(&truncated_path),
change_folder_shortcut, change_folder_shortcut,
reset_folder_shortcut, reset_folder_shortcut,
); );
@ -663,7 +681,7 @@ fn render_new_session_folder_prompt(
let folder_prompt = "New session folder:"; let folder_prompt = "New session folder:";
let short_folder_prompt = "Folder:"; let short_folder_prompt = "Folder:";
let change_folder_shortcut_text = "<Ctrl f>"; let change_folder_shortcut_text = "<Ctrl f>";
let change_folder_shortcut = colors.magenta(change_folder_shortcut_text); let change_folder_shortcut = colors.shortcuts(change_folder_shortcut_text);
let to_set = "to set"; let to_set = "to set";
if max_cols if max_cols
@ -672,7 +690,7 @@ fn render_new_session_folder_prompt(
print!( print!(
"\u{1b}[m{}{} ({} {})", "\u{1b}[m{}{} ({} {})",
format!("\u{1b}[{};{}H", y + 1, x + 1), format!("\u{1b}[{};{}H", y + 1, x + 1),
colors.green(folder_prompt), colors.session_name_prompt(folder_prompt),
change_folder_shortcut, change_folder_shortcut,
to_set, to_set,
); );
@ -685,7 +703,7 @@ fn render_new_session_folder_prompt(
print!( print!(
"\u{1b}[m{}{} ({} {})", "\u{1b}[m{}{} ({} {})",
format!("\u{1b}[{};{}H", y + 1, x + 1), format!("\u{1b}[{};{}H", y + 1, x + 1),
colors.green(short_folder_prompt), colors.session_name_prompt(short_folder_prompt),
change_folder_shortcut, change_folder_shortcut,
to_set, to_set,
); );
@ -693,7 +711,7 @@ fn render_new_session_folder_prompt(
print!( print!(
"\u{1b}[m{}{} {}", "\u{1b}[m{}{} {}",
format!("\u{1b}[{};{}H", y + 1, x + 1), format!("\u{1b}[{};{}H", y + 1, x + 1),
colors.green(short_folder_prompt), colors.session_name_prompt(short_folder_prompt),
change_folder_shortcut, change_folder_shortcut,
); );
} }
@ -709,7 +727,7 @@ pub fn render_new_session_block(
x: usize, x: usize,
y: usize, y: usize,
) { ) {
let enter = colors.magenta("<ENTER>"); let enter = colors.shortcuts("<ENTER>");
if new_session_info.entering_new_session_name() { if new_session_info.entering_new_session_name() {
let prompt = "New session name:"; let prompt = "New session name:";
let long_instruction = "when done, blank for random"; let long_instruction = "when done, blank for random";
@ -720,8 +738,8 @@ pub fn render_new_session_block(
println!( println!(
"\u{1b}[m{}{} {}_ ({} {})", "\u{1b}[m{}{} {}_ ({} {})",
format!("\u{1b}[{};{}H", y + 1, x + 1), format!("\u{1b}[{};{}H", y + 1, x + 1),
colors.green(prompt), colors.session_name_prompt(prompt),
colors.orange(&new_session_name), colors.session_and_folder_entry(&new_session_name),
enter, enter,
long_instruction, long_instruction,
); );
@ -746,8 +764,8 @@ pub fn render_new_session_block(
println!( println!(
"\u{1b}[m{}{} {}_ {}", "\u{1b}[m{}{} {}_ {}",
format!("\u{1b}[{};{}H", y + 1, x + 1), format!("\u{1b}[{};{}H", y + 1, x + 1),
colors.green(prompt), colors.session_name_prompt(prompt),
colors.orange(&new_session_name), colors.session_and_folder_entry(&new_session_name),
enter, enter,
); );
} }
@ -759,23 +777,23 @@ pub fn render_new_session_block(
}; };
let prompt = "New session name:"; let prompt = "New session name:";
let long_instruction = "to correct"; let long_instruction = "to correct";
let esc = colors.magenta("<ESC>"); let esc = colors.shortcuts("<ESC>");
if max_cols_of_new_session_block if max_cols_of_new_session_block
> prompt.width() + long_instruction.width() + new_session_name.width() + 15 > prompt.width() + long_instruction.width() + new_session_name.width() + 15
{ {
println!( println!(
"\u{1b}[m{}{}: {} ({} to correct)", "\u{1b}[m{}{}: {} ({} to correct)",
format!("\u{1b}[{};{}H", y + 1, x + 1), format!("\u{1b}[{};{}H", y + 1, x + 1),
colors.green("New session name"), colors.session_name_prompt(prompt),
colors.orange(new_session_name), colors.session_and_folder_entry(new_session_name),
esc, esc,
); );
} else { } else {
println!( println!(
"\u{1b}[m{}{}: {} {}", "\u{1b}[m{}{}: {} {}",
format!("\u{1b}[{};{}H", y + 1, x + 1), format!("\u{1b}[{};{}H", y + 1, x + 1),
colors.green("New session name"), colors.session_name_prompt("New session name"),
colors.orange(new_session_name), colors.session_and_folder_entry(new_session_name),
esc, esc,
); );
} }
@ -919,13 +937,13 @@ pub fn render_controls_line(
} }
}, },
ActiveScreen::AttachToSession => { ActiveScreen::AttachToSession => {
let rename = colors.magenta("<Ctrl r>"); let rename = colors.shortcuts("<Ctrl r>");
let rename_text = colors.bold("Rename"); let rename_text = colors.bold("Rename");
let disconnect = colors.magenta("<Ctrl x>"); let disconnect = colors.shortcuts("<Ctrl x>");
let disconnect_text = colors.bold("Disconnect others"); let disconnect_text = colors.bold("Disconnect others");
let kill = colors.magenta("<Del>"); let kill = colors.shortcuts("<Del>");
let kill_text = colors.bold("Kill"); let kill_text = colors.bold("Kill");
let kill_all = colors.magenta("<Ctrl d>"); let kill_all = colors.shortcuts("<Ctrl d>");
let kill_all_text = colors.bold("Kill all"); let kill_all_text = colors.bold("Kill all");
if max_cols > 90 { if max_cols > 90 {
@ -937,13 +955,13 @@ pub fn render_controls_line(
} }
}, },
ActiveScreen::ResurrectSession => { ActiveScreen::ResurrectSession => {
let arrows = colors.magenta("<↓↑>"); let arrows = colors.shortcuts("<↓↑>");
let navigate = colors.bold("Navigate"); let navigate = colors.bold("Navigate");
let enter = colors.magenta("<ENTER>"); let enter = colors.shortcuts("<ENTER>");
let select = colors.bold("Resurrect"); let select = colors.bold("Resurrect");
let del = colors.magenta("<DEL>"); let del = colors.shortcuts("<DEL>");
let del_text = colors.bold("Delete"); let del_text = colors.bold("Delete");
let del_all = colors.magenta("<Ctrl d>"); let del_all = colors.shortcuts("<Ctrl d>");
let del_all_text = colors.bold("Delete all"); let del_all_text = colors.bold("Delete all");
if max_cols > 83 { if max_cols > 83 {
@ -957,12 +975,18 @@ pub fn render_controls_line(
} }
} }
// Maps the various prompts and UI elements to the colors to present them with
//
// Since this plugin predates the UI components, this is a developer
// convenience to keep the coloration of dialogs organized by descriptive names
//
// It will be obviated once everything is migrated to UI components from zellij-tile
#[derive(Debug, Default, Clone, Copy)] #[derive(Debug, Default, Clone, Copy)]
pub struct Colors { pub struct Colors {
pub palette: Palette, pub palette: Styling,
} }
impl Colors { impl Colors {
pub fn new(palette: Palette) -> Self { pub fn new(palette: Styling) -> Self {
Colors { palette } Colors { palette }
} }
pub fn bold(&self, text: &str) -> String { pub fn bold(&self, text: &str) -> String {
@ -979,24 +1003,37 @@ impl Colors {
}, },
} }
} }
pub fn orange(&self, text: &str) -> String {
self.color(&self.palette.orange, text) pub fn session_name_prompt(&self, text: &str) -> String {
self.color(&self.palette.exit_code_success.base, text)
} }
pub fn green(&self, text: &str) -> String { pub fn connected_users(&self, text: &str) -> String {
self.color(&self.palette.green, text) self.color(&self.palette.text_unselected.emphasis_2, text)
} }
pub fn red(&self, text: &str) -> String { pub fn session_and_folder_entry(&self, text: &str) -> String {
self.color(&self.palette.red, text) self.color(&self.palette.text_unselected.emphasis_0, text)
} }
pub fn cyan(&self, text: &str) -> String { pub fn current_session_marker(&self, text: &str) -> String {
self.color(&self.palette.cyan, text) self.color(&self.palette.text_unselected.emphasis_0, text)
} }
pub fn magenta(&self, text: &str) -> String { pub fn pane_count(&self, text: &str) -> String {
self.color(&self.palette.magenta, text) self.color(&self.palette.text_unselected.emphasis_2, text)
}
pub fn exit_code_error(&self, text: &str) -> String {
self.color(&self.palette.exit_code_error.base, text)
}
pub fn tab_count(&self, text: &str) -> String {
self.color(&self.palette.text_unselected.emphasis_1, text)
}
pub fn shortcuts(&self, text: &str) -> String {
self.color(&self.palette.text_unselected.emphasis_3, text)
} }
} }

View file

@ -344,14 +344,17 @@ fn key_indicators(
line_part line_part
} }
fn swap_layout_keycode(mode_info: &ModeInfo, palette: &Palette) -> LinePart { fn swap_layout_keycode(mode_info: &ModeInfo) -> LinePart {
let mode_keybinds = mode_info.get_mode_keybinds(); let mode_keybinds = mode_info.get_mode_keybinds();
let prev_next_keys = action_key_group( let prev_next_keys = action_key_group(
&mode_keybinds, &mode_keybinds,
&[&[Action::PreviousSwapLayout], &[Action::NextSwapLayout]], &[&[Action::PreviousSwapLayout], &[Action::NextSwapLayout]],
); );
let prev_next_keys_indicator = let prev_next_keys_indicator = style_key_with_modifier(
style_key_with_modifier(&prev_next_keys, palette, Some(palette.black)); &prev_next_keys,
&mode_info.style.colors,
Some(mode_info.style.colors.text_unselected.background),
);
let keycode = ANSIStrings(&prev_next_keys_indicator); let keycode = ANSIStrings(&prev_next_keys_indicator);
let len = unstyled_len(&keycode); let len = unstyled_len(&keycode);
let part = keycode.to_string(); let part = keycode.to_string();
@ -364,14 +367,13 @@ fn swap_layout_status(
is_swap_layout_damaged: bool, is_swap_layout_damaged: bool,
mode_info: &ModeInfo, mode_info: &ModeInfo,
colored_elements: ColoredElements, colored_elements: ColoredElements,
palette: &Palette,
separator: &str, separator: &str,
) -> Option<LinePart> { ) -> Option<LinePart> {
match swap_layout_name { match swap_layout_name {
Some(swap_layout_name) => { Some(swap_layout_name) => {
let mut swap_layout_name = format!(" {} ", swap_layout_name); let mut swap_layout_name = format!(" {} ", swap_layout_name);
swap_layout_name.make_ascii_uppercase(); swap_layout_name.make_ascii_uppercase();
let keycode = swap_layout_keycode(mode_info, palette); let keycode = swap_layout_keycode(mode_info);
let swap_layout_name_len = swap_layout_name.len() + 3; // 2 for the arrow separators, one for the screen end buffer let swap_layout_name_len = swap_layout_name.len() + 3; // 2 for the arrow separators, one for the screen end buffer
// //
macro_rules! style_swap_layout_indicator { macro_rules! style_swap_layout_indicator {
@ -701,7 +703,6 @@ pub fn first_line(
tab_info.is_swap_layout_dirty, tab_info.is_swap_layout_dirty,
help, help,
colored_elements, colored_elements,
&help.style.colors,
separator, separator,
) { ) {
remaining_space -= swap_layout_status.len; remaining_space -= swap_layout_status.len;
@ -730,7 +731,7 @@ mod tests {
use super::*; use super::*;
fn colored_elements() -> ColoredElements { fn colored_elements() -> ColoredElements {
let palette = Palette::default(); let palette = Styling::default();
color_elements(palette, false) color_elements(palette, false)
} }

View file

@ -87,96 +87,105 @@ pub struct SegmentStyle {
// we need different colors from palette for the default theme // we need different colors from palette for the default theme
// plus here we can add new sources in the future, like Theme // plus here we can add new sources in the future, like Theme
// that can be defined in the config perhaps // that can be defined in the config perhaps
fn color_elements(palette: Palette, different_color_alternates: bool) -> ColoredElements { fn color_elements(palette: Styling, different_color_alternates: bool) -> ColoredElements {
let background = match palette.theme_hue { let background = palette.text_unselected.background;
ThemeHue::Dark => palette.black, let foreground = palette.text_unselected.base;
ThemeHue::Light => palette.white,
};
let foreground = match palette.theme_hue {
ThemeHue::Dark => palette.white,
ThemeHue::Light => palette.black,
};
let alternate_background_color = if different_color_alternates { let alternate_background_color = if different_color_alternates {
match palette.theme_hue { palette.ribbon_unselected.base
ThemeHue::Dark => palette.white,
ThemeHue::Light => palette.black,
}
} else { } else {
palette.fg palette.ribbon_unselected.background
}; };
match palette.source { ColoredElements {
PaletteSource::Default => ColoredElements { selected: SegmentStyle {
selected: SegmentStyle { prefix_separator: style!(background, palette.ribbon_selected.background),
prefix_separator: style!(background, palette.green), char_left_separator: style!(
char_left_separator: style!(background, palette.green).bold(), palette.ribbon_selected.base,
char_shortcut: style!(palette.red, palette.green).bold(), palette.ribbon_selected.background
char_right_separator: style!(background, palette.green).bold(), )
styled_text: style!(background, palette.green).bold(), .bold(),
suffix_separator: style!(palette.green, background).bold(), char_shortcut: style!(
}, palette.ribbon_selected.emphasis_0,
unselected: SegmentStyle { palette.ribbon_selected.background
prefix_separator: style!(background, palette.fg), )
char_left_separator: style!(background, palette.fg).bold(), .bold(),
char_shortcut: style!(palette.red, palette.fg).bold(), char_right_separator: style!(
char_right_separator: style!(background, palette.fg).bold(), palette.ribbon_selected.base,
styled_text: style!(background, palette.fg).bold(), palette.ribbon_selected.background
suffix_separator: style!(palette.fg, background), )
}, .bold(),
unselected_alternate: SegmentStyle { styled_text: style!(
prefix_separator: style!(background, alternate_background_color), palette.ribbon_selected.base,
char_left_separator: style!(background, alternate_background_color).bold(), palette.ribbon_selected.background
char_shortcut: style!(palette.red, alternate_background_color).bold(), )
char_right_separator: style!(background, alternate_background_color).bold(), .bold(),
styled_text: style!(background, alternate_background_color).bold(), suffix_separator: style!(palette.ribbon_selected.background, background).bold(),
suffix_separator: style!(alternate_background_color, background),
},
disabled: SegmentStyle {
prefix_separator: style!(background, palette.fg),
char_left_separator: style!(background, palette.fg).dimmed().italic(),
char_shortcut: style!(background, palette.fg).dimmed().italic(),
char_right_separator: style!(background, palette.fg).dimmed().italic(),
styled_text: style!(background, palette.fg).dimmed().italic(),
suffix_separator: style!(palette.fg, background),
},
superkey_prefix: style!(foreground, background).bold(),
superkey_suffix_separator: style!(background, background),
}, },
PaletteSource::Xresources => ColoredElements { unselected: SegmentStyle {
selected: SegmentStyle { prefix_separator: style!(background, palette.ribbon_unselected.background),
prefix_separator: style!(background, palette.green), char_left_separator: style!(
char_left_separator: style!(palette.fg, palette.green).bold(), palette.ribbon_unselected.base,
char_shortcut: style!(palette.red, palette.green).bold(), palette.ribbon_unselected.background
char_right_separator: style!(palette.fg, palette.green).bold(), )
styled_text: style!(background, palette.green).bold(), .bold(),
suffix_separator: style!(palette.green, background).bold(), char_shortcut: style!(
}, palette.ribbon_unselected.emphasis_0,
unselected: SegmentStyle { palette.ribbon_unselected.background
prefix_separator: style!(background, palette.fg), )
char_left_separator: style!(background, palette.fg).bold(), .bold(),
char_shortcut: style!(palette.red, palette.fg).bold(), char_right_separator: style!(
char_right_separator: style!(background, palette.fg).bold(), palette.ribbon_unselected.base,
styled_text: style!(background, palette.fg).bold(), palette.ribbon_unselected.background
suffix_separator: style!(palette.fg, background), )
}, .bold(),
unselected_alternate: SegmentStyle { styled_text: style!(
prefix_separator: style!(background, alternate_background_color), palette.ribbon_unselected.base,
char_left_separator: style!(background, alternate_background_color).bold(), palette.ribbon_unselected.background
char_shortcut: style!(palette.red, alternate_background_color).bold(), )
char_right_separator: style!(background, alternate_background_color).bold(), .bold(),
styled_text: style!(background, alternate_background_color).bold(), suffix_separator: style!(palette.ribbon_unselected.background, background).bold(),
suffix_separator: style!(alternate_background_color, background),
},
disabled: SegmentStyle {
prefix_separator: style!(background, palette.fg),
char_left_separator: style!(background, palette.fg).dimmed(),
char_shortcut: style!(background, palette.fg).dimmed(),
char_right_separator: style!(background, palette.fg).dimmed(),
styled_text: style!(background, palette.fg).dimmed(),
suffix_separator: style!(palette.fg, background),
},
superkey_prefix: style!(background, palette.fg).bold(),
superkey_suffix_separator: style!(palette.fg, background),
}, },
unselected_alternate: SegmentStyle {
prefix_separator: style!(background, alternate_background_color),
char_left_separator: style!(background, alternate_background_color).bold(),
char_shortcut: style!(
palette.ribbon_unselected.emphasis_0,
alternate_background_color
)
.bold(),
char_right_separator: style!(background, alternate_background_color).bold(),
styled_text: style!(palette.ribbon_unselected.base, alternate_background_color).bold(),
suffix_separator: style!(alternate_background_color, background).bold(),
},
disabled: SegmentStyle {
prefix_separator: style!(background, palette.ribbon_unselected.background),
char_left_separator: style!(
palette.ribbon_unselected.base,
palette.ribbon_unselected.background
)
.dimmed()
.italic(),
char_shortcut: style!(
palette.ribbon_unselected.base,
palette.ribbon_unselected.background
)
.dimmed()
.italic(),
char_right_separator: style!(
palette.ribbon_unselected.base,
palette.ribbon_unselected.background
)
.dimmed()
.italic(),
styled_text: style!(
palette.ribbon_unselected.base,
palette.ribbon_unselected.background
)
.dimmed()
.italic(),
suffix_separator: style!(palette.ribbon_unselected.background, background),
},
superkey_prefix: style!(foreground, background).bold(),
superkey_suffix_separator: style!(background, background),
} }
} }
@ -253,10 +262,7 @@ impl ZellijPlugin for State {
"" ""
}; };
let background = match self.mode_info.style.colors.theme_hue { let background = self.mode_info.style.colors.text_unselected.background;
ThemeHue::Dark => self.mode_info.style.colors.black,
ThemeHue::Light => self.mode_info.style.colors.white,
};
if rows == 1 && !self.classic_ui { if rows == 1 && !self.classic_ui {
let fill_bg = match background { let fill_bg = match background {
@ -280,6 +286,7 @@ impl ZellijPlugin for State {
return; return;
} }
//TODO: Switch to UI components here
let active_tab = self.tabs.iter().find(|t| t.active); let active_tab = self.tabs.iter().find(|t| t.active);
let first_line = first_line(&self.mode_info, active_tab, cols, separator); let first_line = first_line(&self.mode_info, active_tab, cols, separator);
let second_line = self.second_line(cols); let second_line = self.second_line(cols);
@ -432,19 +439,16 @@ pub fn action_key_group(
/// type. /// type.
pub fn style_key_with_modifier( pub fn style_key_with_modifier(
keyvec: &[KeyWithModifier], keyvec: &[KeyWithModifier],
palette: &Palette, palette: &Styling,
background: Option<PaletteColor>, background: Option<PaletteColor>,
) -> Vec<ANSIString<'static>> { ) -> Vec<ANSIString<'static>> {
if keyvec.is_empty() { if keyvec.is_empty() {
return vec![]; return vec![];
} }
let text_color = palette_match!(match palette.theme_hue { let text_color = palette_match!(palette.text_unselected.base);
ThemeHue::Dark => palette.white, let green_color = palette_match!(palette.text_unselected.emphasis_2);
ThemeHue::Light => palette.black, let orange_color = palette_match!(palette.text_unselected.emphasis_0);
});
let green_color = palette_match!(palette.green);
let orange_color = palette_match!(palette.orange);
let mut ret = vec![]; let mut ret = vec![];
let common_modifiers = get_common_modifiers(keyvec.iter().collect()); let common_modifiers = get_common_modifiers(keyvec.iter().collect());
@ -706,7 +710,7 @@ pub mod tests {
KeyWithModifier::new(BareKey::Char('b')), KeyWithModifier::new(BareKey::Char('b')),
KeyWithModifier::new(BareKey::Char('c')), KeyWithModifier::new(BareKey::Char('c')),
]; ];
let palette = get_palette(); let palette = Styling::default();
let ret = style_key_with_modifier(&keyvec, &palette, None); let ret = style_key_with_modifier(&keyvec, &palette, None);
let ret = unstyle(&ANSIStrings(&ret)); let ret = unstyle(&ANSIStrings(&ret));
@ -722,7 +726,7 @@ pub mod tests {
KeyWithModifier::new(BareKey::Char('k')), KeyWithModifier::new(BareKey::Char('k')),
KeyWithModifier::new(BareKey::Char('l')), KeyWithModifier::new(BareKey::Char('l')),
]; ];
let palette = get_palette(); let palette = Styling::default();
let ret = style_key_with_modifier(&keyvec, &palette, None); let ret = style_key_with_modifier(&keyvec, &palette, None);
let ret = unstyle(&ANSIStrings(&ret)); let ret = unstyle(&ANSIStrings(&ret));
@ -738,7 +742,7 @@ pub mod tests {
KeyWithModifier::new(BareKey::Up), KeyWithModifier::new(BareKey::Up),
KeyWithModifier::new(BareKey::Right), KeyWithModifier::new(BareKey::Right),
]; ];
let palette = get_palette(); let palette = Styling::default();
let ret = style_key_with_modifier(&keyvec, &palette, None); let ret = style_key_with_modifier(&keyvec, &palette, None);
let ret = unstyle(&ANSIStrings(&ret)); let ret = unstyle(&ANSIStrings(&ret));
@ -752,7 +756,7 @@ pub mod tests {
KeyWithModifier::new(BareKey::Left), KeyWithModifier::new(BareKey::Left),
KeyWithModifier::new(BareKey::Right), KeyWithModifier::new(BareKey::Right),
]; ];
let palette = get_palette(); let palette = Styling::default();
let ret = style_key_with_modifier(&keyvec, &palette, None); let ret = style_key_with_modifier(&keyvec, &palette, None);
let ret = unstyle(&ANSIStrings(&ret)); let ret = unstyle(&ANSIStrings(&ret));
@ -766,7 +770,7 @@ pub mod tests {
KeyWithModifier::new(BareKey::Down), KeyWithModifier::new(BareKey::Down),
KeyWithModifier::new(BareKey::Up), KeyWithModifier::new(BareKey::Up),
]; ];
let palette = get_palette(); let palette = Styling::default();
let ret = style_key_with_modifier(&keyvec, &palette, None); let ret = style_key_with_modifier(&keyvec, &palette, None);
let ret = unstyle(&ANSIStrings(&ret)); let ret = unstyle(&ANSIStrings(&ret));
@ -782,7 +786,7 @@ pub mod tests {
KeyWithModifier::new(BareKey::Char('c')).with_ctrl_modifier(), KeyWithModifier::new(BareKey::Char('c')).with_ctrl_modifier(),
KeyWithModifier::new(BareKey::Char('d')).with_ctrl_modifier(), KeyWithModifier::new(BareKey::Char('d')).with_ctrl_modifier(),
]; ];
let palette = get_palette(); let palette = Styling::default();
let ret = style_key_with_modifier(&keyvec, &palette, None); let ret = style_key_with_modifier(&keyvec, &palette, None);
let ret = unstyle(&ANSIStrings(&ret)); let ret = unstyle(&ANSIStrings(&ret));
@ -798,7 +802,7 @@ pub mod tests {
KeyWithModifier::new(BareKey::Char('c')).with_alt_modifier(), KeyWithModifier::new(BareKey::Char('c')).with_alt_modifier(),
KeyWithModifier::new(BareKey::Char('d')).with_alt_modifier(), KeyWithModifier::new(BareKey::Char('d')).with_alt_modifier(),
]; ];
let palette = get_palette(); let palette = Styling::default();
let ret = style_key_with_modifier(&keyvec, &palette, None); let ret = style_key_with_modifier(&keyvec, &palette, None);
let ret = unstyle(&ANSIStrings(&ret)); let ret = unstyle(&ANSIStrings(&ret));
@ -814,7 +818,7 @@ pub mod tests {
KeyWithModifier::new(BareKey::Up).with_alt_modifier(), KeyWithModifier::new(BareKey::Up).with_alt_modifier(),
KeyWithModifier::new(BareKey::Right).with_alt_modifier(), KeyWithModifier::new(BareKey::Right).with_alt_modifier(),
]; ];
let palette = get_palette(); let palette = Styling::default();
let ret = style_key_with_modifier(&keyvec, &palette, None); let ret = style_key_with_modifier(&keyvec, &palette, None);
let ret = unstyle(&ANSIStrings(&ret)); let ret = unstyle(&ANSIStrings(&ret));
@ -829,7 +833,7 @@ pub mod tests {
KeyWithModifier::new(BareKey::Char('b')).with_ctrl_modifier(), KeyWithModifier::new(BareKey::Char('b')).with_ctrl_modifier(),
KeyWithModifier::new(BareKey::Char('c')), KeyWithModifier::new(BareKey::Char('c')),
]; ];
let palette = get_palette(); let palette = Styling::default();
let ret = style_key_with_modifier(&keyvec, &palette, None); let ret = style_key_with_modifier(&keyvec, &palette, None);
let ret = unstyle(&ANSIStrings(&ret)); let ret = unstyle(&ANSIStrings(&ret));
@ -852,7 +856,7 @@ pub mod tests {
KeyWithModifier::new(BareKey::Tab), KeyWithModifier::new(BareKey::Tab),
KeyWithModifier::new(BareKey::Esc), KeyWithModifier::new(BareKey::Esc),
]; ];
let palette = get_palette(); let palette = Styling::default();
let ret = style_key_with_modifier(&keyvec, &palette, None); let ret = style_key_with_modifier(&keyvec, &palette, None);
let ret = unstyle(&ANSIStrings(&ret)); let ret = unstyle(&ANSIStrings(&ret));
@ -870,7 +874,7 @@ pub mod tests {
KeyWithModifier::new(BareKey::Char(' ')).with_ctrl_modifier(), KeyWithModifier::new(BareKey::Char(' ')).with_ctrl_modifier(),
KeyWithModifier::new(BareKey::Tab).with_ctrl_modifier(), KeyWithModifier::new(BareKey::Tab).with_ctrl_modifier(),
]; ];
let palette = get_palette(); let palette = Styling::default();
let ret = style_key_with_modifier(&keyvec, &palette, None); let ret = style_key_with_modifier(&keyvec, &palette, None);
let ret = unstyle(&ANSIStrings(&ret)); let ret = unstyle(&ANSIStrings(&ret));
@ -885,7 +889,7 @@ pub mod tests {
KeyWithModifier::new(BareKey::Char(' ')).with_alt_modifier(), KeyWithModifier::new(BareKey::Char(' ')).with_alt_modifier(),
KeyWithModifier::new(BareKey::Tab).with_alt_modifier(), KeyWithModifier::new(BareKey::Tab).with_alt_modifier(),
]; ];
let palette = get_palette(); let palette = Styling::default();
let ret = style_key_with_modifier(&keyvec, &palette, None); let ret = style_key_with_modifier(&keyvec, &palette, None);
let ret = unstyle(&ANSIStrings(&ret)); let ret = unstyle(&ANSIStrings(&ret));

View file

@ -1064,8 +1064,8 @@ fn add_keygroup_separator(help: &ModeInfo, max_len: usize) -> Option<LinePart> {
let mut ret = LinePart::default(); let mut ret = LinePart::default();
let separator_color = palette_match!(palette.orange); let separator_color = palette_match!(palette.text_unselected.emphasis_0);
let bg_color = palette_match!(palette.black); let bg_color = palette_match!(palette.ribbon_selected.base);
let mut bits: Vec<ANSIString> = vec![]; let mut bits: Vec<ANSIString> = vec![];
let mode_help_text = match help.mode { let mode_help_text = match help.mode {
InputMode::RenamePane => Some("RENAMING PANE"), InputMode::RenamePane => Some("RENAMING PANE"),

View file

@ -17,16 +17,13 @@ fn full_length_shortcut(
is_first_shortcut: bool, is_first_shortcut: bool,
key: Vec<KeyWithModifier>, key: Vec<KeyWithModifier>,
action: &str, action: &str,
palette: Palette, palette: Styling,
) -> LinePart { ) -> LinePart {
if key.is_empty() { if key.is_empty() {
return LinePart::default(); return LinePart::default();
} }
let text_color = palette_match!(match palette.theme_hue { let text_color = palette_match!(palette.text_unselected.base);
ThemeHue::Dark => palette.white,
ThemeHue::Light => palette.black,
});
let separator = if is_first_shortcut { " " } else { " / " }; let separator = if is_first_shortcut { " " } else { " / " };
let mut bits: Vec<ANSIString> = vec![Style::new().fg(text_color).paint(separator)]; let mut bits: Vec<ANSIString> = vec![Style::new().fg(text_color).paint(separator)];
@ -45,13 +42,10 @@ fn full_length_shortcut(
} }
} }
fn locked_interface_indication(palette: Palette) -> LinePart { fn locked_interface_indication(palette: Styling) -> LinePart {
let locked_text = " -- INTERFACE LOCKED -- "; let locked_text = " -- INTERFACE LOCKED -- ";
let locked_text_len = locked_text.chars().count(); let locked_text_len = locked_text.chars().count();
let text_color = palette_match!(match palette.theme_hue { let text_color = palette_match!(palette.text_unselected.base);
ThemeHue::Dark => palette.white,
ThemeHue::Light => palette.black,
});
let locked_styled_text = Style::new().fg(text_color).bold().paint(locked_text); let locked_styled_text = Style::new().fg(text_color).bold().paint(locked_text);
LinePart { LinePart {
part: locked_styled_text.to_string(), part: locked_styled_text.to_string(),
@ -354,8 +348,8 @@ pub fn keybinds(help: &ModeInfo, tip_name: &str, max_width: usize) -> LinePart {
best_effort_shortcut_list(help, tip_body.short, max_width) best_effort_shortcut_list(help, tip_body.short, max_width)
} }
pub fn text_copied_hint(palette: &Palette, copy_destination: CopyDestination) -> LinePart { pub fn text_copied_hint(palette: &Styling, copy_destination: CopyDestination) -> LinePart {
let green_color = palette_match!(palette.green); let green_color = palette_match!(palette.text_unselected.emphasis_2);
let hint = match copy_destination { let hint = match copy_destination {
CopyDestination::Command => "Text piped to external command", CopyDestination::Command => "Text piped to external command",
#[cfg(not(target_os = "macos"))] #[cfg(not(target_os = "macos"))]
@ -370,22 +364,19 @@ pub fn text_copied_hint(palette: &Palette, copy_destination: CopyDestination) ->
} }
} }
pub fn system_clipboard_error(palette: &Palette) -> LinePart { pub fn system_clipboard_error(palette: &Styling) -> LinePart {
let hint = " Error using the system clipboard."; let hint = " Error using the system clipboard.";
let red_color = palette_match!(palette.red); let red_color = palette_match!(palette.text_unselected.emphasis_3);
LinePart { LinePart {
part: Style::new().fg(red_color).bold().paint(hint).to_string(), part: Style::new().fg(red_color).bold().paint(hint).to_string(),
len: hint.len(), len: hint.len(),
} }
} }
pub fn fullscreen_panes_to_hide(palette: &Palette, panes_to_hide: usize) -> LinePart { pub fn fullscreen_panes_to_hide(palette: &Styling, panes_to_hide: usize) -> LinePart {
let text_color = palette_match!(match palette.theme_hue { let text_color = palette_match!(palette.text_unselected.base);
ThemeHue::Dark => palette.white, let green_color = palette_match!(palette.text_unselected.emphasis_2);
ThemeHue::Light => palette.black, let orange_color = palette_match!(palette.text_unselected.emphasis_0);
});
let green_color = palette_match!(palette.green);
let orange_color = palette_match!(palette.orange);
let shortcut_left_separator = Style::new().fg(text_color).bold().paint(" ("); let shortcut_left_separator = Style::new().fg(text_color).bold().paint(" (");
let shortcut_right_separator = Style::new().fg(text_color).bold().paint("): "); let shortcut_right_separator = Style::new().fg(text_color).bold().paint("): ");
let fullscreen = "FULLSCREEN"; let fullscreen = "FULLSCREEN";
@ -414,18 +405,9 @@ pub fn fullscreen_panes_to_hide(palette: &Palette, panes_to_hide: usize) -> Line
pub fn floating_panes_are_visible(mode_info: &ModeInfo) -> LinePart { pub fn floating_panes_are_visible(mode_info: &ModeInfo) -> LinePart {
let palette = mode_info.style.colors; let palette = mode_info.style.colors;
let km = &mode_info.get_mode_keybinds(); let km = &mode_info.get_mode_keybinds();
let white_color = match palette.white { let white_color = palette_match!(palette.text_unselected.base);
PaletteColor::Rgb((r, g, b)) => RGB(r, g, b), let green_color = palette_match!(palette.text_unselected.emphasis_2);
PaletteColor::EightBit(color) => Fixed(color), let orange_color = palette_match!(palette.text_unselected.emphasis_0);
};
let green_color = match palette.green {
PaletteColor::Rgb((r, g, b)) => RGB(r, g, b),
PaletteColor::EightBit(color) => Fixed(color),
};
let orange_color = match palette.orange {
PaletteColor::Rgb((r, g, b)) => RGB(r, g, b),
PaletteColor::EightBit(color) => Fixed(color),
};
let shortcut_left_separator = Style::new().fg(white_color).bold().paint(" ("); let shortcut_left_separator = Style::new().fg(white_color).bold().paint(" (");
let shortcut_right_separator = Style::new().fg(white_color).bold().paint("): "); let shortcut_right_separator = Style::new().fg(white_color).bold().paint("): ");
let floating_panes = "FLOATING PANES VISIBLE"; let floating_panes = "FLOATING PANES VISIBLE";
@ -477,13 +459,10 @@ pub fn floating_panes_are_visible(mode_info: &ModeInfo) -> LinePart {
} }
} }
pub fn locked_fullscreen_panes_to_hide(palette: &Palette, panes_to_hide: usize) -> LinePart { pub fn locked_fullscreen_panes_to_hide(palette: &Styling, panes_to_hide: usize) -> LinePart {
let text_color = palette_match!(match palette.theme_hue { let text_color = palette_match!(palette.text_unselected.base);
ThemeHue::Dark => palette.white, let green_color = palette_match!(palette.text_unselected.emphasis_2);
ThemeHue::Light => palette.black, let orange_color = palette_match!(palette.text_unselected.emphasis_0);
});
let green_color = palette_match!(palette.green);
let orange_color = palette_match!(palette.orange);
let locked_text = " -- INTERFACE LOCKED -- "; let locked_text = " -- INTERFACE LOCKED -- ";
let shortcut_left_separator = Style::new().fg(text_color).bold().paint(" ("); let shortcut_left_separator = Style::new().fg(text_color).bold().paint(" (");
let shortcut_right_separator = Style::new().fg(text_color).bold().paint("): "); let shortcut_right_separator = Style::new().fg(text_color).bold().paint("): ");
@ -512,15 +491,9 @@ pub fn locked_fullscreen_panes_to_hide(palette: &Palette, panes_to_hide: usize)
} }
} }
pub fn locked_floating_panes_are_visible(palette: &Palette) -> LinePart { pub fn locked_floating_panes_are_visible(palette: &Styling) -> LinePart {
let white_color = match palette.white { let white_color = palette_match!(palette.text_unselected.base);
PaletteColor::Rgb((r, g, b)) => RGB(r, g, b), let orange_color = palette_match!(palette.text_unselected.emphasis_0);
PaletteColor::EightBit(color) => Fixed(color),
};
let orange_color = match palette.orange {
PaletteColor::Rgb((r, g, b)) => RGB(r, g, b),
PaletteColor::EightBit(color) => Fixed(color),
};
let shortcut_left_separator = Style::new().fg(white_color).bold().paint(" ("); let shortcut_left_separator = Style::new().fg(white_color).bold().paint(" (");
let shortcut_right_separator = Style::new().fg(white_color).bold().paint(")"); let shortcut_right_separator = Style::new().fg(white_color).bold().paint(")");
let locked_text = " -- INTERFACE LOCKED -- "; let locked_text = " -- INTERFACE LOCKED -- ";
@ -566,7 +539,7 @@ mod tests {
#[test] #[test]
fn full_length_shortcut_with_key() { fn full_length_shortcut_with_key() {
let keyvec = vec![KeyWithModifier::new(BareKey::Char('a'))]; let keyvec = vec![KeyWithModifier::new(BareKey::Char('a'))];
let palette = get_palette(); let palette = Styling::default();
let ret = full_length_shortcut(false, keyvec, "Foobar", palette); let ret = full_length_shortcut(false, keyvec, "Foobar", palette);
let ret = unstyle(ret); let ret = unstyle(ret);
@ -577,7 +550,7 @@ mod tests {
#[test] #[test]
fn full_length_shortcut_with_key_first_element() { fn full_length_shortcut_with_key_first_element() {
let keyvec = vec![KeyWithModifier::new(BareKey::Char('a'))]; let keyvec = vec![KeyWithModifier::new(BareKey::Char('a'))];
let palette = get_palette(); let palette = Styling::default();
let ret = full_length_shortcut(true, keyvec, "Foobar", palette); let ret = full_length_shortcut(true, keyvec, "Foobar", palette);
let ret = unstyle(ret); let ret = unstyle(ret);
@ -589,7 +562,7 @@ mod tests {
// When there is no binding, we print no shortcut either // When there is no binding, we print no shortcut either
fn full_length_shortcut_without_key() { fn full_length_shortcut_without_key() {
let keyvec = vec![]; let keyvec = vec![];
let palette = get_palette(); let palette = Styling::default();
let ret = full_length_shortcut(false, keyvec, "Foobar", palette); let ret = full_length_shortcut(false, keyvec, "Foobar", palette);
let ret = unstyle(ret); let ret = unstyle(ret);
@ -600,7 +573,7 @@ mod tests {
#[test] #[test]
fn full_length_shortcut_with_key_unprintable_1() { fn full_length_shortcut_with_key_unprintable_1() {
let keyvec = vec![KeyWithModifier::new(BareKey::Enter)]; let keyvec = vec![KeyWithModifier::new(BareKey::Enter)];
let palette = get_palette(); let palette = Styling::default();
let ret = full_length_shortcut(false, keyvec, "Foobar", palette); let ret = full_length_shortcut(false, keyvec, "Foobar", palette);
let ret = unstyle(ret); let ret = unstyle(ret);
@ -611,7 +584,7 @@ mod tests {
#[test] #[test]
fn full_length_shortcut_with_key_unprintable_2() { fn full_length_shortcut_with_key_unprintable_2() {
let keyvec = vec![KeyWithModifier::new(BareKey::Backspace)]; let keyvec = vec![KeyWithModifier::new(BareKey::Backspace)];
let palette = get_palette(); let palette = Styling::default();
let ret = full_length_shortcut(false, keyvec, "Foobar", palette); let ret = full_length_shortcut(false, keyvec, "Foobar", palette);
let ret = unstyle(ret); let ret = unstyle(ret);
@ -622,7 +595,7 @@ mod tests {
#[test] #[test]
fn full_length_shortcut_with_ctrl_key() { fn full_length_shortcut_with_ctrl_key() {
let keyvec = vec![KeyWithModifier::new(BareKey::Char('a')).with_ctrl_modifier()]; let keyvec = vec![KeyWithModifier::new(BareKey::Char('a')).with_ctrl_modifier()];
let palette = get_palette(); let palette = Styling::default();
let ret = full_length_shortcut(false, keyvec, "Foobar", palette); let ret = full_length_shortcut(false, keyvec, "Foobar", palette);
let ret = unstyle(ret); let ret = unstyle(ret);
@ -633,7 +606,7 @@ mod tests {
#[test] #[test]
fn full_length_shortcut_with_alt_key() { fn full_length_shortcut_with_alt_key() {
let keyvec = vec![KeyWithModifier::new(BareKey::Char('a')).with_alt_modifier()]; let keyvec = vec![KeyWithModifier::new(BareKey::Char('a')).with_alt_modifier()];
let palette = get_palette(); let palette = Styling::default();
let ret = full_length_shortcut(false, keyvec, "Foobar", palette); let ret = full_length_shortcut(false, keyvec, "Foobar", palette);
let ret = unstyle(ret); let ret = unstyle(ret);
@ -648,7 +621,7 @@ mod tests {
KeyWithModifier::new(BareKey::Char('b')), KeyWithModifier::new(BareKey::Char('b')),
KeyWithModifier::new(BareKey::Char('c')), KeyWithModifier::new(BareKey::Char('c')),
]; ];
let palette = get_palette(); let palette = Styling::default();
let ret = full_length_shortcut(false, keyvec, "Foobar", palette); let ret = full_length_shortcut(false, keyvec, "Foobar", palette);
let ret = unstyle(ret); let ret = unstyle(ret);
@ -663,7 +636,7 @@ mod tests {
KeyWithModifier::new(BareKey::Char('b')).with_ctrl_modifier(), KeyWithModifier::new(BareKey::Char('b')).with_ctrl_modifier(),
KeyWithModifier::new(BareKey::Enter), KeyWithModifier::new(BareKey::Enter),
]; ];
let palette = get_palette(); let palette = Styling::default();
let ret = full_length_shortcut(false, keyvec, "Foobar", palette); let ret = full_length_shortcut(false, keyvec, "Foobar", palette);
let ret = unstyle(ret); let ret = unstyle(ret);
@ -678,7 +651,7 @@ mod tests {
KeyWithModifier::new(BareKey::Char('b')).with_ctrl_modifier(), KeyWithModifier::new(BareKey::Char('b')).with_ctrl_modifier(),
KeyWithModifier::new(BareKey::Char('c')).with_ctrl_modifier(), KeyWithModifier::new(BareKey::Char('c')).with_ctrl_modifier(),
]; ];
let palette = get_palette(); let palette = Styling::default();
let ret = full_length_shortcut(false, keyvec, "Foobar", palette); let ret = full_length_shortcut(false, keyvec, "Foobar", palette);
let ret = unstyle(ret); let ret = unstyle(ret);

View file

@ -25,7 +25,7 @@ macro_rules! strings {
pub fn compact_layout_full(help: &ModeInfo) -> LinePart { pub fn compact_layout_full(help: &ModeInfo) -> LinePart {
// Tip: UI taking up too much space? Start Zellij with // Tip: UI taking up too much space? Start Zellij with
// zellij -l compact or remove pane frames with Ctrl + <p> + <z> // zellij -l compact or remove pane frames with Ctrl + <p> + <z>
let green_color = palette_match!(help.style.colors.green); let green_color = palette_match!(help.style.colors.text_unselected.emphasis_0);
let mut bits = vec![ let mut bits = vec![
Style::new().paint(" Tip: "), Style::new().paint(" Tip: "),
@ -43,7 +43,7 @@ pub fn compact_layout_full(help: &ModeInfo) -> LinePart {
pub fn compact_layout_medium(help: &ModeInfo) -> LinePart { pub fn compact_layout_medium(help: &ModeInfo) -> LinePart {
// Tip: To save screen space, start Zellij with // Tip: To save screen space, start Zellij with
// zellij -l compact or remove pane frames with Ctrl + <p> + <z> // zellij -l compact or remove pane frames with Ctrl + <p> + <z>
let green_color = palette_match!(help.style.colors.green); let green_color = palette_match!(help.style.colors.text_unselected.emphasis_0);
let mut bits = vec![ let mut bits = vec![
Style::new().paint(" Tip: "), Style::new().paint(" Tip: "),
@ -61,7 +61,7 @@ pub fn compact_layout_medium(help: &ModeInfo) -> LinePart {
pub fn compact_layout_short(help: &ModeInfo) -> LinePart { pub fn compact_layout_short(help: &ModeInfo) -> LinePart {
// Save screen space, start Zellij with // Save screen space, start Zellij with
// zellij -l compact or remove pane frames with Ctrl + <p> + <z> // zellij -l compact or remove pane frames with Ctrl + <p> + <z>
let green_color = palette_match!(help.style.colors.green); let green_color = palette_match!(help.style.colors.text_unselected.emphasis_0);
let mut bits = vec![ let mut bits = vec![
Style::new().paint(" Save screen space, start with: "), Style::new().paint(" Save screen space, start with: "),

View file

@ -24,7 +24,7 @@ macro_rules! strings {
pub fn edit_scrollbuffer_full(help: &ModeInfo) -> LinePart { pub fn edit_scrollbuffer_full(help: &ModeInfo) -> LinePart {
// Tip: Search through the scrollbuffer using your default $EDITOR with // Tip: Search through the scrollbuffer using your default $EDITOR with
// Ctrl + <s> + <e> // Ctrl + <s> + <e>
let green_color = palette_match!(help.style.colors.green); let green_color = palette_match!(help.style.colors.text_unselected.emphasis_0);
let mut bits = vec![ let mut bits = vec![
Style::new().paint(" Tip: "), Style::new().paint(" Tip: "),
@ -39,7 +39,7 @@ pub fn edit_scrollbuffer_full(help: &ModeInfo) -> LinePart {
pub fn edit_scrollbuffer_medium(help: &ModeInfo) -> LinePart { pub fn edit_scrollbuffer_medium(help: &ModeInfo) -> LinePart {
// Tip: Search the scrollbuffer using your $EDITOR with // Tip: Search the scrollbuffer using your $EDITOR with
// Ctrl + <s> + <e> // Ctrl + <s> + <e>
let green_color = palette_match!(help.style.colors.green); let green_color = palette_match!(help.style.colors.text_unselected.emphasis_0);
let mut bits = vec![ let mut bits = vec![
Style::new().paint(" Tip: "), Style::new().paint(" Tip: "),
@ -54,7 +54,7 @@ pub fn edit_scrollbuffer_medium(help: &ModeInfo) -> LinePart {
pub fn edit_scrollbuffer_short(help: &ModeInfo) -> LinePart { pub fn edit_scrollbuffer_short(help: &ModeInfo) -> LinePart {
// Search using $EDITOR with // Search using $EDITOR with
// Ctrl + <s> + <e> // Ctrl + <s> + <e>
let green_color = palette_match!(help.style.colors.green); let green_color = palette_match!(help.style.colors.text_unselected.emphasis_0);
let mut bits = vec![ let mut bits = vec![
Style::new().paint(" Search using "), Style::new().paint(" Search using "),

View file

@ -25,7 +25,7 @@ macro_rules! strings {
pub fn move_tabs_full(help: &ModeInfo) -> LinePart { pub fn move_tabs_full(help: &ModeInfo) -> LinePart {
// Tip: Wrong order of tabs? You can move them to left and right with: // Tip: Wrong order of tabs? You can move them to left and right with:
// Alt + i (left) and Alt + o (right) // Alt + i (left) and Alt + o (right)
let green_color = palette_match!(help.style.colors.green); let green_color = palette_match!(help.style.colors.text_unselected.emphasis_2);
let bits = vec![ let bits = vec![
Style::new().paint(" Tip: "), Style::new().paint(" Tip: "),
@ -41,7 +41,7 @@ pub fn move_tabs_full(help: &ModeInfo) -> LinePart {
pub fn move_tabs_medium(help: &ModeInfo) -> LinePart { pub fn move_tabs_medium(help: &ModeInfo) -> LinePart {
// Tip: You can move tabs to left and right with: // Tip: You can move tabs to left and right with:
// Alt + i (left) and Alt + o (right) // Alt + i (left) and Alt + o (right)
let green_color = palette_match!(help.style.colors.green); let green_color = palette_match!(help.style.colors.text_unselected.emphasis_2);
let bits = vec![ let bits = vec![
Style::new().paint(" Tip: "), Style::new().paint(" Tip: "),
@ -56,7 +56,7 @@ pub fn move_tabs_medium(help: &ModeInfo) -> LinePart {
pub fn move_tabs_short(help: &ModeInfo) -> LinePart { pub fn move_tabs_short(help: &ModeInfo) -> LinePart {
// Move tabs with: Alt + i (left) and Alt + o (right) // Move tabs with: Alt + i (left) and Alt + o (right)
let green_color = palette_match!(help.style.colors.green); let green_color = palette_match!(help.style.colors.text_unselected.emphasis_2);
let bits = vec![ let bits = vec![
Style::new().paint(" Move tabs with: "), Style::new().paint(" Move tabs with: "),

View file

@ -23,8 +23,8 @@ macro_rules! strings {
pub fn mouse_click_to_terminal_full(help: &ModeInfo) -> LinePart { pub fn mouse_click_to_terminal_full(help: &ModeInfo) -> LinePart {
// Tip: SHIFT + <mouse-click> bypasses Zellij and sends the mouse click directly to the terminal // Tip: SHIFT + <mouse-click> bypasses Zellij and sends the mouse click directly to the terminal
let green_color = palette_match!(help.style.colors.green); let green_color = palette_match!(help.style.colors.text_unselected.emphasis_2);
let orange_color = palette_match!(help.style.colors.orange); let orange_color = palette_match!(help.style.colors.text_unselected.emphasis_0);
strings!(&[ strings!(&[
Style::new().paint(" Tip: "), Style::new().paint(" Tip: "),
@ -37,8 +37,8 @@ pub fn mouse_click_to_terminal_full(help: &ModeInfo) -> LinePart {
pub fn mouse_click_to_terminal_medium(help: &ModeInfo) -> LinePart { pub fn mouse_click_to_terminal_medium(help: &ModeInfo) -> LinePart {
// Tip: SHIFT + <mouse-click> sends the click directly to the terminal // Tip: SHIFT + <mouse-click> sends the click directly to the terminal
let green_color = palette_match!(help.style.colors.green); let green_color = palette_match!(help.style.colors.text_unselected.emphasis_2);
let orange_color = palette_match!(help.style.colors.orange); let orange_color = palette_match!(help.style.colors.text_unselected.emphasis_0);
strings!(&[ strings!(&[
Style::new().paint(" Tip: "), Style::new().paint(" Tip: "),
Style::new().fg(orange_color).bold().paint("Shift"), Style::new().fg(orange_color).bold().paint("Shift"),
@ -50,8 +50,8 @@ pub fn mouse_click_to_terminal_medium(help: &ModeInfo) -> LinePart {
pub fn mouse_click_to_terminal_short(help: &ModeInfo) -> LinePart { pub fn mouse_click_to_terminal_short(help: &ModeInfo) -> LinePart {
// Tip: SHIFT + <mouse-click> => sends click to terminal. // Tip: SHIFT + <mouse-click> => sends click to terminal.
let green_color = palette_match!(help.style.colors.green); let green_color = palette_match!(help.style.colors.text_unselected.emphasis_2);
let orange_color = palette_match!(help.style.colors.orange); let orange_color = palette_match!(help.style.colors.text_unselected.emphasis_0);
strings!(&[ strings!(&[
Style::new().paint(" Tip: "), Style::new().paint(" Tip: "),

View file

@ -24,7 +24,7 @@ macro_rules! strings {
pub fn use_mouse_full(help: &ModeInfo) -> LinePart { pub fn use_mouse_full(help: &ModeInfo) -> LinePart {
// Tip: Use the mouse to switch pane focus, scroll through the pane // Tip: Use the mouse to switch pane focus, scroll through the pane
// scrollbuffer, switch or scroll through tabs // scrollbuffer, switch or scroll through tabs
let green_color = palette_match!(help.style.colors.green); let green_color = palette_match!(help.style.colors.text_unselected.emphasis_2);
strings!(&[ strings!(&[
Style::new().paint(" Tip: "), Style::new().paint(" Tip: "),
@ -36,7 +36,7 @@ pub fn use_mouse_full(help: &ModeInfo) -> LinePart {
pub fn use_mouse_medium(help: &ModeInfo) -> LinePart { pub fn use_mouse_medium(help: &ModeInfo) -> LinePart {
// Tip: Use the mouse to switch panes/tabs or scroll through the pane // Tip: Use the mouse to switch panes/tabs or scroll through the pane
// scrollbuffer // scrollbuffer
let green_color = palette_match!(help.style.colors.green); let green_color = palette_match!(help.style.colors.text_unselected.emphasis_2);
strings!(&[ strings!(&[
Style::new().paint(" Tip: "), Style::new().paint(" Tip: "),
@ -47,7 +47,7 @@ pub fn use_mouse_medium(help: &ModeInfo) -> LinePart {
pub fn use_mouse_short(help: &ModeInfo) -> LinePart { pub fn use_mouse_short(help: &ModeInfo) -> LinePart {
// Tip: Use the mouse to switch panes/tabs or scroll // Tip: Use the mouse to switch panes/tabs or scroll
let green_color = palette_match!(help.style.colors.green); let green_color = palette_match!(help.style.colors.text_unselected.emphasis_2);
strings!(&[ strings!(&[
Style::new().fg(green_color).bold().paint(" Use the mouse"), Style::new().fg(green_color).bold().paint(" Use the mouse"),

View file

@ -23,7 +23,7 @@ macro_rules! strings {
pub fn zellij_setup_check_full(help: &ModeInfo) -> LinePart { pub fn zellij_setup_check_full(help: &ModeInfo) -> LinePart {
// Tip: Having issues with Zellij? Try running "zellij setup --check" // Tip: Having issues with Zellij? Try running "zellij setup --check"
let orange_color = palette_match!(help.style.colors.orange); let orange_color = palette_match!(help.style.colors.text_unselected.emphasis_0);
strings!(&[ strings!(&[
Style::new().paint(" Tip: "), Style::new().paint(" Tip: "),
@ -37,7 +37,7 @@ pub fn zellij_setup_check_full(help: &ModeInfo) -> LinePart {
pub fn zellij_setup_check_medium(help: &ModeInfo) -> LinePart { pub fn zellij_setup_check_medium(help: &ModeInfo) -> LinePart {
// Tip: Run "zellij setup --check" to find issues // Tip: Run "zellij setup --check" to find issues
let orange_color = palette_match!(help.style.colors.orange); let orange_color = palette_match!(help.style.colors.text_unselected.emphasis_0);
strings!(&[ strings!(&[
Style::new().paint(" Tip: "), Style::new().paint(" Tip: "),
@ -52,7 +52,7 @@ pub fn zellij_setup_check_medium(help: &ModeInfo) -> LinePart {
pub fn zellij_setup_check_short(help: &ModeInfo) -> LinePart { pub fn zellij_setup_check_short(help: &ModeInfo) -> LinePart {
// Run "zellij setup --check" to find issues // Run "zellij setup --check" to find issues
let orange_color = palette_match!(help.style.colors.orange); let orange_color = palette_match!(help.style.colors.text_unselected.emphasis_0);
strings!(&[ strings!(&[
Style::new().paint(" Run "), Style::new().paint(" Run "),

View file

@ -17,7 +17,7 @@ fn populate_tabs_in_tab_line(
tabs_after_active: &mut Vec<LinePart>, tabs_after_active: &mut Vec<LinePart>,
tabs_to_render: &mut Vec<LinePart>, tabs_to_render: &mut Vec<LinePart>,
cols: usize, cols: usize,
palette: Palette, palette: Styling,
capabilities: PluginCapabilities, capabilities: PluginCapabilities,
) { ) {
let mut middle_size = get_current_title_len(tabs_to_render); let mut middle_size = get_current_title_len(tabs_to_render);
@ -109,7 +109,7 @@ fn populate_tabs_in_tab_line(
fn left_more_message( fn left_more_message(
tab_count_to_the_left: usize, tab_count_to_the_left: usize,
palette: Palette, palette: Styling,
separator: &str, separator: &str,
tab_index: usize, tab_index: usize,
) -> LinePart { ) -> LinePart {
@ -124,13 +124,15 @@ fn left_more_message(
// 238 // 238
// chars length plus separator length on both sides // chars length plus separator length on both sides
let more_text_len = more_text.width() + 2 * separator.width(); let more_text_len = more_text.width() + 2 * separator.width();
let (text_color, sep_color) = match palette.theme_hue { let (text_color, sep_color) = (
ThemeHue::Dark => (palette.white, palette.black), palette.ribbon_unselected.base,
ThemeHue::Light => (palette.black, palette.white), palette.text_unselected.background,
}; );
let left_separator = style!(sep_color, palette.orange).paint(separator); let left_separator = style!(sep_color, palette.ribbon_unselected.background).paint(separator);
let more_styled_text = style!(text_color, palette.orange).bold().paint(more_text); let more_styled_text = style!(text_color, palette.ribbon_unselected.background)
let right_separator = style!(palette.orange, sep_color).paint(separator); .bold()
.paint(more_text);
let right_separator = style!(palette.ribbon_unselected.background, sep_color).paint(separator);
let more_styled_text = let more_styled_text =
ANSIStrings(&[left_separator, more_styled_text, right_separator]).to_string(); ANSIStrings(&[left_separator, more_styled_text, right_separator]).to_string();
LinePart { LinePart {
@ -142,7 +144,7 @@ fn left_more_message(
fn right_more_message( fn right_more_message(
tab_count_to_the_right: usize, tab_count_to_the_right: usize,
palette: Palette, palette: Styling,
separator: &str, separator: &str,
tab_index: usize, tab_index: usize,
) -> LinePart { ) -> LinePart {
@ -156,13 +158,15 @@ fn right_more_message(
}; };
// chars length plus separator length on both sides // chars length plus separator length on both sides
let more_text_len = more_text.width() + 2 * separator.width(); let more_text_len = more_text.width() + 2 * separator.width();
let (text_color, sep_color) = match palette.theme_hue { let (text_color, sep_color) = (
ThemeHue::Dark => (palette.white, palette.black), palette.ribbon_unselected.base,
ThemeHue::Light => (palette.black, palette.white), palette.text_unselected.background,
}; );
let left_separator = style!(sep_color, palette.orange).paint(separator); let left_separator = style!(sep_color, palette.ribbon_unselected.background).paint(separator);
let more_styled_text = style!(text_color, palette.orange).bold().paint(more_text); let more_styled_text = style!(text_color, palette.ribbon_unselected.background)
let right_separator = style!(palette.orange, sep_color).paint(separator); .bold()
.paint(more_text);
let right_separator = style!(palette.ribbon_unselected.background, sep_color).paint(separator);
let more_styled_text = let more_styled_text =
ANSIStrings(&[left_separator, more_styled_text, right_separator]).to_string(); ANSIStrings(&[left_separator, more_styled_text, right_separator]).to_string();
LinePart { LinePart {
@ -172,18 +176,12 @@ fn right_more_message(
} }
} }
fn tab_line_prefix(session_name: Option<&str>, palette: Palette, cols: usize) -> Vec<LinePart> { fn tab_line_prefix(session_name: Option<&str>, palette: Styling, cols: usize) -> Vec<LinePart> {
let prefix_text = " Zellij ".to_string(); let prefix_text = " Zellij ".to_string();
let prefix_text_len = prefix_text.chars().count(); let prefix_text_len = prefix_text.chars().count();
let text_color = match palette.theme_hue { let text_color = palette.text_unselected.base;
ThemeHue::Dark => palette.white, let bg_color = palette.text_unselected.background;
ThemeHue::Light => palette.black,
};
let bg_color = match palette.theme_hue {
ThemeHue::Dark => palette.black,
ThemeHue::Light => palette.white,
};
let prefix_styled_text = style!(text_color, bg_color).bold().paint(prefix_text); let prefix_styled_text = style!(text_color, bg_color).bold().paint(prefix_text);
let mut parts = vec![LinePart { let mut parts = vec![LinePart {
part: prefix_styled_text.to_string(), part: prefix_styled_text.to_string(),
@ -193,10 +191,7 @@ fn tab_line_prefix(session_name: Option<&str>, palette: Palette, cols: usize) ->
if let Some(name) = session_name { if let Some(name) = session_name {
let name_part = format!("({}) ", name); let name_part = format!("({}) ", name);
let name_part_len = name_part.width(); let name_part_len = name_part.width();
let text_color = match palette.theme_hue { let text_color = palette.text_unselected.base;
ThemeHue::Dark => palette.white,
ThemeHue::Light => palette.black,
};
let name_part_styled_text = style!(text_color, bg_color).bold().paint(name_part); let name_part_styled_text = style!(text_color, bg_color).bold().paint(name_part);
if cols.saturating_sub(prefix_text_len) >= name_part_len { if cols.saturating_sub(prefix_text_len) >= name_part_len {
parts.push(LinePart { parts.push(LinePart {
@ -222,7 +217,7 @@ pub fn tab_line(
mut all_tabs: Vec<LinePart>, mut all_tabs: Vec<LinePart>,
active_tab_index: usize, active_tab_index: usize,
cols: usize, cols: usize,
palette: Palette, palette: Styling,
capabilities: PluginCapabilities, capabilities: PluginCapabilities,
hide_session_name: bool, hide_session_name: bool,
tab_info: Option<&TabInfo>, tab_info: Option<&TabInfo>,
@ -290,7 +285,14 @@ pub fn tab_line(
let mut padding = String::new(); let mut padding = String::new();
let mut padding_len = 0; let mut padding_len = 0;
for _ in 0..remaining_space { for _ in 0..remaining_space {
padding.push_str(" "); padding.push_str(
&style!(
palette.text_unselected.background,
palette.text_unselected.background
)
.paint(" ")
.to_string(),
);
padding_len += 1; padding_len += 1;
} }
swap_layout_indicator.part = format!("{}{}", padding, swap_layout_indicator.part); swap_layout_indicator.part = format!("{}{}", padding, swap_layout_indicator.part);

View file

@ -125,10 +125,7 @@ impl ZellijPlugin for State {
all_tabs.push(tab); all_tabs.push(tab);
} }
let background = match self.mode_info.style.colors.theme_hue { let background = self.mode_info.style.colors.text_unselected.background;
ThemeHue::Dark => self.mode_info.style.colors.black,
ThemeHue::Light => self.mode_info.style.colors.white,
};
self.tab_line = tab_line( self.tab_line = tab_line(
self.mode_info.session_name.as_deref(), self.mode_info.session_name.as_deref(),

View file

@ -4,12 +4,15 @@ use unicode_width::UnicodeWidthStr;
use zellij_tile::prelude::*; use zellij_tile::prelude::*;
use zellij_tile_utils::style; use zellij_tile_utils::style;
fn cursors(focused_clients: &[ClientId], palette: Palette) -> (Vec<ANSIString>, usize) { fn cursors(
focused_clients: &[ClientId],
multiplayer_colors: MultiplayerColors,
) -> (Vec<ANSIString>, usize) {
// cursor section, text length // cursor section, text length
let mut len = 0; let mut len = 0;
let mut cursors = vec![]; let mut cursors = vec![];
for client_id in focused_clients.iter() { for client_id in focused_clients.iter() {
if let Some(color) = client_id_to_colors(*client_id, palette) { if let Some(color) = client_id_to_colors(*client_id, multiplayer_colors) {
cursors.push(style!(color.1, color.0).paint(" ")); cursors.push(style!(color.1, color.0).paint(" "));
len += 1; len += 1;
} }
@ -21,36 +24,41 @@ pub fn render_tab(
text: String, text: String,
tab: &TabInfo, tab: &TabInfo,
is_alternate_tab: bool, is_alternate_tab: bool,
palette: Palette, palette: Styling,
separator: &str, separator: &str,
) -> LinePart { ) -> LinePart {
let focused_clients = tab.other_focused_clients.as_slice(); let focused_clients = tab.other_focused_clients.as_slice();
let separator_width = separator.width(); let separator_width = separator.width();
let alternate_tab_color = match palette.theme_hue {
// TODO: only do this if we don't have the arrow capabilities let alternate_tab_color = if is_alternate_tab {
ThemeHue::Dark => palette.white, palette.ribbon_unselected.emphasis_1
ThemeHue::Light => palette.black, } else {
palette.ribbon_unselected.background
}; };
let background_color = if tab.active { let background_color = if tab.active {
palette.green palette.ribbon_selected.background
} else if is_alternate_tab { } else if is_alternate_tab {
alternate_tab_color alternate_tab_color
} else { } else {
palette.fg palette.ribbon_unselected.background
}; };
let foreground_color = match palette.theme_hue { let foreground_color = if tab.active {
ThemeHue::Dark => palette.black, palette.ribbon_selected.base
ThemeHue::Light => palette.white, } else {
palette.ribbon_unselected.base
}; };
let left_separator = style!(foreground_color, background_color).paint(separator);
let separator_fill_color = palette.text_unselected.background;
let left_separator = style!(separator_fill_color, background_color).paint(separator);
let mut tab_text_len = text.width() + (separator_width * 2) + 2; // +2 for padding let mut tab_text_len = text.width() + (separator_width * 2) + 2; // +2 for padding
let tab_styled_text = style!(foreground_color, background_color) let tab_styled_text = style!(foreground_color, background_color)
.bold() .bold()
.paint(format!(" {} ", text)); .paint(format!(" {} ", text));
let right_separator = style!(background_color, foreground_color).paint(separator); let right_separator = style!(background_color, separator_fill_color).paint(separator);
let tab_styled_text = if !focused_clients.is_empty() { let tab_styled_text = if !focused_clients.is_empty() {
let (cursor_section, extra_length) = cursors(focused_clients, palette); let (cursor_section, extra_length) =
cursors(focused_clients, palette.multiplayer_user_colors);
tab_text_len += extra_length + 2; // 2 for cursor_beginning and cursor_end tab_text_len += extra_length + 2; // 2 for cursor_beginning and cursor_end
let mut s = String::new(); let mut s = String::new();
let cursor_beginning = style!(foreground_color, background_color) let cursor_beginning = style!(foreground_color, background_color)
@ -84,7 +92,7 @@ pub fn tab_style(
mut tabname: String, mut tabname: String,
tab: &TabInfo, tab: &TabInfo,
mut is_alternate_tab: bool, mut is_alternate_tab: bool,
palette: Palette, palette: Styling,
capabilities: PluginCapabilities, capabilities: PluginCapabilities,
) -> LinePart { ) -> LinePart {
let separator = tab_separator(capabilities); let separator = tab_separator(capabilities);

View file

@ -1 +1 @@
Pzribbon;2/2/10/;1,2,3,4$114,105,98,98,111,110,32,49\ Pzribbon;2/2/12/;1,2,3,4$114,105,98,98,111,110,32,49\

View file

@ -216,7 +216,7 @@ pub fn start_client(
let palette = config let palette = config
.theme_config(config_options.theme.as_ref()) .theme_config(config_options.theme.as_ref())
.unwrap_or_else(|| os_input.load_palette()); .unwrap_or_else(|| os_input.load_palette().into());
let full_screen_ws = os_input.get_terminal_size_using_fd(0); let full_screen_ws = os_input.get_terminal_size_using_fd(0);
let client_attributes = ClientAttributes { let client_attributes = ClientAttributes {
@ -616,7 +616,7 @@ pub fn start_server_detached(
let palette = config let palette = config
.theme_config(config_options.theme.as_ref()) .theme_config(config_options.theme.as_ref())
.unwrap_or_else(|| os_input.load_palette()); .unwrap_or_else(|| os_input.load_palette().into());
let client_attributes = ClientAttributes { let client_attributes = ClientAttributes {
size: Size { rows: 50, cols: 50 }, // just so size is not 0, it doesn't matter because we size: Size { rows: 50, cols: 50 }, // just so size is not 0, it doesn't matter because we

View file

@ -353,7 +353,7 @@ impl SessionMetaData {
.unwrap_or_else(Default::default), .unwrap_or_else(Default::default),
theme: new_config theme: new_config
.theme_config(new_config.options.theme.as_ref()) .theme_config(new_config.options.theme.as_ref())
.unwrap_or_else(|| default_palette()), .unwrap_or_else(|| default_palette().into()),
simplified_ui: new_config.options.simplified_ui.unwrap_or(false), simplified_ui: new_config.options.simplified_ui.unwrap_or(false),
default_shell: new_config.options.default_shell, default_shell: new_config.options.default_shell,
pane_frames: new_config.options.pane_frames.unwrap_or(true), pane_frames: new_config.options.pane_frames.unwrap_or(true),

View file

@ -22,7 +22,7 @@ use std::collections::{BTreeMap, HashMap, HashSet};
use std::rc::Rc; use std::rc::Rc;
use std::time::Instant; use std::time::Instant;
use zellij_utils::{ use zellij_utils::{
data::{ModeInfo, Palette, Style}, data::{ModeInfo, Style, Styling},
errors::prelude::*, errors::prelude::*,
input::command::RunCommand, input::command::RunCommand,
input::layout::{FloatingPaneLayout, Run, RunPluginOrAlias}, input::layout::{FloatingPaneLayout, Run, RunPluginOrAlias},
@ -1121,7 +1121,7 @@ impl FloatingPanes {
}, },
} }
} }
pub fn update_pane_themes(&mut self, theme: Palette) { pub fn update_pane_themes(&mut self, theme: Styling) {
self.style.colors = theme; self.style.colors = theme;
for pane in self.panes.values_mut() { for pane in self.panes.values_mut() {
pane.update_theme(theme); pane.update_theme(theme);

View file

@ -16,7 +16,7 @@ use std::{
use zellij_utils::{ use zellij_utils::{
consts::{DEFAULT_SCROLL_BUFFER_SIZE, SCROLL_BUFFER_SIZE}, consts::{DEFAULT_SCROLL_BUFFER_SIZE, SCROLL_BUFFER_SIZE},
data::{Palette, PaletteColor}, data::{Palette, PaletteColor, Styling},
input::mouse::{MouseEvent, MouseEventType}, input::mouse::{MouseEvent, MouseEventType},
pane_size::SizeInPixels, pane_size::SizeInPixels,
position::Position, position::Position,
@ -1095,14 +1095,19 @@ impl Grid {
.selection .selection
.contains_row(character_chunk.y.saturating_sub(content_y)) .contains_row(character_chunk.y.saturating_sub(content_y))
{ {
let background_color = match style.colors.bg { let background_color = match style.colors.text_selected.background {
PaletteColor::Rgb(rgb) => AnsiCode::RgbCode(rgb), PaletteColor::Rgb(rgb) => AnsiCode::RgbCode(rgb),
PaletteColor::EightBit(col) => AnsiCode::ColorIndex(col), PaletteColor::EightBit(col) => AnsiCode::ColorIndex(col),
}; };
let foreground_color = match style.colors.text_selected.base {
PaletteColor::Rgb(rgb) => AnsiCode::RgbCode(rgb),
PaletteColor::EightBit(col) => AnsiCode::ColorIndex(col),
};
character_chunk.add_selection_and_colors( character_chunk.add_selection_and_colors(
self.selection, self.selection,
background_color, background_color,
None, Some(foreground_color),
content_x, content_x,
content_y, content_y,
); );
@ -1111,9 +1116,15 @@ impl Grid {
if res.contains_row(character_chunk.y.saturating_sub(content_y)) { if res.contains_row(character_chunk.y.saturating_sub(content_y)) {
let (select_background_palette, select_foreground_palette) = let (select_background_palette, select_foreground_palette) =
if Some(res) == self.search_results.active.as_ref() { if Some(res) == self.search_results.active.as_ref() {
(style.colors.orange, style.colors.black) (
style.colors.text_unselected.emphasis_0,
style.colors.text_unselected.background,
)
} else { } else {
(style.colors.green, style.colors.black) (
style.colors.text_unselected.emphasis_2,
style.colors.text_unselected.background,
)
}; };
let background_color = match select_background_palette { let background_color = match select_background_palette {
PaletteColor::Rgb(rgb) => AnsiCode::RgbCode(rgb), PaletteColor::Rgb(rgb) => AnsiCode::RgbCode(rgb),
@ -2270,7 +2281,7 @@ impl Grid {
pub fn unlock_renders(&mut self) { pub fn unlock_renders(&mut self) {
self.lock_renders = false; self.lock_renders = false;
} }
pub fn update_theme(&mut self, theme: Palette) { pub fn update_theme(&mut self, theme: Styling) {
self.style.colors = theme.clone(); self.style.colors = theme.clone();
} }
pub fn update_arrow_fonts(&mut self, should_support_arrow_fonts: bool) { pub fn update_arrow_fonts(&mut self, should_support_arrow_fonts: bool) {

View file

@ -25,7 +25,7 @@ use zellij_utils::pane_size::{Offset, SizeInPixels};
use zellij_utils::position::Position; use zellij_utils::position::Position;
use zellij_utils::{ use zellij_utils::{
channels::SenderWithContext, channels::SenderWithContext,
data::{Event, InputMode, Mouse, Palette, PaletteColor, Style}, data::{Event, InputMode, Mouse, Palette, PaletteColor, Style, Styling},
errors::prelude::*, errors::prelude::*,
input::layout::Run, input::layout::Run,
pane_size::PaneGeom, pane_size::PaneGeom,
@ -645,7 +645,7 @@ impl Pane for PluginPane {
.unwrap(); .unwrap();
} }
fn add_red_pane_frame_color_override(&mut self, error_text: Option<String>) { fn add_red_pane_frame_color_override(&mut self, error_text: Option<String>) {
self.pane_frame_color_override = Some((self.style.colors.red, error_text)); self.pane_frame_color_override = Some((self.style.colors.exit_code_error.base, error_text));
} }
fn clear_pane_frame_color_override(&mut self) { fn clear_pane_frame_color_override(&mut self) {
self.pane_frame_color_override = None; self.pane_frame_color_override = None;
@ -703,7 +703,7 @@ impl Pane for PluginPane {
self.pane_name = String::from_utf8_lossy(&buf).to_string(); self.pane_name = String::from_utf8_lossy(&buf).to_string();
self.set_should_render(true); self.set_should_render(true);
} }
fn update_theme(&mut self, theme: Palette) { fn update_theme(&mut self, theme: Styling) {
self.style.colors = theme.clone(); self.style.colors = theme.clone();
for grid in self.grids.values_mut() { for grid in self.grids.values_mut() {
grid.update_theme(theme.clone()); grid.update_theme(theme.clone());
@ -768,10 +768,10 @@ impl PluginPane {
} }
} }
fn display_request_permission_message(&self, plugin_permission: &PluginPermission) -> String { fn display_request_permission_message(&self, plugin_permission: &PluginPermission) -> String {
let bold_white = style!(self.style.colors.white).bold(); let bold_white = style!(self.style.colors.text_unselected.base).bold();
let cyan = style!(self.style.colors.cyan).bold(); let cyan = style!(self.style.colors.text_unselected.emphasis_1).bold();
let orange = style!(self.style.colors.orange).bold(); let orange = style!(self.style.colors.text_unselected.emphasis_0).bold();
let green = style!(self.style.colors.green).bold(); let green = style!(self.style.colors.text_unselected.emphasis_2).bold();
let mut messages = String::new(); let mut messages = String::new();
let permissions: BTreeSet<PermissionType> = let permissions: BTreeSet<PermissionType> =

View file

@ -123,7 +123,7 @@ impl SearchResult {
}; };
(skip, take) (skip, take)
} else if ridx as isize == s.end.line() { } else if ridx as isize == s.end.line() {
// We wrapped a line and the end is in this row, so take from the begging to the end // We wrapped a line and the end is in this row, so take from the beginning to the end
(0, s.end.column()) (0, s.end.column())
} else { } else {
// We are in the middle (start is above and end is below), so mark all // We are in the middle (start is above and end is below), so mark all

View file

@ -5,6 +5,7 @@ use std::rc::Rc;
use unicode_width::UnicodeWidthChar; use unicode_width::UnicodeWidthChar;
use unicode_width::UnicodeWidthStr; use unicode_width::UnicodeWidthStr;
use zellij_utils::data::StyleDeclaration;
use zellij_utils::input::command::RunCommand; use zellij_utils::input::command::RunCommand;
use zellij_utils::{ use zellij_utils::{
data::{PaletteColor, Style}, data::{PaletteColor, Style},
@ -762,6 +763,12 @@ impl Display for CharacterStyles {
} }
} }
impl From<StyleDeclaration> for CharacterStyles {
fn from(declaration: StyleDeclaration) -> Self {
RESET_STYLES.foreground(Some(declaration.base.into()))
}
}
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
pub enum LinkAnchor { pub enum LinkAnchor {
Start(u16), Start(u16),
@ -977,7 +984,9 @@ pub fn render_first_run_banner(
Some(run_command) => { Some(run_command) => {
let bold_text = RESET_STYLES.bold(Some(AnsiCode::On)); let bold_text = RESET_STYLES.bold(Some(AnsiCode::On));
let command_color_text = RESET_STYLES let command_color_text = RESET_STYLES
.foreground(Some(AnsiCode::from(style.colors.green))) .foreground(Some(AnsiCode::from(
style.colors.text_unselected.emphasis_2,
)))
.bold(Some(AnsiCode::On)); .bold(Some(AnsiCode::On));
let waiting_to_run_text = "Waiting to run: "; let waiting_to_run_text = "Waiting to run: ";
let command_text = run_command.to_string(); let command_text = run_command.to_string();
@ -1002,7 +1011,9 @@ pub fn render_first_run_banner(
let ctrl_c_bare_text = "Ctrl-c"; let ctrl_c_bare_text = "Ctrl-c";
let controls_bare_text_fourth_part = "> exit"; let controls_bare_text_fourth_part = "> exit";
let controls_color = RESET_STYLES let controls_color = RESET_STYLES
.foreground(Some(AnsiCode::from(style.colors.orange))) .foreground(Some(AnsiCode::from(
style.colors.text_unselected.emphasis_0,
)))
.bold(Some(AnsiCode::On)); .bold(Some(AnsiCode::On));
let controls_line_length = controls_bare_text_first_part.len() let controls_line_length = controls_bare_text_first_part.len()
+ enter_bare_text.len() + enter_bare_text.len()
@ -1054,7 +1065,9 @@ pub fn render_first_run_banner(
let ctrl_c_bare_text = "Ctrl-c"; let ctrl_c_bare_text = "Ctrl-c";
let controls_bare_text_fourth_part = "> exit"; let controls_bare_text_fourth_part = "> exit";
let controls_color = RESET_STYLES let controls_color = RESET_STYLES
.foreground(Some(AnsiCode::from(style.colors.orange))) .foreground(Some(AnsiCode::from(
style.colors.text_unselected.emphasis_0,
)))
.bold(Some(AnsiCode::On)); .bold(Some(AnsiCode::On));
let controls_line_length = controls_bare_text_first_part.len() let controls_line_length = controls_bare_text_first_part.len()
+ enter_bare_text.len() + enter_bare_text.len()

View file

@ -19,7 +19,7 @@ use zellij_utils::pane_size::Offset;
use zellij_utils::{ use zellij_utils::{
data::{ data::{
BareKey, InputMode, KeyWithModifier, Palette, PaletteColor, PaneId as ZellijUtilsPaneId, BareKey, InputMode, KeyWithModifier, Palette, PaletteColor, PaneId as ZellijUtilsPaneId,
Style, Style, Styling,
}, },
errors::prelude::*, errors::prelude::*,
input::layout::Run, input::layout::Run,
@ -735,7 +735,7 @@ impl Pane for TerminalPane {
self.set_should_render(true); self.set_should_render(true);
} }
fn add_red_pane_frame_color_override(&mut self, error_text: Option<String>) { fn add_red_pane_frame_color_override(&mut self, error_text: Option<String>) {
self.pane_frame_color_override = Some((self.style.colors.red, error_text)); self.pane_frame_color_override = Some((self.style.colors.exit_code_error.base, error_text));
} }
fn clear_pane_frame_color_override(&mut self) { fn clear_pane_frame_color_override(&mut self) {
self.pane_frame_color_override = None; self.pane_frame_color_override = None;
@ -802,7 +802,7 @@ impl Pane for TerminalPane {
run_command.clone() run_command.clone()
}) })
} }
fn update_theme(&mut self, theme: Palette) { fn update_theme(&mut self, theme: Styling) {
self.style.colors = theme.clone(); self.style.colors = theme.clone();
self.grid.update_theme(theme); self.grid.update_theme(theme);
if self.banner.is_some() { if self.banner.is_some() {

View file

@ -18,7 +18,7 @@ use crate::{
}; };
use stacked_panes::StackedPanes; use stacked_panes::StackedPanes;
use zellij_utils::{ use zellij_utils::{
data::{Direction, ModeInfo, Palette, PaneInfo, Resize, ResizeStrategy, Style}, data::{Direction, ModeInfo, PaneInfo, Resize, ResizeStrategy, Style, Styling},
errors::prelude::*, errors::prelude::*,
input::{ input::{
command::RunCommand, command::RunCommand,
@ -2383,10 +2383,12 @@ impl TiledPanes {
} }
pane_infos pane_infos
} }
pub fn pane_id_is_focused(&self, pane_id: &PaneId) -> bool { pub fn pane_id_is_focused(&self, pane_id: &PaneId) -> bool {
self.active_panes.pane_id_is_focused(pane_id) self.active_panes.pane_id_is_focused(pane_id)
} }
pub fn update_pane_themes(&mut self, theme: Palette) {
pub fn update_pane_themes(&mut self, theme: Styling) {
self.style.colors = theme; self.style.colors = theme;
for pane in self.panes.values_mut() { for pane in self.panes.values_mut() {
pane.update_theme(theme); pane.update_theme(theme);

View file

@ -1,6 +1,5 @@
--- ---
source: zellij-server/src/panes/./unit/grid_tests.rs source: zellij-server/src/panes/./unit/grid_tests.rs
assertion_line: 2921
expression: "format!(\"{:?}\", grid)" expression: "format!(\"{:?}\", grid)"
--- ---
00 (C):  <n> RESIZE  00 (C):  <n> RESIZE 
@ -43,5 +42,4 @@ expression: "format!(\"{:?}\", grid)"
37 (C): 37 (C):
38 (C): 38 (C):
39 (C): 39 (C):
40 (C): 40 (C):

View file

@ -1,6 +1,5 @@
--- ---
source: zellij-server/src/panes/./unit/grid_tests.rs source: zellij-server/src/panes/./unit/grid_tests.rs
assertion_line: 3102
expression: "format!(\"{:?}\", grid)" expression: "format!(\"{:?}\", grid)"
--- ---
00 (C): title1 title2 title3 title4 title5 00 (C): title1 title2 title3 title4 title5
@ -43,5 +42,4 @@ expression: "format!(\"{:?}\", grid)"
37 (C): 37 (C):
38 (C): 38 (C):
39 (C): 39 (C):
40 (C): 40 (C):

View file

@ -12,60 +12,300 @@ Some(
), ),
keybinds: [], keybinds: [],
style: Style { style: Style {
colors: Palette { colors: Styling {
source: Default, text_unselected: StyleDeclaration {
theme_hue: Dark, base: EightBit(
fg: EightBit( 245,
0, ),
), background: EightBit(
bg: EightBit( 238,
0, ),
), emphasis_0: EightBit(
black: EightBit( 166,
0, ),
), emphasis_1: EightBit(
red: EightBit( 51,
0, ),
), emphasis_2: EightBit(
green: EightBit( 154,
0, ),
), emphasis_3: EightBit(
yellow: EightBit( 201,
0, ),
), },
blue: EightBit( text_selected: StyleDeclaration {
0, base: EightBit(
), 245,
magenta: EightBit( ),
0, background: EightBit(
), 238,
cyan: EightBit( ),
0, emphasis_0: EightBit(
), 166,
white: EightBit( ),
0, emphasis_1: EightBit(
), 51,
orange: EightBit( ),
0, emphasis_2: EightBit(
), 154,
gray: EightBit( ),
0, emphasis_3: EightBit(
), 201,
purple: EightBit( ),
0, },
), ribbon_unselected: StyleDeclaration {
gold: EightBit( base: EightBit(
0, 16,
), ),
silver: EightBit( background: EightBit(
0, 238,
), ),
pink: EightBit( emphasis_0: EightBit(
0, 124,
), ),
brown: EightBit( emphasis_1: EightBit(
0, 255,
), ),
emphasis_2: EightBit(
45,
),
emphasis_3: EightBit(
201,
),
},
ribbon_selected: StyleDeclaration {
base: EightBit(
16,
),
background: EightBit(
154,
),
emphasis_0: EightBit(
124,
),
emphasis_1: EightBit(
166,
),
emphasis_2: EightBit(
201,
),
emphasis_3: EightBit(
45,
),
},
table_title: StyleDeclaration {
base: EightBit(
154,
),
background: EightBit(
238,
),
emphasis_0: EightBit(
166,
),
emphasis_1: EightBit(
51,
),
emphasis_2: EightBit(
154,
),
emphasis_3: EightBit(
201,
),
},
table_cell_unselected: StyleDeclaration {
base: EightBit(
245,
),
background: EightBit(
238,
),
emphasis_0: EightBit(
166,
),
emphasis_1: EightBit(
51,
),
emphasis_2: EightBit(
154,
),
emphasis_3: EightBit(
201,
),
},
table_cell_selected: StyleDeclaration {
base: EightBit(
154,
),
background: EightBit(
238,
),
emphasis_0: EightBit(
166,
),
emphasis_1: EightBit(
51,
),
emphasis_2: EightBit(
124,
),
emphasis_3: EightBit(
201,
),
},
list_unselected: StyleDeclaration {
base: EightBit(
245,
),
background: EightBit(
238,
),
emphasis_0: EightBit(
166,
),
emphasis_1: EightBit(
51,
),
emphasis_2: EightBit(
154,
),
emphasis_3: EightBit(
201,
),
},
list_selected: StyleDeclaration {
base: EightBit(
154,
),
background: EightBit(
238,
),
emphasis_0: EightBit(
166,
),
emphasis_1: EightBit(
51,
),
emphasis_2: EightBit(
124,
),
emphasis_3: EightBit(
201,
),
},
frame_unselected: None,
frame_selected: StyleDeclaration {
base: EightBit(
154,
),
background: EightBit(
238,
),
emphasis_0: EightBit(
166,
),
emphasis_1: EightBit(
51,
),
emphasis_2: EightBit(
201,
),
emphasis_3: EightBit(
215,
),
},
frame_highlight: StyleDeclaration {
base: EightBit(
166,
),
background: EightBit(
154,
),
emphasis_0: EightBit(
154,
),
emphasis_1: EightBit(
154,
),
emphasis_2: EightBit(
154,
),
emphasis_3: EightBit(
154,
),
},
exit_code_success: StyleDeclaration {
base: EightBit(
154,
),
background: EightBit(
238,
),
emphasis_0: EightBit(
51,
),
emphasis_1: EightBit(
16,
),
emphasis_2: EightBit(
201,
),
emphasis_3: EightBit(
45,
),
},
exit_code_error: StyleDeclaration {
base: EightBit(
124,
),
background: EightBit(
238,
),
emphasis_0: EightBit(
226,
),
emphasis_1: EightBit(
136,
),
emphasis_2: EightBit(
245,
),
emphasis_3: EightBit(
99,
),
},
multiplayer_user_colors: MultiplayerColors {
player_1: EightBit(
201,
),
player_2: EightBit(
45,
),
player_3: EightBit(
99,
),
player_4: EightBit(
226,
),
player_5: EightBit(
51,
),
player_6: EightBit(
136,
),
player_7: EightBit(
124,
),
player_8: EightBit(
245,
),
player_9: EightBit(
207,
),
player_10: EightBit(
215,
),
},
}, },
rounded_corners: false, rounded_corners: false,
hide_session_name: false, hide_session_name: false,

View file

@ -9,7 +9,8 @@ use std::time::Duration;
use log::{debug, warn}; use log::{debug, warn};
use zellij_utils::data::{ use zellij_utils::data::{
Direction, KeyWithModifier, PaneManifest, PluginPermission, Resize, ResizeStrategy, SessionInfo, Direction, KeyWithModifier, PaneManifest, PluginPermission, Resize, ResizeStrategy,
SessionInfo, Styling,
}; };
use zellij_utils::errors::prelude::*; use zellij_utils::errors::prelude::*;
use zellij_utils::input::command::RunCommand; use zellij_utils::input::command::RunCommand;
@ -357,7 +358,7 @@ pub enum ScreenInstruction {
client_id: ClientId, client_id: ClientId,
keybinds: Keybinds, keybinds: Keybinds,
default_mode: InputMode, default_mode: InputMode,
theme: Palette, theme: Styling,
simplified_ui: bool, simplified_ui: bool,
default_shell: Option<PathBuf>, default_shell: Option<PathBuf>,
pane_frames: bool, pane_frames: bool,
@ -2445,7 +2446,7 @@ impl Screen {
&mut self, &mut self,
new_keybinds: Keybinds, new_keybinds: Keybinds,
new_default_mode: InputMode, new_default_mode: InputMode,
theme: Palette, theme: Styling,
simplified_ui: bool, simplified_ui: bool,
default_shell: Option<PathBuf>, default_shell: Option<PathBuf>,
pane_frames: bool, pane_frames: bool,

View file

@ -49,7 +49,9 @@ use std::{
str, str,
}; };
use zellij_utils::{ use zellij_utils::{
data::{Event, FloatingPaneCoordinates, InputMode, ModeInfo, Palette, PaletteColor, Style}, data::{
Event, FloatingPaneCoordinates, InputMode, ModeInfo, Palette, PaletteColor, Style, Styling,
},
input::{ input::{
command::TerminalAction, command::TerminalAction,
layout::{ layout::{
@ -203,7 +205,7 @@ pub(crate) struct TabData {
pub name: String, pub name: String,
pub active: bool, pub active: bool,
pub mode_info: ModeInfo, pub mode_info: ModeInfo,
pub colors: Palette, pub colors: Styling,
} }
// FIXME: Use a struct that has a pane_type enum, to reduce all of the duplication // FIXME: Use a struct that has a pane_type enum, to reduce all of the duplication
@ -513,7 +515,7 @@ pub trait Pane {
fn rerun(&mut self) -> Option<RunCommand> { fn rerun(&mut self) -> Option<RunCommand> {
None None
} // only relevant to terminal panes } // only relevant to terminal panes
fn update_theme(&mut self, _theme: Palette) {} fn update_theme(&mut self, _theme: Styling) {}
fn update_arrow_fonts(&mut self, _should_support_arrow_fonts: bool) {} fn update_arrow_fonts(&mut self, _should_support_arrow_fonts: bool) {}
fn update_rounded_corners(&mut self, _rounded_corners: bool) {} fn update_rounded_corners(&mut self, _rounded_corners: bool) {}
fn set_should_be_suppressed(&mut self, _should_be_suppressed: bool) {} fn set_should_be_suppressed(&mut self, _should_be_suppressed: bool) {}
@ -4402,7 +4404,7 @@ impl Tab {
} }
Ok(()) Ok(())
} }
pub fn update_theme(&mut self, theme: Palette) { pub fn update_theme(&mut self, theme: Styling) {
self.style.colors = theme; self.style.colors = theme;
self.floating_panes.update_pane_themes(theme); self.floating_panes.update_pane_themes(theme);
self.tiled_panes.update_pane_themes(theme); self.tiled_panes.update_pane_themes(theme);

View file

@ -10,7 +10,7 @@ use zellij_utils::{data::Style, lazy_static::lazy_static, regex::Regex, vte};
use component_coordinates::{is_too_high, is_too_wide, Coordinates}; use component_coordinates::{is_too_high, is_too_wide, Coordinates};
use nested_list::{nested_list, parse_nested_list_items}; use nested_list::{nested_list, parse_nested_list_items};
use ribbon::{emphasis_variants_for_ribbon, emphasis_variants_for_selected_ribbon, ribbon}; use ribbon::ribbon;
use table::table; use table::table;
use text::{parse_text, parse_text_params, stringify_text, text, Text}; use text::{parse_text, parse_text_params, stringify_text, text, Text};
@ -87,7 +87,6 @@ impl<'a> UiComponentParser<'a> {
columns, columns,
rows, rows,
stringified_params, stringified_params,
Some(self.style.colors.green),
&self.style, &self.style,
component_coordinates, component_coordinates,
); );

View file

@ -2,7 +2,7 @@ use super::{
is_too_high, parse_indices, parse_opaque, parse_selected, parse_text, stringify_text, is_too_high, parse_indices, parse_opaque, parse_selected, parse_text, stringify_text,
Coordinates, Text, Coordinates, Text,
}; };
use crate::panes::terminal_character::{AnsiCode, RESET_STYLES}; use crate::panes::terminal_character::{AnsiCode, CharacterStyles, RESET_STYLES};
use zellij_utils::data::Style; use zellij_utils::data::Style;
use unicode_width::UnicodeWidthChar; use unicode_width::UnicodeWidthChar;
@ -27,37 +27,29 @@ pub fn nested_list(
if is_too_high(line_index + 1, &coordinates) { if is_too_high(line_index + 1, &coordinates) {
break; break;
} }
let mut reset_styles_for_item = RESET_STYLES; let style_declaration = if line_item.text.selected {
reset_styles_for_item.background = None; style.colors.list_selected
reset_styles_for_item.foreground = None; } else {
style.colors.list_unselected
};
let padding = line_item.indentation_level * 2 + 1; let padding = line_item.indentation_level * 2 + 1;
let bulletin = if line_item.indentation_level % 2 == 0 { let bulletin = if line_item.indentation_level % 2 == 0 {
"> " "> "
} else { } else {
"- " "- "
}; };
let text_style = if line_item.text.selected { let text_style = if line_item.text.opaque || line_item.text.selected {
reset_styles_for_item CharacterStyles::from(style_declaration)
.bold(Some(AnsiCode::On)) .background(Some(style_declaration.background.into()))
.foreground(Some(style.colors.white.into()))
.background(Some(style.colors.bg.into()))
} else if line_item.text.opaque {
reset_styles_for_item
.bold(Some(AnsiCode::On))
.foreground(Some(style.colors.white.into()))
.background(Some(style.colors.black.into()))
} else { } else {
reset_styles_for_item CharacterStyles::from(style_declaration)
.bold(Some(AnsiCode::On))
.foreground(Some(style.colors.white.into()))
}; };
let (mut text, text_width) = stringify_text( let (mut text, text_width) = stringify_text(
&line_item.text, &line_item.text,
Some(padding + bulletin.len()), Some(padding + bulletin.len()),
&coordinates, &coordinates,
style, &style_declaration,
text_style, text_style.bold(Some(AnsiCode::On)),
line_item.text.selected,
); );
text = pad_line(text, max_width, padding, text_width); text = pad_line(text, max_width, padding, text_width);
let go_to_row_instruction = coordinates let go_to_row_instruction = coordinates
@ -70,20 +62,13 @@ pub fn nested_list(
"".to_owned() "".to_owned()
} }
}); });
let line_style = if line_item.text.selected {
RESET_STYLES
.foreground(Some(style.colors.white.into()))
.background(Some(style.colors.bg.into()))
} else if line_item.text.opaque {
RESET_STYLES
.foreground(Some(style.colors.white.into()))
.background(Some(style.colors.black.into()))
} else {
RESET_STYLES.foreground(Some(style.colors.white.into()))
};
stringified.push_str(&format!( stringified.push_str(&format!(
"{}{}{}{:padding$}{bulletin}{}{text}{}", "{}{}{:padding$}{bulletin}{}{text}{}",
go_to_row_instruction, line_style, reset_styles_for_item, " ", text_style, RESET_STYLES go_to_row_instruction,
text_style,
" ",
text_style.bold(Some(AnsiCode::On)),
RESET_STYLES
)); ));
} }
stringified.as_bytes().to_vec() stringified.as_bytes().to_vec()

View file

@ -1,6 +1,5 @@
use super::{is_too_wide, Coordinates, Text}; use super::{text::stringify_text, Coordinates, Text};
use crate::panes::terminal_character::{AnsiCode, CharacterStyles, RESET_STYLES}; use crate::panes::terminal_character::{AnsiCode, CharacterStyles, RESET_STYLES};
use unicode_width::UnicodeWidthChar;
use zellij_utils::data::{PaletteColor, Style}; use zellij_utils::data::{PaletteColor, Style};
static ARROW_SEPARATOR: &str = ""; static ARROW_SEPARATOR: &str = "";
@ -12,25 +11,34 @@ pub fn ribbon(
component_coordinates: Option<Coordinates>, component_coordinates: Option<Coordinates>,
) -> Vec<u8> { ) -> Vec<u8> {
let colors = style.colors; let colors = style.colors;
let (first_arrow_styles, text_style, last_arrow_styles) = if content.selected { let background = colors.text_unselected.background;
( let declaration = if content.selected {
character_style(colors.black, colors.green), colors.ribbon_selected
character_style(colors.black, colors.green),
character_style(colors.green, colors.black),
)
} else { } else {
( colors.ribbon_unselected
character_style(colors.black, colors.fg),
character_style(colors.black, colors.fg),
character_style(colors.fg, colors.black),
)
}; };
let (text, _text_width) = let (first_arrow_styles, text_style, last_arrow_styles) = (
stringify_ribbon_text(&content, &component_coordinates, style, text_style); character_style(background, declaration.background),
character_style(declaration.base, declaration.background),
character_style(declaration.background, background),
);
let (arrow, padding) = if arrow_fonts {
(ARROW_SEPARATOR, Some(4))
} else {
("", None)
};
let (text, _text_width) = stringify_text(
&content,
padding,
&component_coordinates,
&declaration,
text_style,
);
let mut stringified = component_coordinates let mut stringified = component_coordinates
.map(|c| c.to_string()) .map(|c| c.to_string())
.unwrap_or_else(|| String::new()); .unwrap_or_else(|| String::new());
let arrow = if arrow_fonts { ARROW_SEPARATOR } else { "" };
stringified.push_str(&format!( stringified.push_str(&format!(
"{}{}{}{} {} {}{}{}", "{}{}{}{} {} {}{}{}",
RESET_STYLES, RESET_STYLES,
@ -45,68 +53,6 @@ pub fn ribbon(
stringified.as_bytes().to_vec() stringified.as_bytes().to_vec()
} }
pub fn emphasis_variants_for_ribbon(style: &Style) -> [PaletteColor; 4] {
[
style.colors.red,
style.colors.white,
style.colors.blue,
style.colors.magenta,
]
}
pub fn emphasis_variants_for_selected_ribbon(style: &Style) -> [PaletteColor; 4] {
[
style.colors.red,
style.colors.orange,
style.colors.magenta,
style.colors.blue,
]
}
fn stringify_ribbon_text(
text: &Text,
coordinates: &Option<Coordinates>,
style: &Style,
text_style: CharacterStyles,
) -> (String, usize) {
let mut stringified = String::new();
let mut text_width = 0;
for (i, character) in text.text.chars().enumerate() {
let character_width = character.width().unwrap_or(0);
if is_too_wide(character_width, text_width, &coordinates) {
break;
}
if !text.indices.is_empty() {
let character_with_styling =
color_ribbon_index_character(character, i, &text, style, text_style);
stringified.push_str(&character_with_styling);
} else {
stringified.push(character);
}
text_width += character_width;
}
(stringified, text_width)
}
fn color_ribbon_index_character(
character: char,
index: usize,
text: &Text,
style: &Style,
base_style: CharacterStyles,
) -> String {
let character_style = if text.selected {
text.style_of_index_for_selected_ribbon(index, style)
.map(|foreground_style| base_style.foreground(Some(foreground_style.into())))
.unwrap_or(base_style)
} else {
text.style_of_index_for_ribbon(index, style)
.map(|foreground_style| base_style.foreground(Some(foreground_style.into())))
.unwrap_or(base_style)
};
format!("{}{}{}", character_style, character, base_style)
}
fn character_style(foreground: PaletteColor, background: PaletteColor) -> CharacterStyles { fn character_style(foreground: PaletteColor, background: PaletteColor) -> CharacterStyles {
RESET_STYLES RESET_STYLES
.foreground(Some(foreground.into())) .foreground(Some(foreground.into()))

View file

@ -1,16 +1,15 @@
use super::{is_too_high, is_too_wide, stringify_text, Coordinates, Text}; use super::{is_too_high, is_too_wide, stringify_text, Coordinates, Text};
use crate::panes::terminal_character::{AnsiCode, RESET_STYLES}; use crate::panes::{
use std::collections::BTreeMap; terminal_character::{AnsiCode, RESET_STYLES},
use zellij_utils::{ CharacterStyles,
data::{PaletteColor, Style},
shared::ansi_len,
}; };
use std::collections::BTreeMap;
use zellij_utils::{data::Style, shared::ansi_len};
pub fn table( pub fn table(
columns: usize, columns: usize,
_rows: usize, _rows: usize,
contents: Vec<Text>, contents: Vec<Text>,
title_color: Option<PaletteColor>,
style: &Style, style: &Style,
coordinates: Option<Coordinates>, coordinates: Option<Coordinates>,
) -> Vec<u8> { ) -> Vec<u8> {
@ -18,34 +17,37 @@ pub fn table(
// we first arrange the data by columns so that we can pad them by the widest one // we first arrange the data by columns so that we can pad them by the widest one
let stringified_columns = stringify_table_columns(contents, columns); let stringified_columns = stringify_table_columns(contents, columns);
let stringified_rows = stringify_table_rows(stringified_columns, &coordinates); let stringified_rows = stringify_table_rows(stringified_columns, &coordinates);
let title_styles = RESET_STYLES
.foreground(title_color.map(|t| t.into()))
.bold(Some(AnsiCode::On));
let cell_styles = RESET_STYLES.bold(Some(AnsiCode::On));
for (row_index, (_, row)) in stringified_rows.into_iter().enumerate() { for (row_index, (_, row)) in stringified_rows.into_iter().enumerate() {
let is_title_row = row_index == 0; let is_title_row = row_index == 0;
if is_too_high(row_index + 1, &coordinates) { if is_too_high(row_index + 1, &coordinates) {
break; break;
} }
for cell in row { for cell in row {
let mut reset_styles_for_item = RESET_STYLES; let declaration = if is_title_row {
let mut text_style = if is_title_row { style.colors.table_title
title_styles
} else { } else {
cell_styles if cell.selected {
style.colors.table_cell_selected
} else {
style.colors.table_cell_unselected
}
};
let text_style = if cell.opaque || cell.selected {
CharacterStyles::from(declaration).background(Some(declaration.background.into()))
} else {
CharacterStyles::from(declaration)
}; };
if cell.selected {
reset_styles_for_item.background = None;
text_style = text_style.background(Some(style.colors.bg.into()));
} else if cell.opaque {
reset_styles_for_item.background = None;
text_style = text_style.background(Some(style.colors.black.into()));
}
// here we intentionally don't pass our coordinates even if we have them, because // here we intentionally don't pass our coordinates even if we have them, because
// these cells have already been padded and truncated // these cells have already been padded and truncated
let (text, _text_width) = let (text, _text_width) = stringify_text(
stringify_text(&cell, None, &None, style, text_style, cell.selected); &cell,
stringified.push_str(&format!("{}{}{} ", text_style, text, reset_styles_for_item)); None,
&None,
&declaration,
text_style.bold(Some(AnsiCode::On)),
);
stringified.push_str(&format!("{}{} {}", text_style, text, RESET_STYLES));
} }
let next_row_instruction = coordinates let next_row_instruction = coordinates
.as_ref() .as_ref()

View file

@ -1,10 +1,7 @@
use super::{ use super::{is_too_wide, parse_indices, parse_opaque, parse_selected, Coordinates};
emphasis_variants_for_ribbon, emphasis_variants_for_selected_ribbon, is_too_wide, use crate::panes::{terminal_character::CharacterStyles, AnsiCode};
parse_indices, parse_opaque, parse_selected, Coordinates,
};
use crate::panes::terminal_character::{AnsiCode, CharacterStyles, RESET_STYLES};
use zellij_utils::{ use zellij_utils::{
data::{PaletteColor, Style}, data::{PaletteColor, Style, StyleDeclaration},
shared::ansi_len, shared::ansi_len,
}; };
@ -12,28 +9,28 @@ use unicode_width::UnicodeWidthChar;
use zellij_utils::errors::prelude::*; use zellij_utils::errors::prelude::*;
pub fn text(content: Text, style: &Style, component_coordinates: Option<Coordinates>) -> Vec<u8> { pub fn text(content: Text, style: &Style, component_coordinates: Option<Coordinates>) -> Vec<u8> {
let mut text_style = RESET_STYLES let declaration = if content.selected {
.bold(Some(AnsiCode::On)) style.colors.text_selected
.foreground(Some(style.colors.white.into())); } else {
style.colors.text_unselected
};
let base_text_style = CharacterStyles::from(declaration).bold(Some(AnsiCode::On));
if content.selected {
text_style = text_style.background(Some(style.colors.bg.into()));
} else if content.opaque {
text_style = text_style.background(Some(style.colors.black.into()));
}
let (text, _text_width) = stringify_text( let (text, _text_width) = stringify_text(
&content, &content,
None, None,
&component_coordinates, &component_coordinates,
style, &declaration,
text_style, base_text_style,
content.selected,
); );
match component_coordinates { match component_coordinates {
Some(component_coordinates) => format!("{}{}{}", component_coordinates, text_style, text) Some(component_coordinates) => {
.as_bytes() format!("{}{}{}", component_coordinates, base_text_style, text)
.to_vec(), .as_bytes()
None => format!("{}{}", text_style, text).as_bytes().to_vec(), .to_vec()
},
None => format!("{}{}", base_text_style, text).as_bytes().to_vec(),
} }
} }
@ -41,12 +38,16 @@ pub fn stringify_text(
text: &Text, text: &Text,
left_padding: Option<usize>, left_padding: Option<usize>,
coordinates: &Option<Coordinates>, coordinates: &Option<Coordinates>,
style: &Style, style: &StyleDeclaration,
text_style: CharacterStyles, component_text_style: CharacterStyles,
is_selected: bool,
) -> (String, usize) { ) -> (String, usize) {
let mut text_width = 0; let mut text_width = 0;
let mut stringified = String::new(); let mut stringified = String::new();
let base_text_style = if text.opaque || text.selected {
component_text_style.background(Some(style.background.into()))
} else {
component_text_style
};
for (i, character) in text.text.chars().enumerate() { for (i, character) in text.text.chars().enumerate() {
let character_width = character.width().unwrap_or(0); let character_width = character.width().unwrap_or(0);
if is_too_wide( if is_too_wide(
@ -59,14 +60,14 @@ pub fn stringify_text(
text_width += character_width; text_width += character_width;
if !text.indices.is_empty() { if !text.indices.is_empty() {
let character_with_styling = let character_with_styling =
color_index_character(character, i, &text, style, text_style, is_selected); color_index_character(character, i, &text, style, base_text_style);
stringified.push_str(&character_with_styling); stringified.push_str(&character_with_styling);
} else { } else {
stringified.push(character); stringified.push(character)
} }
} }
let coordinates_width = coordinates.as_ref().and_then(|c| c.width); let coordinates_width = coordinates.as_ref().and_then(|c| c.width);
match (coordinates_width, text_style.background) { match (coordinates_width, base_text_style.background) {
(Some(coordinates_width), Some(_background_style)) => { (Some(coordinates_width), Some(_background_style)) => {
let text_width_with_left_padding = text_width + left_padding.unwrap_or(0); let text_width_with_left_padding = text_width + left_padding.unwrap_or(0);
let background_padding_length = let background_padding_length =
@ -91,32 +92,16 @@ pub fn color_index_character(
character: char, character: char,
index: usize, index: usize,
text: &Text, text: &Text,
style: &Style, declaration: &StyleDeclaration,
base_text_style: CharacterStyles, base_text_style: CharacterStyles,
is_selected: bool,
) -> String { ) -> String {
let character_style = text let character_style = text
.style_of_index(index, style) .style_of_index(index, declaration)
.map(|foreground_style| { .map(|foreground_style| base_text_style.foreground(Some(foreground_style.into())))
let mut character_style = base_text_style.foreground(Some(foreground_style.into()));
if is_selected {
character_style = character_style.background(Some(style.colors.bg.into()));
};
character_style
})
.unwrap_or(base_text_style); .unwrap_or(base_text_style);
format!("{}{}{}", character_style, character, base_text_style) format!("{}{}{}", character_style, character, base_text_style)
} }
pub fn emphasis_variants(style: &Style) -> [PaletteColor; 4] {
[
style.colors.orange,
style.colors.cyan,
style.colors.green,
style.colors.magenta,
]
}
pub fn parse_text_params<'a>(params_iter: impl Iterator<Item = &'a mut String>) -> Vec<Text> { pub fn parse_text_params<'a>(params_iter: impl Iterator<Item = &'a mut String>) -> Vec<Text> {
params_iter params_iter
.flat_map(|mut stringified| { .flat_map(|mut stringified| {
@ -148,8 +133,14 @@ impl Text {
self.text.push(' '); self.text.push(' ');
} }
} }
pub fn style_of_index(&self, index: usize, style: &Style) -> Option<PaletteColor> {
let index_variant_styles = emphasis_variants(style); pub fn style_of_index(&self, index: usize, style: &StyleDeclaration) -> Option<PaletteColor> {
let index_variant_styles = [
style.emphasis_0,
style.emphasis_1,
style.emphasis_2,
style.emphasis_3,
];
for i in (0..=3).rev() { for i in (0..=3).rev() {
// we do this in reverse to give precedence to the last applied // we do this in reverse to give precedence to the last applied
// style // style
@ -159,37 +150,7 @@ impl Text {
} }
} }
} }
None Some(style.base)
}
pub fn style_of_index_for_ribbon(&self, index: usize, style: &Style) -> Option<PaletteColor> {
let index_variant_styles = emphasis_variants_for_ribbon(style);
for i in (0..=3).rev() {
// we do this in reverse to give precedence to the last applied
// style
if let Some(indices) = self.indices.get(i) {
if indices.contains(&index) {
return Some(index_variant_styles[i]);
}
}
}
None
}
pub fn style_of_index_for_selected_ribbon(
&self,
index: usize,
style: &Style,
) -> Option<PaletteColor> {
let index_variant_styles = emphasis_variants_for_selected_ribbon(style);
for i in (0..=3).rev() {
// we do this in reverse to give precedence to the last applied
// style
if let Some(indices) = self.indices.get(i) {
if indices.contains(&index) {
return Some(index_variant_styles[i]);
}
}
}
None
} }
} }

View file

@ -1,7 +1,7 @@
use std::fmt::{Display, Error, Formatter}; use std::fmt::{Display, Error, Formatter};
use zellij_utils::{ use zellij_utils::{
data::{Palette, PaletteColor}, data::{PaletteColor, Styling},
errors::prelude::*, errors::prelude::*,
}; };
@ -24,7 +24,7 @@ pub struct LoadingIndication {
error: Option<String>, error: Option<String>,
animation_offset: usize, animation_offset: usize,
plugin_name: String, plugin_name: String,
terminal_emulator_colors: Option<Palette>, terminal_emulator_colors: Option<Styling>,
override_previous_error: bool, override_previous_error: bool,
} }
@ -39,7 +39,7 @@ impl LoadingIndication {
pub fn set_name(&mut self, plugin_name: String) { pub fn set_name(&mut self, plugin_name: String) {
self.plugin_name = plugin_name; self.plugin_name = plugin_name;
} }
pub fn with_colors(mut self, terminal_emulator_colors: Palette) -> Self { pub fn with_colors(mut self, terminal_emulator_colors: Styling) -> Self {
self.terminal_emulator_colors = Some(terminal_emulator_colors); self.terminal_emulator_colors = Some(terminal_emulator_colors);
self self
} }
@ -142,19 +142,27 @@ macro_rules! style {
impl Display for LoadingIndication { impl Display for LoadingIndication {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
let cyan = match self.terminal_emulator_colors { let cyan = match self.terminal_emulator_colors {
Some(terminal_emulator_colors) => style!(terminal_emulator_colors.cyan).bold(), Some(terminal_emulator_colors) => {
style!(terminal_emulator_colors.exit_code_success.emphasis_0).bold()
},
None => ansi_term::Style::new(), None => ansi_term::Style::new(),
}; };
let green = match self.terminal_emulator_colors { let green = match self.terminal_emulator_colors {
Some(terminal_emulator_colors) => style!(terminal_emulator_colors.green).bold(), Some(terminal_emulator_colors) => {
style!(terminal_emulator_colors.exit_code_success.base).bold()
},
None => ansi_term::Style::new(), None => ansi_term::Style::new(),
}; };
let yellow = match self.terminal_emulator_colors { let yellow = match self.terminal_emulator_colors {
Some(terminal_emulator_colors) => style!(terminal_emulator_colors.yellow).bold(), Some(terminal_emulator_colors) => {
style!(terminal_emulator_colors.exit_code_error.emphasis_0).bold()
},
None => ansi_term::Style::new(), None => ansi_term::Style::new(),
}; };
let red = match self.terminal_emulator_colors { let red = match self.terminal_emulator_colors {
Some(terminal_emulator_colors) => style!(terminal_emulator_colors.red).bold(), Some(terminal_emulator_colors) => {
style!(terminal_emulator_colors.exit_code_error.base).bold()
},
None => ansi_term::Style::new(), None => ansi_term::Style::new(),
}; };
let bold = ansi_term::Style::new().bold().italic(); let bold = ansi_term::Style::new().bold().italic();

View file

@ -127,7 +127,7 @@ impl PaneFrame {
self.color = Some(color); self.color = Some(color);
} }
fn client_cursor(&self, client_id: ClientId) -> Vec<TerminalCharacter> { fn client_cursor(&self, client_id: ClientId) -> Vec<TerminalCharacter> {
let color = client_id_to_colors(client_id, self.style.colors); let color = client_id_to_colors(client_id, self.style.colors.multiplayer_user_colors);
background_color(" ", color.map(|c| c.0)) background_color(" ", color.map(|c| c.0))
} }
fn get_corner(&self, corner: &'static str) -> &'static str { fn get_corner(&self, corner: &'static str) -> &'static str {
@ -847,9 +847,9 @@ impl PaneFrame {
let exited_text = "EXIT CODE: "; let exited_text = "EXIT CODE: ";
let exit_code_text = format!("{}", exit_code); let exit_code_text = format!("{}", exit_code);
let exit_code_color = if exit_code == 0 { let exit_code_color = if exit_code == 0 {
self.style.colors.green self.style.colors.exit_code_success.base
} else { } else {
self.style.colors.red self.style.colors.exit_code_error.base
}; };
let right_bracket = " ] "; let right_bracket = " ] ";
first_part.append(&mut foreground_color(left_bracket, self.color)); first_part.append(&mut foreground_color(left_bracket, self.color));
@ -875,7 +875,7 @@ impl PaneFrame {
first_part.append(&mut foreground_color(left_bracket, self.color)); first_part.append(&mut foreground_color(left_bracket, self.color));
first_part.append(&mut foreground_color( first_part.append(&mut foreground_color(
exited_text, exited_text,
Some(self.style.colors.red), Some(self.style.colors.exit_code_error.base),
)); ));
first_part.append(&mut foreground_color(right_bracket, self.color)); first_part.append(&mut foreground_color(right_bracket, self.color));
( (
@ -910,7 +910,7 @@ impl PaneFrame {
second_part.append(&mut foreground_color(left_enter_bracket, self.color)); second_part.append(&mut foreground_color(left_enter_bracket, self.color));
second_part.append(&mut foreground_color( second_part.append(&mut foreground_color(
enter_text, enter_text,
Some(self.style.colors.orange), Some(self.style.colors.text_unselected.emphasis_0),
)); ));
second_part.append(&mut foreground_color(right_enter_bracket, self.color)); second_part.append(&mut foreground_color(right_enter_bracket, self.color));
second_part.append(&mut foreground_color(enter_tip, self.color)); second_part.append(&mut foreground_color(enter_tip, self.color));
@ -918,7 +918,7 @@ impl PaneFrame {
second_part.append(&mut foreground_color(left_esc_bracket, self.color)); second_part.append(&mut foreground_color(left_esc_bracket, self.color));
second_part.append(&mut foreground_color( second_part.append(&mut foreground_color(
esc_text, esc_text,
Some(self.style.colors.orange), Some(self.style.colors.text_unselected.emphasis_0),
)); ));
second_part.append(&mut foreground_color(right_esc_bracket, self.color)); second_part.append(&mut foreground_color(right_esc_bracket, self.color));
second_part.append(&mut foreground_color(esc_tip, self.color)); second_part.append(&mut foreground_color(esc_tip, self.color));
@ -926,7 +926,7 @@ impl PaneFrame {
second_part.append(&mut foreground_color(left_break_bracket, self.color)); second_part.append(&mut foreground_color(left_break_bracket, self.color));
second_part.append(&mut foreground_color( second_part.append(&mut foreground_color(
break_text, break_text,
Some(self.style.colors.orange), Some(self.style.colors.text_unselected.emphasis_0),
)); ));
second_part.append(&mut foreground_color(right_break_bracket, self.color)); second_part.append(&mut foreground_color(right_break_bracket, self.color));
second_part.append(&mut foreground_color(break_tip, self.color)); second_part.append(&mut foreground_color(break_tip, self.color));

View file

@ -5,9 +5,7 @@ use crate::ui::boundaries::Boundaries;
use crate::ui::pane_boundaries_frame::FrameParams; use crate::ui::pane_boundaries_frame::FrameParams;
use crate::ClientId; use crate::ClientId;
use std::collections::HashMap; use std::collections::HashMap;
use zellij_utils::data::{ use zellij_utils::data::{client_id_to_colors, InputMode, PaletteColor, Style};
client_id_to_colors, single_client_color, InputMode, PaletteColor, Style,
};
use zellij_utils::errors::prelude::*; use zellij_utils::errors::prelude::*;
pub struct PaneContentsAndUi<'a> { pub struct PaneContentsAndUi<'a> {
pane: &'a mut Box<dyn Pane>, pane: &'a mut Box<dyn Pane>,
@ -139,7 +137,10 @@ impl<'a> PaneContentsAndUi<'a> {
.with_context(|| { .with_context(|| {
format!("failed to render fake cursor if needed for client {client_id}") format!("failed to render fake cursor if needed for client {client_id}")
})?; })?;
if let Some(colors) = client_id_to_colors(*fake_cursor_client_id, self.style.colors) { if let Some(colors) = client_id_to_colors(
*fake_cursor_client_id,
self.style.colors.multiplayer_user_colors,
) {
let cursor_is_visible = self let cursor_is_visible = self
.pane .pane
.cursor_coordinates() .cursor_coordinates()
@ -276,17 +277,19 @@ impl<'a> PaneContentsAndUi<'a> {
match mode { match mode {
InputMode::Normal | InputMode::Locked => { InputMode::Normal | InputMode::Locked => {
if session_is_mirrored || !self.multiple_users_exist_in_session { if session_is_mirrored || !self.multiple_users_exist_in_session {
let colors = single_client_color(self.style.colors); // mirrored sessions only have one focused color Some(self.style.colors.frame_selected.base)
Some(colors.0)
} else { } else {
let colors = client_id_to_colors(client_id, self.style.colors); let colors = client_id_to_colors(
client_id,
self.style.colors.multiplayer_user_colors,
);
colors.map(|colors| colors.0) colors.map(|colors| colors.0)
} }
}, },
_ => Some(self.style.colors.orange), _ => Some(self.style.colors.frame_highlight.base),
} }
} else { } else {
None self.style.colors.frame_unselected.map(|frame| frame.base)
} }
} }
} }

View file

@ -1,12 +1,15 @@
#[allow(clippy::derive_partial_eq_without_eq)] #[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)] #[derive(Clone, PartialEq, ::prost::Message)]
pub struct Style { pub struct Style {
#[deprecated]
#[prost(message, optional, tag = "1")] #[prost(message, optional, tag = "1")]
pub palette: ::core::option::Option<Palette>, pub palette: ::core::option::Option<Palette>,
#[prost(bool, tag = "2")] #[prost(bool, tag = "2")]
pub rounded_corners: bool, pub rounded_corners: bool,
#[prost(bool, tag = "3")] #[prost(bool, tag = "3")]
pub hide_session_name: bool, pub hide_session_name: bool,
#[prost(message, optional, tag = "4")]
pub styling: ::core::option::Option<Styling>,
} }
#[allow(clippy::derive_partial_eq_without_eq)] #[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)] #[derive(Clone, PartialEq, ::prost::Message)]
@ -77,6 +80,40 @@ pub struct RgbColorPayload {
#[prost(uint32, tag = "3")] #[prost(uint32, tag = "3")]
pub blue: u32, pub blue: u32,
} }
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Styling {
#[prost(message, repeated, tag = "1")]
pub text_unselected: ::prost::alloc::vec::Vec<Color>,
#[prost(message, repeated, tag = "2")]
pub text_selected: ::prost::alloc::vec::Vec<Color>,
#[prost(message, repeated, tag = "3")]
pub ribbon_unselected: ::prost::alloc::vec::Vec<Color>,
#[prost(message, repeated, tag = "4")]
pub ribbon_selected: ::prost::alloc::vec::Vec<Color>,
#[prost(message, repeated, tag = "5")]
pub table_title: ::prost::alloc::vec::Vec<Color>,
#[prost(message, repeated, tag = "6")]
pub table_cell_unselected: ::prost::alloc::vec::Vec<Color>,
#[prost(message, repeated, tag = "7")]
pub table_cell_selected: ::prost::alloc::vec::Vec<Color>,
#[prost(message, repeated, tag = "8")]
pub list_unselected: ::prost::alloc::vec::Vec<Color>,
#[prost(message, repeated, tag = "9")]
pub list_selected: ::prost::alloc::vec::Vec<Color>,
#[prost(message, repeated, tag = "10")]
pub frame_unselected: ::prost::alloc::vec::Vec<Color>,
#[prost(message, repeated, tag = "11")]
pub frame_selected: ::prost::alloc::vec::Vec<Color>,
#[prost(message, repeated, tag = "12")]
pub frame_highlight: ::prost::alloc::vec::Vec<Color>,
#[prost(message, repeated, tag = "13")]
pub exit_code_success: ::prost::alloc::vec::Vec<Color>,
#[prost(message, repeated, tag = "14")]
pub exit_code_error: ::prost::alloc::vec::Vec<Color>,
#[prost(message, repeated, tag = "15")]
pub multiplayer_user_colors: ::prost::alloc::vec::Vec<Color>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)] #[repr(i32)]
pub enum ColorType { pub enum ColorType {

View file

@ -2,6 +2,7 @@ use crate::input::actions::Action;
use crate::input::config::ConversionError; use crate::input::config::ConversionError;
use crate::input::keybinds::Keybinds; use crate::input::keybinds::Keybinds;
use crate::input::layout::{RunPlugin, SplitSize}; use crate::input::layout::{RunPlugin, SplitSize};
use crate::shared::colors as default_colors;
use clap::ArgEnum; use clap::ArgEnum;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
@ -22,20 +23,21 @@ pub type ClientId = u16; // TODO: merge with crate type?
pub fn client_id_to_colors( pub fn client_id_to_colors(
client_id: ClientId, client_id: ClientId,
colors: Palette, colors: MultiplayerColors,
) -> Option<(PaletteColor, PaletteColor)> { ) -> Option<(PaletteColor, PaletteColor)> {
// (primary color, secondary color) // (primary color, secondary color)
let black = PaletteColor::EightBit(default_colors::BLACK);
match client_id { match client_id {
1 => Some((colors.magenta, colors.black)), 1 => Some((colors.player_1, black)),
2 => Some((colors.blue, colors.black)), 2 => Some((colors.player_2, black)),
3 => Some((colors.purple, colors.black)), 3 => Some((colors.player_3, black)),
4 => Some((colors.yellow, colors.black)), 4 => Some((colors.player_4, black)),
5 => Some((colors.cyan, colors.black)), 5 => Some((colors.player_5, black)),
6 => Some((colors.gold, colors.black)), 6 => Some((colors.player_6, black)),
7 => Some((colors.red, colors.black)), 7 => Some((colors.player_7, black)),
8 => Some((colors.silver, colors.black)), 8 => Some((colors.player_8, black)),
9 => Some((colors.pink, colors.black)), 9 => Some((colors.player_9, black)),
10 => Some((colors.brown, colors.black)), 10 => Some((colors.player_10, black)),
_ => None, _ => None,
} }
} }
@ -1133,11 +1135,349 @@ pub struct Palette {
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default, Serialize, Deserialize)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default, Serialize, Deserialize)]
pub struct Style { pub struct Style {
pub colors: Palette, pub colors: Styling,
pub rounded_corners: bool, pub rounded_corners: bool,
pub hide_session_name: bool, pub hide_session_name: bool,
} }
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
pub enum Coloration {
NoStyling,
Styled(StyleDeclaration),
}
impl Coloration {
pub fn with_fallback(&self, fallback: StyleDeclaration) -> StyleDeclaration {
match &self {
Coloration::NoStyling => fallback,
Coloration::Styled(style) => *style,
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
pub struct Styling {
pub text_unselected: StyleDeclaration,
pub text_selected: StyleDeclaration,
pub ribbon_unselected: StyleDeclaration,
pub ribbon_selected: StyleDeclaration,
pub table_title: StyleDeclaration,
pub table_cell_unselected: StyleDeclaration,
pub table_cell_selected: StyleDeclaration,
pub list_unselected: StyleDeclaration,
pub list_selected: StyleDeclaration,
pub frame_unselected: Option<StyleDeclaration>,
pub frame_selected: StyleDeclaration,
pub frame_highlight: StyleDeclaration,
pub exit_code_success: StyleDeclaration,
pub exit_code_error: StyleDeclaration,
pub multiplayer_user_colors: MultiplayerColors,
}
#[derive(Debug, Copy, Default, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
pub struct StyleDeclaration {
pub base: PaletteColor,
pub background: PaletteColor,
pub emphasis_0: PaletteColor,
pub emphasis_1: PaletteColor,
pub emphasis_2: PaletteColor,
pub emphasis_3: PaletteColor,
}
#[derive(Debug, Copy, Default, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
pub struct MultiplayerColors {
pub player_1: PaletteColor,
pub player_2: PaletteColor,
pub player_3: PaletteColor,
pub player_4: PaletteColor,
pub player_5: PaletteColor,
pub player_6: PaletteColor,
pub player_7: PaletteColor,
pub player_8: PaletteColor,
pub player_9: PaletteColor,
pub player_10: PaletteColor,
}
pub const DEFAULT_STYLES: Styling = Styling {
text_unselected: StyleDeclaration {
base: PaletteColor::EightBit(default_colors::BRIGHT_GRAY),
emphasis_0: PaletteColor::EightBit(default_colors::ORANGE),
emphasis_1: PaletteColor::EightBit(default_colors::CYAN),
emphasis_2: PaletteColor::EightBit(default_colors::GREEN),
emphasis_3: PaletteColor::EightBit(default_colors::MAGENTA),
background: PaletteColor::EightBit(default_colors::GRAY),
},
text_selected: StyleDeclaration {
base: PaletteColor::EightBit(default_colors::BRIGHT_GRAY),
emphasis_0: PaletteColor::EightBit(default_colors::ORANGE),
emphasis_1: PaletteColor::EightBit(default_colors::CYAN),
emphasis_2: PaletteColor::EightBit(default_colors::GREEN),
emphasis_3: PaletteColor::EightBit(default_colors::MAGENTA),
background: PaletteColor::EightBit(default_colors::GRAY),
},
ribbon_unselected: StyleDeclaration {
base: PaletteColor::EightBit(default_colors::BLACK),
emphasis_0: PaletteColor::EightBit(default_colors::RED),
emphasis_1: PaletteColor::EightBit(default_colors::WHITE),
emphasis_2: PaletteColor::EightBit(default_colors::BLUE),
emphasis_3: PaletteColor::EightBit(default_colors::MAGENTA),
background: PaletteColor::EightBit(default_colors::GRAY),
},
ribbon_selected: StyleDeclaration {
base: PaletteColor::EightBit(default_colors::BLACK),
emphasis_0: PaletteColor::EightBit(default_colors::RED),
emphasis_1: PaletteColor::EightBit(default_colors::ORANGE),
emphasis_2: PaletteColor::EightBit(default_colors::MAGENTA),
emphasis_3: PaletteColor::EightBit(default_colors::BLUE),
background: PaletteColor::EightBit(default_colors::GREEN),
},
exit_code_success: StyleDeclaration {
base: PaletteColor::EightBit(default_colors::GREEN),
emphasis_0: PaletteColor::EightBit(default_colors::CYAN),
emphasis_1: PaletteColor::EightBit(default_colors::BLACK),
emphasis_2: PaletteColor::EightBit(default_colors::MAGENTA),
emphasis_3: PaletteColor::EightBit(default_colors::BLUE),
background: PaletteColor::EightBit(default_colors::GRAY),
},
exit_code_error: StyleDeclaration {
base: PaletteColor::EightBit(default_colors::RED),
emphasis_0: PaletteColor::EightBit(default_colors::YELLOW),
emphasis_1: PaletteColor::EightBit(default_colors::GOLD),
emphasis_2: PaletteColor::EightBit(default_colors::SILVER),
emphasis_3: PaletteColor::EightBit(default_colors::PURPLE),
background: PaletteColor::EightBit(default_colors::GRAY),
},
frame_unselected: None,
frame_selected: StyleDeclaration {
base: PaletteColor::EightBit(default_colors::GREEN),
emphasis_0: PaletteColor::EightBit(default_colors::ORANGE),
emphasis_1: PaletteColor::EightBit(default_colors::CYAN),
emphasis_2: PaletteColor::EightBit(default_colors::MAGENTA),
emphasis_3: PaletteColor::EightBit(default_colors::BROWN),
background: PaletteColor::EightBit(default_colors::GRAY),
},
frame_highlight: StyleDeclaration {
base: PaletteColor::EightBit(default_colors::ORANGE),
emphasis_0: PaletteColor::EightBit(default_colors::GREEN),
emphasis_1: PaletteColor::EightBit(default_colors::GREEN),
emphasis_2: PaletteColor::EightBit(default_colors::GREEN),
emphasis_3: PaletteColor::EightBit(default_colors::GREEN),
background: PaletteColor::EightBit(default_colors::GREEN),
},
table_title: StyleDeclaration {
base: PaletteColor::EightBit(default_colors::GREEN),
emphasis_0: PaletteColor::EightBit(default_colors::ORANGE),
emphasis_1: PaletteColor::EightBit(default_colors::CYAN),
emphasis_2: PaletteColor::EightBit(default_colors::GREEN),
emphasis_3: PaletteColor::EightBit(default_colors::MAGENTA),
background: PaletteColor::EightBit(default_colors::GRAY),
},
table_cell_unselected: StyleDeclaration {
base: PaletteColor::EightBit(default_colors::BRIGHT_GRAY),
emphasis_0: PaletteColor::EightBit(default_colors::ORANGE),
emphasis_1: PaletteColor::EightBit(default_colors::CYAN),
emphasis_2: PaletteColor::EightBit(default_colors::GREEN),
emphasis_3: PaletteColor::EightBit(default_colors::MAGENTA),
background: PaletteColor::EightBit(default_colors::GRAY),
},
table_cell_selected: StyleDeclaration {
base: PaletteColor::EightBit(default_colors::GREEN),
emphasis_0: PaletteColor::EightBit(default_colors::ORANGE),
emphasis_1: PaletteColor::EightBit(default_colors::CYAN),
emphasis_2: PaletteColor::EightBit(default_colors::RED),
emphasis_3: PaletteColor::EightBit(default_colors::MAGENTA),
background: PaletteColor::EightBit(default_colors::GRAY),
},
list_unselected: StyleDeclaration {
base: PaletteColor::EightBit(default_colors::BRIGHT_GRAY),
emphasis_0: PaletteColor::EightBit(default_colors::ORANGE),
emphasis_1: PaletteColor::EightBit(default_colors::CYAN),
emphasis_2: PaletteColor::EightBit(default_colors::GREEN),
emphasis_3: PaletteColor::EightBit(default_colors::MAGENTA),
background: PaletteColor::EightBit(default_colors::GRAY),
},
list_selected: StyleDeclaration {
base: PaletteColor::EightBit(default_colors::GREEN),
emphasis_0: PaletteColor::EightBit(default_colors::ORANGE),
emphasis_1: PaletteColor::EightBit(default_colors::CYAN),
emphasis_2: PaletteColor::EightBit(default_colors::RED),
emphasis_3: PaletteColor::EightBit(default_colors::MAGENTA),
background: PaletteColor::EightBit(default_colors::GRAY),
},
multiplayer_user_colors: MultiplayerColors {
player_1: PaletteColor::EightBit(default_colors::MAGENTA),
player_2: PaletteColor::EightBit(default_colors::BLUE),
player_3: PaletteColor::EightBit(default_colors::PURPLE),
player_4: PaletteColor::EightBit(default_colors::YELLOW),
player_5: PaletteColor::EightBit(default_colors::CYAN),
player_6: PaletteColor::EightBit(default_colors::GOLD),
player_7: PaletteColor::EightBit(default_colors::RED),
player_8: PaletteColor::EightBit(default_colors::SILVER),
player_9: PaletteColor::EightBit(default_colors::PINK),
player_10: PaletteColor::EightBit(default_colors::BROWN),
},
};
impl Default for Styling {
fn default() -> Self {
DEFAULT_STYLES
}
}
impl From<Styling> for Palette {
fn from(styling: Styling) -> Self {
Palette {
theme_hue: ThemeHue::Dark,
source: PaletteSource::Default,
fg: styling.ribbon_unselected.background,
bg: styling.text_unselected.background,
red: styling.exit_code_error.base,
green: styling.text_unselected.emphasis_2,
yellow: styling.exit_code_error.emphasis_0,
blue: styling.ribbon_unselected.emphasis_2,
magenta: styling.text_unselected.emphasis_3,
orange: styling.text_unselected.emphasis_0,
cyan: styling.text_unselected.emphasis_1,
black: styling.ribbon_unselected.base,
white: styling.ribbon_unselected.emphasis_1,
gray: styling.list_unselected.background,
purple: styling.multiplayer_user_colors.player_3,
gold: styling.multiplayer_user_colors.player_6,
silver: styling.multiplayer_user_colors.player_8,
pink: styling.multiplayer_user_colors.player_9,
brown: styling.multiplayer_user_colors.player_10,
}
}
}
impl From<Palette> for Styling {
fn from(palette: Palette) -> Self {
let (fg, bg) = match palette.theme_hue {
ThemeHue::Light => (palette.black, palette.white),
ThemeHue::Dark => (palette.white, palette.black),
};
Styling {
text_unselected: StyleDeclaration {
base: fg,
emphasis_0: palette.orange,
emphasis_1: palette.cyan,
emphasis_2: palette.green,
emphasis_3: palette.magenta,
background: bg,
},
text_selected: StyleDeclaration {
base: fg,
emphasis_0: palette.orange,
emphasis_1: palette.cyan,
emphasis_2: palette.green,
emphasis_3: palette.magenta,
background: palette.bg,
},
ribbon_unselected: StyleDeclaration {
base: palette.black,
emphasis_0: palette.red,
emphasis_1: palette.white,
emphasis_2: palette.blue,
emphasis_3: palette.magenta,
background: palette.fg,
},
ribbon_selected: StyleDeclaration {
base: palette.black,
emphasis_0: palette.red,
emphasis_1: palette.orange,
emphasis_2: palette.magenta,
emphasis_3: palette.blue,
background: palette.green,
},
exit_code_success: StyleDeclaration {
base: palette.green,
emphasis_0: palette.cyan,
emphasis_1: palette.black,
emphasis_2: palette.magenta,
emphasis_3: palette.blue,
background: Default::default(),
},
exit_code_error: StyleDeclaration {
base: palette.red,
emphasis_0: palette.yellow,
emphasis_1: palette.gold,
emphasis_2: palette.silver,
emphasis_3: palette.purple,
background: Default::default(),
},
frame_unselected: None,
frame_selected: StyleDeclaration {
base: palette.green,
emphasis_0: palette.orange,
emphasis_1: palette.cyan,
emphasis_2: palette.magenta,
emphasis_3: palette.brown,
background: Default::default(),
},
frame_highlight: StyleDeclaration {
base: palette.orange,
emphasis_0: palette.orange,
emphasis_1: palette.orange,
emphasis_2: palette.orange,
emphasis_3: palette.orange,
background: Default::default(),
},
table_title: StyleDeclaration {
base: palette.green,
emphasis_0: palette.orange,
emphasis_1: palette.cyan,
emphasis_2: palette.green,
emphasis_3: palette.magenta,
background: palette.gray,
},
table_cell_unselected: StyleDeclaration {
base: fg,
emphasis_0: palette.orange,
emphasis_1: palette.cyan,
emphasis_2: palette.green,
emphasis_3: palette.magenta,
background: palette.black,
},
table_cell_selected: StyleDeclaration {
base: fg,
emphasis_0: palette.orange,
emphasis_1: palette.cyan,
emphasis_2: palette.green,
emphasis_3: palette.magenta,
background: palette.bg,
},
list_unselected: StyleDeclaration {
base: palette.white,
emphasis_0: palette.orange,
emphasis_1: palette.cyan,
emphasis_2: palette.green,
emphasis_3: palette.magenta,
background: palette.black,
},
list_selected: StyleDeclaration {
base: palette.white,
emphasis_0: palette.orange,
emphasis_1: palette.cyan,
emphasis_2: palette.green,
emphasis_3: palette.magenta,
background: palette.bg,
},
multiplayer_user_colors: MultiplayerColors {
player_1: palette.magenta,
player_2: palette.blue,
player_3: palette.purple,
player_4: palette.yellow,
player_5: palette.cyan,
player_6: palette.gold,
player_7: palette.red,
player_8: palette.silver,
player_9: palette.pink,
player_10: palette.brown,
},
}
}
}
// FIXME: Poor devs hashtable since HashTable can't derive `Default`... // FIXME: Poor devs hashtable since HashTable can't derive `Default`...
pub type KeybindsVec = Vec<(InputMode, Vec<(KeyWithModifier, Vec<Action>)>)>; pub type KeybindsVec = Vec<(InputMode, Vec<(KeyWithModifier, Vec<Action>)>)>;
@ -1173,8 +1513,8 @@ impl ModeInfo {
pub fn update_default_mode(&mut self, new_default_mode: InputMode) { pub fn update_default_mode(&mut self, new_default_mode: InputMode) {
self.base_mode = Some(new_default_mode); self.base_mode = Some(new_default_mode);
} }
pub fn update_theme(&mut self, theme: Palette) { pub fn update_theme(&mut self, theme: Styling) {
self.style.colors = theme; self.style.colors = theme.into();
} }
pub fn update_rounded_corners(&mut self, rounded_corners: bool) { pub fn update_rounded_corners(&mut self, rounded_corners: bool) {
self.style.rounded_corners = rounded_corners; self.style.rounded_corners = rounded_corners;

View file

@ -1,4 +1,4 @@
use crate::data::Palette; use crate::data::Styling;
use miette::{Diagnostic, LabeledSpan, NamedSource, SourceCode}; use miette::{Diagnostic, LabeledSpan, NamedSource, SourceCode};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::HashSet; use std::collections::HashSet;
@ -166,7 +166,7 @@ impl TryFrom<&CliArgs> for Config {
} }
impl Config { impl Config {
pub fn theme_config(&self, theme_name: Option<&String>) -> Option<Palette> { pub fn theme_config(&self, theme_name: Option<&String>) -> Option<Styling> {
match &theme_name { match &theme_name {
Some(theme_name) => self.themes.get_theme(theme_name).map(|theme| theme.palette), Some(theme_name) => self.themes.get_theme(theme_name).map(|theme| theme.palette),
None => self.themes.get_theme("default").map(|theme| theme.palette), None => self.themes.get_theme("default").map(|theme| theme.palette),
@ -407,8 +407,8 @@ impl Config {
#[cfg(test)] #[cfg(test)]
mod config_test { mod config_test {
use super::*; use super::*;
use crate::data::{InputMode, Palette, PaletteColor}; use crate::data::{InputMode, Palette, PaletteColor, PluginTag, StyleDeclaration, Styling};
use crate::input::layout::RunPlugin; use crate::input::layout::{RunPlugin, RunPluginLocation};
use crate::input::options::{Clipboard, OnForceClose}; use crate::input::options::{Clipboard, OnForceClose};
use crate::input::theme::{FrameConfig, Theme, Themes, UiConfig}; use crate::input::theme::{FrameConfig, Theme, Themes, UiConfig};
use std::collections::{BTreeMap, HashMap}; use std::collections::{BTreeMap, HashMap};
@ -630,7 +630,8 @@ mod config_test {
black: PaletteColor::Rgb((0, 0, 0)), black: PaletteColor::Rgb((0, 0, 0)),
white: PaletteColor::Rgb((255, 255, 255)), white: PaletteColor::Rgb((255, 255, 255)),
..Default::default() ..Default::default()
}, }
.into(),
sourced_from_external_file: false, sourced_from_external_file: false,
}, },
); );
@ -688,7 +689,8 @@ mod config_test {
black: PaletteColor::Rgb((0, 0, 0)), black: PaletteColor::Rgb((0, 0, 0)),
white: PaletteColor::Rgb((255, 255, 255)), white: PaletteColor::Rgb((255, 255, 255)),
..Default::default() ..Default::default()
}, }
.into(),
sourced_from_external_file: false, sourced_from_external_file: false,
}, },
); );
@ -708,7 +710,8 @@ mod config_test {
white: PaletteColor::Rgb((229, 233, 240)), white: PaletteColor::Rgb((229, 233, 240)),
orange: PaletteColor::Rgb((208, 135, 112)), orange: PaletteColor::Rgb((208, 135, 112)),
..Default::default() ..Default::default()
}, }
.into(),
sourced_from_external_file: false, sourced_from_external_file: false,
}, },
); );
@ -753,7 +756,8 @@ mod config_test {
black: PaletteColor::EightBit(1), black: PaletteColor::EightBit(1),
white: PaletteColor::EightBit(255), white: PaletteColor::EightBit(255),
..Default::default() ..Default::default()
}, }
.into(),
sourced_from_external_file: false, sourced_from_external_file: false,
}, },
); );
@ -761,6 +765,304 @@ mod config_test {
assert_eq!(config.themes, expected_themes, "Theme defined in config"); assert_eq!(config.themes, expected_themes, "Theme defined in config");
} }
#[test]
fn can_define_style_for_theme_with_hex() {
let config_contents = r##"
themes {
named_theme {
text_unselected {
base "#DCD7BA"
emphasis_0 "#DCD7CD"
emphasis_1 "#DCD8DD"
emphasis_2 "#DCD899"
emphasis_3 "#ACD7CD"
background "#1F1F28"
}
text_selected {
base "#16161D"
emphasis_0 "#16161D"
emphasis_1 "#16161D"
emphasis_2 "#16161D"
emphasis_3 "#16161D"
background "#9CABCA"
}
ribbon_unselected {
base "#DCD7BA"
emphasis_0 "#7FB4CA"
emphasis_1 "#A3D4D5"
emphasis_2 "#7AA89F"
emphasis_3 "#DCD819"
background "#252535"
}
ribbon_selected {
base "#16161D"
emphasis_0 "#181820"
emphasis_1 "#1A1A22"
emphasis_2 "#2A2A37"
emphasis_3 "#363646"
background "#76946A"
}
table_title {
base "#DCD7BA"
emphasis_0 "#7FB4CA"
emphasis_1 "#A3D4D5"
emphasis_2 "#7AA89F"
emphasis_3 "#DCD819"
background "#252535"
}
table_cell_unselected {
base "#DCD7BA"
emphasis_0 "#DCD7CD"
emphasis_1 "#DCD8DD"
emphasis_2 "#DCD899"
emphasis_3 "#ACD7CD"
background "#1F1F28"
}
table_cell_selected {
base "#16161D"
emphasis_0 "#181820"
emphasis_1 "#1A1A22"
emphasis_2 "#2A2A37"
emphasis_3 "#363646"
background "#76946A"
}
list_unselected {
base "#DCD7BA"
emphasis_0 "#DCD7CD"
emphasis_1 "#DCD8DD"
emphasis_2 "#DCD899"
emphasis_3 "#ACD7CD"
background "#1F1F28"
}
list_selected {
base "#16161D"
emphasis_0 "#181820"
emphasis_1 "#1A1A22"
emphasis_2 "#2A2A37"
emphasis_3 "#363646"
background "#76946A"
}
frame_unselected {
base "#DCD8DD"
emphasis_0 "#7FB4CA"
emphasis_1 "#A3D4D5"
emphasis_2 "#7AA89F"
emphasis_3 "#DCD819"
}
frame_selected {
base "#76946A"
emphasis_0 "#C34043"
emphasis_1 "#C8C093"
emphasis_2 "#ACD7CD"
emphasis_3 "#DCD819"
}
exit_code_success {
base "#76946A"
emphasis_0 "#76946A"
emphasis_1 "#76946A"
emphasis_2 "#76946A"
emphasis_3 "#76946A"
}
exit_code_error {
base "#C34043"
emphasis_0 "#C34043"
emphasis_1 "#C34043"
emphasis_2 "#C34043"
emphasis_3 "#C34043"
}
}
}
"##;
let config = Config::from_kdl(config_contents, None).unwrap();
let mut expected_themes = HashMap::new();
expected_themes.insert(
"named_theme".into(),
Theme {
sourced_from_external_file: false,
palette: Styling {
text_unselected: StyleDeclaration {
base: PaletteColor::Rgb((220, 215, 186)),
emphasis_0: PaletteColor::Rgb((220, 215, 205)),
emphasis_1: PaletteColor::Rgb((220, 216, 221)),
emphasis_2: PaletteColor::Rgb((220, 216, 153)),
emphasis_3: PaletteColor::Rgb((172, 215, 205)),
background: PaletteColor::Rgb((31, 31, 40)),
},
text_selected: StyleDeclaration {
base: PaletteColor::Rgb((22, 22, 29)),
emphasis_0: PaletteColor::Rgb((22, 22, 29)),
emphasis_1: PaletteColor::Rgb((22, 22, 29)),
emphasis_2: PaletteColor::Rgb((22, 22, 29)),
emphasis_3: PaletteColor::Rgb((22, 22, 29)),
background: PaletteColor::Rgb((156, 171, 202)),
},
ribbon_unselected: StyleDeclaration {
base: PaletteColor::Rgb((220, 215, 186)),
emphasis_0: PaletteColor::Rgb((127, 180, 202)),
emphasis_1: PaletteColor::Rgb((163, 212, 213)),
emphasis_2: PaletteColor::Rgb((122, 168, 159)),
emphasis_3: PaletteColor::Rgb((220, 216, 25)),
background: PaletteColor::Rgb((37, 37, 53)),
},
ribbon_selected: StyleDeclaration {
base: PaletteColor::Rgb((22, 22, 29)),
emphasis_0: PaletteColor::Rgb((24, 24, 32)),
emphasis_1: PaletteColor::Rgb((26, 26, 34)),
emphasis_2: PaletteColor::Rgb((42, 42, 55)),
emphasis_3: PaletteColor::Rgb((54, 54, 70)),
background: PaletteColor::Rgb((118, 148, 106)),
},
table_title: StyleDeclaration {
base: PaletteColor::Rgb((220, 215, 186)),
emphasis_0: PaletteColor::Rgb((127, 180, 202)),
emphasis_1: PaletteColor::Rgb((163, 212, 213)),
emphasis_2: PaletteColor::Rgb((122, 168, 159)),
emphasis_3: PaletteColor::Rgb((220, 216, 25)),
background: PaletteColor::Rgb((37, 37, 53)),
},
table_cell_unselected: StyleDeclaration {
base: PaletteColor::Rgb((220, 215, 186)),
emphasis_0: PaletteColor::Rgb((220, 215, 205)),
emphasis_1: PaletteColor::Rgb((220, 216, 221)),
emphasis_2: PaletteColor::Rgb((220, 216, 153)),
emphasis_3: PaletteColor::Rgb((172, 215, 205)),
background: PaletteColor::Rgb((31, 31, 40)),
},
table_cell_selected: StyleDeclaration {
base: PaletteColor::Rgb((22, 22, 29)),
emphasis_0: PaletteColor::Rgb((24, 24, 32)),
emphasis_1: PaletteColor::Rgb((26, 26, 34)),
emphasis_2: PaletteColor::Rgb((42, 42, 55)),
emphasis_3: PaletteColor::Rgb((54, 54, 70)),
background: PaletteColor::Rgb((118, 148, 106)),
},
list_unselected: StyleDeclaration {
base: PaletteColor::Rgb((220, 215, 186)),
emphasis_0: PaletteColor::Rgb((220, 215, 205)),
emphasis_1: PaletteColor::Rgb((220, 216, 221)),
emphasis_2: PaletteColor::Rgb((220, 216, 153)),
emphasis_3: PaletteColor::Rgb((172, 215, 205)),
background: PaletteColor::Rgb((31, 31, 40)),
},
list_selected: StyleDeclaration {
base: PaletteColor::Rgb((22, 22, 29)),
emphasis_0: PaletteColor::Rgb((24, 24, 32)),
emphasis_1: PaletteColor::Rgb((26, 26, 34)),
emphasis_2: PaletteColor::Rgb((42, 42, 55)),
emphasis_3: PaletteColor::Rgb((54, 54, 70)),
background: PaletteColor::Rgb((118, 148, 106)),
},
frame_unselected: Some(StyleDeclaration {
base: PaletteColor::Rgb((220, 216, 221)),
emphasis_0: PaletteColor::Rgb((127, 180, 202)),
emphasis_1: PaletteColor::Rgb((163, 212, 213)),
emphasis_2: PaletteColor::Rgb((122, 168, 159)),
emphasis_3: PaletteColor::Rgb((220, 216, 25)),
..Default::default()
}),
frame_selected: StyleDeclaration {
base: PaletteColor::Rgb((118, 148, 106)),
emphasis_0: PaletteColor::Rgb((195, 64, 67)),
emphasis_1: PaletteColor::Rgb((200, 192, 147)),
emphasis_2: PaletteColor::Rgb((172, 215, 205)),
emphasis_3: PaletteColor::Rgb((220, 216, 25)),
..Default::default()
},
exit_code_success: StyleDeclaration {
base: PaletteColor::Rgb((118, 148, 106)),
emphasis_0: PaletteColor::Rgb((118, 148, 106)),
emphasis_1: PaletteColor::Rgb((118, 148, 106)),
emphasis_2: PaletteColor::Rgb((118, 148, 106)),
emphasis_3: PaletteColor::Rgb((118, 148, 106)),
..Default::default()
},
exit_code_error: StyleDeclaration {
base: PaletteColor::Rgb((195, 64, 67)),
emphasis_0: PaletteColor::Rgb((195, 64, 67)),
emphasis_1: PaletteColor::Rgb((195, 64, 67)),
emphasis_2: PaletteColor::Rgb((195, 64, 67)),
emphasis_3: PaletteColor::Rgb((195, 64, 67)),
..Default::default()
},
..Default::default()
},
},
);
let expected_themes = Themes::from_data(expected_themes);
assert_eq!(config.themes, expected_themes, "Theme defined in config")
}
#[test]
fn omitting_required_style_errors() {
let config_contents = r##"
themes {
named_theme {
text_unselected {
base "#DCD7BA"
emphasis_1 "#DCD8DD"
emphasis_2 "#DCD899"
emphasis_3 "#ACD7CD"
background "#1F1F28"
}
}
}
"##;
let config = Config::from_kdl(config_contents, None);
assert!(config.is_err());
if let Err(ConfigError::KdlError(KdlError {
error_message,
src: _,
offset: _,
len: _,
help_message: _,
})) = config
{
assert_eq!(error_message, "Missing theme color: emphasis_0")
}
}
#[test]
fn partial_declaration_of_styles_defaults_omitted() {
let config_contents = r##"
themes {
named_theme {
text_unselected {
base "#DCD7BA"
emphasis_0 "#DCD7CD"
emphasis_1 "#DCD8DD"
emphasis_2 "#DCD899"
emphasis_3 "#ACD7CD"
background "#1F1F28"
}
}
}
"##;
let config = Config::from_kdl(config_contents, None).unwrap();
let mut expected_themes = HashMap::new();
expected_themes.insert(
"named_theme".into(),
Theme {
sourced_from_external_file: false,
palette: Styling {
text_unselected: StyleDeclaration {
base: PaletteColor::Rgb((220, 215, 186)),
emphasis_0: PaletteColor::Rgb((220, 215, 205)),
emphasis_1: PaletteColor::Rgb((220, 216, 221)),
emphasis_2: PaletteColor::Rgb((220, 216, 153)),
emphasis_3: PaletteColor::Rgb((172, 215, 205)),
background: PaletteColor::Rgb((31, 31, 40)),
},
..Default::default()
},
},
);
let expected_themes = Themes::from_data(expected_themes);
assert_eq!(config.themes, expected_themes, "Theme defined in config")
}
#[test] #[test]
fn can_define_plugin_configuration_in_configfile() { fn can_define_plugin_configuration_in_configfile() {
let config_contents = r#" let config_contents = r#"

View file

@ -7,7 +7,7 @@ use std::{
fmt, fmt,
}; };
use crate::data::Palette; use crate::data::Styling;
#[derive(Debug, Default, Clone, Copy, PartialEq, Deserialize, Serialize)] #[derive(Debug, Default, Clone, Copy, PartialEq, Deserialize, Serialize)]
pub struct UiConfig { pub struct UiConfig {
@ -74,9 +74,9 @@ impl Themes {
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct Theme { pub struct Theme {
#[serde(flatten)]
pub palette: Palette,
pub sourced_from_external_file: bool, pub sourced_from_external_file: bool,
#[serde(flatten)]
pub palette: Styling,
} }
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]

View file

@ -1,109 +1,600 @@
--- ---
source: zellij-utils/src/input/./unit/theme_test.rs source: zellij-utils/src/input/./unit/theme_test.rs
assertion_line: 15
expression: "format!(\"{:#?}\", theme)" expression: "format!(\"{:#?}\", theme)"
--- ---
{ {
"dracula": Theme { "dracula": Theme {
palette: Palette {
source: Default,
theme_hue: Dark,
fg: Rgb(
(
248,
248,
242,
),
),
bg: Rgb(
(
40,
42,
54,
),
),
black: Rgb(
(
0,
0,
0,
),
),
red: Rgb(
(
255,
85,
85,
),
),
green: Rgb(
(
80,
250,
123,
),
),
yellow: Rgb(
(
241,
250,
140,
),
),
blue: Rgb(
(
98,
114,
164,
),
),
magenta: Rgb(
(
255,
121,
198,
),
),
cyan: Rgb(
(
139,
233,
253,
),
),
white: Rgb(
(
255,
255,
255,
),
),
orange: Rgb(
(
255,
184,
108,
),
),
gray: EightBit(
0,
),
purple: EightBit(
0,
),
gold: EightBit(
0,
),
silver: EightBit(
0,
),
pink: EightBit(
0,
),
brown: EightBit(
0,
),
},
sourced_from_external_file: true, sourced_from_external_file: true,
palette: Styling {
text_unselected: StyleDeclaration {
base: Rgb(
(
255,
255,
255,
),
),
background: Rgb(
(
0,
0,
0,
),
),
emphasis_0: Rgb(
(
255,
184,
108,
),
),
emphasis_1: Rgb(
(
139,
233,
253,
),
),
emphasis_2: Rgb(
(
80,
250,
123,
),
),
emphasis_3: Rgb(
(
255,
121,
198,
),
),
},
text_selected: StyleDeclaration {
base: Rgb(
(
255,
255,
255,
),
),
background: Rgb(
(
40,
42,
54,
),
),
emphasis_0: Rgb(
(
255,
184,
108,
),
),
emphasis_1: Rgb(
(
139,
233,
253,
),
),
emphasis_2: Rgb(
(
80,
250,
123,
),
),
emphasis_3: Rgb(
(
255,
121,
198,
),
),
},
ribbon_unselected: StyleDeclaration {
base: Rgb(
(
0,
0,
0,
),
),
background: Rgb(
(
248,
248,
242,
),
),
emphasis_0: Rgb(
(
255,
85,
85,
),
),
emphasis_1: Rgb(
(
255,
255,
255,
),
),
emphasis_2: Rgb(
(
98,
114,
164,
),
),
emphasis_3: Rgb(
(
255,
121,
198,
),
),
},
ribbon_selected: StyleDeclaration {
base: Rgb(
(
0,
0,
0,
),
),
background: Rgb(
(
80,
250,
123,
),
),
emphasis_0: Rgb(
(
255,
85,
85,
),
),
emphasis_1: Rgb(
(
255,
184,
108,
),
),
emphasis_2: Rgb(
(
255,
121,
198,
),
),
emphasis_3: Rgb(
(
98,
114,
164,
),
),
},
table_title: StyleDeclaration {
base: Rgb(
(
80,
250,
123,
),
),
background: EightBit(
0,
),
emphasis_0: Rgb(
(
255,
184,
108,
),
),
emphasis_1: Rgb(
(
139,
233,
253,
),
),
emphasis_2: Rgb(
(
80,
250,
123,
),
),
emphasis_3: Rgb(
(
255,
121,
198,
),
),
},
table_cell_unselected: StyleDeclaration {
base: Rgb(
(
255,
255,
255,
),
),
background: Rgb(
(
0,
0,
0,
),
),
emphasis_0: Rgb(
(
255,
184,
108,
),
),
emphasis_1: Rgb(
(
139,
233,
253,
),
),
emphasis_2: Rgb(
(
80,
250,
123,
),
),
emphasis_3: Rgb(
(
255,
121,
198,
),
),
},
table_cell_selected: StyleDeclaration {
base: Rgb(
(
255,
255,
255,
),
),
background: Rgb(
(
40,
42,
54,
),
),
emphasis_0: Rgb(
(
255,
184,
108,
),
),
emphasis_1: Rgb(
(
139,
233,
253,
),
),
emphasis_2: Rgb(
(
80,
250,
123,
),
),
emphasis_3: Rgb(
(
255,
121,
198,
),
),
},
list_unselected: StyleDeclaration {
base: Rgb(
(
255,
255,
255,
),
),
background: Rgb(
(
0,
0,
0,
),
),
emphasis_0: Rgb(
(
255,
184,
108,
),
),
emphasis_1: Rgb(
(
139,
233,
253,
),
),
emphasis_2: Rgb(
(
80,
250,
123,
),
),
emphasis_3: Rgb(
(
255,
121,
198,
),
),
},
list_selected: StyleDeclaration {
base: Rgb(
(
255,
255,
255,
),
),
background: Rgb(
(
40,
42,
54,
),
),
emphasis_0: Rgb(
(
255,
184,
108,
),
),
emphasis_1: Rgb(
(
139,
233,
253,
),
),
emphasis_2: Rgb(
(
80,
250,
123,
),
),
emphasis_3: Rgb(
(
255,
121,
198,
),
),
},
frame_unselected: None,
frame_selected: StyleDeclaration {
base: Rgb(
(
80,
250,
123,
),
),
background: EightBit(
0,
),
emphasis_0: Rgb(
(
255,
184,
108,
),
),
emphasis_1: Rgb(
(
139,
233,
253,
),
),
emphasis_2: Rgb(
(
255,
121,
198,
),
),
emphasis_3: EightBit(
0,
),
},
frame_highlight: StyleDeclaration {
base: Rgb(
(
255,
184,
108,
),
),
background: EightBit(
0,
),
emphasis_0: Rgb(
(
255,
184,
108,
),
),
emphasis_1: Rgb(
(
255,
184,
108,
),
),
emphasis_2: Rgb(
(
255,
184,
108,
),
),
emphasis_3: Rgb(
(
255,
184,
108,
),
),
},
exit_code_success: StyleDeclaration {
base: Rgb(
(
80,
250,
123,
),
),
background: EightBit(
0,
),
emphasis_0: Rgb(
(
139,
233,
253,
),
),
emphasis_1: Rgb(
(
0,
0,
0,
),
),
emphasis_2: Rgb(
(
255,
121,
198,
),
),
emphasis_3: Rgb(
(
98,
114,
164,
),
),
},
exit_code_error: StyleDeclaration {
base: Rgb(
(
255,
85,
85,
),
),
background: EightBit(
0,
),
emphasis_0: Rgb(
(
241,
250,
140,
),
),
emphasis_1: EightBit(
0,
),
emphasis_2: EightBit(
0,
),
emphasis_3: EightBit(
0,
),
},
multiplayer_user_colors: MultiplayerColors {
player_1: Rgb(
(
255,
121,
198,
),
),
player_2: Rgb(
(
98,
114,
164,
),
),
player_3: EightBit(
0,
),
player_4: Rgb(
(
241,
250,
140,
),
),
player_5: Rgb(
(
139,
233,
253,
),
),
player_6: EightBit(
0,
),
player_7: Rgb(
(
255,
85,
85,
),
),
player_8: EightBit(
0,
),
player_9: EightBit(
0,
),
player_10: EightBit(
0,
),
},
},
}, },
} }

View file

@ -1,7 +1,8 @@
mod kdl_layout_parser; mod kdl_layout_parser;
use crate::data::{ use crate::data::{
BareKey, Direction, FloatingPaneCoordinates, InputMode, KeyWithModifier, LayoutInfo, Palette, BareKey, Direction, FloatingPaneCoordinates, InputMode, KeyWithModifier, LayoutInfo,
PaletteColor, PaneInfo, PaneManifest, PermissionType, Resize, SessionInfo, TabInfo, MultiplayerColors, Palette, PaletteColor, PaneInfo, PaneManifest, PermissionType, Resize,
SessionInfo, StyleDeclaration, Styling, TabInfo, DEFAULT_STYLES,
}; };
use crate::envs::EnvironmentVariables; use crate::envs::EnvironmentVariables;
use crate::home::{find_default_config_dir, get_layout_dir}; use crate::home::{find_default_config_dir, get_layout_dir};
@ -1241,6 +1242,41 @@ impl PaletteColor {
} }
} }
impl StyleDeclaration {
pub fn to_kdl(&self, declaration_name: &str) -> KdlNode {
let mut node = KdlNode::new(declaration_name);
let mut doc = KdlDocument::new();
doc.nodes_mut().push(self.base.to_kdl("base"));
doc.nodes_mut().push(self.background.to_kdl("background"));
doc.nodes_mut().push(self.emphasis_0.to_kdl("emphasis_0"));
doc.nodes_mut().push(self.emphasis_1.to_kdl("emphasis_1"));
doc.nodes_mut().push(self.emphasis_2.to_kdl("emphasis_2"));
doc.nodes_mut().push(self.emphasis_3.to_kdl("emphasis_3"));
node.set_children(doc);
node
}
}
impl MultiplayerColors {
pub fn to_kdl(&self) -> KdlNode {
let mut node = KdlNode::new("multiplayer_user_colors");
let mut doc = KdlDocument::new();
doc.nodes_mut().push(self.player_1.to_kdl("player_1"));
doc.nodes_mut().push(self.player_2.to_kdl("player_2"));
doc.nodes_mut().push(self.player_3.to_kdl("player_3"));
doc.nodes_mut().push(self.player_4.to_kdl("player_4"));
doc.nodes_mut().push(self.player_5.to_kdl("player_5"));
doc.nodes_mut().push(self.player_6.to_kdl("player_6"));
doc.nodes_mut().push(self.player_7.to_kdl("player_7"));
doc.nodes_mut().push(self.player_8.to_kdl("player_8"));
doc.nodes_mut().push(self.player_9.to_kdl("player_9"));
doc.nodes_mut().push(self.player_10.to_kdl("player_10"));
node.set_children(doc);
node
}
}
impl TryFrom<(&KdlNode, &Options)> for Action { impl TryFrom<(&KdlNode, &Options)> for Action {
type Error = ConfigError; type Error = ConfigError;
fn try_from((kdl_action, config_options): (&KdlNode, &Options)) -> Result<Self, Self::Error> { fn try_from((kdl_action, config_options): (&KdlNode, &Options)) -> Result<Self, Self::Error> {
@ -2051,6 +2087,20 @@ macro_rules! kdl_child_with_name {
}}; }};
} }
#[macro_export]
macro_rules! kdl_child_with_name_or_error {
( $kdl_node:expr, $name:expr) => {{
$kdl_node
.children()
.and_then(|children| children.nodes().iter().find(|c| c.name().value() == $name))
.ok_or(ConfigError::new_kdl_error(
format!("Missing node {}", $name).into(),
$kdl_node.span().offset(),
$kdl_node.span().len(),
))
}};
}
#[macro_export] #[macro_export]
macro_rules! kdl_get_string_property_or_child_value_with_error { macro_rules! kdl_get_string_property_or_child_value_with_error {
( $kdl_node:expr, $name:expr ) => { ( $kdl_node:expr, $name:expr ) => {
@ -3930,6 +3980,66 @@ impl UiConfig {
} }
impl Themes { impl Themes {
fn style_declaration_from_node(
style_node: &KdlNode,
style_descriptor: &str,
) -> Result<Option<StyleDeclaration>, ConfigError> {
let descriptor_node = kdl_child_with_name!(style_node, style_descriptor);
match descriptor_node {
Some(descriptor) => {
let colors = kdl_children_or_error!(
descriptor,
format!("Missing colors for {}", style_descriptor)
);
Ok(Some(StyleDeclaration {
base: PaletteColor::try_from(("base", colors))?,
background: PaletteColor::try_from(("background", colors)).unwrap_or_default(),
emphasis_0: PaletteColor::try_from(("emphasis_0", colors))?,
emphasis_1: PaletteColor::try_from(("emphasis_1", colors))?,
emphasis_2: PaletteColor::try_from(("emphasis_2", colors))?,
emphasis_3: PaletteColor::try_from(("emphasis_3", colors))?,
}))
},
None => Ok(None),
}
}
fn multiplayer_colors(style_node: &KdlNode) -> Result<MultiplayerColors, ConfigError> {
let descriptor_node = kdl_child_with_name!(style_node, "multiplayer_user_colors");
match descriptor_node {
Some(descriptor) => {
let colors = kdl_children_or_error!(
descriptor,
format!("Missing colors for {}", "multiplayer_user_colors")
);
Ok(MultiplayerColors {
player_1: PaletteColor::try_from(("player_1", colors))
.unwrap_or(DEFAULT_STYLES.multiplayer_user_colors.player_1),
player_2: PaletteColor::try_from(("player_2", colors))
.unwrap_or(DEFAULT_STYLES.multiplayer_user_colors.player_2),
player_3: PaletteColor::try_from(("player_3", colors))
.unwrap_or(DEFAULT_STYLES.multiplayer_user_colors.player_3),
player_4: PaletteColor::try_from(("player_4", colors))
.unwrap_or(DEFAULT_STYLES.multiplayer_user_colors.player_4),
player_5: PaletteColor::try_from(("player_5", colors))
.unwrap_or(DEFAULT_STYLES.multiplayer_user_colors.player_5),
player_6: PaletteColor::try_from(("player_6", colors))
.unwrap_or(DEFAULT_STYLES.multiplayer_user_colors.player_6),
player_7: PaletteColor::try_from(("player_7", colors))
.unwrap_or(DEFAULT_STYLES.multiplayer_user_colors.player_7),
player_8: PaletteColor::try_from(("player_8", colors))
.unwrap_or(DEFAULT_STYLES.multiplayer_user_colors.player_8),
player_9: PaletteColor::try_from(("player_9", colors))
.unwrap_or(DEFAULT_STYLES.multiplayer_user_colors.player_9),
player_10: PaletteColor::try_from(("player_10", colors))
.unwrap_or(DEFAULT_STYLES.multiplayer_user_colors.player_10),
})
},
None => Ok(DEFAULT_STYLES.multiplayer_user_colors),
}
}
pub fn from_kdl( pub fn from_kdl(
themes_from_kdl: &KdlNode, themes_from_kdl: &KdlNode,
sourced_from_external_file: bool, sourced_from_external_file: bool,
@ -3938,8 +4048,17 @@ impl Themes {
for theme_config in kdl_children_nodes_or_error!(themes_from_kdl, "no themes found") { for theme_config in kdl_children_nodes_or_error!(themes_from_kdl, "no themes found") {
let theme_name = kdl_name!(theme_config); let theme_name = kdl_name!(theme_config);
let theme_colors = kdl_children_or_error!(theme_config, "empty theme"); let theme_colors = kdl_children_or_error!(theme_config, "empty theme");
let theme = Theme { let palette_color_names = HashSet::from([
palette: Palette { "fg", "bg", "red", "green", "blue", "yellow", "magenta", "orange", "cyan", "black",
"white",
]);
let theme = if theme_colors
.nodes()
.iter()
.all(|n| palette_color_names.contains(n.name().value()))
{
// Older palette based theme definition
let palette = Palette {
fg: PaletteColor::try_from(("fg", theme_colors))?, fg: PaletteColor::try_from(("fg", theme_colors))?,
bg: PaletteColor::try_from(("bg", theme_colors))?, bg: PaletteColor::try_from(("bg", theme_colors))?,
red: PaletteColor::try_from(("red", theme_colors))?, red: PaletteColor::try_from(("red", theme_colors))?,
@ -3952,8 +4071,92 @@ impl Themes {
black: PaletteColor::try_from(("black", theme_colors))?, black: PaletteColor::try_from(("black", theme_colors))?,
white: PaletteColor::try_from(("white", theme_colors))?, white: PaletteColor::try_from(("white", theme_colors))?,
..Default::default() ..Default::default()
}, };
sourced_from_external_file, Theme {
palette: palette.into(),
sourced_from_external_file,
}
} else {
// Newer theme definition with named styles
let s = Styling {
text_unselected: Themes::style_declaration_from_node(
theme_config,
"text_unselected",
)
.map(|maybe_style| maybe_style.unwrap_or(DEFAULT_STYLES.text_unselected))?,
text_selected: Themes::style_declaration_from_node(
theme_config,
"text_selected",
)
.map(|maybe_style| maybe_style.unwrap_or(DEFAULT_STYLES.text_selected))?,
ribbon_unselected: Themes::style_declaration_from_node(
theme_config,
"ribbon_unselected",
)
.map(|maybe_style| maybe_style.unwrap_or(DEFAULT_STYLES.ribbon_unselected))?,
ribbon_selected: Themes::style_declaration_from_node(
theme_config,
"ribbon_selected",
)
.map(|maybe_style| maybe_style.unwrap_or(DEFAULT_STYLES.ribbon_selected))?,
table_title: Themes::style_declaration_from_node(theme_config, "table_title")
.map(|maybe_style| {
maybe_style.unwrap_or(DEFAULT_STYLES.table_title)
})?,
table_cell_unselected: Themes::style_declaration_from_node(
theme_config,
"table_cell_unselected",
)
.map(|maybe_style| {
maybe_style.unwrap_or(DEFAULT_STYLES.table_cell_unselected)
})?,
table_cell_selected: Themes::style_declaration_from_node(
theme_config,
"table_cell_selected",
)
.map(|maybe_style| maybe_style.unwrap_or(DEFAULT_STYLES.table_cell_selected))?,
list_unselected: Themes::style_declaration_from_node(
theme_config,
"list_unselected",
)
.map(|maybe_style| maybe_style.unwrap_or(DEFAULT_STYLES.list_unselected))?,
list_selected: Themes::style_declaration_from_node(
theme_config,
"list_selected",
)
.map(|maybe_style| maybe_style.unwrap_or(DEFAULT_STYLES.list_selected))?,
frame_unselected: Themes::style_declaration_from_node(
theme_config,
"frame_unselected",
)?,
frame_selected: Themes::style_declaration_from_node(
theme_config,
"frame_selected",
)
.map(|maybe_style| maybe_style.unwrap_or(DEFAULT_STYLES.frame_selected))?,
frame_highlight: Themes::style_declaration_from_node(
theme_config,
"frame_highlight",
)
.map(|maybe_style| maybe_style.unwrap_or(DEFAULT_STYLES.frame_highlight))?,
exit_code_success: Themes::style_declaration_from_node(
theme_config,
"exit_code_success",
)
.map(|maybe_style| maybe_style.unwrap_or(DEFAULT_STYLES.exit_code_success))?,
exit_code_error: Themes::style_declaration_from_node(
theme_config,
"exit_code_error",
)
.map(|maybe_style| maybe_style.unwrap_or(DEFAULT_STYLES.exit_code_error))?,
multiplayer_user_colors: Themes::multiplayer_colors(theme_config)
.unwrap_or_default(),
};
Theme {
palette: s,
sourced_from_external_file,
}
}; };
themes.insert(theme_name.into(), theme); themes.insert(theme_name.into(), theme);
} }
@ -4017,39 +4220,64 @@ impl Themes {
has_themes = true; has_themes = true;
let mut current_theme_node = KdlNode::new(theme_name.clone()); let mut current_theme_node = KdlNode::new(theme_name.clone());
let mut current_theme_node_children = KdlDocument::new(); let mut current_theme_node_children = KdlDocument::new();
current_theme_node_children current_theme_node_children
.nodes_mut() .nodes_mut()
.push(theme.palette.fg.to_kdl("fg")); .push(theme.palette.text_unselected.to_kdl("text_unselected"));
current_theme_node_children current_theme_node_children
.nodes_mut() .nodes_mut()
.push(theme.palette.bg.to_kdl("bg")); .push(theme.palette.text_selected.to_kdl("text_selected"));
current_theme_node_children current_theme_node_children
.nodes_mut() .nodes_mut()
.push(theme.palette.red.to_kdl("red")); .push(theme.palette.ribbon_selected.to_kdl("ribbon_selected"));
current_theme_node_children current_theme_node_children
.nodes_mut() .nodes_mut()
.push(theme.palette.green.to_kdl("green")); .push(theme.palette.ribbon_unselected.to_kdl("ribbon_unselected"));
current_theme_node_children current_theme_node_children
.nodes_mut() .nodes_mut()
.push(theme.palette.yellow.to_kdl("yellow")); .push(theme.palette.table_title.to_kdl("table_title"));
current_theme_node_children.nodes_mut().push(
theme
.palette
.table_cell_selected
.to_kdl("table_cell_selected"),
);
current_theme_node_children.nodes_mut().push(
theme
.palette
.table_cell_unselected
.to_kdl("table_cell_unselected"),
);
current_theme_node_children current_theme_node_children
.nodes_mut() .nodes_mut()
.push(theme.palette.blue.to_kdl("blue")); .push(theme.palette.list_selected.to_kdl("list_selected"));
current_theme_node_children current_theme_node_children
.nodes_mut() .nodes_mut()
.push(theme.palette.magenta.to_kdl("magenta")); .push(theme.palette.list_unselected.to_kdl("list_unselected"));
current_theme_node_children current_theme_node_children
.nodes_mut() .nodes_mut()
.push(theme.palette.orange.to_kdl("orange")); .push(theme.palette.frame_selected.to_kdl("frame_selected"));
match theme.palette.frame_unselected {
None => {},
Some(frame_unselected_style) => {
current_theme_node_children
.nodes_mut()
.push(frame_unselected_style.to_kdl("frame_unselected"));
},
}
current_theme_node_children current_theme_node_children
.nodes_mut() .nodes_mut()
.push(theme.palette.cyan.to_kdl("cyan")); .push(theme.palette.frame_highlight.to_kdl("frame_highlight"));
current_theme_node_children current_theme_node_children
.nodes_mut() .nodes_mut()
.push(theme.palette.black.to_kdl("black")); .push(theme.palette.exit_code_success.to_kdl("exit_code_success"));
current_theme_node_children current_theme_node_children
.nodes_mut() .nodes_mut()
.push(theme.palette.white.to_kdl("white")); .push(theme.palette.exit_code_error.to_kdl("exit_code_error"));
current_theme_node_children
.nodes_mut()
.push(theme.palette.multiplayer_user_colors.to_kdl());
current_theme_node.set_children(current_theme_node_children); current_theme_node.set_children(current_theme_node_children);
themes.nodes_mut().push(current_theme_node); themes.nodes_mut().push(current_theme_node);
} }
@ -5168,7 +5396,7 @@ fn themes_to_string() {
.unwrap(); .unwrap();
assert_eq!( assert_eq!(
deserialized, deserialized_from_serialized, deserialized, deserialized_from_serialized,
"Deserialized serialized config equals original config" "Deserialized serialized config equals original config",
); );
insta::assert_snapshot!(serialized.to_string()); insta::assert_snapshot!(serialized.to_string());
} }

View file

@ -1,20 +1,124 @@
--- ---
source: zellij-utils/src/kdl/mod.rs source: zellij-utils/src/kdl/mod.rs
assertion_line: 3697
expression: serialized.to_string() expression: serialized.to_string()
--- ---
themes { themes {
dracula { dracula {
fg 248 248 242 text_unselected {
bg 40 42 54 base 255 255 255
red 255 85 85 background 0 0 0
green 80 250 123 emphasis_0 255 184 108
yellow 241 250 140 emphasis_1 139 233 253
blue 98 114 164 emphasis_2 80 250 123
magenta 255 121 198 emphasis_3 255 121 198
orange 255 184 108 }
cyan 139 233 253 text_selected {
black 0 0 0 base 255 255 255
white 255 255 255 background 40 42 54
emphasis_0 255 184 108
emphasis_1 139 233 253
emphasis_2 80 250 123
emphasis_3 255 121 198
}
ribbon_selected {
base 0 0 0
background 80 250 123
emphasis_0 255 85 85
emphasis_1 255 184 108
emphasis_2 255 121 198
emphasis_3 98 114 164
}
ribbon_unselected {
base 0 0 0
background 248 248 242
emphasis_0 255 85 85
emphasis_1 255 255 255
emphasis_2 98 114 164
emphasis_3 255 121 198
}
table_title {
base 80 250 123
background 0
emphasis_0 255 184 108
emphasis_1 139 233 253
emphasis_2 80 250 123
emphasis_3 255 121 198
}
table_cell_selected {
base 255 255 255
background 40 42 54
emphasis_0 255 184 108
emphasis_1 139 233 253
emphasis_2 80 250 123
emphasis_3 255 121 198
}
table_cell_unselected {
base 255 255 255
background 0 0 0
emphasis_0 255 184 108
emphasis_1 139 233 253
emphasis_2 80 250 123
emphasis_3 255 121 198
}
list_selected {
base 255 255 255
background 40 42 54
emphasis_0 255 184 108
emphasis_1 139 233 253
emphasis_2 80 250 123
emphasis_3 255 121 198
}
list_unselected {
base 255 255 255
background 0 0 0
emphasis_0 255 184 108
emphasis_1 139 233 253
emphasis_2 80 250 123
emphasis_3 255 121 198
}
frame_selected {
base 80 250 123
background 0
emphasis_0 255 184 108
emphasis_1 139 233 253
emphasis_2 255 121 198
emphasis_3 0
}
frame_highlight {
base 255 184 108
background 0
emphasis_0 255 184 108
emphasis_1 255 184 108
emphasis_2 255 184 108
emphasis_3 255 184 108
}
exit_code_success {
base 80 250 123
background 0
emphasis_0 139 233 253
emphasis_1 0 0 0
emphasis_2 255 121 198
emphasis_3 98 114 164
}
exit_code_error {
base 255 85 85
background 0
emphasis_0 241 250 140
emphasis_1 0
emphasis_2 0
emphasis_3 0
}
multiplayer_user_colors {
player_1 255 121 198
player_2 98 114 164
player_3 0
player_4 241 250 140
player_5 139 233 253
player_6 0
player_7 255 85 85
player_8 0
player_9 0
player_10 0
}
} }
} }

View file

@ -1,20 +1,124 @@
--- ---
source: zellij-utils/src/kdl/mod.rs source: zellij-utils/src/kdl/mod.rs
assertion_line: 3775
expression: serialized.to_string() expression: serialized.to_string()
--- ---
themes { themes {
default { default {
fg 1 text_unselected {
bg 10 base 255 255 255
red 30 background 20
green 40 emphasis_0 208 135 112
yellow 50 emphasis_1 80
blue 60 emphasis_2 40
magenta 70 emphasis_3 70
orange 208 135 112 }
cyan 80 text_selected {
black 20 base 255 255 255
white 255 255 255 background 10
emphasis_0 208 135 112
emphasis_1 80
emphasis_2 40
emphasis_3 70
}
ribbon_selected {
base 20
background 40
emphasis_0 30
emphasis_1 208 135 112
emphasis_2 70
emphasis_3 60
}
ribbon_unselected {
base 20
background 1
emphasis_0 30
emphasis_1 255 255 255
emphasis_2 60
emphasis_3 70
}
table_title {
base 40
background 0
emphasis_0 208 135 112
emphasis_1 80
emphasis_2 40
emphasis_3 70
}
table_cell_selected {
base 255 255 255
background 10
emphasis_0 208 135 112
emphasis_1 80
emphasis_2 40
emphasis_3 70
}
table_cell_unselected {
base 255 255 255
background 20
emphasis_0 208 135 112
emphasis_1 80
emphasis_2 40
emphasis_3 70
}
list_selected {
base 255 255 255
background 10
emphasis_0 208 135 112
emphasis_1 80
emphasis_2 40
emphasis_3 70
}
list_unselected {
base 255 255 255
background 20
emphasis_0 208 135 112
emphasis_1 80
emphasis_2 40
emphasis_3 70
}
frame_selected {
base 40
background 0
emphasis_0 208 135 112
emphasis_1 80
emphasis_2 70
emphasis_3 0
}
frame_highlight {
base 208 135 112
background 0
emphasis_0 208 135 112
emphasis_1 208 135 112
emphasis_2 208 135 112
emphasis_3 208 135 112
}
exit_code_success {
base 40
background 0
emphasis_0 80
emphasis_1 20
emphasis_2 70
emphasis_3 60
}
exit_code_error {
base 30
background 0
emphasis_0 50
emphasis_1 0
emphasis_2 0
emphasis_3 0
}
multiplayer_user_colors {
player_1 70
player_2 60
player_3 0
player_4 50
player_5 80
player_6 0
player_7 30
player_8 0
player_9 0
player_10 0
}
} }
} }

View file

@ -1,20 +1,124 @@
--- ---
source: zellij-utils/src/kdl/mod.rs source: zellij-utils/src/kdl/mod.rs
assertion_line: 3749
expression: serialized.to_string() expression: serialized.to_string()
--- ---
themes { themes {
default { default {
fg 1 text_unselected {
bg 10 base 90
red 30 background 20
green 40 emphasis_0 254
yellow 50 emphasis_1 80
blue 60 emphasis_2 40
magenta 70 emphasis_3 70
orange 254 }
cyan 80 text_selected {
black 20 base 90
white 90 background 10
emphasis_0 254
emphasis_1 80
emphasis_2 40
emphasis_3 70
}
ribbon_selected {
base 20
background 40
emphasis_0 30
emphasis_1 254
emphasis_2 70
emphasis_3 60
}
ribbon_unselected {
base 20
background 1
emphasis_0 30
emphasis_1 90
emphasis_2 60
emphasis_3 70
}
table_title {
base 40
background 0
emphasis_0 254
emphasis_1 80
emphasis_2 40
emphasis_3 70
}
table_cell_selected {
base 90
background 10
emphasis_0 254
emphasis_1 80
emphasis_2 40
emphasis_3 70
}
table_cell_unselected {
base 90
background 20
emphasis_0 254
emphasis_1 80
emphasis_2 40
emphasis_3 70
}
list_selected {
base 90
background 10
emphasis_0 254
emphasis_1 80
emphasis_2 40
emphasis_3 70
}
list_unselected {
base 90
background 20
emphasis_0 254
emphasis_1 80
emphasis_2 40
emphasis_3 70
}
frame_selected {
base 40
background 0
emphasis_0 254
emphasis_1 80
emphasis_2 70
emphasis_3 0
}
frame_highlight {
base 254
background 0
emphasis_0 254
emphasis_1 254
emphasis_2 254
emphasis_3 254
}
exit_code_success {
base 40
background 0
emphasis_0 80
emphasis_1 20
emphasis_2 70
emphasis_3 60
}
exit_code_error {
base 30
background 0
emphasis_0 50
emphasis_1 0
emphasis_2 0
emphasis_3 0
}
multiplayer_user_colors {
player_1 70
player_2 60
player_3 0
player_4 50
player_5 80
player_6 0
player_7 30
player_8 0
player_9 0
player_10 0
}
} }
} }

View file

@ -1,20 +1,124 @@
--- ---
source: zellij-utils/src/kdl/mod.rs source: zellij-utils/src/kdl/mod.rs
assertion_line: 3723
expression: serialized.to_string() expression: serialized.to_string()
--- ---
themes { themes {
nord { nord {
fg 216 222 233 text_unselected {
bg 46 52 64 base 229 233 240
red 191 97 106 background 59 66 82
green 163 190 140 emphasis_0 208 135 112
yellow 235 203 139 emphasis_1 136 192 208
blue 129 161 193 emphasis_2 163 190 140
magenta 180 142 173 emphasis_3 180 142 173
orange 208 135 112 }
cyan 136 192 208 text_selected {
black 59 66 82 base 229 233 240
white 229 233 240 background 46 52 64
emphasis_0 208 135 112
emphasis_1 136 192 208
emphasis_2 163 190 140
emphasis_3 180 142 173
}
ribbon_selected {
base 59 66 82
background 163 190 140
emphasis_0 191 97 106
emphasis_1 208 135 112
emphasis_2 180 142 173
emphasis_3 129 161 193
}
ribbon_unselected {
base 59 66 82
background 216 222 233
emphasis_0 191 97 106
emphasis_1 229 233 240
emphasis_2 129 161 193
emphasis_3 180 142 173
}
table_title {
base 163 190 140
background 0
emphasis_0 208 135 112
emphasis_1 136 192 208
emphasis_2 163 190 140
emphasis_3 180 142 173
}
table_cell_selected {
base 229 233 240
background 46 52 64
emphasis_0 208 135 112
emphasis_1 136 192 208
emphasis_2 163 190 140
emphasis_3 180 142 173
}
table_cell_unselected {
base 229 233 240
background 59 66 82
emphasis_0 208 135 112
emphasis_1 136 192 208
emphasis_2 163 190 140
emphasis_3 180 142 173
}
list_selected {
base 229 233 240
background 46 52 64
emphasis_0 208 135 112
emphasis_1 136 192 208
emphasis_2 163 190 140
emphasis_3 180 142 173
}
list_unselected {
base 229 233 240
background 59 66 82
emphasis_0 208 135 112
emphasis_1 136 192 208
emphasis_2 163 190 140
emphasis_3 180 142 173
}
frame_selected {
base 163 190 140
background 0
emphasis_0 208 135 112
emphasis_1 136 192 208
emphasis_2 180 142 173
emphasis_3 0
}
frame_highlight {
base 208 135 112
background 0
emphasis_0 208 135 112
emphasis_1 208 135 112
emphasis_2 208 135 112
emphasis_3 208 135 112
}
exit_code_success {
base 163 190 140
background 0
emphasis_0 136 192 208
emphasis_1 59 66 82
emphasis_2 180 142 173
emphasis_3 129 161 193
}
exit_code_error {
base 191 97 106
background 0
emphasis_0 235 203 139
emphasis_1 0
emphasis_2 0
emphasis_3 0
}
multiplayer_user_colors {
player_1 180 142 173
player_2 129 161 193
player_3 0
player_4 235 203 139
player_5 136 192 208
player_6 0
player_7 191 97 106
player_8 0
player_9 0
player_10 0
}
} }
} }

View file

@ -1,33 +1,242 @@
--- ---
source: zellij-utils/src/kdl/mod.rs source: zellij-utils/src/kdl/mod.rs
assertion_line: 4821
expression: serialized.to_string() expression: serialized.to_string()
--- ---
themes { themes {
dracula { dracula {
fg 248 248 242 text_unselected {
bg 40 42 54 base 255 255 255
red 255 85 85 background 0 0 0
green 80 250 123 emphasis_0 255 184 108
yellow 241 250 140 emphasis_1 139 233 253
blue 98 114 164 emphasis_2 80 250 123
magenta 255 121 198 emphasis_3 255 121 198
orange 255 184 108 }
cyan 139 233 253 text_selected {
black 0 0 0 base 255 255 255
white 255 255 255 background 40 42 54
emphasis_0 255 184 108
emphasis_1 139 233 253
emphasis_2 80 250 123
emphasis_3 255 121 198
}
ribbon_selected {
base 0 0 0
background 80 250 123
emphasis_0 255 85 85
emphasis_1 255 184 108
emphasis_2 255 121 198
emphasis_3 98 114 164
}
ribbon_unselected {
base 0 0 0
background 248 248 242
emphasis_0 255 85 85
emphasis_1 255 255 255
emphasis_2 98 114 164
emphasis_3 255 121 198
}
table_title {
base 80 250 123
background 0
emphasis_0 255 184 108
emphasis_1 139 233 253
emphasis_2 80 250 123
emphasis_3 255 121 198
}
table_cell_selected {
base 255 255 255
background 40 42 54
emphasis_0 255 184 108
emphasis_1 139 233 253
emphasis_2 80 250 123
emphasis_3 255 121 198
}
table_cell_unselected {
base 255 255 255
background 0 0 0
emphasis_0 255 184 108
emphasis_1 139 233 253
emphasis_2 80 250 123
emphasis_3 255 121 198
}
list_selected {
base 255 255 255
background 40 42 54
emphasis_0 255 184 108
emphasis_1 139 233 253
emphasis_2 80 250 123
emphasis_3 255 121 198
}
list_unselected {
base 255 255 255
background 0 0 0
emphasis_0 255 184 108
emphasis_1 139 233 253
emphasis_2 80 250 123
emphasis_3 255 121 198
}
frame_selected {
base 80 250 123
background 0
emphasis_0 255 184 108
emphasis_1 139 233 253
emphasis_2 255 121 198
emphasis_3 0
}
frame_highlight {
base 255 184 108
background 0
emphasis_0 255 184 108
emphasis_1 255 184 108
emphasis_2 255 184 108
emphasis_3 255 184 108
}
exit_code_success {
base 80 250 123
background 0
emphasis_0 139 233 253
emphasis_1 0 0 0
emphasis_2 255 121 198
emphasis_3 98 114 164
}
exit_code_error {
base 255 85 85
background 0
emphasis_0 241 250 140
emphasis_1 0
emphasis_2 0
emphasis_3 0
}
multiplayer_user_colors {
player_1 255 121 198
player_2 98 114 164
player_3 0
player_4 241 250 140
player_5 139 233 253
player_6 0
player_7 255 85 85
player_8 0
player_9 0
player_10 0
}
} }
nord { nord {
fg 216 222 233 text_unselected {
bg 46 52 64 base 229 233 240
red 191 97 106 background 59 66 82
green 163 190 140 emphasis_0 208 135 112
yellow 235 203 139 emphasis_1 136 192 208
blue 129 161 193 emphasis_2 163 190 140
magenta 180 142 173 emphasis_3 180 142 173
orange 208 135 112 }
cyan 136 192 208 text_selected {
black 59 66 82 base 229 233 240
white 229 233 240 background 46 52 64
emphasis_0 208 135 112
emphasis_1 136 192 208
emphasis_2 163 190 140
emphasis_3 180 142 173
}
ribbon_selected {
base 59 66 82
background 163 190 140
emphasis_0 191 97 106
emphasis_1 208 135 112
emphasis_2 180 142 173
emphasis_3 129 161 193
}
ribbon_unselected {
base 59 66 82
background 216 222 233
emphasis_0 191 97 106
emphasis_1 229 233 240
emphasis_2 129 161 193
emphasis_3 180 142 173
}
table_title {
base 163 190 140
background 0
emphasis_0 208 135 112
emphasis_1 136 192 208
emphasis_2 163 190 140
emphasis_3 180 142 173
}
table_cell_selected {
base 229 233 240
background 46 52 64
emphasis_0 208 135 112
emphasis_1 136 192 208
emphasis_2 163 190 140
emphasis_3 180 142 173
}
table_cell_unselected {
base 229 233 240
background 59 66 82
emphasis_0 208 135 112
emphasis_1 136 192 208
emphasis_2 163 190 140
emphasis_3 180 142 173
}
list_selected {
base 229 233 240
background 46 52 64
emphasis_0 208 135 112
emphasis_1 136 192 208
emphasis_2 163 190 140
emphasis_3 180 142 173
}
list_unselected {
base 229 233 240
background 59 66 82
emphasis_0 208 135 112
emphasis_1 136 192 208
emphasis_2 163 190 140
emphasis_3 180 142 173
}
frame_selected {
base 163 190 140
background 0
emphasis_0 208 135 112
emphasis_1 136 192 208
emphasis_2 180 142 173
emphasis_3 0
}
frame_highlight {
base 208 135 112
background 0
emphasis_0 208 135 112
emphasis_1 208 135 112
emphasis_2 208 135 112
emphasis_3 208 135 112
}
exit_code_success {
base 163 190 140
background 0
emphasis_0 136 192 208
emphasis_1 59 66 82
emphasis_2 180 142 173
emphasis_3 129 161 193
}
exit_code_error {
base 191 97 106
background 0
emphasis_0 235 203 139
emphasis_1 0
emphasis_2 0
emphasis_3 0
}
multiplayer_user_colors {
player_1 180 142 173
player_2 129 161 193
player_3 0
player_4 235 203 139
player_5 136 192 208
player_6 0
player_7 191 97 106
player_8 0
player_9 0
player_10 0
}
} }
} }

View file

@ -1458,7 +1458,9 @@ fn serialize_mode_update_event_with_non_default_values() {
silver: PaletteColor::EightBit(2), silver: PaletteColor::EightBit(2),
pink: PaletteColor::EightBit(2), pink: PaletteColor::EightBit(2),
brown: PaletteColor::Rgb((222, 221, 220)), brown: PaletteColor::Rgb((222, 221, 220)),
}, }
.into(),
// TODO: replace default
rounded_corners: true, rounded_corners: true,
hide_session_name: false, hide_session_name: false,
}, },

View file

@ -3,9 +3,10 @@ syntax = "proto3";
package api.style; package api.style;
message Style { message Style {
Palette palette = 1; Palette palette = 1 [deprecated = true];
bool rounded_corners = 2; bool rounded_corners = 2;
bool hide_session_name = 3; bool hide_session_name = 3;
Styling styling = 4;
} }
message Palette { message Palette {
@ -52,3 +53,21 @@ enum ThemeHue {
Dark = 0; Dark = 0;
Light = 1; Light = 1;
} }
message Styling {
repeated Color text_unselected = 1;
repeated Color text_selected = 2;
repeated Color ribbon_unselected = 3;
repeated Color ribbon_selected =4;
repeated Color table_title = 5;
repeated Color table_cell_unselected = 6;
repeated Color table_cell_selected = 7;
repeated Color list_unselected = 8;
repeated Color list_selected = 9;
repeated Color frame_unselected = 10;
repeated Color frame_selected = 11;
repeated Color frame_highlight = 12;
repeated Color exit_code_success = 13;
repeated Color exit_code_error = 14;
repeated Color multiplayer_user_colors = 15;
}

View file

@ -1,9 +1,11 @@
use super::generated_api::api::style::{ use super::generated_api::api::style::{
color::Payload as ProtobufColorPayload, Color as ProtobufColor, ColorType as ProtobufColorType, color::Payload as ProtobufColorPayload, Color as ProtobufColor, ColorType as ProtobufColorType,
Palette as ProtobufPalette, RgbColorPayload as ProtobufRgbColorPayload, Style as ProtobufStyle, Palette as ProtobufPalette, RgbColorPayload as ProtobufRgbColorPayload, Style as ProtobufStyle,
ThemeHue as ProtobufThemeHue, Styling as ProtobufStyling, ThemeHue as ProtobufThemeHue,
};
use crate::data::{
MultiplayerColors, Palette, PaletteColor, Style, StyleDeclaration, Styling, ThemeHue,
}; };
use crate::data::{Palette, PaletteColor, Style, ThemeHue};
use crate::errors::prelude::*; use crate::errors::prelude::*;
use std::convert::TryFrom; use std::convert::TryFrom;
@ -11,24 +13,183 @@ use std::convert::TryFrom;
impl TryFrom<ProtobufStyle> for Style { impl TryFrom<ProtobufStyle> for Style {
type Error = &'static str; type Error = &'static str;
fn try_from(protobuf_style: ProtobufStyle) -> Result<Self, &'static str> { fn try_from(protobuf_style: ProtobufStyle) -> Result<Self, &'static str> {
let s = protobuf_style
.styling
.ok_or("malformed style payload")?
.try_into()?;
Ok(Style { Ok(Style {
colors: protobuf_style colors: s,
.palette
.ok_or("malformed style payload")?
.try_into()?,
rounded_corners: protobuf_style.rounded_corners, rounded_corners: protobuf_style.rounded_corners,
hide_session_name: protobuf_style.hide_session_name, hide_session_name: protobuf_style.hide_session_name,
}) })
} }
} }
#[allow(deprecated)]
impl TryFrom<Style> for ProtobufStyle { impl TryFrom<Style> for ProtobufStyle {
type Error = &'static str; type Error = &'static str;
fn try_from(style: Style) -> Result<Self, &'static str> { fn try_from(style: Style) -> Result<Self, &'static str> {
let s = ProtobufStyling::try_from(style.colors)?;
let palette = Palette::try_from(style.colors).map_err(|_| "malformed style payload")?;
Ok(ProtobufStyle { Ok(ProtobufStyle {
palette: Some(style.colors.try_into()?), palette: Some(palette.try_into()?),
rounded_corners: style.rounded_corners, rounded_corners: style.rounded_corners,
hide_session_name: style.hide_session_name, hide_session_name: style.hide_session_name,
styling: Some(s),
})
}
}
fn to_array<T, const N: usize>(v: Vec<T>) -> std::result::Result<[T; N], &'static str> {
v.try_into()
.map_err(|_| "Could not obtain array from protobuf field")
}
fn to_style_declaration(
parsed_array: Result<[PaletteColor; 6], &'static str>,
) -> Result<StyleDeclaration, &'static str> {
parsed_array.map(|arr| StyleDeclaration {
base: arr[0],
background: arr[1],
emphasis_0: arr[2],
emphasis_1: arr[3],
emphasis_2: arr[4],
emphasis_3: arr[5],
})
}
fn to_multiplayer_colors(
parsed_array: Result<[PaletteColor; 10], &'static str>,
) -> Result<MultiplayerColors, &'static str> {
parsed_array.map(|arr| MultiplayerColors {
player_1: arr[0],
player_2: arr[1],
player_3: arr[2],
player_4: arr[3],
player_5: arr[4],
player_6: arr[5],
player_7: arr[6],
player_8: arr[7],
player_9: arr[8],
player_10: arr[9],
})
}
#[macro_export]
macro_rules! color_definitions {
($proto:expr, $declaration:ident, $size:expr) => {
to_style_declaration(to_array::<PaletteColor, $size>(
$proto
.$declaration
.into_iter()
.map(PaletteColor::try_from)
.collect::<Result<Vec<PaletteColor>, _>>()?,
))?
};
}
#[macro_export]
macro_rules! multiplayer_colors {
($proto:expr, $size: expr) => {
to_multiplayer_colors(to_array::<PaletteColor, $size>(
$proto
.multiplayer_user_colors
.into_iter()
.map(PaletteColor::try_from)
.collect::<Result<Vec<PaletteColor>, _>>()?,
))?
};
}
impl TryFrom<ProtobufStyling> for Styling {
type Error = &'static str;
fn try_from(proto: ProtobufStyling) -> std::result::Result<Self, Self::Error> {
let frame_unselected = if proto.frame_unselected.len() > 0 {
Some(color_definitions!(proto, frame_unselected, 6))
} else {
None
};
Ok(Styling {
text_unselected: color_definitions!(proto, text_unselected, 6),
text_selected: color_definitions!(proto, text_selected, 6),
ribbon_unselected: color_definitions!(proto, ribbon_unselected, 6),
ribbon_selected: color_definitions!(proto, ribbon_selected, 6),
table_title: color_definitions!(proto, table_title, 6),
table_cell_unselected: color_definitions!(proto, table_cell_unselected, 6),
table_cell_selected: color_definitions!(proto, table_cell_selected, 6),
list_unselected: color_definitions!(proto, list_unselected, 6),
list_selected: color_definitions!(proto, list_selected, 6),
frame_unselected,
frame_selected: color_definitions!(proto, frame_selected, 6),
frame_highlight: color_definitions!(proto, frame_highlight, 6),
exit_code_success: color_definitions!(proto, exit_code_success, 6),
exit_code_error: color_definitions!(proto, exit_code_error, 6),
multiplayer_user_colors: multiplayer_colors!(proto, 10),
})
}
}
impl TryFrom<StyleDeclaration> for Vec<ProtobufColor> {
type Error = &'static str;
fn try_from(colors: StyleDeclaration) -> std::result::Result<Self, Self::Error> {
Ok(vec![
colors.base.try_into()?,
colors.background.try_into()?,
colors.emphasis_0.try_into()?,
colors.emphasis_1.try_into()?,
colors.emphasis_2.try_into()?,
colors.emphasis_3.try_into()?,
])
}
}
impl TryFrom<MultiplayerColors> for Vec<ProtobufColor> {
type Error = &'static str;
fn try_from(value: MultiplayerColors) -> std::result::Result<Self, Self::Error> {
Ok(vec![
value.player_1.try_into()?,
value.player_2.try_into()?,
value.player_3.try_into()?,
value.player_4.try_into()?,
value.player_5.try_into()?,
value.player_6.try_into()?,
value.player_7.try_into()?,
value.player_8.try_into()?,
value.player_9.try_into()?,
value.player_10.try_into()?,
])
}
}
impl TryFrom<Styling> for ProtobufStyling {
type Error = &'static str;
fn try_from(style: Styling) -> std::result::Result<Self, Self::Error> {
let frame_unselected_vec = match style.frame_unselected {
None => Ok(Vec::new()),
Some(frame_unselected) => frame_unselected.try_into(),
};
Ok(ProtobufStyling {
text_unselected: style.text_unselected.try_into()?,
text_selected: style.text_selected.try_into()?,
ribbon_unselected: style.ribbon_unselected.try_into()?,
ribbon_selected: style.ribbon_selected.try_into()?,
table_title: style.table_title.try_into()?,
table_cell_unselected: style.table_cell_unselected.try_into()?,
table_cell_selected: style.table_cell_selected.try_into()?,
list_unselected: style.list_unselected.try_into()?,
list_selected: style.list_selected.try_into()?,
frame_unselected: frame_unselected_vec?,
frame_selected: style.frame_selected.try_into()?,
frame_highlight: style.frame_highlight.try_into()?,
exit_code_success: style.exit_code_success.try_into()?,
exit_code_error: style.exit_code_error.try_into()?,
multiplayer_user_colors: style.multiplayer_user_colors.try_into()?,
}) })
} }
} }