From b21baf41fec60047ac260f8b6053d5a73bc8e219 Mon Sep 17 00:00:00 2001 From: Hendrik Sollich Date: Fri, 1 Aug 2025 00:04:28 +0200 Subject: [PATCH 1/3] Preserve selected item when refiltering outline search --- crates/outline/src/outline.rs | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/crates/outline/src/outline.rs b/crates/outline/src/outline.rs index 8c5e78d77b..c32f803d89 100644 --- a/crates/outline/src/outline.rs +++ b/crates/outline/src/outline.rs @@ -119,6 +119,7 @@ struct OutlineViewDelegate { active_editor: Entity, outline: Outline, selected_match_index: usize, + manually_selected: Option, prev_scroll_position: Option>, matches: Vec, last_query: String, @@ -139,6 +140,7 @@ impl OutlineViewDelegate { last_query: Default::default(), matches: Default::default(), selected_match_index: 0, + manually_selected: None, prev_scroll_position: Some(editor.update(cx, |editor, cx| editor.scroll_position(cx))), active_editor: editor, outline, @@ -165,6 +167,7 @@ impl OutlineViewDelegate { if navigate && !self.matches.is_empty() { let selected_match = &self.matches[self.selected_match_index]; + self.manually_selected = Some(selected_match.candidate_id); let outline_item = &self.outline.items[selected_match.candidate_id]; self.active_editor.update(cx, |active_editor, cx| { @@ -180,6 +183,8 @@ impl OutlineViewDelegate { ); active_editor.request_autoscroll(Autoscroll::center(), cx); }); + } else if self.manually_selected.is_some() { + self.manually_selected = None; } } } @@ -261,13 +266,29 @@ impl PickerDelegate for OutlineViewDelegate { self.outline .search(&query, cx.background_executor().clone()), ); - selected_index = self - .matches - .iter() - .enumerate() - .max_by_key(|(_, m)| OrderedFloat(m.score)) - .map(|(ix, _)| ix) - .unwrap_or(0); + + if let Some(manually_selected) = self.manually_selected.and_then(|manually_selected| { + self.matches + .iter() + .find(|mtch| mtch.candidate_id == manually_selected) + .map(|mtch| mtch.candidate_id) + }) { + selected_index = self + .matches + .iter() + .enumerate() + .find(|(_, m)| m.candidate_id == manually_selected) + .map(|(ix, _)| ix) + .unwrap_or(0); + } else { + selected_index = self + .matches + .iter() + .enumerate() + .max_by_key(|(_, m)| OrderedFloat(m.score)) + .map(|(ix, _)| ix) + .unwrap_or(0); + } } self.last_query = query; self.set_selected_index(selected_index, !self.last_query.is_empty(), cx); From a8b83985abb0f059e79950420a8010aa646c5af0 Mon Sep 17 00:00:00 2001 From: Hendrik Sollich Date: Fri, 1 Aug 2025 20:29:00 +0200 Subject: [PATCH 2/3] Rename selected_theme to manually_selected for consistency with outline and project_symbols --- crates/theme_selector/src/theme_selector.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/theme_selector/src/theme_selector.rs b/crates/theme_selector/src/theme_selector.rs index 022daced7a..ad4667000f 100644 --- a/crates/theme_selector/src/theme_selector.rs +++ b/crates/theme_selector/src/theme_selector.rs @@ -113,7 +113,7 @@ struct ThemeSelectorDelegate { matches: Vec, original_theme: Arc, selection_completed: bool, - selected_theme: Option>, + manually_selected: Option>, selected_index: usize, selector: WeakEntity, } @@ -162,7 +162,7 @@ impl ThemeSelectorDelegate { original_theme: original_theme.clone(), selected_index: 0, selection_completed: false, - selected_theme: None, + manually_selected: None, selector, }; @@ -268,7 +268,7 @@ impl PickerDelegate for ThemeSelectorDelegate { cx: &mut Context>, ) { self.selected_index = ix; - self.selected_theme = self.show_selected_theme(cx); + self.manually_selected = self.show_selected_theme(cx); } fn update_matches( @@ -312,12 +312,12 @@ impl PickerDelegate for ThemeSelectorDelegate { this.update(cx, |this, cx| { this.delegate.matches = matches; - if query.is_empty() && this.delegate.selected_theme.is_none() { + if query.is_empty() && this.delegate.manually_selected.is_none() { this.delegate.selected_index = this .delegate .selected_index .min(this.delegate.matches.len().saturating_sub(1)); - } else if let Some(selected) = this.delegate.selected_theme.as_ref() { + } else if let Some(selected) = this.delegate.manually_selected.as_ref() { this.delegate.selected_index = this .delegate .matches @@ -329,7 +329,7 @@ impl PickerDelegate for ThemeSelectorDelegate { } else { this.delegate.selected_index = 0; } - this.delegate.selected_theme = this.delegate.show_selected_theme(cx); + this.delegate.manually_selected = this.delegate.show_selected_theme(cx); }) .log_err(); }) From c0ffeeef2c96caa89e5f8dc90e0f9fcec1718336 Mon Sep 17 00:00:00 2001 From: Hendrik Sollich Date: Fri, 1 Aug 2025 20:29:50 +0200 Subject: [PATCH 3/3] Preserve selected item when refiltering project symbols Add manual symbol selection in project symbols picker When navigating to a symbol using arrow keys, store the selected symbol so we can restore the same selection after re-filtering. --- crates/project_symbols/src/project_symbols.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/crates/project_symbols/src/project_symbols.rs b/crates/project_symbols/src/project_symbols.rs index 47aed8f470..f74bbbf2e0 100644 --- a/crates/project_symbols/src/project_symbols.rs +++ b/crates/project_symbols/src/project_symbols.rs @@ -44,6 +44,7 @@ pub struct ProjectSymbolsDelegate { external_match_candidates: Vec, show_worktree_root_name: bool, matches: Vec, + manually_selected: Option, } impl ProjectSymbolsDelegate { @@ -57,6 +58,7 @@ impl ProjectSymbolsDelegate { external_match_candidates: Default::default(), matches: Default::default(), show_worktree_root_name: false, + manually_selected: None, } } @@ -99,6 +101,18 @@ impl ProjectSymbolsDelegate { } self.matches = matches; + + // Preserve manually selected item if it exists + if let Some(manually_selected) = &self.manually_selected { + if let Some(index) = self.matches.iter().position(|mat| { + let symbol = &self.symbols[mat.candidate_id]; + symbol.path == manually_selected.path && symbol.range == manually_selected.range + }) { + self.set_selected_index(index, window, cx); + return; + } + } + self.set_selected_index(0, window, cx); } } @@ -168,6 +182,11 @@ impl PickerDelegate for ProjectSymbolsDelegate { _cx: &mut Context>, ) { self.selected_match_index = ix; + + // Store the manually selected symbol + if let Some(mat) = self.matches.get(ix) { + self.manually_selected = Some(self.symbols[mat.candidate_id].clone()); + } } fn update_matches(