summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md1
-rw-r--r--build.rs2
-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
-rw-r--r--website/docs/panels.md37
17 files changed, 207 insertions, 126 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6500316..f82dca0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,7 @@
- fix style characters being written in `--no-style` mode - Fix #346
- replace `--no-style` with `--color` taking `yes`, `no` or `auto`, with detection of output being piped in `auto` mode (default). `--no-style` is still usable but it's not documented anymore - Fix #347
- fix wrong version number written in log file - Fix #349
+- by default the number of panels is now limited to 2 (can be changed in conf with `max_panels_count`) - Fix #345
<a name="v1.2.4"></a>
### v1.2.4 - 2021-02-14
diff --git a/build.rs b/build.rs
index b78802f..e7a3914 100644
--- a/build.rs
+++ b/build.rs
@@ -11,7 +11,7 @@ use {
},
};
-include!("src/clap.rs");
+include!("src/cli/clap_args.rs");
include!("src/conf/default_conf.rs");
/// write the shell completion scripts which will be added to
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);
diff --git a/website/docs/panels.md b/website/docs/panels.md
index 30d976d..f3fb76d 100644
--- a/website/docs/panels.md
+++ b/website/docs/panels.md
@@ -1,28 +1,36 @@
+Broot can display two panels. Most frequent uses are:
+* previewing files
+* copying or moving files between two locations
-# Open panels, switch between them
+# Keyboard shortcuts
-To focus a panel when several are displayed, you may click on the desired one, or use the `:panel_left` and `:panel_right` verbs which are, in standard, bound to <kbd>ctrl</kbd><kbd>←</kbd> and <kbd>ctrl</kbd><kbd>→</kbd>.
+The <kbd>ctrl</kbd><kbd>←</kbd> and <kbd>ctrl</kbd><kbd>→</kbd> shortcuts should be enough to support all common panel related operation:
-When there's no panel in that direction, a new one is created:
+* When there's only one panel, use <kbd>ctrl</kbd><kbd>←</kbd> to open a panel to the left, and <kbd>ctrl</kbd><kbd>→</kbd> to open one to the right
+* When two panels are open, you may go to the panel left of the current one with <kbd>ctrl</kbd><kbd>←</kbd> and to the panel to the right with <kbd>ctrl</kbd><kbd>→</kbd>
+* When two panels are open, you may close the non selected one by going the opposite direction (i.e. if you're in the left panel, you may close the right one with <kbd>ctrl</kbd><kbd>←</kbd>)
-* if the current selection is a regular file and you've hit <kbd>ctrl</kbd><kbd>→</kbd>, you get the preview panel
-* in other cases you get a new tree whose root is the selected line.
+The type of open panel depends on the selection:
-This makes those shortcuts the easiest way to create a panel.
+* If the current selection is a directory, the new panel will be a file tree
+* If the current selection is a regular file, the new panel will be a preview
-Another way is to add a bang (`!`) to a verb. It tells broot to show the result in a new panel.
+You may also close the current panel with <kbd>ctrl</kbd><kbd>W</kbd>, which is a shortcut for `:close_panel` (you can [change all bindings](../conf_verbs/#keyboard-key)).
-For example, while `:focus ~` navigates to your home directory in the current panel, you can use `:!focus ~` or `:focus! ~` to open a new panel on your home.
+# Use a verb to open a panel
+
+Another way to open a panel is to add a bang (`!`) to a verb. It tells broot to show the result in a new panel.
-The `:close_panel` closes the current panel and is bound to <kbd>ctrl</kbd><kbd>W</kbd> (remember: you can [change all bindings](../conf_verbs/#keyboard-key)).
+For example, while `:focus ~` navigates to your home directory in the current panel, you can use `:!focus ~` or `:focus! ~` to open a new panel on your home.
# The preview panel
![preview](img/20200716-preview.png)
It's not immediately focused on creation, because most often you'll want to preview a few files and it's convenient to stay in the tree to navigate.
-To focus it, for example to scroll it, do <kbd>ctrl</kbd><kbd>→</kbd> again.
+
+To focus it, for example to scroll it or to do a search, do <kbd>ctrl</kbd><kbd>→</kbd> again.
Files that can't be interpreted as text or image are shown as binary:
@@ -36,7 +44,6 @@ You can go from the selected matched line to the unfiltered text, at the right p
Hopefully [this blog post](https://dystroy.org/blog/broot-c-search/) should make the complete search workflow look natural.
-
# Copy, move between panels... or more
When exactly two panels are displayed, `{other-panel-file}` `{other-panel-directory}`, and `{other-panel-parent}` are available for verbs.
@@ -80,9 +87,13 @@ You may now hit enter to execute the command, maybe after having completed the p
This workflow is based on the `:start_end_panel` verb which can be bound to another key if desired.
-# More about panels
+# More panels
+
+The default configuration limits the number of panels to two, because most people never needs more and it makes it easier to alternate between one or two panels.
+
+But if you want more panels, for a specific configuration of for your main one, you may change the value of `max_panels_count` in the configuration file.
-If your terminal is wide enough, you may open more panels:
+If your terminal is wide enough, you may then open more panels:
![image](img/20200526-3-panels.png)