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

View file

@ -131,10 +131,7 @@ impl ZellijPlugin for State {
.tab_line
.iter()
.fold(String::new(), |output, part| output + &part.part);
let background = match self.mode_info.style.colors.theme_hue {
ThemeHue::Dark => self.mode_info.style.colors.black,
ThemeHue::Light => self.mode_info.style.colors.white,
};
let background = self.mode_info.style.colors.text_unselected.background;
match background {
PaletteColor::Rgb((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_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
let mut len = 0;
let mut cursors = vec![];
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(" "));
len += 1;
}
@ -21,37 +21,40 @@ pub fn render_tab(
text: String,
tab: &TabInfo,
is_alternate_tab: bool,
palette: Palette,
palette: Styling,
separator: &str,
) -> LinePart {
let focused_clients = tab.other_focused_clients.as_slice();
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
ThemeHue::Dark => palette.white,
ThemeHue::Light => palette.black,
let alternate_tab_color = if is_alternate_tab {
palette.ribbon_unselected.emphasis_1
} else {
palette.ribbon_unselected.background
};
let background_color = if tab.active {
palette.green
palette.ribbon_selected.background
} else if is_alternate_tab {
alternate_tab_color
} else {
palette.fg
palette.ribbon_unselected.background
};
let foreground_color = match palette.theme_hue {
ThemeHue::Dark => palette.black,
ThemeHue::Light => palette.white,
let foreground_color = if tab.active {
palette.ribbon_selected.base
} 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 tab_styled_text = style!(foreground_color, background_color)
.bold()
.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 (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;
let mut s = String::new();
let cursor_beginning = style!(foreground_color, background_color)
@ -85,7 +88,7 @@ pub fn tab_style(
mut tabname: String,
tab: &TabInfo,
mut is_alternate_tab: bool,
palette: Palette,
palette: Styling,
capabilities: PluginCapabilities,
) -> LinePart {
let separator = tab_separator(capabilities);

View file

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

View file

@ -1,11 +1,8 @@
use crate::{Screen, WIDTH_BREAKPOINTS};
use zellij_tile::prelude::*;
pub fn top_tab_menu(cols: usize, current_screen: &Screen, colors: &Palette) {
let background = match colors.theme_hue {
ThemeHue::Dark => colors.black,
ThemeHue::Light => colors.white,
};
pub fn top_tab_menu(cols: usize, current_screen: &Screen, colors: &Styling) {
let background = colors.text_unselected.background;
let bg_color = match background {
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),

View file

@ -34,7 +34,7 @@ pub struct NewPluginScreen {
selected_config_index: Option<usize>,
request_ids: Vec<String>,
load_in_background: bool,
colors: Palette,
colors: Styling,
}
impl Default for NewPluginScreen {
@ -50,13 +50,13 @@ impl Default for NewPluginScreen {
selected_config_index: None,
request_ids: vec![],
load_in_background: false,
colors: Palette::default(),
colors: Palette::default().into(),
}
}
}
impl NewPluginScreen {
pub fn new(colors: Palette) -> Self {
pub fn new(colors: Styling) -> Self {
Self {
colors,
..Default::default()
@ -261,10 +261,7 @@ impl NewPluginScreen {
None,
None,
);
let background = match self.colors.theme_hue {
ThemeHue::Dark => self.colors.black,
ThemeHue::Light => self.colors.white,
};
let background = self.colors.text_unselected.background;
let bg_color = match background {
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),
@ -496,7 +493,7 @@ struct State {
plugin_id_to_tab_position: HashMap<u32, usize>,
search_term: String,
new_plugin_screen: Option<NewPluginScreen>,
colors: Palette,
colors: Styling,
}
register_plugin!(State);

View file

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

View file

@ -83,9 +83,14 @@ impl ListItem {
let mut remaining_cols = max_cols;
for span in session_name {
span.render(
indices
.clone()
.map(|i| (SpanStyle::ForegroundBold(self.colors.palette.magenta), i)),
indices.clone().map(|i| {
(
SpanStyle::ForegroundBold(
self.colors.palette.text_unselected.emphasis_3,
),
i,
)
}),
&mut line_to_render,
&mut remaining_cols,
);
@ -102,9 +107,14 @@ impl ListItem {
let mut remaining_cols = max_cols;
for span in tab_name {
span.render(
indices
.clone()
.map(|i| (SpanStyle::ForegroundBold(self.colors.palette.magenta), i)),
indices.clone().map(|i| {
(
SpanStyle::ForegroundBold(
self.colors.palette.text_unselected.emphasis_3,
),
i,
)
}),
&mut line_to_render,
&mut remaining_cols,
);
@ -116,9 +126,14 @@ impl ListItem {
let mut remaining_cols = max_cols;
for span in pane_name {
span.render(
indices
.clone()
.map(|i| (SpanStyle::ForegroundBold(self.colors.palette.magenta), i)),
indices.clone().map(|i| {
(
SpanStyle::ForegroundBold(
self.colors.palette.text_unselected.emphasis_3,
),
i,
)
}),
&mut line_to_render,
&mut remaining_cols,
);
@ -297,11 +312,11 @@ impl LineToRender {
pub fn make_selected_as_search(&mut self, add_arrows: bool) {
self.is_selected = true;
let arrows = if add_arrows {
self.colors.magenta(" <↓↑> ")
self.colors.shortcuts(" <↓↑> ")
} else {
" ".to_owned()
};
match self.colors.palette.bg {
match self.colors.palette.list_selected.background {
PaletteColor::EightBit(byte) => {
self.line = format!(
"\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) {
self.is_selected = true;
let arrows = if add_arrows {
self.colors.magenta("<←↓↑→>")
self.colors.shortcuts("<←↓↑→>")
} else {
" ".to_owned()
};
match self.colors.palette.bg {
match self.colors.palette.list_selected.background {
PaletteColor::EightBit(byte) => {
self.line = format!(
"\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 {
self.colors
.red(&format!(" [+{}]", self.truncated_result_count))
.exit_code_error(&format!(" [+{}]", self.truncated_result_count))
} else {
String::new()
};
@ -368,12 +383,12 @@ pub fn build_session_ui_line(session_ui_info: &SessionUiInfo, colors: Colors) ->
.iter()
.fold(0, |acc, tab| acc + tab.panes.len());
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_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 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 =
UiSpan::UiSpanTelescope(UiSpanTelescope::new(vec![StringAndLength::new(
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(
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![
StringAndLength::new(
@ -409,9 +424,12 @@ pub fn build_session_ui_line(session_ui_info: &SessionUiInfo, colors: Colors) ->
ui_spans.push(connected_users_count);
if session_ui_info.is_current_session {
let current_session_indication = UiSpan::UiSpanTelescope(UiSpanTelescope::new(vec![
StringAndLength::new(colors.orange(&format!(" <CURRENT SESSION>")), 18),
StringAndLength::new(colors.orange(&format!(" <CURRENT>")), 10),
StringAndLength::new(colors.orange(&format!(" <C>")), 4),
StringAndLength::new(
colors.current_session_marker(&format!(" <CURRENT SESSION>")),
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);
}
@ -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 pane_count_text = tab_ui_info.panes.len();
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 =
UiSpan::UiSpanTelescope(UiSpanTelescope::new(vec![StringAndLength::new(
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(
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![
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 = format!("{}", exit_code_number);
let exit_code = if exit_code_number == 0 {
colors.green(&exit_code)
colors.session_and_folder_entry(&exit_code)
} else {
colors.red(&exit_code)
colors.exit_code_error(&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) {
let prompt = colors.green(&format!("Search:"));
let prompt = colors.session_and_folder_entry(&format!("Search:"));
let search_term = colors.bold(&format!("{}_", search_term));
println!(
"\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_folder = new_session_folder.display().to_string();
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 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";
if max_cols
>= folder_prompt.width()
@ -598,8 +616,8 @@ fn render_new_session_folder_prompt(
print!(
"\u{1b}[m{}{} {} ({} {}, {} {})",
format!("\u{1b}[{};{}H", y + 1, x + 1),
colors.green(folder_prompt),
colors.orange(&new_session_folder),
colors.session_name_prompt(folder_prompt),
colors.session_and_folder_entry(&new_session_folder),
change_folder_shortcut,
to_change,
reset_folder_shortcut,
@ -617,8 +635,8 @@ fn render_new_session_folder_prompt(
print!(
"\u{1b}[m{}{} {} ({} {}, {} {})",
format!("\u{1b}[{};{}H", y + 1, x + 1),
colors.green(short_folder_prompt),
colors.orange(&new_session_folder),
colors.session_name_prompt(short_folder_prompt),
colors.session_and_folder_entry(&new_session_folder),
change_folder_shortcut,
to_change,
reset_folder_shortcut,
@ -634,8 +652,8 @@ fn render_new_session_folder_prompt(
print!(
"\u{1b}[m{}{} {} ({}/{})",
format!("\u{1b}[{};{}H", y + 1, x + 1),
colors.green(short_folder_prompt),
colors.orange(&new_session_folder),
colors.session_name_prompt(short_folder_prompt),
colors.session_and_folder_entry(&new_session_folder),
change_folder_shortcut,
reset_folder_shortcut,
);
@ -652,8 +670,8 @@ fn render_new_session_folder_prompt(
print!(
"\u{1b}[m{}{} {} ({}/{})",
format!("\u{1b}[{};{}H", y + 1, x + 1),
colors.green(short_folder_prompt),
colors.orange(&truncated_path),
colors.session_name_prompt(short_folder_prompt),
colors.session_and_folder_entry(&truncated_path),
change_folder_shortcut,
reset_folder_shortcut,
);
@ -663,7 +681,7 @@ fn render_new_session_folder_prompt(
let folder_prompt = "New session folder:";
let short_folder_prompt = "Folder:";
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";
if max_cols
@ -672,7 +690,7 @@ fn render_new_session_folder_prompt(
print!(
"\u{1b}[m{}{} ({} {})",
format!("\u{1b}[{};{}H", y + 1, x + 1),
colors.green(folder_prompt),
colors.session_name_prompt(folder_prompt),
change_folder_shortcut,
to_set,
);
@ -685,7 +703,7 @@ fn render_new_session_folder_prompt(
print!(
"\u{1b}[m{}{} ({} {})",
format!("\u{1b}[{};{}H", y + 1, x + 1),
colors.green(short_folder_prompt),
colors.session_name_prompt(short_folder_prompt),
change_folder_shortcut,
to_set,
);
@ -693,7 +711,7 @@ fn render_new_session_folder_prompt(
print!(
"\u{1b}[m{}{} {}",
format!("\u{1b}[{};{}H", y + 1, x + 1),
colors.green(short_folder_prompt),
colors.session_name_prompt(short_folder_prompt),
change_folder_shortcut,
);
}
@ -709,7 +727,7 @@ pub fn render_new_session_block(
x: usize,
y: usize,
) {
let enter = colors.magenta("<ENTER>");
let enter = colors.shortcuts("<ENTER>");
if new_session_info.entering_new_session_name() {
let prompt = "New session name:";
let long_instruction = "when done, blank for random";
@ -720,8 +738,8 @@ pub fn render_new_session_block(
println!(
"\u{1b}[m{}{} {}_ ({} {})",
format!("\u{1b}[{};{}H", y + 1, x + 1),
colors.green(prompt),
colors.orange(&new_session_name),
colors.session_name_prompt(prompt),
colors.session_and_folder_entry(&new_session_name),
enter,
long_instruction,
);
@ -746,8 +764,8 @@ pub fn render_new_session_block(
println!(
"\u{1b}[m{}{} {}_ {}",
format!("\u{1b}[{};{}H", y + 1, x + 1),
colors.green(prompt),
colors.orange(&new_session_name),
colors.session_name_prompt(prompt),
colors.session_and_folder_entry(&new_session_name),
enter,
);
}
@ -759,23 +777,23 @@ pub fn render_new_session_block(
};
let prompt = "New session name:";
let long_instruction = "to correct";
let esc = colors.magenta("<ESC>");
let esc = colors.shortcuts("<ESC>");
if max_cols_of_new_session_block
> prompt.width() + long_instruction.width() + new_session_name.width() + 15
{
println!(
"\u{1b}[m{}{}: {} ({} to correct)",
format!("\u{1b}[{};{}H", y + 1, x + 1),
colors.green("New session name"),
colors.orange(new_session_name),
colors.session_name_prompt(prompt),
colors.session_and_folder_entry(new_session_name),
esc,
);
} else {
println!(
"\u{1b}[m{}{}: {} {}",
format!("\u{1b}[{};{}H", y + 1, x + 1),
colors.green("New session name"),
colors.orange(new_session_name),
colors.session_name_prompt("New session name"),
colors.session_and_folder_entry(new_session_name),
esc,
);
}
@ -919,13 +937,13 @@ pub fn render_controls_line(
}
},
ActiveScreen::AttachToSession => {
let rename = colors.magenta("<Ctrl r>");
let rename = colors.shortcuts("<Ctrl r>");
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 kill = colors.magenta("<Del>");
let kill = colors.shortcuts("<Del>");
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");
if max_cols > 90 {
@ -937,13 +955,13 @@ pub fn render_controls_line(
}
},
ActiveScreen::ResurrectSession => {
let arrows = colors.magenta("<↓↑>");
let arrows = colors.shortcuts("<↓↑>");
let navigate = colors.bold("Navigate");
let enter = colors.magenta("<ENTER>");
let enter = colors.shortcuts("<ENTER>");
let select = colors.bold("Resurrect");
let del = colors.magenta("<DEL>");
let del = colors.shortcuts("<DEL>");
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");
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)]
pub struct Colors {
pub palette: Palette,
pub palette: Styling,
}
impl Colors {
pub fn new(palette: Palette) -> Self {
pub fn new(palette: Styling) -> Self {
Colors { palette }
}
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 {
self.color(&self.palette.green, text)
pub fn connected_users(&self, text: &str) -> String {
self.color(&self.palette.text_unselected.emphasis_2, text)
}
pub fn red(&self, text: &str) -> String {
self.color(&self.palette.red, text)
pub fn session_and_folder_entry(&self, text: &str) -> String {
self.color(&self.palette.text_unselected.emphasis_0, text)
}
pub fn cyan(&self, text: &str) -> String {
self.color(&self.palette.cyan, text)
pub fn current_session_marker(&self, text: &str) -> String {
self.color(&self.palette.text_unselected.emphasis_0, text)
}
pub fn magenta(&self, text: &str) -> String {
self.color(&self.palette.magenta, text)
pub fn pane_count(&self, text: &str) -> String {
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
}
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 prev_next_keys = action_key_group(
&mode_keybinds,
&[&[Action::PreviousSwapLayout], &[Action::NextSwapLayout]],
);
let prev_next_keys_indicator =
style_key_with_modifier(&prev_next_keys, palette, Some(palette.black));
let prev_next_keys_indicator = style_key_with_modifier(
&prev_next_keys,
&mode_info.style.colors,
Some(mode_info.style.colors.text_unselected.background),
);
let keycode = ANSIStrings(&prev_next_keys_indicator);
let len = unstyled_len(&keycode);
let part = keycode.to_string();
@ -364,14 +367,13 @@ fn swap_layout_status(
is_swap_layout_damaged: bool,
mode_info: &ModeInfo,
colored_elements: ColoredElements,
palette: &Palette,
separator: &str,
) -> Option<LinePart> {
match swap_layout_name {
Some(swap_layout_name) => {
let mut swap_layout_name = format!(" {} ", swap_layout_name);
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
//
macro_rules! style_swap_layout_indicator {
@ -701,7 +703,6 @@ pub fn first_line(
tab_info.is_swap_layout_dirty,
help,
colored_elements,
&help.style.colors,
separator,
) {
remaining_space -= swap_layout_status.len;
@ -730,7 +731,7 @@ mod tests {
use super::*;
fn colored_elements() -> ColoredElements {
let palette = Palette::default();
let palette = Styling::default();
color_elements(palette, false)
}

View file

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

View file

@ -17,16 +17,13 @@ fn full_length_shortcut(
is_first_shortcut: bool,
key: Vec<KeyWithModifier>,
action: &str,
palette: Palette,
palette: Styling,
) -> LinePart {
if key.is_empty() {
return LinePart::default();
}
let text_color = palette_match!(match palette.theme_hue {
ThemeHue::Dark => palette.white,
ThemeHue::Light => palette.black,
});
let text_color = palette_match!(palette.text_unselected.base);
let separator = if is_first_shortcut { " " } else { " / " };
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_len = locked_text.chars().count();
let text_color = palette_match!(match palette.theme_hue {
ThemeHue::Dark => palette.white,
ThemeHue::Light => palette.black,
});
let text_color = palette_match!(palette.text_unselected.base);
let locked_styled_text = Style::new().fg(text_color).bold().paint(locked_text);
LinePart {
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)
}
pub fn text_copied_hint(palette: &Palette, copy_destination: CopyDestination) -> LinePart {
let green_color = palette_match!(palette.green);
pub fn text_copied_hint(palette: &Styling, copy_destination: CopyDestination) -> LinePart {
let green_color = palette_match!(palette.text_unselected.emphasis_2);
let hint = match copy_destination {
CopyDestination::Command => "Text piped to external command",
#[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 red_color = palette_match!(palette.red);
let red_color = palette_match!(palette.text_unselected.emphasis_3);
LinePart {
part: Style::new().fg(red_color).bold().paint(hint).to_string(),
len: hint.len(),
}
}
pub fn fullscreen_panes_to_hide(palette: &Palette, panes_to_hide: usize) -> LinePart {
let text_color = palette_match!(match palette.theme_hue {
ThemeHue::Dark => palette.white,
ThemeHue::Light => palette.black,
});
let green_color = palette_match!(palette.green);
let orange_color = palette_match!(palette.orange);
pub fn fullscreen_panes_to_hide(palette: &Styling, panes_to_hide: usize) -> LinePart {
let text_color = palette_match!(palette.text_unselected.base);
let green_color = palette_match!(palette.text_unselected.emphasis_2);
let orange_color = palette_match!(palette.text_unselected.emphasis_0);
let shortcut_left_separator = Style::new().fg(text_color).bold().paint(" (");
let shortcut_right_separator = Style::new().fg(text_color).bold().paint("): ");
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 {
let palette = mode_info.style.colors;
let km = &mode_info.get_mode_keybinds();
let white_color = match palette.white {
PaletteColor::Rgb((r, g, b)) => RGB(r, g, b),
PaletteColor::EightBit(color) => Fixed(color),
};
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 white_color = palette_match!(palette.text_unselected.base);
let green_color = palette_match!(palette.text_unselected.emphasis_2);
let orange_color = palette_match!(palette.text_unselected.emphasis_0);
let shortcut_left_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";
@ -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 {
let text_color = palette_match!(match palette.theme_hue {
ThemeHue::Dark => palette.white,
ThemeHue::Light => palette.black,
});
let green_color = palette_match!(palette.green);
let orange_color = palette_match!(palette.orange);
pub fn locked_fullscreen_panes_to_hide(palette: &Styling, panes_to_hide: usize) -> LinePart {
let text_color = palette_match!(palette.text_unselected.base);
let green_color = palette_match!(palette.text_unselected.emphasis_2);
let orange_color = palette_match!(palette.text_unselected.emphasis_0);
let locked_text = " -- INTERFACE LOCKED -- ";
let shortcut_left_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 {
let white_color = match palette.white {
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),
};
pub fn locked_floating_panes_are_visible(palette: &Styling) -> LinePart {
let white_color = palette_match!(palette.text_unselected.base);
let orange_color = palette_match!(palette.text_unselected.emphasis_0);
let shortcut_left_separator = Style::new().fg(white_color).bold().paint(" (");
let shortcut_right_separator = Style::new().fg(white_color).bold().paint(")");
let locked_text = " -- INTERFACE LOCKED -- ";
@ -566,7 +539,7 @@ mod tests {
#[test]
fn full_length_shortcut_with_key() {
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 = unstyle(ret);
@ -577,7 +550,7 @@ mod tests {
#[test]
fn full_length_shortcut_with_key_first_element() {
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 = unstyle(ret);
@ -589,7 +562,7 @@ mod tests {
// When there is no binding, we print no shortcut either
fn full_length_shortcut_without_key() {
let keyvec = vec![];
let palette = get_palette();
let palette = Styling::default();
let ret = full_length_shortcut(false, keyvec, "Foobar", palette);
let ret = unstyle(ret);
@ -600,7 +573,7 @@ mod tests {
#[test]
fn full_length_shortcut_with_key_unprintable_1() {
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 = unstyle(ret);
@ -611,7 +584,7 @@ mod tests {
#[test]
fn full_length_shortcut_with_key_unprintable_2() {
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 = unstyle(ret);
@ -622,7 +595,7 @@ mod tests {
#[test]
fn full_length_shortcut_with_ctrl_key() {
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 = unstyle(ret);
@ -633,7 +606,7 @@ mod tests {
#[test]
fn full_length_shortcut_with_alt_key() {
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 = unstyle(ret);
@ -648,7 +621,7 @@ mod tests {
KeyWithModifier::new(BareKey::Char('b')),
KeyWithModifier::new(BareKey::Char('c')),
];
let palette = get_palette();
let palette = Styling::default();
let ret = full_length_shortcut(false, keyvec, "Foobar", palette);
let ret = unstyle(ret);
@ -663,7 +636,7 @@ mod tests {
KeyWithModifier::new(BareKey::Char('b')).with_ctrl_modifier(),
KeyWithModifier::new(BareKey::Enter),
];
let palette = get_palette();
let palette = Styling::default();
let ret = full_length_shortcut(false, keyvec, "Foobar", palette);
let ret = unstyle(ret);
@ -678,7 +651,7 @@ mod tests {
KeyWithModifier::new(BareKey::Char('b')).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 = unstyle(ret);

View file

@ -25,7 +25,7 @@ macro_rules! strings {
pub fn compact_layout_full(help: &ModeInfo) -> LinePart {
// Tip: UI taking up too much space? Start Zellij with
// 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![
Style::new().paint(" Tip: "),
@ -43,7 +43,7 @@ pub fn compact_layout_full(help: &ModeInfo) -> LinePart {
pub fn compact_layout_medium(help: &ModeInfo) -> LinePart {
// Tip: To save screen space, start Zellij with
// 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![
Style::new().paint(" Tip: "),
@ -61,7 +61,7 @@ pub fn compact_layout_medium(help: &ModeInfo) -> LinePart {
pub fn compact_layout_short(help: &ModeInfo) -> LinePart {
// Save screen space, start Zellij with
// 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![
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 {
// Tip: Search through the scrollbuffer using your default $EDITOR with
// 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![
Style::new().paint(" Tip: "),
@ -39,7 +39,7 @@ pub fn edit_scrollbuffer_full(help: &ModeInfo) -> LinePart {
pub fn edit_scrollbuffer_medium(help: &ModeInfo) -> LinePart {
// Tip: Search the scrollbuffer using your $EDITOR with
// 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![
Style::new().paint(" Tip: "),
@ -54,7 +54,7 @@ pub fn edit_scrollbuffer_medium(help: &ModeInfo) -> LinePart {
pub fn edit_scrollbuffer_short(help: &ModeInfo) -> LinePart {
// Search using $EDITOR with
// 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![
Style::new().paint(" Search using "),

View file

@ -25,7 +25,7 @@ macro_rules! strings {
pub fn move_tabs_full(help: &ModeInfo) -> LinePart {
// Tip: Wrong order of tabs? You can move them to left and right 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![
Style::new().paint(" Tip: "),
@ -41,7 +41,7 @@ pub fn move_tabs_full(help: &ModeInfo) -> LinePart {
pub fn move_tabs_medium(help: &ModeInfo) -> LinePart {
// Tip: You can move tabs to left and right 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![
Style::new().paint(" Tip: "),
@ -56,7 +56,7 @@ pub fn move_tabs_medium(help: &ModeInfo) -> LinePart {
pub fn move_tabs_short(help: &ModeInfo) -> LinePart {
// 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![
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 {
// 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 orange_color = palette_match!(help.style.colors.orange);
let green_color = palette_match!(help.style.colors.text_unselected.emphasis_2);
let orange_color = palette_match!(help.style.colors.text_unselected.emphasis_0);
strings!(&[
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 {
// Tip: SHIFT + <mouse-click> sends the click directly to the terminal
let green_color = palette_match!(help.style.colors.green);
let orange_color = palette_match!(help.style.colors.orange);
let green_color = palette_match!(help.style.colors.text_unselected.emphasis_2);
let orange_color = palette_match!(help.style.colors.text_unselected.emphasis_0);
strings!(&[
Style::new().paint(" Tip: "),
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 {
// Tip: SHIFT + <mouse-click> => sends click to terminal.
let green_color = palette_match!(help.style.colors.green);
let orange_color = palette_match!(help.style.colors.orange);
let green_color = palette_match!(help.style.colors.text_unselected.emphasis_2);
let orange_color = palette_match!(help.style.colors.text_unselected.emphasis_0);
strings!(&[
Style::new().paint(" Tip: "),

View file

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

View file

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

View file

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

View file

@ -4,12 +4,15 @@ use unicode_width::UnicodeWidthStr;
use zellij_tile::prelude::*;
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
let mut len = 0;
let mut cursors = vec![];
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(" "));
len += 1;
}
@ -21,36 +24,41 @@ pub fn render_tab(
text: String,
tab: &TabInfo,
is_alternate_tab: bool,
palette: Palette,
palette: Styling,
separator: &str,
) -> LinePart {
let focused_clients = tab.other_focused_clients.as_slice();
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
ThemeHue::Dark => palette.white,
ThemeHue::Light => palette.black,
let alternate_tab_color = if is_alternate_tab {
palette.ribbon_unselected.emphasis_1
} else {
palette.ribbon_unselected.background
};
let background_color = if tab.active {
palette.green
palette.ribbon_selected.background
} else if is_alternate_tab {
alternate_tab_color
} else {
palette.fg
palette.ribbon_unselected.background
};
let foreground_color = match palette.theme_hue {
ThemeHue::Dark => palette.black,
ThemeHue::Light => palette.white,
let foreground_color = if tab.active {
palette.ribbon_selected.base
} 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 tab_styled_text = style!(foreground_color, background_color)
.bold()
.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 (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
let mut s = String::new();
let cursor_beginning = style!(foreground_color, background_color)
@ -84,7 +92,7 @@ pub fn tab_style(
mut tabname: String,
tab: &TabInfo,
mut is_alternate_tab: bool,
palette: Palette,
palette: Styling,
capabilities: PluginCapabilities,
) -> LinePart {
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
.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 client_attributes = ClientAttributes {
@ -616,7 +616,7 @@ pub fn start_server_detached(
let palette = config
.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 {
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),
theme: new_config
.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),
default_shell: new_config.options.default_shell,
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::time::Instant;
use zellij_utils::{
data::{ModeInfo, Palette, Style},
data::{ModeInfo, Style, Styling},
errors::prelude::*,
input::command::RunCommand,
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;
for pane in self.panes.values_mut() {
pane.update_theme(theme);

View file

@ -16,7 +16,7 @@ use std::{
use zellij_utils::{
consts::{DEFAULT_SCROLL_BUFFER_SIZE, SCROLL_BUFFER_SIZE},
data::{Palette, PaletteColor},
data::{Palette, PaletteColor, Styling},
input::mouse::{MouseEvent, MouseEventType},
pane_size::SizeInPixels,
position::Position,
@ -1095,14 +1095,19 @@ impl Grid {
.selection
.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::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(
self.selection,
background_color,
None,
Some(foreground_color),
content_x,
content_y,
);
@ -1111,9 +1116,15 @@ impl Grid {
if res.contains_row(character_chunk.y.saturating_sub(content_y)) {
let (select_background_palette, select_foreground_palette) =
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 {
(style.colors.green, style.colors.black)
(
style.colors.text_unselected.emphasis_2,
style.colors.text_unselected.background,
)
};
let background_color = match select_background_palette {
PaletteColor::Rgb(rgb) => AnsiCode::RgbCode(rgb),
@ -2270,7 +2281,7 @@ impl Grid {
pub fn unlock_renders(&mut self) {
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();
}
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::{
channels::SenderWithContext,
data::{Event, InputMode, Mouse, Palette, PaletteColor, Style},
data::{Event, InputMode, Mouse, Palette, PaletteColor, Style, Styling},
errors::prelude::*,
input::layout::Run,
pane_size::PaneGeom,
@ -645,7 +645,7 @@ impl Pane for PluginPane {
.unwrap();
}
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) {
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.set_should_render(true);
}
fn update_theme(&mut self, theme: Palette) {
fn update_theme(&mut self, theme: Styling) {
self.style.colors = theme.clone();
for grid in self.grids.values_mut() {
grid.update_theme(theme.clone());
@ -768,10 +768,10 @@ impl PluginPane {
}
}
fn display_request_permission_message(&self, plugin_permission: &PluginPermission) -> String {
let bold_white = style!(self.style.colors.white).bold();
let cyan = style!(self.style.colors.cyan).bold();
let orange = style!(self.style.colors.orange).bold();
let green = style!(self.style.colors.green).bold();
let bold_white = style!(self.style.colors.text_unselected.base).bold();
let cyan = style!(self.style.colors.text_unselected.emphasis_1).bold();
let orange = style!(self.style.colors.text_unselected.emphasis_0).bold();
let green = style!(self.style.colors.text_unselected.emphasis_2).bold();
let mut messages = String::new();
let permissions: BTreeSet<PermissionType> =

View file

@ -123,7 +123,7 @@ impl SearchResult {
};
(skip, take)
} 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())
} else {
// 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::UnicodeWidthStr;
use zellij_utils::data::StyleDeclaration;
use zellij_utils::input::command::RunCommand;
use zellij_utils::{
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)]
pub enum LinkAnchor {
Start(u16),
@ -977,7 +984,9 @@ pub fn render_first_run_banner(
Some(run_command) => {
let bold_text = RESET_STYLES.bold(Some(AnsiCode::On));
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));
let waiting_to_run_text = "Waiting to run: ";
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 controls_bare_text_fourth_part = "> exit";
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));
let controls_line_length = controls_bare_text_first_part.len()
+ enter_bare_text.len()
@ -1054,7 +1065,9 @@ pub fn render_first_run_banner(
let ctrl_c_bare_text = "Ctrl-c";
let controls_bare_text_fourth_part = "> exit";
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));
let controls_line_length = controls_bare_text_first_part.len()
+ enter_bare_text.len()

View file

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

View file

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

View file

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

View file

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

View file

@ -12,60 +12,300 @@ Some(
),
keybinds: [],
style: Style {
colors: Palette {
source: Default,
theme_hue: Dark,
fg: EightBit(
0,
colors: Styling {
text_unselected: StyleDeclaration {
base: EightBit(
245,
),
bg: EightBit(
0,
background: EightBit(
238,
),
black: EightBit(
0,
emphasis_0: EightBit(
166,
),
red: EightBit(
0,
emphasis_1: EightBit(
51,
),
green: EightBit(
0,
emphasis_2: EightBit(
154,
),
yellow: EightBit(
0,
emphasis_3: EightBit(
201,
),
blue: EightBit(
0,
},
text_selected: StyleDeclaration {
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 {
base: EightBit(
16,
),
gold: EightBit(
0,
background: EightBit(
238,
),
silver: EightBit(
0,
emphasis_0: EightBit(
124,
),
pink: EightBit(
0,
emphasis_1: EightBit(
255,
),
brown: EightBit(
0,
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,
hide_session_name: false,

View file

@ -9,7 +9,8 @@ use std::time::Duration;
use log::{debug, warn};
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::input::command::RunCommand;
@ -357,7 +358,7 @@ pub enum ScreenInstruction {
client_id: ClientId,
keybinds: Keybinds,
default_mode: InputMode,
theme: Palette,
theme: Styling,
simplified_ui: bool,
default_shell: Option<PathBuf>,
pane_frames: bool,
@ -2445,7 +2446,7 @@ impl Screen {
&mut self,
new_keybinds: Keybinds,
new_default_mode: InputMode,
theme: Palette,
theme: Styling,
simplified_ui: bool,
default_shell: Option<PathBuf>,
pane_frames: bool,

View file

@ -49,7 +49,9 @@ use std::{
str,
};
use zellij_utils::{
data::{Event, FloatingPaneCoordinates, InputMode, ModeInfo, Palette, PaletteColor, Style},
data::{
Event, FloatingPaneCoordinates, InputMode, ModeInfo, Palette, PaletteColor, Style, Styling,
},
input::{
command::TerminalAction,
layout::{
@ -203,7 +205,7 @@ pub(crate) struct TabData {
pub name: String,
pub active: bool,
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
@ -513,7 +515,7 @@ pub trait Pane {
fn rerun(&mut self) -> Option<RunCommand> {
None
} // 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_rounded_corners(&mut self, _rounded_corners: bool) {}
fn set_should_be_suppressed(&mut self, _should_be_suppressed: bool) {}
@ -4402,7 +4404,7 @@ impl Tab {
}
Ok(())
}
pub fn update_theme(&mut self, theme: Palette) {
pub fn update_theme(&mut self, theme: Styling) {
self.style.colors = theme;
self.floating_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 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 text::{parse_text, parse_text_params, stringify_text, text, Text};
@ -87,7 +87,6 @@ impl<'a> UiComponentParser<'a> {
columns,
rows,
stringified_params,
Some(self.style.colors.green),
&self.style,
component_coordinates,
);

View file

@ -2,7 +2,7 @@ use super::{
is_too_high, parse_indices, parse_opaque, parse_selected, parse_text, stringify_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 unicode_width::UnicodeWidthChar;
@ -27,37 +27,29 @@ pub fn nested_list(
if is_too_high(line_index + 1, &coordinates) {
break;
}
let mut reset_styles_for_item = RESET_STYLES;
reset_styles_for_item.background = None;
reset_styles_for_item.foreground = None;
let style_declaration = if line_item.text.selected {
style.colors.list_selected
} else {
style.colors.list_unselected
};
let padding = line_item.indentation_level * 2 + 1;
let bulletin = if line_item.indentation_level % 2 == 0 {
"> "
} else {
"- "
};
let text_style = if line_item.text.selected {
reset_styles_for_item
.bold(Some(AnsiCode::On))
.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()))
let text_style = if line_item.text.opaque || line_item.text.selected {
CharacterStyles::from(style_declaration)
.background(Some(style_declaration.background.into()))
} else {
reset_styles_for_item
.bold(Some(AnsiCode::On))
.foreground(Some(style.colors.white.into()))
CharacterStyles::from(style_declaration)
};
let (mut text, text_width) = stringify_text(
&line_item.text,
Some(padding + bulletin.len()),
&coordinates,
style,
text_style,
line_item.text.selected,
&style_declaration,
text_style.bold(Some(AnsiCode::On)),
);
text = pad_line(text, max_width, padding, text_width);
let go_to_row_instruction = coordinates
@ -70,20 +62,13 @@ pub fn nested_list(
"".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!(
"{}{}{}{:padding$}{bulletin}{}{text}{}",
go_to_row_instruction, line_style, reset_styles_for_item, " ", text_style, RESET_STYLES
"{}{}{:padding$}{bulletin}{}{text}{}",
go_to_row_instruction,
text_style,
" ",
text_style.bold(Some(AnsiCode::On)),
RESET_STYLES
));
}
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 unicode_width::UnicodeWidthChar;
use zellij_utils::data::{PaletteColor, Style};
static ARROW_SEPARATOR: &str = "";
@ -12,25 +11,34 @@ pub fn ribbon(
component_coordinates: Option<Coordinates>,
) -> Vec<u8> {
let colors = style.colors;
let (first_arrow_styles, text_style, last_arrow_styles) = if content.selected {
(
character_style(colors.black, colors.green),
character_style(colors.black, colors.green),
character_style(colors.green, colors.black),
)
let background = colors.text_unselected.background;
let declaration = if content.selected {
colors.ribbon_selected
} else {
(
character_style(colors.black, colors.fg),
character_style(colors.black, colors.fg),
character_style(colors.fg, colors.black),
)
colors.ribbon_unselected
};
let (text, _text_width) =
stringify_ribbon_text(&content, &component_coordinates, style, text_style);
let (first_arrow_styles, text_style, last_arrow_styles) = (
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
.map(|c| c.to_string())
.unwrap_or_else(|| String::new());
let arrow = if arrow_fonts { ARROW_SEPARATOR } else { "" };
stringified.push_str(&format!(
"{}{}{}{} {} {}{}{}",
RESET_STYLES,
@ -45,68 +53,6 @@ pub fn ribbon(
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 {
RESET_STYLES
.foreground(Some(foreground.into()))

View file

@ -1,16 +1,15 @@
use super::{is_too_high, is_too_wide, stringify_text, Coordinates, Text};
use crate::panes::terminal_character::{AnsiCode, RESET_STYLES};
use std::collections::BTreeMap;
use zellij_utils::{
data::{PaletteColor, Style},
shared::ansi_len,
use crate::panes::{
terminal_character::{AnsiCode, RESET_STYLES},
CharacterStyles,
};
use std::collections::BTreeMap;
use zellij_utils::{data::Style, shared::ansi_len};
pub fn table(
columns: usize,
_rows: usize,
contents: Vec<Text>,
title_color: Option<PaletteColor>,
style: &Style,
coordinates: Option<Coordinates>,
) -> 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
let stringified_columns = stringify_table_columns(contents, columns);
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() {
let is_title_row = row_index == 0;
if is_too_high(row_index + 1, &coordinates) {
break;
}
for cell in row {
let mut reset_styles_for_item = RESET_STYLES;
let mut text_style = if is_title_row {
title_styles
let declaration = if is_title_row {
style.colors.table_title
} else {
cell_styles
};
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()));
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)
};
// here we intentionally don't pass our coordinates even if we have them, because
// these cells have already been padded and truncated
let (text, _text_width) =
stringify_text(&cell, None, &None, style, text_style, cell.selected);
stringified.push_str(&format!("{}{}{} ", text_style, text, reset_styles_for_item));
let (text, _text_width) = stringify_text(
&cell,
None,
&None,
&declaration,
text_style.bold(Some(AnsiCode::On)),
);
stringified.push_str(&format!("{}{} {}", text_style, text, RESET_STYLES));
}
let next_row_instruction = coordinates
.as_ref()

View file

@ -1,10 +1,7 @@
use super::{
emphasis_variants_for_ribbon, emphasis_variants_for_selected_ribbon, is_too_wide,
parse_indices, parse_opaque, parse_selected, Coordinates,
};
use crate::panes::terminal_character::{AnsiCode, CharacterStyles, RESET_STYLES};
use super::{is_too_wide, parse_indices, parse_opaque, parse_selected, Coordinates};
use crate::panes::{terminal_character::CharacterStyles, AnsiCode};
use zellij_utils::{
data::{PaletteColor, Style},
data::{PaletteColor, Style, StyleDeclaration},
shared::ansi_len,
};
@ -12,28 +9,28 @@ use unicode_width::UnicodeWidthChar;
use zellij_utils::errors::prelude::*;
pub fn text(content: Text, style: &Style, component_coordinates: Option<Coordinates>) -> Vec<u8> {
let mut text_style = RESET_STYLES
.bold(Some(AnsiCode::On))
.foreground(Some(style.colors.white.into()));
let declaration = if content.selected {
style.colors.text_selected
} 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(
&content,
None,
&component_coordinates,
style,
text_style,
content.selected,
&declaration,
base_text_style,
);
match component_coordinates {
Some(component_coordinates) => format!("{}{}{}", component_coordinates, text_style, text)
Some(component_coordinates) => {
format!("{}{}{}", component_coordinates, base_text_style, text)
.as_bytes()
.to_vec(),
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,
left_padding: Option<usize>,
coordinates: &Option<Coordinates>,
style: &Style,
text_style: CharacterStyles,
is_selected: bool,
style: &StyleDeclaration,
component_text_style: CharacterStyles,
) -> (String, usize) {
let mut text_width = 0;
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() {
let character_width = character.width().unwrap_or(0);
if is_too_wide(
@ -59,14 +60,14 @@ pub fn stringify_text(
text_width += character_width;
if !text.indices.is_empty() {
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);
} else {
stringified.push(character);
stringified.push(character)
}
}
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)) => {
let text_width_with_left_padding = text_width + left_padding.unwrap_or(0);
let background_padding_length =
@ -91,32 +92,16 @@ pub fn color_index_character(
character: char,
index: usize,
text: &Text,
style: &Style,
declaration: &StyleDeclaration,
base_text_style: CharacterStyles,
is_selected: bool,
) -> String {
let character_style = text
.style_of_index(index, style)
.map(|foreground_style| {
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
})
.style_of_index(index, declaration)
.map(|foreground_style| base_text_style.foreground(Some(foreground_style.into())))
.unwrap_or(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> {
params_iter
.flat_map(|mut stringified| {
@ -148,8 +133,14 @@ impl Text {
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() {
// we do this in reverse to give precedence to the last applied
// style
@ -159,37 +150,7 @@ impl Text {
}
}
}
None
}
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
Some(style.base)
}
}

View file

@ -1,7 +1,7 @@
use std::fmt::{Display, Error, Formatter};
use zellij_utils::{
data::{Palette, PaletteColor},
data::{PaletteColor, Styling},
errors::prelude::*,
};
@ -24,7 +24,7 @@ pub struct LoadingIndication {
error: Option<String>,
animation_offset: usize,
plugin_name: String,
terminal_emulator_colors: Option<Palette>,
terminal_emulator_colors: Option<Styling>,
override_previous_error: bool,
}
@ -39,7 +39,7 @@ impl LoadingIndication {
pub fn set_name(&mut self, plugin_name: String) {
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
}
@ -142,19 +142,27 @@ macro_rules! style {
impl Display for LoadingIndication {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
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(),
};
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(),
};
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(),
};
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(),
};
let bold = ansi_term::Style::new().bold().italic();

View file

@ -127,7 +127,7 @@ impl PaneFrame {
self.color = Some(color);
}
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))
}
fn get_corner(&self, corner: &'static str) -> &'static str {
@ -847,9 +847,9 @@ impl PaneFrame {
let exited_text = "EXIT CODE: ";
let exit_code_text = format!("{}", exit_code);
let exit_code_color = if exit_code == 0 {
self.style.colors.green
self.style.colors.exit_code_success.base
} else {
self.style.colors.red
self.style.colors.exit_code_error.base
};
let right_bracket = " ] ";
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(
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));
(
@ -910,7 +910,7 @@ impl PaneFrame {
second_part.append(&mut foreground_color(left_enter_bracket, self.color));
second_part.append(&mut foreground_color(
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(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(
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(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(
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(break_tip, self.color));

View file

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

View file

@ -1,12 +1,15 @@
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Style {
#[deprecated]
#[prost(message, optional, tag = "1")]
pub palette: ::core::option::Option<Palette>,
#[prost(bool, tag = "2")]
pub rounded_corners: bool,
#[prost(bool, tag = "3")]
pub hide_session_name: bool,
#[prost(message, optional, tag = "4")]
pub styling: ::core::option::Option<Styling>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
@ -77,6 +80,40 @@ pub struct RgbColorPayload {
#[prost(uint32, tag = "3")]
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)]
#[repr(i32)]
pub enum ColorType {

View file

@ -2,6 +2,7 @@ use crate::input::actions::Action;
use crate::input::config::ConversionError;
use crate::input::keybinds::Keybinds;
use crate::input::layout::{RunPlugin, SplitSize};
use crate::shared::colors as default_colors;
use clap::ArgEnum;
use serde::{Deserialize, Serialize};
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(
client_id: ClientId,
colors: Palette,
colors: MultiplayerColors,
) -> Option<(PaletteColor, PaletteColor)> {
// (primary color, secondary color)
let black = PaletteColor::EightBit(default_colors::BLACK);
match client_id {
1 => Some((colors.magenta, colors.black)),
2 => Some((colors.blue, colors.black)),
3 => Some((colors.purple, colors.black)),
4 => Some((colors.yellow, colors.black)),
5 => Some((colors.cyan, colors.black)),
6 => Some((colors.gold, colors.black)),
7 => Some((colors.red, colors.black)),
8 => Some((colors.silver, colors.black)),
9 => Some((colors.pink, colors.black)),
10 => Some((colors.brown, colors.black)),
1 => Some((colors.player_1, black)),
2 => Some((colors.player_2, black)),
3 => Some((colors.player_3, black)),
4 => Some((colors.player_4, black)),
5 => Some((colors.player_5, black)),
6 => Some((colors.player_6, black)),
7 => Some((colors.player_7, black)),
8 => Some((colors.player_8, black)),
9 => Some((colors.player_9, black)),
10 => Some((colors.player_10, black)),
_ => None,
}
}
@ -1133,11 +1135,349 @@ pub struct Palette {
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default, Serialize, Deserialize)]
pub struct Style {
pub colors: Palette,
pub colors: Styling,
pub rounded_corners: 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`...
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) {
self.base_mode = Some(new_default_mode);
}
pub fn update_theme(&mut self, theme: Palette) {
self.style.colors = theme;
pub fn update_theme(&mut self, theme: Styling) {
self.style.colors = theme.into();
}
pub fn update_rounded_corners(&mut self, rounded_corners: bool) {
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 serde::{Deserialize, Serialize};
use std::collections::HashSet;
@ -166,7 +166,7 @@ impl TryFrom<&CliArgs> for 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 {
Some(theme_name) => self.themes.get_theme(theme_name).map(|theme| theme.palette),
None => self.themes.get_theme("default").map(|theme| theme.palette),
@ -407,8 +407,8 @@ impl Config {
#[cfg(test)]
mod config_test {
use super::*;
use crate::data::{InputMode, Palette, PaletteColor};
use crate::input::layout::RunPlugin;
use crate::data::{InputMode, Palette, PaletteColor, PluginTag, StyleDeclaration, Styling};
use crate::input::layout::{RunPlugin, RunPluginLocation};
use crate::input::options::{Clipboard, OnForceClose};
use crate::input::theme::{FrameConfig, Theme, Themes, UiConfig};
use std::collections::{BTreeMap, HashMap};
@ -630,7 +630,8 @@ mod config_test {
black: PaletteColor::Rgb((0, 0, 0)),
white: PaletteColor::Rgb((255, 255, 255)),
..Default::default()
},
}
.into(),
sourced_from_external_file: false,
},
);
@ -688,7 +689,8 @@ mod config_test {
black: PaletteColor::Rgb((0, 0, 0)),
white: PaletteColor::Rgb((255, 255, 255)),
..Default::default()
},
}
.into(),
sourced_from_external_file: false,
},
);
@ -708,7 +710,8 @@ mod config_test {
white: PaletteColor::Rgb((229, 233, 240)),
orange: PaletteColor::Rgb((208, 135, 112)),
..Default::default()
},
}
.into(),
sourced_from_external_file: false,
},
);
@ -753,7 +756,8 @@ mod config_test {
black: PaletteColor::EightBit(1),
white: PaletteColor::EightBit(255),
..Default::default()
},
}
.into(),
sourced_from_external_file: false,
},
);
@ -761,6 +765,304 @@ mod config_test {
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]
fn can_define_plugin_configuration_in_configfile() {
let config_contents = r#"

View file

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

View file

@ -1,109 +1,600 @@
---
source: zellij-utils/src/input/./unit/theme_test.rs
assertion_line: 15
expression: "format!(\"{:#?}\", theme)"
---
{
"dracula": Theme {
palette: Palette {
source: Default,
theme_hue: Dark,
fg: Rgb(
sourced_from_external_file: true,
palette: Styling {
text_unselected: StyleDeclaration {
base: Rgb(
(
248,
248,
242,
255,
255,
255,
),
),
bg: Rgb(
(
40,
42,
54,
),
),
black: Rgb(
background: 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(
emphasis_0: Rgb(
(
255,
184,
108,
),
),
gray: EightBit(
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,
),
purple: EightBit(
),
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,
),
gold: EightBit(
),
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,
),
silver: EightBit(
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,
),
pink: EightBit(
),
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,
),
brown: EightBit(
),
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,
),
},
sourced_from_external_file: true,
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;
use crate::data::{
BareKey, Direction, FloatingPaneCoordinates, InputMode, KeyWithModifier, LayoutInfo, Palette,
PaletteColor, PaneInfo, PaneManifest, PermissionType, Resize, SessionInfo, TabInfo,
BareKey, Direction, FloatingPaneCoordinates, InputMode, KeyWithModifier, LayoutInfo,
MultiplayerColors, Palette, PaletteColor, PaneInfo, PaneManifest, PermissionType, Resize,
SessionInfo, StyleDeclaration, Styling, TabInfo, DEFAULT_STYLES,
};
use crate::envs::EnvironmentVariables;
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 {
type Error = ConfigError;
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_rules! kdl_get_string_property_or_child_value_with_error {
( $kdl_node:expr, $name:expr ) => {
@ -3930,6 +3980,66 @@ impl UiConfig {
}
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(
themes_from_kdl: &KdlNode,
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") {
let theme_name = kdl_name!(theme_config);
let theme_colors = kdl_children_or_error!(theme_config, "empty theme");
let theme = Theme {
palette: Palette {
let palette_color_names = HashSet::from([
"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))?,
bg: PaletteColor::try_from(("bg", theme_colors))?,
red: PaletteColor::try_from(("red", theme_colors))?,
@ -3952,8 +4071,92 @@ impl Themes {
black: PaletteColor::try_from(("black", theme_colors))?,
white: PaletteColor::try_from(("white", theme_colors))?,
..Default::default()
},
};
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);
}
@ -4017,39 +4220,64 @@ impl Themes {
has_themes = true;
let mut current_theme_node = KdlNode::new(theme_name.clone());
let mut current_theme_node_children = KdlDocument::new();
current_theme_node_children
.nodes_mut()
.push(theme.palette.fg.to_kdl("fg"));
.push(theme.palette.text_unselected.to_kdl("text_unselected"));
current_theme_node_children
.nodes_mut()
.push(theme.palette.bg.to_kdl("bg"));
.push(theme.palette.text_selected.to_kdl("text_selected"));
current_theme_node_children
.nodes_mut()
.push(theme.palette.red.to_kdl("red"));
.push(theme.palette.ribbon_selected.to_kdl("ribbon_selected"));
current_theme_node_children
.nodes_mut()
.push(theme.palette.green.to_kdl("green"));
.push(theme.palette.ribbon_unselected.to_kdl("ribbon_unselected"));
current_theme_node_children
.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
.nodes_mut()
.push(theme.palette.blue.to_kdl("blue"));
.push(theme.palette.list_selected.to_kdl("list_selected"));
current_theme_node_children
.nodes_mut()
.push(theme.palette.magenta.to_kdl("magenta"));
.push(theme.palette.list_unselected.to_kdl("list_unselected"));
current_theme_node_children
.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(theme.palette.cyan.to_kdl("cyan"));
.push(frame_unselected_style.to_kdl("frame_unselected"));
},
}
current_theme_node_children
.nodes_mut()
.push(theme.palette.black.to_kdl("black"));
.push(theme.palette.frame_highlight.to_kdl("frame_highlight"));
current_theme_node_children
.nodes_mut()
.push(theme.palette.white.to_kdl("white"));
.push(theme.palette.exit_code_success.to_kdl("exit_code_success"));
current_theme_node_children
.nodes_mut()
.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);
themes.nodes_mut().push(current_theme_node);
}
@ -5168,7 +5396,7 @@ fn themes_to_string() {
.unwrap();
assert_eq!(
deserialized, deserialized_from_serialized,
"Deserialized serialized config equals original config"
"Deserialized serialized config equals original config",
);
insta::assert_snapshot!(serialized.to_string());
}

View file

@ -1,20 +1,124 @@
---
source: zellij-utils/src/kdl/mod.rs
assertion_line: 3697
expression: serialized.to_string()
---
themes {
dracula {
fg 248 248 242
bg 40 42 54
red 255 85 85
green 80 250 123
yellow 241 250 140
blue 98 114 164
magenta 255 121 198
orange 255 184 108
cyan 139 233 253
black 0 0 0
white 255 255 255
text_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
}
text_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
}
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
assertion_line: 3775
expression: serialized.to_string()
---
themes {
default {
fg 1
bg 10
red 30
green 40
yellow 50
blue 60
magenta 70
orange 208 135 112
cyan 80
black 20
white 255 255 255
text_unselected {
base 255 255 255
background 20
emphasis_0 208 135 112
emphasis_1 80
emphasis_2 40
emphasis_3 70
}
text_selected {
base 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
assertion_line: 3749
expression: serialized.to_string()
---
themes {
default {
fg 1
bg 10
red 30
green 40
yellow 50
blue 60
magenta 70
orange 254
cyan 80
black 20
white 90
text_unselected {
base 90
background 20
emphasis_0 254
emphasis_1 80
emphasis_2 40
emphasis_3 70
}
text_selected {
base 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
assertion_line: 3723
expression: serialized.to_string()
---
themes {
nord {
fg 216 222 233
bg 46 52 64
red 191 97 106
green 163 190 140
yellow 235 203 139
blue 129 161 193
magenta 180 142 173
orange 208 135 112
cyan 136 192 208
black 59 66 82
white 229 233 240
text_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
}
text_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
}
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
assertion_line: 4821
expression: serialized.to_string()
---
themes {
dracula {
fg 248 248 242
bg 40 42 54
red 255 85 85
green 80 250 123
yellow 241 250 140
blue 98 114 164
magenta 255 121 198
orange 255 184 108
cyan 139 233 253
black 0 0 0
white 255 255 255
text_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
}
text_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
}
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 {
fg 216 222 233
bg 46 52 64
red 191 97 106
green 163 190 140
yellow 235 203 139
blue 129 161 193
magenta 180 142 173
orange 208 135 112
cyan 136 192 208
black 59 66 82
white 229 233 240
text_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
}
text_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
}
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),
pink: PaletteColor::EightBit(2),
brown: PaletteColor::Rgb((222, 221, 220)),
},
}
.into(),
// TODO: replace default
rounded_corners: true,
hide_session_name: false,
},

View file

@ -3,9 +3,10 @@ syntax = "proto3";
package api.style;
message Style {
Palette palette = 1;
Palette palette = 1 [deprecated = true];
bool rounded_corners = 2;
bool hide_session_name = 3;
Styling styling = 4;
}
message Palette {
@ -52,3 +53,21 @@ enum ThemeHue {
Dark = 0;
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::{
color::Payload as ProtobufColorPayload, Color as ProtobufColor, ColorType as ProtobufColorType,
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 std::convert::TryFrom;
@ -11,24 +13,183 @@ use std::convert::TryFrom;
impl TryFrom<ProtobufStyle> for Style {
type Error = &'static str;
fn try_from(protobuf_style: ProtobufStyle) -> Result<Self, &'static str> {
Ok(Style {
colors: protobuf_style
.palette
let s = protobuf_style
.styling
.ok_or("malformed style payload")?
.try_into()?,
.try_into()?;
Ok(Style {
colors: s,
rounded_corners: protobuf_style.rounded_corners,
hide_session_name: protobuf_style.hide_session_name,
})
}
}
#[allow(deprecated)]
impl TryFrom<Style> for ProtobufStyle {
type Error = &'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 {
palette: Some(style.colors.try_into()?),
palette: Some(palette.try_into()?),
rounded_corners: style.rounded_corners,
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()?,
})
}
}