git_ui: Prevent crash when selecting collapsed sections (#63164)
## Summary - Select the first Git panel entry from the visible row indices instead of treating an entry index as a visible-row position - Avoid selecting files hidden by collapsed sections in both tree and flat views - Add a regression test for collapsing the only populated section in tree view with no active selection Fixes ZED-AZ3 Fixes ZED-B0Z Release Notes: - Fixed a crash in the Git panel when collapsed sections were used in tree view.
This commit is contained in:
1 parent
192772f95e
commit
3bd76bb912
1 file changed
+54
-9
@@ -1764,18 +1764,21 @@ impl GitPanel {
|
||||
_window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let is_selectable = |index| {
|
||||
self.entries
|
||||
.get(index)
|
||||
.is_some_and(GitListEntry::is_selectable)
|
||||
};
|
||||
let first_entry = match &self.view_mode {
|
||||
GitPanelViewMode::Flat => self
|
||||
.entries
|
||||
.visible_flat_entry_indices()
|
||||
.into_iter()
|
||||
.find(|&index| is_selectable(index)),
|
||||
GitPanelViewMode::Tree(state) => state
|
||||
.logical_indices
|
||||
.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])
|
||||
}
|
||||
.copied()
|
||||
.find(|&index| is_selectable(index)),
|
||||
};
|
||||
|
||||
if let Some(first_entry) = first_entry {
|
||||
@@ -12389,6 +12392,48 @@ mod tests {
|
||||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_tree_view_select_first_skips_collapsed_section(cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
cx.update(|cx| {
|
||||
SettingsStore::update_global(cx, |store, cx| {
|
||||
store.update_user_settings(cx, |settings| {
|
||||
settings.git_panel.get_or_insert_default().tree_view = Some(true);
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
let (_, _, _, panel, mut cx) = setup_git_panel_with_changes(
|
||||
cx,
|
||||
json!({
|
||||
".git": {},
|
||||
"modified.rs": "fn main() {}",
|
||||
}),
|
||||
&[("modified.rs", StatusCode::Modified)],
|
||||
)
|
||||
.await;
|
||||
|
||||
panel.update_in(&mut cx, |panel, window, cx| {
|
||||
panel.selected_entry = None;
|
||||
panel.toggle_section_collapsed(Section::Tracked, window, cx);
|
||||
|
||||
let state = panel
|
||||
.view_mode
|
||||
.tree_state()
|
||||
.expect("tree view state should exist");
|
||||
assert_eq!(state.logical_indices, [0]);
|
||||
assert!(panel.selected_entry.is_none());
|
||||
|
||||
panel.toggle_section_collapsed(Section::Tracked, window, cx);
|
||||
|
||||
let selected_entry = panel
|
||||
.get_selected_entry()
|
||||
.and_then(GitListEntry::status_entry)
|
||||
.expect("the first visible file should be selected");
|
||||
assert_eq!(selected_entry.repo_path, repo_path("modified.rs"));
|
||||
});
|
||||
}
|
||||
|
||||
fn assert_entry_paths(entries: &[GitListEntry], expected_paths: &[Option<&str>]) {
|
||||
assert_eq!(entries.len(), expected_paths.len());
|
||||
for (entry, expected_path) in entries.iter().zip(expected_paths) {
|
||||
|
||||
Reference in new issue
Block a user