diff options
author | Canop <cano.petrole@gmail.com> | 2021-02-24 19:49:41 +0100 |
---|---|---|
committer | Canop <cano.petrole@gmail.com> | 2021-02-24 19:49:41 +0100 |
commit | 7d512894808500946a6acb6d4939d4ba1473c14d (patch) | |
tree | 78ce8071e4c3f85a2b22c621c5a75c03cca8d81a /src | |
parent | ab3602693a5361187427a5ebab3e4705956c01e6 (diff) |
limit the number of panels to 2
Can be changed in conf with `max_panels_count`.
Fix #345
Diffstat (limited to 'src')
-rw-r--r-- | src/app/app.rs | 44 | ||||
-rw-r--r-- | src/app/cmd_result.rs | 12 | ||||
-rw-r--r-- | src/app/context.rs | 8 | ||||
-rw-r--r-- | src/app/state.rs | 22 | ||||
-rw-r--r-- | src/browser/browser_state.rs | 36 | ||||
-rw-r--r-- | src/cli/app_launch_args.rs | 25 | ||||
-rw-r--r-- | src/cli/clap_args.rs (renamed from src/clap.rs) | 0 | ||||
-rw-r--r-- | src/cli/install_launch_args.rs | 54 | ||||
-rw-r--r-- | src/cli/mod.rs (renamed from src/cli.rs) | 74 | ||||
-rw-r--r-- | src/conf/conf.rs | 3 | ||||
-rw-r--r-- | src/conf/default_conf.rs | 7 | ||||
-rw-r--r-- | src/filesystems/filesystems_state.rs | 4 | ||||
-rw-r--r-- | src/lib.rs | 1 | ||||
-rw-r--r-- | src/tree/tree_options.rs | 3 |
14 files changed, 181 insertions, 112 deletions
diff --git a/src/app/app.rs b/src/app/app.rs index da6f057..f30fc60 100644 --- a/src/app/app.rs +++ b/src/app/app.rs @@ -103,8 +103,18 @@ impl App { }) } + fn panel_ref_to_idx(&self, panel_ref: PanelReference) -> Option<usize> { + match panel_ref { + PanelReference::Active => Some(self.active_panel_idx), + PanelReference::Leftest => Some(0), + PanelReference::Rightest => Some(self.panels.len().get() - 1), + PanelReference::Id(id) => self.panel_id_to_idx(id), + PanelReference::Preview => self.preview.and_then(|id| self.panel_id_to_idx(id)), + } + } + /// return the current index of the panel whith given id - fn panel_idx(&self, id: PanelId) -> Option<usize> { + fn panel_id_to_idx(&self, id: PanelId) -> Option<usize> { self.panels.iter().position(|panel| panel.id == id) } @@ -249,7 +259,7 @@ impl App { con, )? { ApplyOnPanel { id } => { - if let Some(idx) = self.panel_idx(id) { + if let Some(idx) = self.panel_id_to_idx(id) { if let DisplayError(txt) = self.panels[idx].apply_command( w, &cmd, @@ -269,12 +279,11 @@ impl App { warn!("no panel found for ApplyOnPanel"); } } - ClosePanel { validate_purpose, id } => { + ClosePanel { validate_purpose, panel_ref } => { if is_input_invocation { self.mut_panel().clear_input_invocation(); } - let close_idx = id - .and_then(|id| self.panel_idx(id)) + let close_idx = self.panel_ref_to_idx(panel_ref) .unwrap_or_else(|| // when there's a preview panel, we close it rather than the app if self.panels.len().get()==2 && self.preview.is_some() { @@ -320,11 +329,26 @@ impl App { } HandleInApp(internal) => { let new_active_panel_idx = match internal { - Internal::panel_left if self.active_panel_idx > 0 => { - Some(self.active_panel_idx - 1) + Internal::panel_left => { + // we're not here to create a panel, this is handled in the state + // we're here because the state wants us to either move to the panel + // to the left, or close the rightest one + if self.active_panel_idx == 0 { + self.close_panel(self.panels.len().get()-1); + None + } else { + Some(self.active_panel_idx - 1) + } } - Internal::panel_right if self.active_panel_idx + 1 < self.panels.len().get() => { - Some(self.active_panel_idx + 1) + Internal::panel_right => { + // we're not here to create panels (it's done in the state). + // So we either move to the right or close the leftes panel + if self.active_panel_idx + 1 == self.panels.len().get() { + self.close_panel(0); + None + } else { + Some(self.active_panel_idx + 1) + } } _ => { debug!("unhandled propagated internal. cmd={:?}", &cmd); @@ -456,7 +480,7 @@ impl App { /// update the state of the preview, if there's some fn update_preview(&mut self, con: &AppContext) { - let preview_idx = self.preview.and_then(|id| self.panel_idx(id)); + let preview_idx = self.preview.and_then(|id| self.panel_id_to_idx(id)); if let Some(preview_idx) = preview_idx { let path = self.state().selected_path(); let old_path = self.panels[preview_idx].state().selected_path(); diff --git a/src/app/cmd_result.rs b/src/app/cmd_result.rs index 528bf6f..9c822a0 100644 --- a/src/app/cmd_result.rs +++ b/src/app/cmd_result.rs @@ -17,6 +17,16 @@ pub enum HDir { Right, } +/// the symbolic reference to the panel to close +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum PanelReference { + Active, + Leftest, + Rightest, + Id(PanelId), + Preview, +} + /// Result of applying a command to a state pub enum AppStateCmdResult { ApplyOnPanel { @@ -24,7 +34,7 @@ pub enum AppStateCmdResult { }, ClosePanel { validate_purpose: bool, - id: Option<PanelId>, // None if current panel + panel_ref: PanelReference, }, DisplayError(String), ExecuteSequence { diff --git a/src/app/context.rs b/src/app/context.rs index 1d429d9..55bf296 100644 --- a/src/app/context.rs +++ b/src/app/context.rs @@ -61,6 +61,10 @@ pub struct AppContext { pub modal: bool, pub mouse_capture_disabled: bool, + + /// max number of panels (including preview) that can be + /// open. Guaranteed to be at least 2. + pub max_panels_count: usize, } impl AppContext { @@ -89,6 +93,9 @@ impl AppContext { .transpose()? .unwrap_or_default(); let ext_colors = ExtColorMap::try_from(&config.ext_colors)?; + let max_panels_count = config.max_panels_count + .unwrap_or(2) + .clamp(2, 100); Ok(Self { config_paths, launch_args, @@ -103,6 +110,7 @@ impl AppContext { icons, modal: config.modal.unwrap_or(false), mouse_capture_disabled: config.disable_mouse_capture.unwrap_or(false), + max_panels_count, }) } } diff --git a/src/app/state.rs b/src/app/state.rs index 29a4579..ed911c4 100644 --- a/src/app/state.rs +++ b/src/app/state.rs @@ -127,11 +127,11 @@ pub trait AppState { } Internal::close_panel_ok => AppStateCmdResult::ClosePanel { validate_purpose: true, - id: None, + panel_ref: PanelReference::Active, }, Internal::close_panel_cancel => AppStateCmdResult::ClosePanel { validate_purpose: false, - id: None, + panel_ref: PanelReference::Active, }, #[cfg(unix)] Internal::filesystems => { @@ -283,27 +283,17 @@ pub trait AppState { if let Some(id) = cc.preview { AppStateCmdResult::ClosePanel { validate_purpose: false, - id: Some(id), + panel_ref: PanelReference::Id(id), } } else { AppStateCmdResult::Keep } } Internal::panel_left => { - if cc.areas.is_first() { - AppStateCmdResult::Keep - } else { - // we ask the app to focus the panel to the left - AppStateCmdResult::HandleInApp(Internal::panel_left) - } + AppStateCmdResult::HandleInApp(Internal::panel_left) } Internal::panel_right => { - if cc.areas.is_last() { - AppStateCmdResult::Keep - } else { - // we ask the app to focus the panel to the left - AppStateCmdResult::HandleInApp(Internal::panel_right) - } + AppStateCmdResult::HandleInApp(Internal::panel_right) } Internal::print_path => { print::print_path(self.selected_path(), con)? @@ -431,7 +421,7 @@ pub trait AppState { if close_if_open { AppStateCmdResult::ClosePanel { validate_purpose: false, - id: Some(id), + panel_ref: PanelReference::Id(id), } } else { if prefered_mode.is_some() { diff --git a/src/browser/browser_state.rs b/src/browser/browser_state.rs index 91110a3..9dae74c 100644 --- a/src/browser/browser_state.rs +++ b/src/browser/browser_state.rs @@ -346,30 +346,23 @@ impl AppState for BrowserState { AppStateCmdResult::Keep } Internal::panel_left => { - if cc.areas.is_first() { - if cc.preview.is_some() && cc.areas.nb_pos == 2 { - AppStateCmdResult::ClosePanel { - validate_purpose: false, - id: cc.preview, - } - } else { - // we ask for the creation of a panel to the left - internal_focus::new_panel_on_path( - self.selected_path().to_path_buf(), - screen, - self.displayed_tree().options.clone(), - PanelPurpose::None, - con, - HDir::Left, - ) - } + if cc.areas.is_first() && cc.areas.nb_pos < cc.con.max_panels_count { + // we ask for the creation of a panel to the left + internal_focus::new_panel_on_path( + self.selected_path().to_path_buf(), + screen, + self.displayed_tree().options.clone(), + PanelPurpose::None, + con, + HDir::Left, + ) } else { - // we ask the app to focus the panel to the left + // we let the app handle other cases AppStateCmdResult::HandleInApp(Internal::panel_left) } } Internal::panel_right => { - if cc.areas.is_last() { + if cc.areas.is_last() && cc.areas.nb_pos < cc.con.max_panels_count { let purpose = if self.selected_path().is_file() && cc.preview.is_none() { PanelPurpose::Preview } else { @@ -385,7 +378,8 @@ impl AppState for BrowserState { HDir::Right, ) } else { - // we ask the app to focus the panel to the right + // we ask the app to handle other cases : + // focus the panel to the right or close the leftest one AppStateCmdResult::HandleInApp(Internal::panel_right) } } @@ -415,7 +409,7 @@ impl AppState for BrowserState { debug!("start_end understood as end"); AppStateCmdResult::ClosePanel { validate_purpose: true, - id: None, + panel_ref: PanelReference::Active, } } else { debug!("start_end understood as start"); diff --git a/src/cli/app_launch_args.rs b/src/cli/app_launch_args.rs new file mode 100644 index 0000000..59be3fe --- /dev/null +++ b/src/cli/app_launch_args.rs @@ -0,0 +1,25 @@ + +use { + crate::{ + tree::TreeOptions, + }, + std::{ + path::PathBuf, + }, +}; + + +/// the parsed program launch arguments which are kept for the +/// life of the program +pub struct AppLaunchArgs { + pub root: PathBuf, // what should be the initial root + pub file_export_path: Option<String>, // where to write the produced path (if required with --out) + pub cmd_export_path: Option<String>, // where to write the produced command (if required with --outcmd) + pub tree_options: TreeOptions, // initial tree options + pub commands: Option<String>, // commands passed as cli argument, still unparsed + pub height: Option<u16>, // an optional height to replace the screen's one + pub no_style: bool, // whether to remove all styles (including colors) + + #[cfg(feature = "client-server")] + pub listen: Option<String>, +} diff --git a/src/clap.rs b/src/cli/clap_args.rs index 765a8bf..765a8bf 100644 --- a/src/clap.rs +++ b/src/cli/clap_args.rs diff --git a/src/cli/install_launch_args.rs b/src/cli/install_launch_args.rs new file mode 100644 index 0000000..5b8ef39 --- /dev/null +++ b/src/cli/install_launch_args.rs @@ -0,0 +1,54 @@ + + +use { + crate::{ + errors::ProgramError, + shell_install::ShellInstallState, + }, + clap::{self, ArgMatches}, + std::{ + env, + str::FromStr, + }, +}; + + +/// launch arguments related to installation +/// (not used by the application after the first step) +pub struct InstallLaunchArgs { + pub install: Option<bool>, // installation is required + pub set_install_state: Option<ShellInstallState>, // the state to set + pub print_shell_function: Option<String>, // shell function to print on stdout +} +impl InstallLaunchArgs { + pub fn from(cli_args: &ArgMatches<'_>) -> Result<Self, ProgramError> { + let mut install = None; + if let Ok(s) = env::var("BR_INSTALL") { + if s == "yes" { + install = Some(true); + } else if s == "no" { + install = Some(false); + } else { + warn!("Unexpected value of BR_INSTALL: {:?}", s); + } + } + // the cli arguments may override the env var value + if cli_args.is_present("install") { + install = Some(true); + } else if cli_args.value_of("cmd-export-path").is_some() { + install = Some(false); + } + let print_shell_function = cli_args + .value_of("print-shell-function") + .map(str::to_string); + let set_install_state = cli_args + .value_of("set-install-state") + .map(ShellInstallState::from_str) + .transpose()?; + Ok(Self { + install, + set_install_state, + print_shell_function, + }) + } +} diff --git a/src/cli.rs b/src/cli/mod.rs index 8bed34d..c92d41f 100644 --- a/src/cli.rs +++ b/src/cli/mod.rs @@ -1,5 +1,15 @@ -/// this module manages reading and translating -/// the arguments passed on launch of the application. +//! this module manages reading and translating +//! the arguments passed on launch of the application. + +pub mod clap_args; +mod app_launch_args; +mod install_launch_args; + +pub use { + app_launch_args::*, + install_launch_args::*, +}; + use { crate::{ app::{App, AppContext}, @@ -7,7 +17,7 @@ use { display, errors::{ProgramError, TreeBuildError}, launchable::Launchable, - shell_install::{ShellInstall, ShellInstallState}, + shell_install::ShellInstall, tree::TreeOptions, verb::VerbStore, }, @@ -23,65 +33,9 @@ use { env, io::{self, Write}, path::{Path, PathBuf}, - str::FromStr, }, }; -/// launch arguments related to installation -/// (not used by the application after the first step) -struct InstallLaunchArgs { - install: Option<bool>, // installation is required - set_install_state: Option<ShellInstallState>, // the state to set - print_shell_function: Option<String>, // shell function to print on stdout -} -impl InstallLaunchArgs { - fn from(cli_args: &ArgMatches<'_>) -> Result<Self, ProgramError> { - let mut install = None; - if let Ok(s) = env::var("BR_INSTALL") { - if s == "yes" { - install = Some(true); - } else if s == "no" { - install = Some(false); - } else { - warn!("Unexpected value of BR_INSTALL: {:?}", s); - } - } - // the cli arguments may override the env var value - if cli_args.is_present("install") { - install = Some(true); - } else if cli_args.value_of("cmd-export-path").is_some() { - install = Some(false); - } - let print_shell_function = cli_args - .value_of("print-shell-function") - .map(str::to_string); - let set_install_state = cli_args - .value_of("set-install-state") - .map(ShellInstallState::from_str) - .transpose()?; - Ok(Self { - install, - set_install_state, - print_shell_function, - }) - } -} - -/// the parsed program launch arguments which are kept for the -/// life of the program -pub struct AppLaunchArgs { - pub root: PathBuf, // what should be the initial root - pub file_export_path: Option<String>, // where to write the produced path (if required with --out) - pub cmd_export_path: Option<String>, // where to write the produced command (if required with --outcmd) - pub tree_options: TreeOptions, // initial tree options - pub commands: Option<String>, // commands passed as cli argument, still unparsed - pub height: Option<u16>, // an optional height to replace the screen's one - pub no_style: bool, // whether to remove all styles (including colors) - - #[cfg(feature = "client-server")] - pub listen: Option<String>, -} - #[cfg(not(windows))] fn canonicalize_root(root: &Path) -> io::Result<PathBuf> { root.canonicalize() @@ -138,7 +92,7 @@ fn is_no_style(cli_matches: &ArgMatches) -> bool { /// run the application, and maybe return a launchable /// which must be run after broot pub fn run() -> Result<Option<Launchable>, ProgramError> { - let clap_app = crate::clap::clap_app(); + let clap_app = clap_args::clap_app(); // parse the launch arguments we got from cli let cli_matches = clap_app.get_matches(); diff --git a/src/conf/conf.rs b/src/conf/conf.rs index 2ac0399..51a40ce 100644 --- a/src/conf/conf.rs +++ b/src/conf/conf.rs @@ -82,6 +82,8 @@ pub struct Conf { pub modal: Option<bool>, + pub max_panels_count: Option<usize>, + } impl Conf { @@ -145,6 +147,7 @@ impl Conf { overwrite!(self, cols_order, conf); overwrite!(self, skin, conf); overwrite!(self, search_modes, conf); + overwrite!(self, max_panels_count, conf); overwrite!(self, modal, conf); self.verbs.append(&mut conf.verbs); // the following maps are "additive": we can add entries from several diff --git a/src/conf/default_conf.rs b/src/conf/default_conf.rs index df1868b..b8a21e4 100644 --- a/src/conf/default_conf.rs +++ b/src/conf/default_conf.rs @@ -327,5 +327,12 @@ pub const DEFAULT_CONF_FILE: &str = r#" # rs: yellow # } + + ############################################################### + # Max Panels Count + # + # Change this if you sometimes want to have more than 2 panels + # open + # max_panels_count: 2 } "#; diff --git a/src/filesystems/filesystems_state.rs b/src/filesystems/filesystems_state.rs index fa990a5..22d57e1 100644 --- a/src/filesystems/filesystems_state.rs +++ b/src/filesystems/filesystems_state.rs @@ -496,7 +496,7 @@ impl AppState for FilesystemState { ) } Internal::panel_left => { - if cc.areas.is_first() { + if cc.areas.is_first() && cc.areas.nb_pos < cc.con.max_panels_count { // we ask for the creation of a panel to the left internal_focus::new_panel_on_path( self.selected_path().to_path_buf(), @@ -512,7 +512,7 @@ impl AppState for FilesystemState { } } Internal::panel_right => { - if cc.areas.is_last() { + if cc.areas.is_last() && cc.areas.nb_pos < cc.con.max_panels_count { // we ask for the creation of a panel to the right internal_focus::new_panel_on_path( self.selected_path().to_path_buf(), @@ -9,7 +9,6 @@ pub mod app; pub mod browser; -pub mod clap; pub mod cli; pub mod command; pub mod conf; diff --git a/src/tree/tree_options.rs b/src/tree/tree_options.rs index 862b8f9..636b9c8 100644 --- a/src/tree/tree_options.rs +++ b/src/tree/tree_options.rs @@ -1,6 +1,7 @@ use { super::Sort, crate::{ + cli::clap_args, conf::Conf, display::{Cols, DEFAULT_COLS}, errors::ConfError, @@ -76,7 +77,7 @@ impl TreeOptions { /// change tree options according to configuration pub fn apply_config(&mut self, config: &Conf) -> Result<(), ConfError> { if let Some(default_flags) = &config.default_flags { - let clap_app = crate::clap::clap_app().setting(clap::AppSettings::NoBinaryName); + let clap_app = clap_args::clap_app().setting(clap::AppSettings::NoBinaryName); let flags_args = format!("-{}", default_flags); let conf_matches = clap_app.get_matches_from(vec![&flags_args]); self.apply_launch_args(&conf_matches); |