diff --git a/CHANGELOG.md b/CHANGELOG.md index 77287236ce..62d0e87a07 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) * Add more functionality to unbinding the default keybindings (https://github.com/zellij-org/zellij/pull/468) * Terminal compatibility: fix support for CSI subparameters (https://github.com/zellij-org/zellij/pull/469) * Move the sync command to tab mode (https://github.com/zellij-org/zellij/pull/412) +* Add support for requesting a simpler layout from plugins, move `clean` flag from `options` to `setup` (https://github.com/zellij-org/zellij/pull/479) * Fix exit code of `dump-default-config` (https://github.com/zellij-org/zellij/pull/480) * Feature: Switch tabs using `Alt + h/l` in normal mode if there are no panes in the direction (https://github.com/zellij-org/zellij/pull/471) * Terminal Compatibility: various behaviour fixes (https://github.com/zellij-org/zellij/pull/486) diff --git a/README.md b/README.md index 3751e9acf4..a1a41fe6bc 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,11 @@ cargo install zellij Or you can download a prebuilt binary from our [Releases](https://github.com/zellij-org/zellij/releases). +As the default plugins make use of characters that are mostly only found in [nerdfonts](https://www.nerdfonts.com/), +you get the best experience either with installing nerdfonts, or telling the plugins that you request a ui, that +does not rely on such characters with `zellij options --simplified-ui`, or putting `simplified_ui: true` in the +config file. + ## How do I hack on it? (Contributing) * Clone the project * Install cargo-make with `cargo install --force cargo-make` diff --git a/default-plugins/status-bar/src/first_line.rs b/default-plugins/status-bar/src/first_line.rs index f679e8637c..37175e3fae 100644 --- a/default-plugins/status-bar/src/first_line.rs +++ b/default-plugins/status-bar/src/first_line.rs @@ -2,7 +2,7 @@ use ansi_term::ANSIStrings; use zellij_tile::prelude::*; use crate::color_elements; -use crate::{ColoredElements, LinePart, ARROW_SEPARATOR}; +use crate::{ColoredElements, LinePart}; struct CtrlKeyShortcut { mode: CtrlKeyMode, @@ -63,13 +63,18 @@ impl CtrlKeyShortcut { } } -fn unselected_mode_shortcut(letter: char, text: &str, palette: ColoredElements) -> LinePart { - let prefix_separator = palette.unselected_prefix_separator.paint(ARROW_SEPARATOR); +fn unselected_mode_shortcut( + letter: char, + text: &str, + palette: ColoredElements, + separator: &str, +) -> LinePart { + let prefix_separator = palette.unselected_prefix_separator.paint(separator); let char_left_separator = palette.unselected_char_left_separator.paint(" <"); let char_shortcut = palette.unselected_char_shortcut.paint(letter.to_string()); let char_right_separator = palette.unselected_char_right_separator.paint(">"); let styled_text = palette.unselected_styled_text.paint(format!("{} ", text)); - let suffix_separator = palette.unselected_suffix_separator.paint(ARROW_SEPARATOR); + let suffix_separator = palette.unselected_suffix_separator.paint(separator); LinePart { part: ANSIStrings(&[ prefix_separator, @@ -84,13 +89,18 @@ fn unselected_mode_shortcut(letter: char, text: &str, palette: ColoredElements) } } -fn selected_mode_shortcut(letter: char, text: &str, palette: ColoredElements) -> LinePart { - let prefix_separator = palette.selected_prefix_separator.paint(ARROW_SEPARATOR); +fn selected_mode_shortcut( + letter: char, + text: &str, + palette: ColoredElements, + separator: &str, +) -> LinePart { + let prefix_separator = palette.selected_prefix_separator.paint(separator); let char_left_separator = palette.selected_char_left_separator.paint(" <".to_string()); let char_shortcut = palette.selected_char_shortcut.paint(format!("{}", letter)); let char_right_separator = palette.selected_char_right_separator.paint(">".to_string()); let styled_text = palette.selected_styled_text.paint(format!("{} ", text)); - let suffix_separator = palette.selected_suffix_separator.paint(ARROW_SEPARATOR); + let suffix_separator = palette.selected_suffix_separator.paint(separator); LinePart { part: ANSIStrings(&[ prefix_separator, @@ -105,69 +115,89 @@ fn selected_mode_shortcut(letter: char, text: &str, palette: ColoredElements) -> } } -fn disabled_mode_shortcut(text: &str, palette: ColoredElements) -> LinePart { - let prefix_separator = palette.disabled_prefix_separator.paint(ARROW_SEPARATOR); +fn disabled_mode_shortcut(text: &str, palette: ColoredElements, separator: &str) -> LinePart { + let prefix_separator = palette.disabled_prefix_separator.paint(separator); let styled_text = palette.disabled_styled_text.paint(format!("{} ", text)); - let suffix_separator = palette.disabled_suffix_separator.paint(ARROW_SEPARATOR); + let suffix_separator = palette.disabled_suffix_separator.paint(separator); LinePart { part: format!("{}{}{}", prefix_separator, styled_text, suffix_separator), len: text.chars().count() + 2 + 1, // 2 for the arrows, 1 for the padding in the end } } -fn selected_mode_shortcut_single_letter(letter: char, palette: ColoredElements) -> LinePart { +fn selected_mode_shortcut_single_letter( + letter: char, + palette: ColoredElements, + separator: &str, +) -> LinePart { let char_shortcut_text = format!(" {} ", letter); let len = char_shortcut_text.chars().count() + 4; // 2 for the arrows, 2 for the padding let prefix_separator = palette .selected_single_letter_prefix_separator - .paint(ARROW_SEPARATOR); + .paint(separator); let char_shortcut = palette .selected_single_letter_char_shortcut .paint(char_shortcut_text); let suffix_separator = palette .selected_single_letter_suffix_separator - .paint(ARROW_SEPARATOR); + .paint(separator); LinePart { part: ANSIStrings(&[prefix_separator, char_shortcut, suffix_separator]).to_string(), len, } } -fn unselected_mode_shortcut_single_letter(letter: char, palette: ColoredElements) -> LinePart { +fn unselected_mode_shortcut_single_letter( + letter: char, + palette: ColoredElements, + separator: &str, +) -> LinePart { let char_shortcut_text = format!(" {} ", letter); let len = char_shortcut_text.chars().count() + 4; // 2 for the arrows, 2 for the padding let prefix_separator = palette .unselected_single_letter_prefix_separator - .paint(ARROW_SEPARATOR); + .paint(separator); let char_shortcut = palette .unselected_single_letter_char_shortcut .paint(char_shortcut_text); let suffix_separator = palette .unselected_single_letter_suffix_separator - .paint(ARROW_SEPARATOR); + .paint(separator); LinePart { part: ANSIStrings(&[prefix_separator, char_shortcut, suffix_separator]).to_string(), len, } } -fn full_ctrl_key(key: &CtrlKeyShortcut, palette: ColoredElements) -> LinePart { +fn full_ctrl_key(key: &CtrlKeyShortcut, palette: ColoredElements, separator: &str) -> LinePart { let full_text = key.full_text(); let letter_shortcut = key.letter_shortcut(); match key.mode { - CtrlKeyMode::Unselected => { - unselected_mode_shortcut(letter_shortcut, &format!(" {}", full_text), palette) - } - CtrlKeyMode::Selected => { - selected_mode_shortcut(letter_shortcut, &format!(" {}", full_text), palette) - } - CtrlKeyMode::Disabled => { - disabled_mode_shortcut(&format!(" <{}> {}", letter_shortcut, full_text), palette) - } + CtrlKeyMode::Unselected => unselected_mode_shortcut( + letter_shortcut, + &format!(" {}", full_text), + palette, + separator, + ), + CtrlKeyMode::Selected => selected_mode_shortcut( + letter_shortcut, + &format!(" {}", full_text), + palette, + separator, + ), + CtrlKeyMode::Disabled => disabled_mode_shortcut( + &format!(" <{}> {}", letter_shortcut, full_text), + palette, + separator, + ), } } -fn shortened_ctrl_key(key: &CtrlKeyShortcut, palette: ColoredElements) -> LinePart { +fn shortened_ctrl_key( + key: &CtrlKeyShortcut, + palette: ColoredElements, + separator: &str, +) -> LinePart { let shortened_text = key.shortened_text(); let letter_shortcut = key.letter_shortcut(); let shortened_text = match key.action { @@ -176,33 +206,47 @@ fn shortened_ctrl_key(key: &CtrlKeyShortcut, palette: ColoredElements) -> LinePa }; match key.mode { CtrlKeyMode::Unselected => { - unselected_mode_shortcut(letter_shortcut, &shortened_text, palette) + unselected_mode_shortcut(letter_shortcut, &shortened_text, palette, separator) + } + CtrlKeyMode::Selected => { + selected_mode_shortcut(letter_shortcut, &shortened_text, palette, separator) } - CtrlKeyMode::Selected => selected_mode_shortcut(letter_shortcut, &shortened_text, palette), - CtrlKeyMode::Disabled => disabled_mode_shortcut( - &format!(" <{}>{}", letter_shortcut, shortened_text), - palette, - ), CtrlKeyMode::Disabled => disabled_mode_shortcut( &format!(" <{}>{}", letter_shortcut, shortened_text), palette, + separator, ), } } -fn single_letter_ctrl_key(key: &CtrlKeyShortcut, palette: ColoredElements) -> LinePart { +fn single_letter_ctrl_key( + key: &CtrlKeyShortcut, + palette: ColoredElements, + separator: &str, +) -> LinePart { let letter_shortcut = key.letter_shortcut(); match key.mode { - CtrlKeyMode::Unselected => unselected_mode_shortcut_single_letter(letter_shortcut, palette), - CtrlKeyMode::Selected => selected_mode_shortcut_single_letter(letter_shortcut, palette), - CtrlKeyMode::Disabled => disabled_mode_shortcut(&format!(" {}", letter_shortcut), palette), + CtrlKeyMode::Unselected => { + unselected_mode_shortcut_single_letter(letter_shortcut, palette, separator) + } + CtrlKeyMode::Selected => { + selected_mode_shortcut_single_letter(letter_shortcut, palette, separator) + } + CtrlKeyMode::Disabled => { + disabled_mode_shortcut(&format!(" {}", letter_shortcut), palette, separator) + } } } -fn key_indicators(max_len: usize, keys: &[CtrlKeyShortcut], palette: ColoredElements) -> LinePart { +fn key_indicators( + max_len: usize, + keys: &[CtrlKeyShortcut], + palette: ColoredElements, + separator: &str, +) -> LinePart { let mut line_part = LinePart::default(); for ctrl_key in keys { - let key = full_ctrl_key(ctrl_key, palette); + let key = full_ctrl_key(ctrl_key, palette, separator); line_part.part = format!("{}{}", line_part.part, key.part); line_part.len += key.len; } @@ -211,7 +255,7 @@ fn key_indicators(max_len: usize, keys: &[CtrlKeyShortcut], palette: ColoredElem } line_part = LinePart::default(); for ctrl_key in keys { - let key = shortened_ctrl_key(ctrl_key, palette); + let key = shortened_ctrl_key(ctrl_key, palette, separator); line_part.part = format!("{}{}", line_part.part, key.part); line_part.len += key.len; } @@ -220,7 +264,7 @@ fn key_indicators(max_len: usize, keys: &[CtrlKeyShortcut], palette: ColoredElem } line_part = LinePart::default(); for ctrl_key in keys { - let key = single_letter_ctrl_key(ctrl_key, palette); + let key = single_letter_ctrl_key(ctrl_key, palette, separator); line_part.part = format!("{}{}", line_part.part, key.part); line_part.len += key.len; } @@ -231,17 +275,17 @@ fn key_indicators(max_len: usize, keys: &[CtrlKeyShortcut], palette: ColoredElem line_part } -pub fn superkey(palette: ColoredElements) -> LinePart { +pub fn superkey(palette: ColoredElements, separator: &str) -> LinePart { let prefix_text = " Ctrl +"; let prefix = palette.superkey_prefix.paint(prefix_text); - let suffix_separator = palette.superkey_suffix_separator.paint(ARROW_SEPARATOR); + let suffix_separator = palette.superkey_suffix_separator.paint(separator); LinePart { part: ANSIStrings(&[prefix, suffix_separator]).to_string(), len: prefix_text.chars().count(), } } -pub fn ctrl_keys(help: &ModeInfo, max_len: usize) -> LinePart { +pub fn ctrl_keys(help: &ModeInfo, max_len: usize, separator: &str) -> LinePart { let colored_elements = color_elements(help.palette); match &help.mode { InputMode::Locked => key_indicators( @@ -255,6 +299,7 @@ pub fn ctrl_keys(help: &ModeInfo, max_len: usize) -> LinePart { CtrlKeyShortcut::new(CtrlKeyMode::Disabled, CtrlKeyAction::Quit), ], colored_elements, + separator, ), InputMode::Resize => key_indicators( max_len, @@ -267,6 +312,7 @@ pub fn ctrl_keys(help: &ModeInfo, max_len: usize) -> LinePart { CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Quit), ], colored_elements, + separator, ), InputMode::Pane => key_indicators( max_len, @@ -279,6 +325,7 @@ pub fn ctrl_keys(help: &ModeInfo, max_len: usize) -> LinePart { CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Quit), ], colored_elements, + separator, ), InputMode::Tab | InputMode::RenameTab => key_indicators( max_len, @@ -291,6 +338,7 @@ pub fn ctrl_keys(help: &ModeInfo, max_len: usize) -> LinePart { CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Quit), ], colored_elements, + separator, ), InputMode::Scroll => key_indicators( max_len, @@ -303,6 +351,7 @@ pub fn ctrl_keys(help: &ModeInfo, max_len: usize) -> LinePart { CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Quit), ], colored_elements, + separator, ), InputMode::Normal => key_indicators( max_len, @@ -315,6 +364,7 @@ pub fn ctrl_keys(help: &ModeInfo, max_len: usize) -> LinePart { CtrlKeyShortcut::new(CtrlKeyMode::Unselected, CtrlKeyAction::Quit), ], colored_elements, + separator, ), } } diff --git a/default-plugins/status-bar/src/main.rs b/default-plugins/status-bar/src/main.rs index e1a79d49a0..bb56c279a9 100644 --- a/default-plugins/status-bar/src/main.rs +++ b/default-plugins/status-bar/src/main.rs @@ -140,9 +140,15 @@ impl ZellijPlugin for State { } fn render(&mut self, _rows: usize, cols: usize) { + let separator = if !self.mode_info.capabilities.arrow_fonts { + ARROW_SEPARATOR + } else { + &"" + }; + let colored_elements = color_elements(self.mode_info.palette); - let superkey = superkey(colored_elements); - let ctrl_keys = ctrl_keys(&self.mode_info, cols - superkey.len); + let superkey = superkey(colored_elements, separator); + let ctrl_keys = ctrl_keys(&self.mode_info, cols - superkey.len, separator); let first_line = format!("{}{}", superkey, ctrl_keys); let second_line = keybinds(&self.mode_info, cols); diff --git a/default-plugins/tab-bar/src/line.rs b/default-plugins/tab-bar/src/line.rs index 89a7aa1b39..574edb78d7 100644 --- a/default-plugins/tab-bar/src/line.rs +++ b/default-plugins/tab-bar/src/line.rs @@ -48,7 +48,7 @@ fn populate_tabs_in_tab_line( } } -fn left_more_message(tab_count_to_the_left: usize, palette: Palette) -> LinePart { +fn left_more_message(tab_count_to_the_left: usize, palette: Palette, separator: &str) -> LinePart { if tab_count_to_the_left == 0 { return LinePart { part: String::new(), @@ -62,11 +62,11 @@ fn left_more_message(tab_count_to_the_left: usize, palette: Palette) -> LinePart }; // 238 let more_text_len = more_text.chars().count() + 2; // 2 for the arrows - let left_separator = style!(palette.bg, palette.orange).paint(ARROW_SEPARATOR); + let left_separator = style!(palette.bg, palette.orange).paint(separator); let more_styled_text = style!(palette.black, palette.orange) .bold() .paint(more_text); - let right_separator = style!(palette.orange, palette.bg).paint(ARROW_SEPARATOR); + let right_separator = style!(palette.orange, palette.bg).paint(separator); let more_styled_text = format!( "{}", ANSIStrings(&[left_separator, more_styled_text, right_separator,]) @@ -77,7 +77,11 @@ fn left_more_message(tab_count_to_the_left: usize, palette: Palette) -> LinePart } } -fn right_more_message(tab_count_to_the_right: usize, palette: Palette) -> LinePart { +fn right_more_message( + tab_count_to_the_right: usize, + palette: Palette, + separator: &str, +) -> LinePart { if tab_count_to_the_right == 0 { return LinePart { part: String::new(), @@ -90,11 +94,11 @@ fn right_more_message(tab_count_to_the_right: usize, palette: Palette) -> LinePa " +many → ".to_string() }; let more_text_len = more_text.chars().count() + 1; // 2 for the arrow - let left_separator = style!(palette.bg, palette.orange).paint(ARROW_SEPARATOR); + let left_separator = style!(palette.bg, palette.orange).paint(separator); let more_styled_text = style!(palette.black, palette.orange) .bold() .paint(more_text); - let right_separator = style!(palette.orange, palette.bg).paint(ARROW_SEPARATOR); + let right_separator = style!(palette.orange, palette.bg).paint(separator); let more_styled_text = format!( "{}", ANSIStrings(&[left_separator, more_styled_text, right_separator,]) @@ -111,14 +115,15 @@ fn add_previous_tabs_msg( title_bar: &mut Vec, cols: usize, palette: Palette, + separator: &str, ) { while get_current_title_len(&tabs_to_render) - + left_more_message(tabs_before_active.len(), palette).len + + left_more_message(tabs_before_active.len(), palette, separator).len >= cols { tabs_before_active.push(tabs_to_render.remove(0)); } - let left_more_message = left_more_message(tabs_before_active.len(), palette); + let left_more_message = left_more_message(tabs_before_active.len(), palette, separator); title_bar.push(left_more_message); } @@ -127,14 +132,15 @@ fn add_next_tabs_msg( title_bar: &mut Vec, cols: usize, palette: Palette, + separator: &str, ) { while get_current_title_len(&title_bar) - + right_more_message(tabs_after_active.len(), palette).len + + right_more_message(tabs_after_active.len(), palette, separator).len >= cols { tabs_after_active.insert(0, title_bar.pop().unwrap()); } - let right_more_message = right_more_message(tabs_after_active.len(), palette); + let right_more_message = right_more_message(tabs_after_active.len(), palette, separator); title_bar.push(right_more_message); } @@ -148,11 +154,20 @@ fn tab_line_prefix(palette: Palette) -> LinePart { } } +pub fn tab_separator(capabilities: PluginCapabilities) -> &'static str { + if !capabilities.arrow_fonts { + ARROW_SEPARATOR + } else { + &"" + } +} + pub fn tab_line( mut all_tabs: Vec, active_tab_index: usize, cols: usize, palette: Palette, + capabilities: PluginCapabilities, ) -> Vec { let mut tabs_to_render: Vec = vec![]; let mut tabs_after_active = all_tabs.split_off(active_tab_index); @@ -180,6 +195,7 @@ pub fn tab_line( &mut tab_line, cols - prefix.len, palette, + tab_separator(capabilities), ); } tab_line.append(&mut tabs_to_render); @@ -189,6 +205,7 @@ pub fn tab_line( &mut tab_line, cols - prefix.len, palette, + tab_separator(capabilities), ); } tab_line.insert(0, prefix); diff --git a/default-plugins/tab-bar/src/main.rs b/default-plugins/tab-bar/src/main.rs index c62770137e..00ff4bd967 100644 --- a/default-plugins/tab-bar/src/main.rs +++ b/default-plugins/tab-bar/src/main.rs @@ -60,10 +60,17 @@ impl ZellijPlugin for State { t.position, t.is_sync_panes_active, self.mode_info.palette, + self.mode_info.capabilities, ); all_tabs.push(tab); } - let tab_line = tab_line(all_tabs, active_tab_index, cols, self.mode_info.palette); + let tab_line = tab_line( + all_tabs, + active_tab_index, + cols, + self.mode_info.palette, + self.mode_info.capabilities, + ); let mut s = String::new(); for bar_part in tab_line { s = format!("{}{}", s, bar_part.part); diff --git a/default-plugins/tab-bar/src/tab.rs b/default-plugins/tab-bar/src/tab.rs index 7c1fe6b32c..85e2c378d3 100644 --- a/default-plugins/tab-bar/src/tab.rs +++ b/default-plugins/tab-bar/src/tab.rs @@ -1,15 +1,15 @@ -use crate::{LinePart, ARROW_SEPARATOR}; +use crate::{line::tab_separator, LinePart}; use ansi_term::ANSIStrings; use zellij_tile::prelude::*; use zellij_tile_utils::style; -pub fn active_tab(text: String, palette: Palette) -> LinePart { - let left_separator = style!(palette.bg, palette.green).paint(ARROW_SEPARATOR); +pub fn active_tab(text: String, palette: Palette, separator: &str) -> LinePart { + let left_separator = style!(palette.bg, palette.green).paint(separator); let tab_text_len = text.chars().count() + 4; // 2 for left and right separators, 2 for the text padding let tab_styled_text = style!(palette.black, palette.green) .bold() .paint(format!(" {} ", text)); - let right_separator = style!(palette.green, palette.bg).paint(ARROW_SEPARATOR); + let right_separator = style!(palette.green, palette.bg).paint(separator); let tab_styled_text = format!( "{}", ANSIStrings(&[left_separator, tab_styled_text, right_separator,]) @@ -20,13 +20,13 @@ pub fn active_tab(text: String, palette: Palette) -> LinePart { } } -pub fn non_active_tab(text: String, palette: Palette) -> LinePart { - let left_separator = style!(palette.bg, palette.fg).paint(ARROW_SEPARATOR); +pub fn non_active_tab(text: String, palette: Palette, separator: &str) -> LinePart { + let left_separator = style!(palette.bg, palette.fg).paint(separator); let tab_text_len = text.chars().count() + 4; // 2 for left and right separators, 2 for the padding let tab_styled_text = style!(palette.black, palette.fg) .bold() .paint(format!(" {} ", text)); - let right_separator = style!(palette.fg, palette.bg).paint(ARROW_SEPARATOR); + let right_separator = style!(palette.fg, palette.bg).paint(separator); let tab_styled_text = format!( "{}", ANSIStrings(&[left_separator, tab_styled_text, right_separator,]) @@ -43,7 +43,9 @@ pub fn tab_style( position: usize, is_sync_panes_active: bool, palette: Palette, + capabilities: PluginCapabilities, ) -> LinePart { + let separator = tab_separator(capabilities); let mut tab_text = if text.is_empty() { format!("Tab #{}", position + 1) } else { @@ -53,8 +55,8 @@ pub fn tab_style( tab_text.push_str(" (Sync)"); } if is_active_tab { - active_tab(tab_text, palette) + active_tab(tab_text, palette, separator) } else { - non_active_tab(tab_text, palette) + non_active_tab(tab_text, palette, separator) } } diff --git a/example/config.yaml b/example/config.yaml index 3bb4fbfada..962822db5b 100644 --- a/example/config.yaml +++ b/example/config.yaml @@ -1,6 +1,7 @@ --- keybinds: normal: + - unbind : true - action: [GoToTab: 1,] key: [F: 1,] - action: [GoToTab: 2,] diff --git a/example/default.yaml b/example/default.yaml index cdddf1d353..9b6c890458 100644 --- a/example/default.yaml +++ b/example/default.yaml @@ -1,4 +1,5 @@ --- +simplified_ui: true keybinds: unbind: true normal: diff --git a/src/cli.rs b/src/cli.rs index 91b0ed39d0..6ab33d4554 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,4 +1,5 @@ use super::common::utils::consts::{ZELLIJ_CONFIG_DIR_ENV, ZELLIJ_CONFIG_FILE_ENV}; +use crate::common::input::options::Options; use serde::{Deserialize, Serialize}; use std::path::PathBuf; use structopt::StructOpt; @@ -10,6 +11,10 @@ pub struct CliArgs { #[structopt(long)] pub max_panes: Option, + /// Speficy, if a simplified layout should be used that is compatible with more fonts + #[structopt(long)] + pub simplified: bool, + /// Change where zellij looks for layouts and plugins #[structopt(long)] pub data_dir: Option, @@ -36,21 +41,20 @@ pub struct CliArgs { #[derive(Debug, StructOpt, Clone, Serialize, Deserialize)] pub enum ConfigCli { /// Change the behaviour of zellij - #[structopt(name = "option")] - Config { - /// Disables loading of configuration file at default location - #[structopt(long)] - clean: bool, - }, + #[structopt(name = "options")] + Options(Options), #[structopt(name = "generate-completion")] GenerateCompletion { shell: String }, #[structopt(name = "setup")] Setup { - /// Disables loading of configuration file at default location /// Dump the default configuration file to stdout #[structopt(long)] dump_config: bool, + /// Disables loading of configuration file at default location, + /// loads the defaults that zellij ships with + #[structopt(long)] + clean: bool, }, } diff --git a/src/client/mod.rs b/src/client/mod.rs index ba27bc3e7d..8fcbc07050 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -42,7 +42,11 @@ pub fn start_client(mut os_input: Box, opts: CliArgs, config: C let full_screen_ws = os_input.get_terminal_size_using_fd(0); os_input.connect_to_server(); - os_input.send_to_server(ServerInstruction::NewClient(full_screen_ws, opts)); + os_input.send_to_server(ServerInstruction::NewClient( + full_screen_ws, + opts, + config.options.clone(), + )); os_input.set_raw_mode(0); let (send_client_instructions, receive_client_instructions): SyncChannelWithContext< diff --git a/src/common/input/config.rs b/src/common/input/config.rs index 3263b57101..5f2656f380 100644 --- a/src/common/input/config.rs +++ b/src/common/input/config.rs @@ -6,10 +6,11 @@ use std::io::{self, Read}; use std::path::{Path, PathBuf}; use super::keybinds::{Keybinds, KeybindsFromYaml}; +use super::options::Options; use crate::cli::{CliArgs, ConfigCli}; use crate::common::setup; -use serde::Deserialize; +use serde::{Deserialize, Serialize}; use std::convert::TryFrom; const DEFAULT_CONFIG_FILE_NAME: &str = "config.yaml"; @@ -19,13 +20,16 @@ type ConfigResult = Result; /// Intermediate deserialization config struct #[derive(Debug, Deserialize)] pub struct ConfigFromYaml { + #[serde(flatten)] + pub options: Option, pub keybinds: Option, } /// Main configuration. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] pub struct Config { pub keybinds: Keybinds, + pub options: Options, } #[derive(Debug)] @@ -43,7 +47,8 @@ pub enum ConfigError { impl Default for Config { fn default() -> Self { let keybinds = Keybinds::default(); - Config { keybinds } + let options = Options::default(); + Config { keybinds, options } } } @@ -55,7 +60,7 @@ impl TryFrom<&CliArgs> for Config { return Config::new(&path); } - if let Some(ConfigCli::Config { clean, .. }) = opts.option { + if let Some(ConfigCli::Setup { clean, .. }) = opts.option { if clean { return Config::from_default_assets(); } @@ -84,7 +89,8 @@ impl Config { pub fn from_yaml(yaml_config: &str) -> ConfigResult { let config_from_yaml: ConfigFromYaml = serde_yaml::from_str(&yaml_config)?; let keybinds = Keybinds::get_default_keybinds_with_config(config_from_yaml.keybinds); - Ok(Config { keybinds }) + let options = Options::from_yaml(config_from_yaml.options); + Ok(Config { keybinds, options }) } /// Deserializes from given path. @@ -172,7 +178,10 @@ mod config_test { #[test] fn try_from_cli_args_with_option_clean() { let mut opts = CliArgs::default(); - opts.option = Some(ConfigCli::Config { clean: true }); + opts.option = Some(ConfigCli::Setup { + clean: true, + dump_config: false, + }); let result = Config::try_from(&opts); assert!(result.is_ok()); } diff --git a/src/common/input/handler.rs b/src/common/input/handler.rs index aa20485017..68a75448dc 100644 --- a/src/common/input/handler.rs +++ b/src/common/input/handler.rs @@ -11,7 +11,7 @@ use crate::server::ServerInstruction; use crate::CommandIsExecuting; use termion::input::{TermRead, TermReadEventsAndRaw}; -use zellij_tile::data::{InputMode, Key, ModeInfo, Palette}; +use zellij_tile::data::{InputMode, Key, ModeInfo, Palette, PluginCapabilities}; /// Handles the dispatching of [`Action`]s according to the current /// [`InputMode`], and keep tracks of the current [`InputMode`]. @@ -149,6 +149,7 @@ impl InputHandler { // TODO this should probably be automatically generated in some way pub fn get_mode_info(mode: InputMode, palette: Palette) -> ModeInfo { let mut keybinds: Vec<(String, String)> = vec![]; + let capabilities = PluginCapabilities { arrow_fonts: true }; match mode { InputMode::Normal | InputMode::Locked => {} InputMode::Resize => { @@ -182,6 +183,7 @@ pub fn get_mode_info(mode: InputMode, palette: Palette) -> ModeInfo { mode, keybinds, palette, + capabilities, } } diff --git a/src/common/input/keybinds.rs b/src/common/input/keybinds.rs index 823ca264b1..8bef47fded 100644 --- a/src/common/input/keybinds.rs +++ b/src/common/input/keybinds.rs @@ -4,14 +4,14 @@ use std::collections::HashMap; use super::actions::Action; use super::config; -use serde::Deserialize; +use serde::{Deserialize, Serialize}; use strum::IntoEnumIterator; use zellij_tile::data::*; /// Used in the config struct -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] pub struct Keybinds(HashMap); -#[derive(Clone, Debug, Default, PartialEq)] +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] pub struct ModeKeybinds(HashMap>); /// Intermediate struct used for deserialisation diff --git a/src/common/input/mod.rs b/src/common/input/mod.rs index 6589cac2c4..f30ccf23b7 100644 --- a/src/common/input/mod.rs +++ b/src/common/input/mod.rs @@ -4,3 +4,4 @@ pub mod actions; pub mod config; pub mod handler; pub mod keybinds; +pub mod options; diff --git a/src/common/input/options.rs b/src/common/input/options.rs new file mode 100644 index 0000000000..3ff2fd8e53 --- /dev/null +++ b/src/common/input/options.rs @@ -0,0 +1,21 @@ +use serde::{Deserialize, Serialize}; +use structopt::StructOpt; + +#[derive(Clone, Default, Debug, PartialEq, Deserialize, Serialize, StructOpt)] +/// Options that can be set either through the config file, +/// or cli flags +pub struct Options { + /// Allow plugins to use a more compatible font type + #[structopt(long)] + pub simplified_ui: bool, +} + +impl Options { + pub fn from_yaml(from_yaml: Option) -> Options { + if let Some(opts) = from_yaml { + opts + } else { + Options::default() + } + } +} diff --git a/src/common/screen.rs b/src/common/screen.rs index 44cfe3ba9b..6f5a4cb378 100644 --- a/src/common/screen.rs +++ b/src/common/screen.rs @@ -4,6 +4,8 @@ use std::collections::BTreeMap; use std::os::unix::io::RawFd; use std::str; +use crate::cli::ConfigCli; +use crate::common::input::options::Options; use crate::common::pty::{PtyInstruction, VteBytes}; use crate::common::thread_bus::Bus; use crate::errors::{ContextType, ScreenContext}; @@ -14,7 +16,7 @@ use crate::server::ServerInstruction; use crate::tab::Tab; use crate::wasm_vm::PluginInstruction; -use zellij_tile::data::{Event, InputMode, ModeInfo, Palette, TabInfo}; +use zellij_tile::data::{Event, InputMode, ModeInfo, Palette, PluginCapabilities, TabInfo}; /// Instructions that can be sent to the [`Screen`]. #[derive(Debug, Clone)] @@ -328,14 +330,24 @@ pub fn screen_thread_main( bus: Bus, max_panes: Option, full_screen_ws: PositionAndSize, + options: Option, + config_options: Options, ) { let colors = bus.os_input.as_ref().unwrap().load_palette(); + let capabilities = if let Some(ConfigCli::Options(options)) = options { + options.simplified_ui + } else { + config_options.simplified_ui + }; let mut screen = Screen::new( bus, &full_screen_ws, max_panes, ModeInfo { palette: colors, + capabilities: PluginCapabilities { + arrow_fonts: capabilities, + }, ..ModeInfo::default() }, InputMode::Normal, diff --git a/src/server/mod.rs b/src/server/mod.rs index 3655ed19a1..d987572707 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -12,7 +12,7 @@ use crate::client::ClientInstruction; use crate::common::thread_bus::{Bus, ThreadSenders}; use crate::common::{ errors::{ContextType, ServerContext}, - input::actions::Action, + input::{actions::Action, options::Options}, os_input_output::{set_permissions, ServerOsApi}, pty::{pty_thread_main, Pty, PtyInstruction}, screen::{screen_thread_main, ScreenInstruction}, @@ -30,7 +30,7 @@ use route::route_thread_main; #[derive(Serialize, Deserialize, Debug, Clone)] pub enum ServerInstruction { TerminalResize(PositionAndSize), - NewClient(PositionAndSize, CliArgs), + NewClient(PositionAndSize, CliArgs, Options), Action(Action), Render(Option), UnblockInputThread, @@ -115,9 +115,14 @@ pub fn start_server(os_input: Box) -> thread::JoinHandle<()> { let (instruction, mut err_ctx) = server_receiver.recv().unwrap(); err_ctx.add_call(ContextType::IPCServer(ServerContext::from(&instruction))); match instruction { - ServerInstruction::NewClient(full_screen_ws, opts) => { - let session_data = - init_session(os_input.clone(), opts, to_server.clone(), full_screen_ws); + ServerInstruction::NewClient(full_screen_ws, opts, config_options) => { + let session_data = init_session( + os_input.clone(), + opts, + config_options, + to_server.clone(), + full_screen_ws, + ); *sessions.write().unwrap() = Some(session_data); sessions .read() @@ -150,6 +155,7 @@ pub fn start_server(os_input: Box) -> thread::JoinHandle<()> { fn init_session( os_input: Box, opts: CliArgs, + config_options: Options, to_server: SenderWithContext, full_screen_ws: PositionAndSize, ) -> SessionMetaData { @@ -208,9 +214,16 @@ fn init_session( Some(os_input.clone()), ); let max_panes = opts.max_panes; + let options = opts.option; move || { - screen_thread_main(screen_bus, max_panes, full_screen_ws); + screen_thread_main( + screen_bus, + max_panes, + full_screen_ws, + options, + config_options, + ); } }) .unwrap(); diff --git a/zellij-tile/src/data.rs b/zellij-tile/src/data.rs index 63c031ab39..4ff44eacf2 100644 --- a/zellij-tile/src/data.rs +++ b/zellij-tile/src/data.rs @@ -125,6 +125,7 @@ pub struct ModeInfo { // FIXME: This should probably return Keys and Actions, then sort out strings plugin-side pub keybinds: Vec<(String, String)>, // => pub palette: Palette, + pub capabilities: PluginCapabilities, } #[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)] @@ -141,3 +142,8 @@ pub struct PluginIds { pub plugin_id: u32, pub zellij_pid: u32, } + +#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)] +pub struct PluginCapabilities { + pub arrow_fonts: bool, +}