Repository: Canop/broot (language: rust)

Issue:
stage_all_directories internal
Similar to stage_all_files, it would stage all directories matching the current filter.

Related: #775 


Discussion / hints:

Fix patch:
diff --git a/Cargo.lock b/Cargo.lock
index f9ed0441..49e9e035 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -350,9 +350,7 @@ dependencies = [
 
 [[package]]
 name = "clap-help"
-version = "1.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f9905b63b5378811dd974fad735dd177c02bf8390a8ccc7c3676aff8ecc1a881"
+version = "1.2.0"
 dependencies = [
  "clap",
  "termimad",
diff --git a/Cargo.toml b/Cargo.toml
index bff4cff1..8510e30a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -28,7 +28,7 @@ bet = "1.0.2"
 char_reader = "0.1"
 chrono = "0.4"
 clap = { version = "4.4", features = ["derive", "cargo"] }
-clap-help = "1.1.2"
+clap-help = "1.2.0"
 cli-log = "2.0"
 crokey = "0.6.3"
 crossbeam = "0.8"
diff --git a/src/browser/browser_state.rs b/src/browser/browser_state.rs
index e84788ef..bec88087 100644
--- a/src/browser/browser_state.rs
+++ b/src/browser/browser_state.rs
@@ -37,7 +37,10 @@ enum BrowserTask {
         pattern: InputPattern,
         total: bool,
     },
-    StageAll(InputPattern),
+    StageAll {
+        pattern: InputPattern,
+        file_type_condition: FileTypeCondition,
+    },
 }
 
 impl BrowserState {
@@ -215,7 +218,7 @@ impl PanelState for BrowserState {
             self
                 .pending_task.as_ref().map(|task| match task {
                     BrowserTask::Search{ .. } => "searching",
-                    BrowserTask::StageAll(_) => "staging",
+                    BrowserTask::StageAll{ .. } => "staging",
                 })
         }
     }
@@ -526,9 +529,25 @@ impl PanelState for BrowserState {
                     CmdResult::error("No selected line")
                 }
             }
+            Internal::stage_all_directories => {
+                let pattern = self.displayed_tree().options.pattern.clone();
+                let file_type_condition = FileTypeCondition::Directory;
+                self.pending_task = Some(BrowserTask::StageAll{pattern, file_type_condition});
+                if cc.app.stage_panel.is_none() {
+                    let stage_options = self.tree.options.without_pattern();
+                    CmdResult::NewPanel {
+                        state: Box::new(StageState::new(app_state, stage_options, con)),
+                        purpose: PanelPurpose::None,
+                        direction: HDir::Right,
+                    }
+                } else {
+                    CmdResult::Keep
+                }
+            }
             Internal::stage_all_files => {
                 let pattern = self.displayed_tree().options.pattern.clone();
-                self.pending_task = Some(BrowserTask::StageAll(pattern));
+                let file_type_condition = FileTypeCondition::File;
+                self.pending_task = Some(BrowserTask::StageAll{pattern, file_type_condition});
                 if cc.app.stage_panel.is_none() {
                     let stage_options = self.tree.options.without_pattern();
                     CmdResult::NewPanel {
@@ -684,7 +703,8 @@ impl PanelState for BrowserState {
                         self.filtered_tree = Some(ft);
                     }
                 }
-                BrowserTask::StageAll(pattern) => {
+                BrowserTask::StageAll { pattern, file_type_condition } => {
+                    info!("stage all pattern: {:?}", pattern);
                     let tree = self.displayed_tree();
                     let root = tree.root().clone();
                     let mut options = tree.options.clone();
@@ -697,7 +717,10 @@ impl PanelState for BrowserState {
                             time!(builder.build_paths(
                                 total_search,
                                 dam,
-                                |line| line.file_type.is_file() || line.file_type.is_symlink(),
+                                |line| {
+                                    info!("??staging {:?}", &line.path);
+                                    file_type_condition.accepts_path(&line.path)
+                                }
                             ))
                         })?;
                     for path in paths.drain(..) {
diff --git a/src/cli/args.rs b/src/cli/args.rs
index 0dd7e86a..3e9ccefd 100644
--- a/src/cli/args.rs
+++ b/src/cli/args.rs
@@ -9,7 +9,7 @@ use {
 
 /// Launch arguments
 #[derive(Debug, Parser)]
-#[command(author, about, version, disable_version_flag = true, disable_help_flag = true)]
+#[command(about, version, disable_version_flag = true, disable_help_flag = true)]
 pub struct Args {
 
     /// Print help information
@@ -140,7 +140,7 @@ pub struct Args {
     #[arg(long, value_name = "path")]
     pub outcmd: Option<PathBuf>,
 
-    /// An optional path where to write when a verb uses `:write_output`
+    /// Optional path for verbs using `:write_output`
     #[arg(long, value_name = "verb-output")]
     pub verb_output: Option<PathBuf>,
 
@@ -148,7 +148,7 @@ pub struct Args {
     #[arg(short, long, value_name = "cmd")]
     pub cmd: Option<String>,
 
-    /// Whether to have styles and colors (default is usually OK)
+    /// Whether to have styles and colors
     #[arg(long, default_value="auto", value_name = "color")]
     pub color: TriBool,
 
@@ -160,7 +160,7 @@ pub struct Args {
     #[arg(long)]
     pub install: bool,
 
-    /// Where to write the produced cmd (if any)
+    /// Manually set installation state
     #[arg(long, value_name = "state")]
     pub set_install_state: Option<CliShellInstallState>,
 
diff --git a/src/cli/mod.rs b/src/cli/mod.rs
index f7cfc22b..934e7acb 100644
--- a/src/cli/mod.rs
+++ b/src/cli/mod.rs
@@ -56,6 +56,7 @@ pub fn run() -> Result<Option<Launchable>, ProgramError> {
         Printer::new(Args::command())
             .with_max_width(140)
             .with("introduction", INTRO)
+            .with("options", clap_help::TEMPLATE_OPTIONS_MERGED_VALUE)
             .without("author")
             .print_help();
         must_quit = true;
diff --git a/src/tree_build/builder.rs b/src/tree_build/builder.rs
index 50019024..a153ae08 100644
--- a/src/tree_build/builder.rs
+++ b/src/tree_build/builder.rs
@@ -499,7 +499,9 @@ impl<'c> TreeBuilder<'c> {
             .map(|mut blines_ids| {
                 blines_ids
                     .drain(..)
-                    .filter(|&bid| filter(&self.blines[bid]))
+                    .filter(|&bid| {
+                        self.blines[bid].direct_match && filter(&self.blines[bid])
+                    })
                     .map(|id| self.blines[id].path.clone())
                     .collect()
             })
diff --git a/src/verb/internal.rs b/src/verb/internal.rs
index d15c7744..744bcd9e 100644
--- a/src/verb/internal.rs
+++ b/src/verb/internal.rs
@@ -125,6 +125,7 @@ Internals! {
     sort_by_type_dirs_first: "sort by type, dirs first" false,
     sort_by_type_dirs_last: "sort by type, dirs last" false,
     stage: "add selection to staging area" true,
+    stage_all_directories: "stage all matching directories" true,
     stage_all_files: "stage all matching files" true,
     start_end_panel: "either open or close an additional panel" true,
     toggle_counts: "toggle showing number of files in directories" false,
diff --git a/src/verb/verb_store.rs b/src/verb/verb_store.rs
index ce2f5ad1..a599c8f7 100644
--- a/src/verb/verb_store.rs
+++ b/src/verb/verb_store.rs
@@ -271,6 +271,7 @@ impl VerbStore {
             .with_key(key!('+'));
         self.add_internal(unstage)
             .with_key(key!('-'));
+        self.add_internal(stage_all_directories);
         self.add_internal(stage_all_files)
             .with_key(key!(ctrl-a));
         self.add_internal(toggle_stage)
diff --git a/website/docs/conf_verbs.md b/website/docs/conf_verbs.md
index cad0b74a..c4f2c04b 100644
--- a/website/docs/conf_verbs.md
+++ b/website/docs/conf_verbs.md
@@ -440,6 +440,7 @@ invocation | default key | default shortcut | behavior / details
 :sort_by_type_dirs_first | - | - | sort by type, dirs first
 :sort_by_type_dirs_last | - | - | sort by type, dirs last
 :stage | <kbd>+</kbd> | - | add selection to staging area
+:stage_all_directories | - | - | add all directories verifying the pattern to the staging area
 :stage_all_files | <kbd>ctrl</kbd><kbd>a</kbd> | - | add all files verifying the pattern to the staging area
 :start_end_panel | - | - | either open or close an additional panel
 :toggle_counts | - | - | toggle display of total counts of files per directory


Test patch: