From 5b8e4e58c5f548ff1eda6ccd57997e2fda89e4b6 Mon Sep 17 00:00:00 2001 From: Remco Smits Date: Wed, 17 Dec 2025 16:31:36 +0100 Subject: [PATCH] git_ui: Fix select first entry selects the wrong visual first entry when tree view is enabled (#45108) This PR fixes a bug where the select first didn't select the first visual entry when the first entry is a collapsed directory. Follow-up: https://github.com/zed-industries/zed/pull/45030 **Before**: https://github.com/user-attachments/assets/5e5865cc-ec0f-471d-a81b-9521fb70df41 **After**: https://github.com/user-attachments/assets/05562572-e43f-4d1e-9638-80e4dccc0998 Release Notes: - git_ui: Fix select first entry selects the wrong visual first entry when tree view is enabled --- crates/git_ui/src/git_panel.rs | 42 ++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/crates/git_ui/src/git_panel.rs b/crates/git_ui/src/git_panel.rs index 1426ed1e65412da5cb8be22e7592e5a42917b367..cc9227093034ac0fa42b55324c0c2ab74a44903e 100644 --- a/crates/git_ui/src/git_panel.rs +++ b/crates/git_ui/src/git_panel.rs @@ -279,6 +279,13 @@ impl GitListEntry { _ => None, } } + + fn directory_entry(&self) -> Option<&GitTreeDirEntry> { + match self { + GitListEntry::Directory(entry) => Some(entry), + _ => None, + } + } } enum GitPanelViewMode { @@ -895,12 +902,6 @@ impl GitPanel { cx.notify(); } - fn first_status_entry_index(&self) -> Option { - self.entries - .iter() - .position(|entry| entry.status_entry().is_some()) - } - fn expand_selected_entry( &mut self, _: &ExpandSelectedEntry, @@ -944,7 +945,21 @@ impl GitPanel { } fn select_first(&mut self, _: &SelectFirst, _window: &mut Window, cx: &mut Context) { - if let Some(first_entry) = self.first_status_entry_index() { + let first_entry = match &self.view_mode { + GitPanelViewMode::Flat => self + .entries + .iter() + .position(|entry| entry.status_entry().is_some()), + GitPanelViewMode::Tree(state) => { + let index = self.entries.iter().position(|entry| { + entry.status_entry().is_some() || entry.directory_entry().is_some() + }); + + index.map(|index| state.logical_indices[index]) + } + }; + + if let Some(first_entry) = first_entry { self.selected_entry = Some(first_entry); self.scroll_to_selected_entry(cx); } @@ -1053,15 +1068,13 @@ impl GitPanel { cx.notify(); } - fn select_first_entry_if_none(&mut self, cx: &mut Context) { + fn select_first_entry_if_none(&mut self, window: &mut Window, cx: &mut Context) { let have_entries = self .active_repository .as_ref() .is_some_and(|active_repository| active_repository.read(cx).status_summary().count > 0); if have_entries && self.selected_entry.is_none() { - self.selected_entry = self.first_status_entry_index(); - self.scroll_to_selected_entry(cx); - cx.notify(); + self.select_first(&SelectFirst, window, cx); } } @@ -1071,10 +1084,9 @@ impl GitPanel { window: &mut Window, cx: &mut Context, ) { - self.select_first_entry_if_none(cx); - self.focus_handle.focus(window); - cx.notify(); + + self.select_first_entry_if_none(window, cx); } fn get_selected_entry(&self) -> Option<&GitListEntry> { @@ -3549,7 +3561,7 @@ impl GitPanel { self.bulk_staging = bulk_staging; } - self.select_first_entry_if_none(cx); + self.select_first_entry_if_none(window, cx); let suggested_commit_message = self.suggest_commit_message(cx); let placeholder_text = suggested_commit_message.unwrap_or("Enter commit message".into());