fix: route pane focus bindings past the file explorer
This commit is contained in:
@@ -199,6 +199,8 @@ Closing a pane gives its space to its sibling:
|
||||
|
||||
There is no default close-pane binding. Option must send Alt/Meta in the terminal; on macOS, configure the terminal's Option-key behavior if it instead produces special characters. These bindings do not replace existing Ctrl+j or uppercase motion/edit bindings.
|
||||
|
||||
Pane-focus bindings also work while the ordinary file explorer or picker has focus. Moving to a neighboring pane returns keyboard focus to its document; a floating picker closes, while a docked explorer remains visible. Explicit `tree` or `selection` navigation overrides and disabled keys take precedence over pane-focus bindings.
|
||||
|
||||
Diff comparisons reuse the split geometry and directional-focus engine. Option/Alt navigation moves between Before, After, and Files first, then to a neighboring workspace pane when there is no internal target in that direction. Splitting a diff text view creates an ordinary sibling showing the same buffer; historical snapshots remain read-only, including after the comparison closes.
|
||||
|
||||
## Buffers
|
||||
|
||||
@@ -1662,6 +1662,9 @@ impl Editor {
|
||||
.neighbor(self.pane_id, direction, self.pane_bounds)
|
||||
{
|
||||
self.finish_pane_interaction();
|
||||
if self.diff.is_none() {
|
||||
self.blur_file_picker();
|
||||
}
|
||||
self.select_pane(id);
|
||||
if self.active.view.mode == Mode::Insert {
|
||||
self.begin_insert();
|
||||
@@ -4260,6 +4263,28 @@ impl Editor {
|
||||
if (picker_focused || self.palette.is_some()) && self.handle_selection_binding(&input) {
|
||||
return None;
|
||||
}
|
||||
if picker_focused
|
||||
&& let Some(Binding::Action(action)) =
|
||||
self.bindings.get(&mode).and_then(|keys| keys.get(&input))
|
||||
&& matches!(
|
||||
action,
|
||||
Action::PaneFocusLeft
|
||||
| Action::PaneFocusDown
|
||||
| Action::PaneFocusUp
|
||||
| Action::PaneFocusRight
|
||||
)
|
||||
{
|
||||
let action = *action;
|
||||
if self
|
||||
.file_picker
|
||||
.as_mut()
|
||||
.expect("focused picker exists")
|
||||
.handle_filter_input(&input)
|
||||
{
|
||||
return None;
|
||||
}
|
||||
return self.act(action);
|
||||
}
|
||||
if picker_focused {
|
||||
self.handle_file_picker(input);
|
||||
return None;
|
||||
@@ -8040,6 +8065,65 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pane_focus_remaps_do_not_steal_printable_picker_filter_input() {
|
||||
let directory = Directory::new();
|
||||
fs::write(directory.path("hello.txt"), "alpha").unwrap();
|
||||
let mut editor = editor();
|
||||
editor.project_root = directory.0.clone();
|
||||
editor.handle(Input::Char('|'));
|
||||
editor
|
||||
.bind("normal", "h", Some("core.pane.focus_left".into()))
|
||||
.unwrap();
|
||||
editor.open_file_picker(FilePresentation::Floating);
|
||||
editor.handle(Input::Char('h'));
|
||||
assert_eq!(editor.pane_id(), 2);
|
||||
assert_eq!(editor.file_picker().unwrap().query, "h");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pane_focus_bindings_escape_focused_explorer_without_changing_documents() {
|
||||
let directory = Directory::new();
|
||||
fs::write(directory.path("a.txt"), "alpha").unwrap();
|
||||
fs::write(directory.path("b.txt"), "beta").unwrap();
|
||||
let mut editor = editor();
|
||||
editor.project_root = directory.0.clone();
|
||||
editor.handle(Input::Char('|'));
|
||||
editor.handle(Input::Char('_'));
|
||||
let original = editor.lines().to_vec();
|
||||
for (key, pane) in [('k', 2), ('h', 1), ('l', 2), ('j', 3)] {
|
||||
editor.open_file_picker(FilePresentation::Docked);
|
||||
assert!(editor.file_picker().unwrap().focused);
|
||||
editor.handle(Input::Alt(key));
|
||||
assert_eq!(editor.pane_id(), pane);
|
||||
assert!(!editor.file_picker().unwrap().focused);
|
||||
assert_eq!(editor.lines(), original);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn explorer_navigation_overrides_take_precedence_over_pane_focus() {
|
||||
for context in ["tree", "selection"] {
|
||||
for target in [None, Some("core.down")] {
|
||||
let directory = Directory::new();
|
||||
fs::write(directory.path("a.txt"), "alpha").unwrap();
|
||||
fs::write(directory.path("b.txt"), "beta").unwrap();
|
||||
let mut editor = editor();
|
||||
editor.project_root = directory.0.clone();
|
||||
editor.handle(Input::Char('|'));
|
||||
editor
|
||||
.bind(context, "alt+h", target.map(str::to_owned))
|
||||
.unwrap();
|
||||
editor.open_file_picker(FilePresentation::Docked);
|
||||
editor.handle(Input::Alt('h'));
|
||||
assert_eq!(editor.pane_id(), 2);
|
||||
let picker = editor.file_picker().unwrap();
|
||||
assert!(picker.focused);
|
||||
assert_eq!(picker.selected, usize::from(target.is_some()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nested_panes_inherit_views_and_focus_geometrically_without_touching_ctrl_j() {
|
||||
let mut editor = editor();
|
||||
|
||||
Reference in New Issue
Block a user