From ab4cd95e9c05fa786dc36934b683995e13c4a99f Mon Sep 17 00:00:00 2001 From: Remco Smits Date: Tue, 16 Dec 2025 22:53:30 +0100 Subject: [PATCH] git_ui: Fix select next/previous entry selects non-visible entry when tree view is enabled (#45030) Before this commit, we would select a non-visible entry when a directory is collapsed. Now we correctly select the visible entry that is visually the previous/next entry in the list. **Note**: I removed the `cx.notify()` call as it's already part of the `self.scroll_to_selected_entry(cx)` call. So we don't notify twice :). Follow-up: https://github.com/zed-industries/zed/pull/45002 **Before** https://github.com/user-attachments/assets/da0b8084-0081-4d98-ad8a-c11c3b95a1b7 **After** https://github.com/user-attachments/assets/8a16afb0-fdde-4317-b419-13143d5d608e Release Notes: - git_ui: Fix select next/previous entry selects non-visible entry when tree view is enabled --- crates/git_ui/src/git_panel.rs | 91 ++++++++++++++++++++++------------ 1 file changed, 59 insertions(+), 32 deletions(-) diff --git a/crates/git_ui/src/git_panel.rs b/crates/git_ui/src/git_panel.rs index 390f5cf2c28bfc0ff1aef5226e125d08db37dd68..37926eae5db12c83ab69613a09c4eceda1f5ffeb 100644 --- a/crates/git_ui/src/git_panel.rs +++ b/crates/git_ui/src/git_panel.rs @@ -961,28 +961,44 @@ impl GitPanel { return; } - if let Some(selected_entry) = self.selected_entry { - let new_selected_entry = if selected_entry > 0 { - selected_entry - 1 - } else { - selected_entry - }; + let Some(selected_entry) = self.selected_entry else { + return; + }; - if matches!( - self.entries.get(new_selected_entry), - Some(GitListEntry::Header(..)) - ) { - if new_selected_entry > 0 { - self.selected_entry = Some(new_selected_entry - 1) - } - } else { - self.selected_entry = Some(new_selected_entry); + let new_index = match &self.view_mode { + GitPanelViewMode::Flat => selected_entry.saturating_sub(1), + GitPanelViewMode::Tree(state) => { + let Some(current_logical_index) = state + .logical_indices + .iter() + .position(|&i| i == selected_entry) + else { + return; + }; + + state.logical_indices[current_logical_index.saturating_sub(1)] } + }; - self.scroll_to_selected_entry(cx); + if selected_entry == 0 && new_index == 0 { + return; } - cx.notify(); + if matches!( + self.entries.get(new_index.saturating_sub(1)), + Some(GitListEntry::Header(..)) + ) && new_index == 0 + { + return; + } + + if matches!(self.entries.get(new_index), Some(GitListEntry::Header(..))) { + self.selected_entry = Some(new_index.saturating_sub(1)); + } else { + self.selected_entry = Some(new_index); + } + + self.scroll_to_selected_entry(cx); } fn select_next(&mut self, _: &SelectNext, _window: &mut Window, cx: &mut Context) { @@ -991,25 +1007,36 @@ impl GitPanel { return; } - if let Some(selected_entry) = self.selected_entry { - let new_selected_entry = if selected_entry < item_count - 1 { - selected_entry + 1 - } else { - selected_entry - }; - if matches!( - self.entries.get(new_selected_entry), - Some(GitListEntry::Header(..)) - ) { - self.selected_entry = Some(new_selected_entry + 1); - } else { - self.selected_entry = Some(new_selected_entry); + let Some(selected_entry) = self.selected_entry else { + return; + }; + + if selected_entry == item_count - 1 { + return; + } + + let new_index = match &self.view_mode { + GitPanelViewMode::Flat => selected_entry.saturating_add(1), + GitPanelViewMode::Tree(state) => { + let Some(current_logical_index) = state + .logical_indices + .iter() + .position(|&i| i == selected_entry) + else { + return; + }; + + state.logical_indices[current_logical_index.saturating_add(1)] } + }; - self.scroll_to_selected_entry(cx); + if matches!(self.entries.get(new_index), Some(GitListEntry::Header(..))) { + self.selected_entry = Some(new_index.saturating_add(1)); + } else { + self.selected_entry = Some(new_index); } - cx.notify(); + self.scroll_to_selected_entry(cx); } fn select_last(&mut self, _: &SelectLast, _window: &mut Window, cx: &mut Context) {