sidebar: Better search (#56166)

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 ...
This commit is contained in:
Cameron Mcloughlin 2026-05-08 14:13:14 +01:00 committed by GitHub
parent 367db0706b
commit 7940ded92a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 22 additions and 37 deletions

View file

@ -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 {

View file

@ -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