From abbe3b237af1308a6108d513c75b41ad0a889e3a Mon Sep 17 00:00:00 2001 From: a-kenji Date: Wed, 10 Nov 2021 13:31:37 +0100 Subject: [PATCH] add(feature): toggle boolean options with cli flag (#855) add the ability to toggle boolean options with a cli flag: example: if the pane frames are turned off in the config file, then passing in the `--no-pane-frames` flag will toggle the pane frames on --- src/commands.rs | 2 +- zellij-client/src/input_handler.rs | 2 +- zellij-server/src/lib.rs | 2 +- zellij-server/src/screen.rs | 4 +- zellij-utils/src/cli.rs | 10 +-- zellij-utils/src/input/options.rs | 100 +++++++++++++++++++++++++++-- 6 files changed, 106 insertions(+), 14 deletions(-) diff --git a/src/commands.rs b/src/commands.rs index da97cee87..aec3970e0 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -176,7 +176,7 @@ pub(crate) fn start_client(opts: CliArgs) { })) = opts.command.clone() { let config_options = match options { - Some(SessionCommand::Options(o)) => config_options.merge(o), + Some(SessionCommand::Options(o)) => config_options.merge_from_cli(o.into()), None => config_options, }; diff --git a/zellij-client/src/input_handler.rs b/zellij-client/src/input_handler.rs index d07c2caa8..c2d93a0cf 100644 --- a/zellij-client/src/input_handler.rs +++ b/zellij-client/src/input_handler.rs @@ -63,7 +63,7 @@ impl InputHandler { let mut err_ctx = OPENCALLS.with(|ctx| *ctx.borrow()); err_ctx.add_call(ContextType::StdinHandler); let alt_left_bracket = vec![27, 91]; - if !self.options.disable_mouse_mode { + if !self.options.disable_mouse_mode.unwrap_or_default() { self.os_input.enable_mouse(); } loop { diff --git a/zellij-server/src/lib.rs b/zellij-server/src/lib.rs index 38e469a89..036d41f0a 100644 --- a/zellij-server/src/lib.rs +++ b/zellij-server/src/lib.rs @@ -523,7 +523,7 @@ fn init_session( let data_dir = opts.data_dir.unwrap_or_else(get_default_data_dir); let capabilities = PluginCapabilities { - arrow_fonts: config_options.simplified_ui, + arrow_fonts: config_options.simplified_ui.unwrap_or_default(), }; let default_shell = config_options.default_shell.clone().map(|command| { diff --git a/zellij-server/src/screen.rs b/zellij-server/src/screen.rs index fb225f78a..2fa964271 100644 --- a/zellij-server/src/screen.rs +++ b/zellij-server/src/screen.rs @@ -560,7 +560,7 @@ pub(crate) fn screen_thread_main( config_options: Box, ) { let capabilities = config_options.simplified_ui; - let draw_pane_frames = !config_options.no_pane_frames; + let draw_pane_frames = !config_options.no_pane_frames.unwrap_or_default(); let mut screen = Screen::new( bus, @@ -570,7 +570,7 @@ pub(crate) fn screen_thread_main( config_options.default_mode.unwrap_or_default(), client_attributes.palette, PluginCapabilities { - arrow_fonts: capabilities, + arrow_fonts: capabilities.unwrap_or_default(), }, ), draw_pane_frames, diff --git a/zellij-utils/src/cli.rs b/zellij-utils/src/cli.rs index 78615d929..2c1aeba37 100644 --- a/zellij-utils/src/cli.rs +++ b/zellij-utils/src/cli.rs @@ -1,6 +1,8 @@ -use crate::consts::{ZELLIJ_CONFIG_DIR_ENV, ZELLIJ_CONFIG_FILE_ENV}; -use crate::input::options::Options; use crate::setup::Setup; +use crate::{ + consts::{ZELLIJ_CONFIG_DIR_ENV, ZELLIJ_CONFIG_FILE_ENV}, + input::options::CliOptions, +}; use serde::{Deserialize, Serialize}; use std::path::PathBuf; use structopt::StructOpt; @@ -51,7 +53,7 @@ pub struct CliArgs { pub enum Command { /// Change the behaviour of zellij #[structopt(name = "options")] - Options(Options), + Options(CliOptions), /// Setup zellij and check its configuration #[structopt(name = "setup")] @@ -66,7 +68,7 @@ pub enum Command { pub enum SessionCommand { /// Change the behaviour of zellij #[structopt(name = "options")] - Options(Options), + Options(CliOptions), } #[derive(Debug, StructOpt, Clone, Serialize, Deserialize)] diff --git a/zellij-utils/src/input/options.rs b/zellij-utils/src/input/options.rs index 94994e1e3..c23267fb6 100644 --- a/zellij-utils/src/input/options.rs +++ b/zellij-utils/src/input/options.rs @@ -35,12 +35,14 @@ impl FromStr for OnForceClose { #[derive(Clone, Default, Debug, PartialEq, Deserialize, Serialize, StructOpt)] /// Options that can be set either through the config file, /// or cli flags - cli flags should take precedence over the config file +/// TODO: In order to correctly parse boolean flags, this is currently split +/// into Options and CliOptions, this could be a good canditate for a macro pub struct Options { /// Allow plugins to use a more simplified layout /// that is compatible with more fonts #[structopt(long)] #[serde(default)] - pub simplified_ui: bool, + pub simplified_ui: Option, /// Set the default theme #[structopt(long)] pub theme: Option, @@ -57,10 +59,10 @@ pub struct Options { #[structopt(long)] #[serde(default)] /// Disable handling of mouse events - pub disable_mouse_mode: bool, + pub disable_mouse_mode: Option, #[structopt(long)] #[serde(default)] - pub no_pane_frames: bool, + pub no_pane_frames: Option, /// Set behaviour on force close (quit or detach) #[structopt(long)] pub on_force_close: Option, @@ -79,7 +81,41 @@ impl Options { /// will supercede a `Some` in `self` // TODO: Maybe a good candidate for a macro? pub fn merge(&self, other: Options) -> Options { - let merge_bool = |opt_other, opt_self| if opt_other { true } else { opt_self }; + let disable_mouse_mode = other.disable_mouse_mode.or(self.disable_mouse_mode); + let no_pane_frames = other.no_pane_frames.or(self.no_pane_frames); + let simplified_ui = other.simplified_ui.or(self.simplified_ui); + let default_mode = other.default_mode.or(self.default_mode); + let default_shell = other.default_shell.or_else(|| self.default_shell.clone()); + let layout_dir = other.layout_dir.or_else(|| self.layout_dir.clone()); + let theme = other.theme.or_else(|| self.theme.clone()); + let on_force_close = other.on_force_close.or(self.on_force_close); + + Options { + simplified_ui, + theme, + default_mode, + default_shell, + layout_dir, + disable_mouse_mode, + no_pane_frames, + on_force_close, + } + } + + /// Merges two [`Options`] structs, + /// - `Some` in `other` will supercede a `Some` in `self` + /// - `Some(bool)` in `other` will toggle a `Some(bool)` in `self` + // TODO: Maybe a good candidate for a macro? + pub fn merge_from_cli(&self, other: Options) -> Options { + let merge_bool = |opt_other: Option, opt_self: Option| { + if opt_other.is_some() ^ opt_self.is_some() { + opt_other.or(opt_self) + } else if opt_other.is_some() && opt_self.is_some() { + Some(opt_other.unwrap() ^ opt_self.unwrap()) + } else { + None + } + }; let simplified_ui = merge_bool(other.simplified_ui, self.simplified_ui); let disable_mouse_mode = merge_bool(other.disable_mouse_mode, self.disable_mouse_mode); @@ -105,9 +141,63 @@ impl Options { pub fn from_cli(&self, other: Option) -> Options { if let Some(Command::Options(options)) = other { - Options::merge(self, options) + Options::merge_from_cli(self, options.into()) } else { self.to_owned() } } } + +#[derive(Clone, Default, Debug, PartialEq, StructOpt, Serialize, Deserialize)] +/// Options that can be set through cli flags +/// boolean flags end up toggling boolean options in `Options` +pub struct CliOptions { + /// Allow plugins to use a more simplified layout + /// that is compatible with more fonts + #[structopt(long)] + pub simplified_ui: bool, + /// Set the default theme + #[structopt(long)] + pub theme: Option, + /// Set the default mode + #[structopt(long)] + pub default_mode: Option, + /// Set the default shell + #[structopt(long, parse(from_os_str))] + pub default_shell: Option, + /// Set the layout_dir, defaults to + /// subdirectory of config dir + #[structopt(long, parse(from_os_str))] + pub layout_dir: Option, + #[structopt(long)] + /// Disable handling of mouse events + pub disable_mouse_mode: bool, + #[structopt(long)] + pub no_pane_frames: bool, + /// Set behaviour on force close (quit or detach) + #[structopt(long)] + pub on_force_close: Option, +} + +impl From for Options { + fn from(cli_options: CliOptions) -> Self { + let handle_bool = |bool| { + if bool { + Some(true) + } else { + None + } + }; + + Self { + simplified_ui: handle_bool(cli_options.simplified_ui), + theme: cli_options.theme, + default_mode: cli_options.default_mode, + default_shell: cli_options.default_shell, + layout_dir: cli_options.layout_dir, + disable_mouse_mode: handle_bool(cli_options.disable_mouse_mode), + no_pane_frames: handle_bool(cli_options.no_pane_frames), + on_force_close: cli_options.on_force_close, + } + } +}