Repository: Canop/broot (language: rust)

Issue:
missing verb when cycling among verb completions
Reported by @AeliusSaionji in https://github.com/Canop/broot/pull/901#issuecomment-2224667086

Test case:

      { invocation: "test_stdout_quit" cmd: ":write_stdout {file};:quit" }
      { invocation: "testln_stdout_quit" cmd: ":writeln_stdout {file};:quit" }
      { invocation: "test_stdout" cmd: ":write_stdout {file}" }
      { invocation: "testln_stdout" cmd: ":writeln_stdout {file}" }

Type `:testln` then the completions aren't exhaustive


Discussion / hints:

Fix patch:
diff --git a/src/app/app.rs b/src/app/app.rs
index c5603a02..c2972475 100644
--- a/src/app/app.rs
+++ b/src/app/app.rs
@@ -842,7 +842,7 @@ impl App {
             if !self.quitting {
                 self.display_panels(w, &skin, &app_state, con)?;
                 time!(
-                    Info,
+                    Debug,
                     "pending_tasks",
                     self.do_pending_tasks(w, &skin, &mut dam, &mut app_state, con)?,
                 );
diff --git a/src/command/completion.rs b/src/command/completion.rs
index e43e6581..d6493622 100644
--- a/src/command/completion.rs
+++ b/src/command/completion.rs
@@ -21,12 +21,13 @@ use {
 
 /// find the longest common start of a and b
 fn common_start<'l>(a: &'l str, b: &str) -> &'l str {
-    for i in 0..a.len().min(b.len()) {
+    let l = a.len().min(b.len());
+    for i in 0..l {
         if a.as_bytes()[i] != b.as_bytes()[i] {
             return &a[..i];
         }
     }
-    a
+    &a[..l]
 }
 
 /// how an input can be completed
@@ -89,7 +90,7 @@ impl Completions {
         con: &AppContext,
         sel_info: SelInfo<'_>,
     ) -> Self {
-        match con.verb_store.search_sel_info(start, sel_info) {
+        match con.verb_store.search(start, Some(sel_info), false) {
             PrefixSearchResult::NoMatch => Self::None,
             PrefixSearchResult::Match(name, _) => {
                 if start.len() >= name.len() {
@@ -113,7 +114,7 @@ impl Completions {
         sel_info: SelInfo<'_>,
         con: &AppContext,
     ) -> io::Result<Vec<String>> {
-        let anchor = match con.verb_store.search_sel_info(verb_name, sel_info) {
+        let anchor = match con.verb_store.search(verb_name, Some(sel_info), false) {
             PrefixSearchResult::Match(_, verb) => verb.get_unique_arg_anchor(),
             _ => PathAnchor::Unspecified,
         };
diff --git a/src/verb/verb_store.rs b/src/verb/verb_store.rs
index 692d4e88..cd202174 100644
--- a/src/verb/verb_store.rs
+++ b/src/verb/verb_store.rs
@@ -539,14 +539,14 @@ impl VerbStore {
         prefix: &str,
         sel_info: SelInfo<'_>,
     ) -> PrefixSearchResult<'v, &Verb> {
-        self.search(prefix, Some(sel_info))
+        self.search(prefix, Some(sel_info), true)
     }
 
     pub fn search_prefix<'v>(
         &'v self,
         prefix: &str,
     ) -> PrefixSearchResult<'v, &Verb> {
-        self.search(prefix, None)
+        self.search(prefix, None, true)
     }
 
     /// Return either the only match, or None if there's not
@@ -566,6 +566,7 @@ impl VerbStore {
         &'v self,
         prefix: &str,
         sel_info: Option<SelInfo>,
+        short_circuit: bool,
     ) -> PrefixSearchResult<'v, &Verb> {
         let mut found_index = 0;
         let mut nb_found = 0;
@@ -591,7 +592,7 @@ impl VerbStore {
             }
             for name in &verb.names {
                 if name.starts_with(prefix) {
-                    if name == prefix {
+                    if short_circuit && name == prefix {
                         return PrefixSearchResult::Match(name, verb);
                     }
                     found_index = index;


Test patch: