fix: preserve selector text input and close on escape

This commit is contained in:
Valdemar Lorenzen
2026-10-12 13:08:56 +02:00
parent 684ba46a2c
commit 7bc5eab22f
9 changed files with 189 additions and 124 deletions
+103 -42
View File
@@ -2628,6 +2628,32 @@ impl Editor {
}
fn handle_diff(&mut self, input: Input) -> Option<Invocation> {
if self.palette.is_some()
|| self.diff_prompt_mode.is_some()
|| self.startup_diagnostic.is_some()
|| self.hover.is_some()
{
return self.handle_input(input);
}
let phase = self.diff.as_ref().expect("active diff").phase;
let files_focused =
phase == Phase::View && self.diff.as_ref().unwrap().focus == Focus::Files;
if phase != Phase::View && input == Input::Escape {
return self.execute_action(Action::DiffClose.entry(), "");
}
let text_focused = phase != Phase::View
|| (files_focused
&& self
.diff
.as_ref()
.and_then(|diff| diff.files.as_ref())
.is_some_and(|files| files.searching || files.view == FileView::List));
if text_focused && matches!(input, Input::Char(ch) if !ch.is_control()) {
if !self.handle_selection_binding(&input) {
self.diff.as_mut().unwrap().handle(input);
}
return None;
}
if self
.bindings
.get(&self.binding_mode())
@@ -2655,9 +2681,7 @@ impl Editor {
{
return self.handle_input(input);
}
if self.palette.is_some()
|| self.diff_prompt_mode.is_some()
|| (self.diff_interacting() && self.active.view.mode != Mode::Normal)
if (self.diff_interacting() && self.active.view.mode != Mode::Normal)
|| self.count.is_some()
|| self.sequence_pending().is_some()
|| self.g_pending
@@ -2666,9 +2690,6 @@ impl Editor {
{
return self.handle_input(input);
}
let phase = self.diff.as_ref().expect("active diff").phase;
let files_focused =
phase == Phase::View && self.diff.as_ref().unwrap().focus == Focus::Files;
if self.diff_interacting() {
if matches!(input, Input::Char('[' | ']')) {
let focus = self.diff_buffer_focus().unwrap();
@@ -2704,29 +2725,7 @@ impl Editor {
if files_focused && self.handle_tree_binding(&input) {
return None;
}
if !self.diff_interacting() {
match self.selection_bindings.get(&input) {
Some(Binding::Action(Action::Down)) => {
self.diff.as_mut().unwrap().navigate(true);
return None;
}
Some(Binding::Action(Action::Up)) => {
self.diff.as_mut().unwrap().navigate(false);
return None;
}
Some(Binding::Disabled) => return None,
_ => {}
}
}
if files_focused
&& matches!(input, Input::Char(ch) if !ch.is_control())
&& self
.diff
.as_ref()
.and_then(|diff| diff.files.as_ref())
.is_some_and(|files| files.searching || files.view == FileView::List)
{
self.diff.as_mut().unwrap().handle(input);
if !self.diff_interacting() && self.handle_selection_binding(&input) {
return None;
}
if self.sequence_pending().is_some()
@@ -2758,7 +2757,6 @@ impl Editor {
return self.handle_input(input);
}
let escape = input == Input::Escape;
let back = input == Input::Escape && phase != Phase::View;
let return_focus = files_focused
.then(|| self.diff_bound.map(|bound| bound.2))
.flatten();
@@ -2772,9 +2770,6 @@ impl Editor {
diff.focus = focus;
diff.normalize_focus();
}
if back {
self.outstanding_diff_request = None;
}
None
}
@@ -4286,6 +4281,10 @@ impl Editor {
} else {
palette.selected - 1
};
} else if self.palette.is_none()
&& let Some(diff) = &mut self.diff
{
diff.navigate(next);
}
true
}
@@ -8721,6 +8720,70 @@ mod tests {
assert_eq!(editor.active.view.targets, targets);
}
#[test]
fn focused_text_fields_keep_printable_normal_bindings_as_text() {
let directory = Directory::new();
fs::write(directory.path("sample.txt"), "text").unwrap();
for field in [
"floating",
"docked",
"diff_tree",
"diff_list",
"palette",
"command",
"search",
] {
let mut editor = editor();
editor.project_root = directory.0.clone();
editor
.bind("normal", "x", Some("core.pane.split_vertical".into()))
.unwrap();
match field {
"floating" => editor.open_file_picker(FilePresentation::Floating),
"docked" => {
editor.open_file_picker(FilePresentation::Docked);
editor.handle(Input::Char('i'));
}
"diff_tree" | "diff_list" => {
historical_diff(
&mut editor,
&directory.0,
vec!["before".into()],
vec!["after".into()],
);
if field == "diff_list" {
editor.set_file_explorer_view("list").unwrap();
}
editor.open_file_picker(FilePresentation::Docked);
if field == "diff_tree" {
editor.handle(Input::Char('i'));
}
}
"palette" => {
editor.handle(Input::Ctrl('p'));
}
"command" => {
editor.handle(Input::Char(':'));
}
"search" => {
editor.handle(Input::Char('/'));
}
_ => unreachable!(),
}
let document = editor.lines().to_vec();
editor.handle(Input::Char(':'));
editor.handle(Input::Char('x'));
let query = match field {
"palette" => editor.palette().unwrap().query.as_str(),
"command" | "search" => editor.command_line(),
_ => editor.file_picker().unwrap().query.as_str(),
};
assert_eq!(query, ":x", "{field}");
assert_eq!(editor.pane_layout().len(), 1, "{field}");
assert_eq!(editor.lines(), document, "{field}");
}
}
#[test]
fn empty_notification_does_not_swallow_escape_but_cursor_diagnostic_does() {
let mut editor = editor();
@@ -9637,12 +9700,12 @@ mod tests {
] {
editor.handle(input);
}
editor.handle(Input::Escape);
assert!(editor.diff().is_some());
type_text(&mut editor, ":unknown\n");
editor.handle(Input::Ctrl('p'));
editor.handle(Input::Escape);
editor.execute("diff.close");
assert!(editor.diff().is_some());
editor.handle(Input::Escape);
assert!(editor.diff().is_none());
assert_eq!(editor.mode(), Mode::Visual);
assert_eq!(editor.carets(), carets);
assert_eq!(editor.selections(), selections);
@@ -9665,14 +9728,12 @@ mod tests {
let caret = editor.cursor();
editor.execute("diff");
editor.handle(Input::Paste("ignored".into()));
editor.handle(Input::Escape);
assert!(editor.diff().is_some());
type_text(&mut editor, ":unfinished");
editor.handle(Input::Escape);
editor
.apply(vec![Effect::Message("message without edits".into())])
.unwrap();
editor.execute("diff.close");
editor.handle(Input::Escape);
assert!(editor.diff().is_none());
assert_eq!(editor.mode(), Mode::Insert);
assert_eq!(editor.cursor(), caret);
type_text(&mut editor, "finish");
@@ -9822,7 +9883,7 @@ mod tests {
editor.handle(Input::Char('q'));
assert_eq!(editor.diff().unwrap().query, "q");
editor.handle(Input::Escape);
assert_eq!(editor.diff().unwrap().query, "");
assert!(editor.diff().is_none());
assert!(editor.notification_visible());
}
@@ -10406,7 +10467,7 @@ mod tests {
editor.execute("diff");
type_text(&mut editor, ":diffclose\n");
assert!(editor.diff().is_some());
type_text(&mut editor, ":diff.close\n");
editor.execute("diff.close");
assert!(editor.diff().is_none());
}