fix: preserve selector text input and close on escape
This commit is contained in:
+62
-66
@@ -164,12 +164,6 @@ pub enum DisplayRow {
|
||||
Fold { start: usize, end: usize },
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct SelectorPosition {
|
||||
category: usize,
|
||||
query: String,
|
||||
selected: RevisionTarget,
|
||||
}
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
enum RequestKind {
|
||||
Catalog,
|
||||
@@ -214,7 +208,6 @@ pub struct DiffState {
|
||||
request_kind: Option<RequestKind>,
|
||||
visible: Vec<usize>,
|
||||
search_labels: Vec<String>,
|
||||
before_position: Option<SelectorPosition>,
|
||||
max_before: usize,
|
||||
max_after: usize,
|
||||
after_widths: Vec<usize>,
|
||||
@@ -255,7 +248,6 @@ impl DiffState {
|
||||
request_kind: Some(RequestKind::Catalog),
|
||||
visible: Vec::new(),
|
||||
search_labels: Vec::new(),
|
||||
before_position: None,
|
||||
max_before: 0,
|
||||
max_after: 0,
|
||||
after_widths: Vec::new(),
|
||||
@@ -468,44 +460,20 @@ impl DiffState {
|
||||
}
|
||||
}
|
||||
|
||||
/// Handles modal input; closing is an explicit editor action.
|
||||
/// Handles selector filtering and comparison navigation; the editor owns selector closing.
|
||||
pub(crate) fn handle(&mut self, input: Input) {
|
||||
if input == Input::Escape {
|
||||
if self.phase == Phase::View
|
||||
&& self.focus == Focus::Files
|
||||
&& let Some(files) = &mut self.files
|
||||
&& files.searching
|
||||
&& files.view == FileView::Tree
|
||||
{
|
||||
files.finish_search();
|
||||
return;
|
||||
}
|
||||
if self.phase == Phase::View {
|
||||
if self.focus == Focus::Files
|
||||
&& let Some(files) = &mut self.files
|
||||
{
|
||||
if files.searching && files.view == FileView::Tree {
|
||||
files.finish_search();
|
||||
} else {
|
||||
files.focused = false;
|
||||
self.files_visible = files.presentation == FilePresentation::Docked;
|
||||
self.focus = self.first_text_focus();
|
||||
}
|
||||
return;
|
||||
}
|
||||
self.pending = None;
|
||||
self.request_kind = None;
|
||||
self.loading = false;
|
||||
self.error = None;
|
||||
if self.phase == Phase::Before {
|
||||
self.query.clear();
|
||||
self.refilter();
|
||||
return;
|
||||
}
|
||||
self.phase = Phase::Before;
|
||||
self.after = None;
|
||||
if let Some(position) = self.before_position.take() {
|
||||
self.category = position.category;
|
||||
self.query = position.query;
|
||||
self.refilter();
|
||||
self.select_target(&position.selected);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -562,11 +530,6 @@ impl DiffState {
|
||||
} else if let RevisionTarget::ListRemote(remote) = &revision.target {
|
||||
self.queue(Operation::ListRemote(remote.clone()));
|
||||
} else if self.phase == Phase::Before {
|
||||
self.before_position = Some(SelectorPosition {
|
||||
category: self.category,
|
||||
query: self.query.clone(),
|
||||
selected: revision.target.clone(),
|
||||
});
|
||||
self.before = Some(revision);
|
||||
self.after = None;
|
||||
self.phase = Phase::After;
|
||||
@@ -2106,32 +2069,66 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn after_escape_restores_before_query_and_selected_revision_and_cancels_request() {
|
||||
fn selector_escape_closes_each_stage_and_rejects_late_results() {
|
||||
for after in [false, true] {
|
||||
let mut editor = editor();
|
||||
editor
|
||||
.apply(vec![Effect::Replace("unsaved source".into())])
|
||||
.unwrap();
|
||||
let buffer = editor.buffer_id();
|
||||
open(&mut editor);
|
||||
let request = if after {
|
||||
Some(choose_pair(&mut editor))
|
||||
} else {
|
||||
text(&mut editor, "query");
|
||||
None
|
||||
};
|
||||
editor.handle(Input::Escape);
|
||||
assert!(editor.diff().is_none());
|
||||
assert_eq!(editor.buffer_id(), buffer);
|
||||
assert_eq!(editor.lines(), ["unsaved source"]);
|
||||
assert!(editor.dirty());
|
||||
if let Some(id) = request {
|
||||
assert!(!editor.apply_diff_result(id, Ok(Outcome::Comparison(comparison()))));
|
||||
assert!(editor.diff().is_none());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn selector_printable_input_precedes_normal_bindings_but_not_selection_overrides() {
|
||||
for after in [false, true] {
|
||||
let mut editor = editor();
|
||||
open(&mut editor);
|
||||
if after {
|
||||
editor.handle(Input::Enter);
|
||||
}
|
||||
editor
|
||||
.bind("normal", "x", Some("core.command".into()))
|
||||
.unwrap();
|
||||
for ch in ":_| x".chars() {
|
||||
editor.handle(Input::Char(ch));
|
||||
assert_eq!(editor.mode(), Mode::Normal);
|
||||
assert_eq!(editor.pane_layout().len(), 1);
|
||||
}
|
||||
assert_eq!(editor.diff().unwrap().query, ":_| x");
|
||||
editor.handle(Input::Ctrl('u'));
|
||||
editor
|
||||
.bind("selection", ":", Some("core.down".into()))
|
||||
.unwrap();
|
||||
editor.handle(Input::Char(':'));
|
||||
assert_eq!(editor.diff().unwrap().selected, 1);
|
||||
assert!(editor.diff().unwrap().query.is_empty());
|
||||
}
|
||||
let mut editor = editor();
|
||||
open(&mut editor);
|
||||
editor.handle(Input::Char('\t'));
|
||||
text(&mut editor, "topic");
|
||||
editor.handle(Input::Down);
|
||||
editor.handle(Input::Enter);
|
||||
assert!(editor.diff().unwrap().query.is_empty());
|
||||
editor.handle(Input::Enter);
|
||||
let (id, _) = editor.take_diff_request().unwrap();
|
||||
editor.handle(Input::Ctrl('p'));
|
||||
editor.handle(Input::Char(':'));
|
||||
assert_eq!(editor.palette().unwrap().query, ":");
|
||||
assert_eq!(editor.mode(), Mode::Normal);
|
||||
editor.handle(Input::Escape);
|
||||
let state = editor.diff().unwrap();
|
||||
assert_eq!(state.phase, Phase::Before);
|
||||
assert_eq!(state.category, 1);
|
||||
assert_eq!(state.query, "topic");
|
||||
assert_eq!(state.selected, 1);
|
||||
assert!(!state.loading);
|
||||
assert!(!editor.apply_diff_result(id, Ok(Outcome::Comparison(comparison()))));
|
||||
editor.handle(Input::Enter);
|
||||
assert_eq!(editor.diff().unwrap().phase, Phase::After);
|
||||
editor.handle(Input::Escape);
|
||||
editor.handle(Input::Escape);
|
||||
assert_eq!(editor.diff().unwrap().phase, Phase::Before);
|
||||
assert!(editor.diff().unwrap().query.is_empty());
|
||||
editor.execute("diff.close");
|
||||
assert!(editor.diff().is_none());
|
||||
assert!(editor.palette().is_none());
|
||||
assert!(editor.diff().is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -2560,8 +2557,7 @@ mod tests {
|
||||
buffers
|
||||
);
|
||||
editor.handle(Input::Escape);
|
||||
assert!(editor.diff().is_some());
|
||||
editor.execute("diff.close");
|
||||
assert!(editor.diff().is_none());
|
||||
assert_eq!(editor.mode(), Mode::Normal);
|
||||
open(&mut editor);
|
||||
let id = choose_pair(&mut editor);
|
||||
|
||||
Reference in New Issue
Block a user