summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorCanop <cano.petrole@gmail.com>2021-02-24 19:49:41 +0100
committerCanop <cano.petrole@gmail.com>2021-02-24 19:49:41 +0100
commit7d512894808500946a6acb6d4939d4ba1473c14d (patch)
tree78ce8071e4c3f85a2b22c621c5a75c03cca8d81a /src
parentab3602693a5361187427a5ebab3e4705956c01e6 (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.rs44
-rw-r--r--src/app/cmd_result.rs12
-rw-r--r--src/app/context.rs8
-rw-r--r--src/app/state.rs22
-rw-r--r--src/browser/browser_state.rs36
-rw-r--r--src/cli/app_launch_args.rs25
-rw-r--r--src/cli/clap_args.rs (renamed from src/clap.rs)0
-rw-r--r--src/cli/install_launch_args.rs54
-rw-r--r--src/cli/mod.rs (renamed from src/cli.rs)74
-rw-r--r--src/conf/conf.rs3
-rw-r--r--src/conf/default_conf.rs7
-rw-r--r--src/filesystems/filesystems_state.rs4
-rw-r--r--src/lib.rs1
-rw-r--r--src/tree/tree_options.rs3
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(),
diff --git a/src/lib.rs b/src/lib.rs
index d552adb..61a5738 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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);