From 7592582bd531df107386a204049244d85ae42960 Mon Sep 17 00:00:00 2001
From: Jordan MacDonald <jordan@wastedintelligence.com>
Date: Sun, 3 Nov 2024 22:13:31 -0500
Subject: [PATCH] Display default results in search/select modes

It's worth noting that we'll immediately exit search/select modes (bypassing
normal mode) despite default results.
---
 Cargo.lock                                    |  4 +-
 Cargo.toml                                    |  2 +-
 src/commands/search_select.rs                 |  8 ++--
 src/models/application/modes/command/mod.rs   | 25 +++++++----
 src/models/application/modes/open/mod.rs      | 42 +++++++++++--------
 src/models/application/modes/search_select.rs |  4 +-
 src/models/application/modes/symbol_jump.rs   | 19 ++++++---
 src/models/application/modes/syntax.rs        | 20 ++++++---
 src/models/application/modes/theme.rs         | 17 ++++++--
 9 files changed, 89 insertions(+), 52 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index f5f3e103..fb3ec370 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -146,9 +146,9 @@ checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
 
 [[package]]
 name = "bloodhound"
-version = "0.5.4"
+version = "0.5.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3adde3a05c6955eb3bbf6134a06d863d0e1ac23b3f46de258839dc1d8f813cb"
+checksum = "51533c509c0f17dca020b34abf9cefb61df9bd2bd3c34e46f3ad0316c586da59"
 dependencies = [
  "fragment",
  "glob",
diff --git a/Cargo.toml b/Cargo.toml
index d34c6842..1f4a0746 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -18,7 +18,7 @@ regex = "1.10"
 [dependencies]
 app_dirs2 = "2.5"
 scribe = "0.8"
-bloodhound = "0.5"
+bloodhound = "0.5.5"
 luthor = "0.2"
 fragment = "0.3"
 regex = "1.10"
diff --git a/src/commands/search_select.rs b/src/commands/search_select.rs
index 01bfe0de..b9a09c4c 100644
--- a/src/commands/search_select.rs
+++ b/src/commands/search_select.rs
@@ -171,11 +171,11 @@ pub fn pop_search_token(app: &mut Application) -> Result {
 
 pub fn step_back(app: &mut Application) -> Result {
     let selection_available = match app.mode {
-        Mode::Command(ref mut mode) => mode.results().count() > 0,
+        Mode::Command(ref mut mode) => mode.results().count() > 0 && !mode.query().is_empty(),
         Mode::Open(ref mut mode) => mode.results().count() > 0 && !mode.query().is_empty(),
-        Mode::Theme(ref mut mode) => mode.results().count() > 0,
-        Mode::SymbolJump(ref mut mode) => mode.results().count() > 0,
-        Mode::Syntax(ref mut mode) => mode.results().count() > 0,
+        Mode::Theme(ref mut mode) => mode.results().count() > 0 && !mode.query().is_empty(),
+        Mode::SymbolJump(ref mut mode) => mode.results().count() > 0 && !mode.query().is_empty(),
+        Mode::Syntax(ref mut mode) => mode.results().count() > 0 && !mode.query().is_empty(),
         _ => bail!("Can't pop search token outside of search select mode"),
     };
 
diff --git a/src/models/application/modes/command/mod.rs b/src/models/application/modes/command/mod.rs
index 0ebc6460..918b9dae 100644
--- a/src/models/application/modes/command/mod.rs
+++ b/src/models/application/modes/command/mod.rs
@@ -46,15 +46,20 @@ impl SearchSelectMode for CommandMode {
     type Item = DisplayableCommand;
 
     fn search(&mut self) {
-        let commands: Vec<&'static str> = self.commands.keys().copied().collect();
-
         // Find the commands we're looking for using the query.
-        let results = fragment::matching::find(&self.input, &commands, self.config.max_results);
+        let results = if self.input.is_empty() {
+            self.commands
+                .iter()
+                .take(self.config.max_results)
+                .map(|(k, v)| DisplayableCommand {
+                    description: *k,
+                    command: *v,
+                })
+                .collect()
+        } else {
+            let commands: Vec<&'static str> = self.commands.keys().copied().collect();
 
-        // We don't care about the result objects; we just want
-        // the underlying commands. Map the collection to get these.
-        self.results = SelectableVec::new(
-            results
+            fragment::matching::find(&self.input, &commands, self.config.max_results)
                 .into_iter()
                 .filter_map(|result| {
                     self.commands
@@ -64,8 +69,10 @@ impl SearchSelectMode for CommandMode {
                             command: *command,
                         })
                 })
-                .collect(),
-        );
+                .collect()
+        };
+
+        self.results = SelectableVec::new(results);
     }
 
     fn query(&mut self) -> &mut String {
diff --git a/src/models/application/modes/open/mod.rs b/src/models/application/modes/open/mod.rs
index 7eed9a44..8be6ed9f 100644
--- a/src/models/application/modes/open/mod.rs
+++ b/src/models/application/modes/open/mod.rs
@@ -158,7 +158,7 @@ impl OpenMode {
     }
 
     fn collection(&self) -> &SelectableVec<DisplayablePath> {
-        if self.input.is_empty() {
+        if self.input.is_empty() && self.buffers.len() > 1 {
             &self.buffers
         } else {
             &self.results
@@ -166,7 +166,7 @@ impl OpenMode {
     }
 
     fn collection_mut(&mut self) -> &mut SelectableVec<DisplayablePath> {
-        if self.input.is_empty() {
+        if self.input.is_empty() && self.buffers.len() > 1 {
             &mut self.buffers
         } else {
             &mut self.results
@@ -185,18 +185,26 @@ impl SearchSelectMode for OpenMode {
 
     fn search(&mut self) {
         let results = if let OpenModeIndex::Complete(ref index) = self.index {
-            index
-                .find(
-                    &format!(
-                        "{} {}",
-                        self.pinned_input.to_lowercase(),
-                        self.input.to_lowercase()
-                    ),
-                    self.config.max_results,
-                )
-                .into_iter()
-                .map(|path| DisplayablePath(path.to_path_buf()))
-                .collect()
+            if self.input.is_empty() {
+                index
+                    .iter()
+                    .take(self.config.max_results)
+                    .map(|path| DisplayablePath(path.to_path_buf()))
+                    .collect()
+            } else {
+                index
+                    .find(
+                        &format!(
+                            "{} {}",
+                            self.pinned_input.to_lowercase(),
+                            self.input.to_lowercase()
+                        ),
+                        self.config.max_results,
+                    )
+                    .into_iter()
+                    .map(|path| DisplayablePath(path.to_path_buf()))
+                    .collect()
+            }
         } else {
             vec![]
         };
@@ -242,16 +250,14 @@ impl SearchSelectMode for OpenMode {
     }
 
     fn message(&mut self) -> Option<String> {
-        // When multiple buffers are open, we show them instead of query prompts
+        // Show open buffers in empty state if there are more than one
         if self.buffers.len() > 1 && self.query().is_empty() {
             return None;
         }
 
         if let OpenModeIndex::Indexing(ref path) = self.index {
             Some(format!("Indexing {}", path.to_string_lossy()))
-        } else if self.pinned_query().is_empty() && self.query().is_empty() {
-            Some(String::from("Enter a search query to start."))
-        } else if self.results().count() == 0 {
+        } else if !self.query().is_empty() && self.results().count() == 0 {
             Some(String::from("No matching entries found."))
         } else {
             None
diff --git a/src/models/application/modes/search_select.rs b/src/models/application/modes/search_select.rs
index ff9459e9..58229dba 100644
--- a/src/models/application/modes/search_select.rs
+++ b/src/models/application/modes/search_select.rs
@@ -28,9 +28,7 @@ pub trait SearchSelectMode: Display {
     fn select_next(&mut self);
     fn config(&self) -> &SearchSelectConfig;
     fn message(&mut self) -> Option<String> {
-        if self.query().is_empty() {
-            Some(String::from("Enter a search query to start."))
-        } else if self.results().count() == 0 {
+        if !self.query().is_empty() && self.results().count() == 0 {
             Some(String::from("No matching entries found."))
         } else {
             None
diff --git a/src/models/application/modes/symbol_jump.rs b/src/models/application/modes/symbol_jump.rs
index e2349465..64c6be7a 100644
--- a/src/models/application/modes/symbol_jump.rs
+++ b/src/models/application/modes/symbol_jump.rs
@@ -84,11 +84,20 @@ impl SearchSelectMode for SymbolJumpMode {
 
     fn search(&mut self) {
         // Find the symbols we're looking for using the query.
-        let results = fragment::matching::find(&self.input, &self.symbols, self.config.max_results);
-
-        // We don't care about the result objects; we just want
-        // the underlying symbols. Map the collection to get these.
-        self.results = SelectableVec::new(results.into_iter().map(|r| r.clone()).collect());
+        let results = if self.input.is_empty() {
+            self.symbols
+                .iter()
+                .take(self.config.max_results)
+                .cloned()
+                .collect()
+        } else {
+            fragment::matching::find(&self.input, &self.symbols, self.config.max_results)
+                .into_iter()
+                .map(|i| i.clone())
+                .collect()
+        };
+
+        self.results = SelectableVec::new(results);
     }
 
     fn query(&mut self) -> &mut String {
diff --git a/src/models/application/modes/syntax.rs b/src/models/application/modes/syntax.rs
index 07ea83df..14ed57db 100644
--- a/src/models/application/modes/syntax.rs
+++ b/src/models/application/modes/syntax.rs
@@ -43,12 +43,20 @@ impl SearchSelectMode for SyntaxMode {
 
     fn search(&mut self) {
         // Find the themes we're looking for using the query.
-        let results =
-            fragment::matching::find(&self.input, &self.syntaxes, self.config.max_results);
-
-        // We don't care about the result objects; we just want
-        // the underlying symbols. Map the collection to get these.
-        self.results = SelectableVec::new(results.into_iter().map(|r| r.clone()).collect());
+        let results = if self.input.is_empty() {
+            self.syntaxes
+                .iter()
+                .take(self.config.max_results)
+                .cloned()
+                .collect()
+        } else {
+            fragment::matching::find(&self.input, &self.syntaxes, self.config.max_results)
+                .into_iter()
+                .map(|i| i.clone())
+                .collect()
+        };
+
+        self.results = SelectableVec::new(results);
     }
 
     fn query(&mut self) -> &mut String {
diff --git a/src/models/application/modes/theme.rs b/src/models/application/modes/theme.rs
index b92a1134..dc447712 100644
--- a/src/models/application/modes/theme.rs
+++ b/src/models/application/modes/theme.rs
@@ -43,11 +43,20 @@ impl SearchSelectMode for ThemeMode {
 
     fn search(&mut self) {
         // Find the themes we're looking for using the query.
-        let results = fragment::matching::find(&self.input, &self.themes, self.config.max_results);
+        let results = if self.input.is_empty() {
+            self.themes
+                .iter()
+                .take(self.config.max_results)
+                .cloned()
+                .collect()
+        } else {
+            fragment::matching::find(&self.input, &self.themes, self.config.max_results)
+                .into_iter()
+                .map(|i| i.clone())
+                .collect()
+        };
 
-        // We don't care about the result objects; we just want
-        // the underlying symbols. Map the collection to get these.
-        self.results = SelectableVec::new(results.into_iter().map(|r| r.clone()).collect());
+        self.results = SelectableVec::new(results);
     }
 
     fn query(&mut self) -> &mut String {