sidebar: Better search (#56166)
Cameron Mcloughlin
created 1 day ago
Makes the sidebar search case insensitive, and also require contiguous
matches. Also removes the duplicate logic for the sidebar and thread
history view
Release Notes:
- N/A or Added/Fixed/Improved ...
Change summary
crates/agent_ui/src/threads_archive_view.rs | 36 +++++++++++++---------
crates/sidebar/src/sidebar.rs | 23 --------------
2 files changed, 22 insertions(+), 37 deletions(-)
Detailed changes
@@ -102,24 +102,30 @@ impl TimeBucket {
}
}
-fn fuzzy_match_positions(query: &str, text: &str) -> Option<Vec<usize>> {
- let mut positions = Vec::new();
- let mut query_chars = query.chars().peekable();
- for (byte_idx, candidate_char) in text.char_indices() {
- if let Some(&query_char) = query_chars.peek() {
- if candidate_char.eq_ignore_ascii_case(&query_char) {
- positions.push(byte_idx);
- query_chars.next();
+pub fn fuzzy_match_positions(query: &str, candidate: &str) -> Option<Vec<usize>> {
+ let query_chars: Vec<char> = query.chars().collect();
+ if query_chars.is_empty() {
+ return Some(Vec::new());
+ }
+
+ let candidate_chars: Vec<(usize, char)> = candidate.char_indices().collect();
+ let window_count = candidate_chars.len().checked_sub(query_chars.len() - 1)?;
+
+ 'outer: for window_start in 0..window_count {
+ for (qi, &query_char) in query_chars.iter().enumerate() {
+ let (_, cand_char) = candidate_chars[window_start + qi];
+ if !cand_char.eq_ignore_ascii_case(&query_char) {
+ continue 'outer;
}
- } else {
- break;
}
+ return Some(
+ (0..query_chars.len())
+ .map(|qi| candidate_chars[window_start + qi].0)
+ .collect(),
+ );
}
- if query_chars.peek().is_none() {
- Some(positions)
- } else {
- None
- }
+
+ None
}
pub enum ThreadsArchiveViewEvent {
@@ -10,6 +10,7 @@ use agent_ui::thread_metadata_store::{
use agent_ui::thread_worktree_archive;
use agent_ui::threads_archive_view::{
ThreadsArchiveView, ThreadsArchiveViewEvent, format_history_entry_timestamp,
+ fuzzy_match_positions,
};
use agent_ui::{
AcpThreadImportOnboarding, Agent, AgentPanel, AgentPanelEvent, AgentPanelTerminalInfo,
@@ -377,28 +378,6 @@ impl SidebarContents {
}
}
-fn fuzzy_match_positions(query: &str, candidate: &str) -> Option<Vec<usize>> {
- let mut positions = Vec::new();
- let mut query_chars = query.chars().peekable();
-
- for (byte_idx, candidate_char) in candidate.char_indices() {
- if let Some(&query_char) = query_chars.peek() {
- if candidate_char.eq_ignore_ascii_case(&query_char) {
- positions.push(byte_idx);
- query_chars.next();
- }
- } else {
- break;
- }
- }
-
- if query_chars.peek().is_none() {
- Some(positions)
- } else {
- None
- }
-}
-
// TODO: The mapping from workspace root paths to git repositories needs a
// unified approach across the codebase: this function, `AgentPanel::classify_worktrees`,
// thread persistence (which PathList is saved to the database), and thread