fix: retain selections and float local review editors

This commit is contained in:
Valdemar Lorenzen
2026-10-16 14:16:29 +02:00
parent d67b874b87
commit 4cc0453344
9 changed files with 336 additions and 68 deletions
+48 -6
View File
@@ -1773,6 +1773,7 @@ struct Pane {
struct Tab {
pane_id: usize,
pane_layout: PaneTree,
review_pane: Option<usize>,
file_picker: Option<FilePicker>,
diff: Option<DiffState>,
parked_diff: Option<DiffState>,
@@ -2060,6 +2061,7 @@ pub struct Editor {
next_pane_id: usize,
panes: BTreeMap<usize, Pane>,
pane_layout: PaneTree,
review_pane: Option<usize>,
tab_id: usize,
next_tab_id: usize,
tab_order: Vec<usize>,
@@ -2160,6 +2162,7 @@ impl Editor {
},
)]),
pane_layout: PaneTree::new(1),
review_pane: None,
tab_id: 1,
next_tab_id: 2,
tab_order: vec![1],
@@ -3485,6 +3488,7 @@ impl Editor {
let previous = Tab {
pane_id: std::mem::replace(&mut self.pane_id, next.pane_id),
pane_layout: std::mem::replace(&mut self.pane_layout, next.pane_layout),
review_pane: std::mem::replace(&mut self.review_pane, next.review_pane),
file_picker: std::mem::replace(&mut self.file_picker, next.file_picker),
diff: std::mem::replace(&mut self.diff, next.diff),
parked_diff: std::mem::replace(&mut self.parked_diff, next.parked_diff),
@@ -3533,6 +3537,7 @@ impl Editor {
Tab {
pane_id,
pane_layout: PaneTree::new(pane_id),
review_pane: None,
file_picker: None,
diff: None,
parked_diff: None,
@@ -3635,6 +3640,11 @@ impl Editor {
// No input dispatch or document copies: source documents stay unique in active/parked.
fn select_pane(&mut self, id: usize) {
let id = if self.review_pane == Some(id) && self.workspace_diff().is_none() {
self.panes[&id].origin.unwrap_or(id)
} else {
id
};
if id == self.pane_id {
return;
}
@@ -3660,13 +3670,13 @@ impl Editor {
assert!(self.panes.contains_key(&id), "rendered pane exists");
let focused = self.pane_id;
let tab = self.tab_id;
let target_tab = if self.pane_layout.contains(id) {
let target_tab = if self.pane_layout.contains(id) || self.review_pane == Some(id) {
tab
} else {
*self
.tabs
.iter()
.find(|(_, tab)| tab.pane_layout.contains(id))
.find(|(_, tab)| tab.pane_layout.contains(id) || tab.review_pane == Some(id))
.map(|(id, _)| id)
.expect("pane belongs to a tab")
};
@@ -3943,7 +3953,7 @@ impl Editor {
.panes
.keys()
.copied()
.filter(|id| self.pane_layout.contains(*id))
.filter(|id| self.pane_layout.contains(*id) || self.review_pane == Some(*id))
.collect();
let mut buffers = self.closing_buffers(&panes);
if let Some(resolver) = self.resolver() {
@@ -3992,6 +4002,9 @@ impl Editor {
}
fn close_pane(&mut self, force: bool) {
if self.dismiss_review_panel() {
return;
}
if self.resolver().is_some() {
self.close_tab(force);
return;
@@ -6685,7 +6698,9 @@ impl Editor {
}
/// Whole-row shape belongs to the active buffer, not the Visual binding context.
pub fn visual_linewise(&self) -> bool {
self.active.view.mode == Mode::Visual && self.active.view.linewise
(self.active.view.mode == Mode::Visual
|| (self.active.view.mode == Mode::Command && self.active.view.command_from_visual))
&& self.active.view.linewise
}
/// Inclusive selected rows, including an empty final row with an empty text range.
@@ -6700,9 +6715,11 @@ impl Editor {
})
}
/// Ordered, end-exclusive Visual ranges in document order; empty in other modes.
/// Ordered Visual ranges, including selections retained by command input.
pub fn selections(&self) -> Vec<Selection> {
if self.active.view.mode == Mode::Visual {
if self.active.view.mode == Mode::Visual
|| (self.active.view.mode == Mode::Command && self.active.view.command_from_visual)
{
self.active
.view
.targets
@@ -9351,6 +9368,31 @@ impl Editor {
}
return None;
}
if self.review_panel().is_some()
&& matches!(
entry.action,
Action::PaneSplitHorizontal
| Action::PaneSplitVertical
| Action::PaneFocusLeft
| Action::PaneFocusRight
| Action::PaneFocusUp
| Action::PaneFocusDown
| Action::TabNew
| Action::Edit
| Action::Buffers
| Action::Buffer
| Action::BufferNext
| Action::BufferPrevious
| Action::BufferDelete
| Action::BufferForceDelete
| Action::Diff
| Action::DiffClose
| Action::PullRequests
| Action::Resolve
)
{
self.dismiss_review_panel();
}
if matches!(
entry.action,
Action::Resolve