feat: retain explorer filters in navigation mode
This commit is contained in:
+311
-13
@@ -1479,7 +1479,7 @@ impl Editor {
|
||||
match input {
|
||||
Input::Ctrl('w') => self.file_picker = None,
|
||||
Input::Escape if picker.view == FileView::Tree && picker.searching => {
|
||||
picker.cancel_search()
|
||||
picker.finish_search()
|
||||
}
|
||||
Input::Escape => self.blur_file_picker(),
|
||||
Input::Ctrl('p') => {
|
||||
@@ -1490,6 +1490,7 @@ impl Editor {
|
||||
}
|
||||
Input::Ctrl('r') => picker.refresh(),
|
||||
Input::Ctrl('t') => picker.toggle_view(),
|
||||
Input::Ctrl('u') => picker.clear_filter(),
|
||||
Input::Backspace if picker.view == FileView::List || picker.searching => {
|
||||
picker.backspace()
|
||||
}
|
||||
@@ -3366,10 +3367,22 @@ mod tests {
|
||||
editor.handle(Input::Escape);
|
||||
let picker = editor.file_picker().unwrap();
|
||||
assert!(picker.focused && !picker.searching);
|
||||
assert_eq!(picker.query, "second.txt");
|
||||
assert_eq!(
|
||||
picker.entries().nth(picker.selected).unwrap().path,
|
||||
Path::new("dir")
|
||||
Path::new("dir/second.txt")
|
||||
);
|
||||
editor.handle(Input::Char('i'));
|
||||
assert!(editor.file_picker().unwrap().searching);
|
||||
assert_eq!(editor.file_picker().unwrap().query, "second.txt");
|
||||
editor.handle(Input::Escape);
|
||||
editor.handle(Input::Char('h'));
|
||||
editor.handle(Input::Char('h'));
|
||||
let picker = editor.file_picker().unwrap();
|
||||
assert_eq!(picker.entries().len(), 1);
|
||||
assert_eq!(picker.entries().next().unwrap().path, Path::new("dir"));
|
||||
assert!(!picker.entries().next().unwrap().expanded);
|
||||
assert_eq!(picker.query, "second.txt");
|
||||
editor.handle(Input::Char('l'));
|
||||
assert!(
|
||||
editor
|
||||
@@ -3391,6 +3404,271 @@ mod tests {
|
||||
assert!(editor.file_picker().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn filter_escape_resume_and_clear_do_not_edit_underlying_buffers_or_history() {
|
||||
let directory = Directory::new();
|
||||
fs::create_dir_all(directory.path("src/deep")).unwrap();
|
||||
fs::write(directory.path("src/deep/needle.txt"), "needle").unwrap();
|
||||
fs::write(directory.path("src/other.txt"), "other").unwrap();
|
||||
let selected_path = |editor: &Editor| {
|
||||
let picker = editor.file_picker().unwrap();
|
||||
picker
|
||||
.entries()
|
||||
.nth(picker.selected)
|
||||
.unwrap()
|
||||
.path
|
||||
.to_owned()
|
||||
};
|
||||
for presentation in [FilePresentation::Floating, FilePresentation::Docked] {
|
||||
for mode in [
|
||||
Mode::Normal,
|
||||
Mode::Insert,
|
||||
Mode::Command,
|
||||
Mode::Search,
|
||||
Mode::Visual,
|
||||
] {
|
||||
let mut editor = project_editor(&directory);
|
||||
editor
|
||||
.apply(vec![Effect::Replace("alpha\nbeta".into())])
|
||||
.unwrap();
|
||||
editor
|
||||
.apply(vec![Effect::Replace("changed".into())])
|
||||
.unwrap();
|
||||
editor.act(Action::Undo);
|
||||
set_carets(&mut editor, &[(0, 1), (1, 2)], 1);
|
||||
editor.begin_insert();
|
||||
editor.active.mode = mode;
|
||||
editor.command_line = "original prompt".into();
|
||||
editor.open_file_picker(presentation);
|
||||
if !editor.file_picker().unwrap().searching {
|
||||
editor.handle(Input::Char('i'));
|
||||
}
|
||||
editor.count = Some(7);
|
||||
let snapshot =
|
||||
|state: &Snapshot| (state.lines.clone(), state.targets.clone(), state.primary);
|
||||
let lines = editor.lines().to_owned();
|
||||
let targets = editor.active.targets.clone();
|
||||
let primary = editor.active.primary;
|
||||
let undo: Vec<_> = editor.active.undo.iter().map(&snapshot).collect();
|
||||
let redo: Vec<_> = editor.active.redo.iter().map(&snapshot).collect();
|
||||
let insert = editor.active.insert_start.as_ref().map(snapshot);
|
||||
let buffer = editor.buffer_id();
|
||||
let buffers = editor.buffer_count();
|
||||
type_text(&mut editor, "needle");
|
||||
let expected = PathBuf::from("src/deep/needle.txt");
|
||||
assert_eq!(selected_path(&editor), expected);
|
||||
editor.handle(Input::Escape);
|
||||
assert!(!editor.file_picker().unwrap().searching);
|
||||
assert_eq!(editor.file_picker().unwrap().query, "needle");
|
||||
assert_eq!(selected_path(&editor), expected);
|
||||
editor.handle(Input::Char('i'));
|
||||
assert!(editor.file_picker().unwrap().searching);
|
||||
assert_eq!(editor.file_picker().unwrap().query, "needle");
|
||||
assert_eq!(selected_path(&editor), expected);
|
||||
editor.handle(Input::Ctrl('U'));
|
||||
assert!(editor.file_picker().unwrap().searching);
|
||||
assert!(editor.file_picker().unwrap().query.is_empty());
|
||||
assert_eq!(selected_path(&editor), expected);
|
||||
type_text(&mut editor, "needle");
|
||||
editor.handle(Input::Escape);
|
||||
editor.handle(Input::Ctrl('u'));
|
||||
assert!(!editor.file_picker().unwrap().searching);
|
||||
assert!(editor.file_picker().unwrap().query.is_empty());
|
||||
assert_eq!(selected_path(&editor), expected);
|
||||
editor.handle(Input::Ctrl('u'));
|
||||
assert_eq!(selected_path(&editor), expected);
|
||||
editor.handle(Input::Char('i'));
|
||||
type_text(&mut editor, "missing");
|
||||
editor.handle(Input::Ctrl('j'));
|
||||
editor.handle(Input::Ctrl('k'));
|
||||
editor.handle(Input::Escape);
|
||||
assert_eq!(editor.file_picker().unwrap().entries().len(), 0);
|
||||
editor.handle(Input::Ctrl('u'));
|
||||
assert_eq!(selected_path(&editor), expected);
|
||||
assert!(editor.file_picker().unwrap().focused);
|
||||
assert!(!editor.file_picker().unwrap().searching);
|
||||
assert_eq!(editor.mode(), mode);
|
||||
assert_eq!(editor.lines(), lines);
|
||||
assert_eq!(editor.active.targets, targets);
|
||||
assert_eq!(editor.active.primary, primary);
|
||||
assert_eq!(editor.command_line, "original prompt");
|
||||
assert_eq!(editor.count(), Some(7));
|
||||
assert_eq!(editor.buffer_id(), buffer);
|
||||
assert_eq!(editor.buffer_count(), buffers);
|
||||
assert_eq!(
|
||||
editor.active.undo.iter().map(&snapshot).collect::<Vec<_>>(),
|
||||
undo
|
||||
);
|
||||
assert_eq!(
|
||||
editor.active.redo.iter().map(&snapshot).collect::<Vec<_>>(),
|
||||
redo
|
||||
);
|
||||
assert_eq!(editor.active.insert_start.as_ref().map(snapshot), insert);
|
||||
editor.handle(Input::Escape);
|
||||
match presentation {
|
||||
FilePresentation::Floating => assert!(editor.file_picker().is_none()),
|
||||
FilePresentation::Docked => {
|
||||
assert!(!editor.file_picker().unwrap().focused);
|
||||
editor.open_file_picker(presentation);
|
||||
assert!(!editor.file_picker().unwrap().searching);
|
||||
assert_eq!(selected_path(&editor), expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn filtered_folder_keys_and_directory_accept_work_in_both_presentations() {
|
||||
let directory = Directory::new();
|
||||
fs::create_dir_all(directory.path("src/deep")).unwrap();
|
||||
fs::write(directory.path("src/deep/needle.txt"), "needle").unwrap();
|
||||
fs::write(directory.path("src/other.txt"), "other").unwrap();
|
||||
for presentation in [FilePresentation::Floating, FilePresentation::Docked] {
|
||||
let mut editor = project_editor(&directory);
|
||||
editor.open_file_picker(presentation);
|
||||
if !editor.file_picker().unwrap().searching {
|
||||
editor.handle(Input::Char('i'));
|
||||
}
|
||||
type_text(&mut editor, "needle");
|
||||
editor.handle(Input::Ctrl('h'));
|
||||
let picker = editor.file_picker().unwrap();
|
||||
assert!(picker.searching);
|
||||
assert_eq!(picker.query, "needle");
|
||||
assert_eq!(
|
||||
picker.entries().nth(picker.selected).unwrap().path,
|
||||
Path::new("src/deep")
|
||||
);
|
||||
assert!(picker.entries().nth(picker.selected).unwrap().expanded);
|
||||
editor.handle(Input::Ctrl('l'));
|
||||
let picker = editor.file_picker().unwrap();
|
||||
assert_eq!(
|
||||
picker.entries().nth(picker.selected).unwrap().path,
|
||||
Path::new("src/deep/needle.txt")
|
||||
);
|
||||
editor.handle(Input::Escape);
|
||||
editor.handle(Input::Char('h'));
|
||||
editor.handle(Input::Char('h'));
|
||||
let picker = editor.file_picker().unwrap();
|
||||
assert!(!picker.searching);
|
||||
assert_eq!(picker.query, "needle");
|
||||
assert_eq!(picker.entries().len(), 2);
|
||||
assert_eq!(
|
||||
picker.entries().nth(picker.selected).unwrap().path,
|
||||
Path::new("src/deep")
|
||||
);
|
||||
assert!(!picker.entries().nth(picker.selected).unwrap().expanded);
|
||||
editor.handle(Input::Char('l'));
|
||||
assert!(
|
||||
editor
|
||||
.file_picker()
|
||||
.unwrap()
|
||||
.entries()
|
||||
.nth(1)
|
||||
.unwrap()
|
||||
.expanded
|
||||
);
|
||||
editor.handle(Input::Char('l'));
|
||||
editor.handle(Input::Char('h'));
|
||||
editor.handle(Input::Enter);
|
||||
assert!(
|
||||
!editor
|
||||
.file_picker()
|
||||
.unwrap()
|
||||
.entries()
|
||||
.nth(1)
|
||||
.unwrap()
|
||||
.expanded
|
||||
);
|
||||
editor.handle(Input::Enter);
|
||||
assert!(
|
||||
editor
|
||||
.file_picker()
|
||||
.unwrap()
|
||||
.entries()
|
||||
.nth(1)
|
||||
.unwrap()
|
||||
.expanded
|
||||
);
|
||||
editor.handle(Input::Char('i'));
|
||||
editor.handle(Input::Enter);
|
||||
let picker = editor.file_picker().unwrap();
|
||||
assert!(!picker.searching && picker.focused);
|
||||
assert_eq!(picker.query, "needle");
|
||||
assert_eq!(
|
||||
picker.entries().nth(picker.selected).unwrap().path,
|
||||
Path::new("src/deep")
|
||||
);
|
||||
assert!(!picker.entries().nth(picker.selected).unwrap().expanded);
|
||||
assert_eq!(editor.context().text, "");
|
||||
editor.handle(Input::Ctrl('r'));
|
||||
editor.handle(Input::Ctrl('t'));
|
||||
editor.handle(Input::Ctrl('t'));
|
||||
let picker = editor.file_picker().unwrap();
|
||||
assert!(!picker.searching && picker.focused);
|
||||
assert_eq!(picker.query, "needle");
|
||||
assert!(!picker.entries().nth(picker.selected).unwrap().expanded);
|
||||
if presentation == FilePresentation::Docked {
|
||||
editor.handle(Input::Escape);
|
||||
editor.open_file_picker(presentation);
|
||||
assert!(!editor.file_picker().unwrap().searching);
|
||||
assert_eq!(editor.file_picker().unwrap().query, "needle");
|
||||
}
|
||||
editor.open_file_picker(FilePresentation::Floating);
|
||||
assert!(editor.file_picker().unwrap().searching);
|
||||
assert_eq!(editor.file_picker().unwrap().query, "needle");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn filter_clear_respects_navigation_bindings_and_does_not_clear_palette_or_idle_dock() {
|
||||
let directory = Directory::new();
|
||||
for name in ["a.txt", "b.txt"] {
|
||||
fs::write(directory.path(name), "text").unwrap();
|
||||
}
|
||||
for view in [FileView::List, FileView::Tree] {
|
||||
let mut editor = project_editor(&directory);
|
||||
editor.open_file_picker(FilePresentation::Docked);
|
||||
editor.file_picker.as_mut().unwrap().set_view(view);
|
||||
if view == FileView::Tree {
|
||||
editor.handle(Input::Char('i'));
|
||||
}
|
||||
type_text(&mut editor, "txt");
|
||||
editor
|
||||
.bind("selection", "ctrl+u", Some("core.down".into()))
|
||||
.unwrap();
|
||||
editor.handle(Input::Ctrl('u'));
|
||||
assert_eq!(editor.file_picker().unwrap().query, "txt");
|
||||
assert_eq!(editor.file_picker().unwrap().selected, 1);
|
||||
editor.bind("selection", "ctrl+u", None).unwrap();
|
||||
editor.handle(Input::Ctrl('u'));
|
||||
assert_eq!(editor.file_picker().unwrap().query, "txt");
|
||||
editor.selection_bindings.remove(&Input::Ctrl('u'));
|
||||
if view == FileView::Tree {
|
||||
editor.bind("tree", "ctrl+u", None).unwrap();
|
||||
editor.handle(Input::Ctrl('u'));
|
||||
assert_eq!(editor.file_picker().unwrap().query, "txt");
|
||||
editor.tree_bindings.remove(&Input::Ctrl('u'));
|
||||
}
|
||||
editor.handle(Input::Ctrl('u'));
|
||||
assert!(editor.file_picker().unwrap().query.is_empty());
|
||||
assert_eq!(editor.file_picker().unwrap().selected, 1);
|
||||
assert_eq!(
|
||||
editor.file_picker().unwrap().searching,
|
||||
view == FileView::Tree
|
||||
);
|
||||
type_text(&mut editor, "txt");
|
||||
editor.handle(Input::Char('\t'));
|
||||
editor.handle(Input::Ctrl('u'));
|
||||
assert_eq!(editor.file_picker().unwrap().query, "txt");
|
||||
editor.handle(Input::Ctrl('p'));
|
||||
type_text(&mut editor, "core");
|
||||
editor.handle(Input::Ctrl('u'));
|
||||
assert_eq!(editor.palette().unwrap().query, "core");
|
||||
assert_eq!(editor.file_picker().unwrap().query, "txt");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn selection_navigation_wraps_without_touching_any_underlying_mode() {
|
||||
let directory = Directory::new();
|
||||
@@ -4185,7 +4463,12 @@ mod tests {
|
||||
assert_eq!(editor.file_picker().unwrap().query, "hjkl");
|
||||
editor.handle(Input::Escape);
|
||||
assert!(editor.file_picker().unwrap().focused);
|
||||
assert_eq!(selected(&editor), Path::new("dir"));
|
||||
assert_eq!(selected(&editor), Path::new("dir/hjkl-a.txt"));
|
||||
assert_eq!(editor.file_picker().unwrap().query, "hjkl");
|
||||
editor.handle(Input::Ctrl('u'));
|
||||
assert_eq!(selected(&editor), Path::new("dir/hjkl-a.txt"));
|
||||
editor.handle(Input::Char('h'));
|
||||
editor.handle(Input::Char('h'));
|
||||
assert!(
|
||||
!editor
|
||||
.file_picker()
|
||||
@@ -4265,12 +4548,6 @@ mod tests {
|
||||
assert_eq!(editor.file_picker().unwrap().selected, 1);
|
||||
editor.handle(Input::Ctrl('h'));
|
||||
assert_eq!(editor.file_picker().unwrap().selected, 0);
|
||||
let before = editor
|
||||
.file_picker()
|
||||
.unwrap()
|
||||
.entries()
|
||||
.map(|row| row.path.to_owned())
|
||||
.collect::<Vec<_>>();
|
||||
type_text(&mut editor, "ideep/");
|
||||
assert!(editor.file_picker().unwrap().searching);
|
||||
assert_eq!(editor.file_picker().unwrap().query, "deep/");
|
||||
@@ -4281,12 +4558,19 @@ mod tests {
|
||||
type_text(&mut editor, "👩💻");
|
||||
editor.handle(Input::Backspace);
|
||||
assert_eq!(editor.file_picker().unwrap().query, "deep");
|
||||
let before = editor
|
||||
.file_picker()
|
||||
.unwrap()
|
||||
.entries()
|
||||
.map(|row| row.path.to_owned())
|
||||
.collect::<Vec<_>>();
|
||||
let selected_before = editor.file_picker().unwrap().selected;
|
||||
editor.handle(Input::Escape);
|
||||
let picker = editor.file_picker().unwrap();
|
||||
assert!(picker.focused);
|
||||
assert!(!picker.searching);
|
||||
assert!(picker.query.is_empty());
|
||||
assert_eq!(picker.selected, 0);
|
||||
assert_eq!(picker.query, "deep");
|
||||
assert_eq!(picker.selected, selected_before);
|
||||
assert_eq!(
|
||||
picker
|
||||
.entries()
|
||||
@@ -4489,10 +4773,24 @@ mod tests {
|
||||
let picker = editor.file_picker().unwrap();
|
||||
assert_eq!(editor.buffer_id(), id);
|
||||
assert!(!picker.searching);
|
||||
assert!(picker.query.is_empty());
|
||||
assert_eq!(picker.query, "module");
|
||||
let selected = picker.entries().nth(picker.selected).unwrap();
|
||||
assert_eq!(selected.path, Path::new("src/module"));
|
||||
assert!(selected.expanded);
|
||||
assert!(!selected.expanded);
|
||||
assert!(
|
||||
!picker
|
||||
.entries()
|
||||
.any(|row| row.path == Path::new("src/module/needle.txt"))
|
||||
);
|
||||
editor.handle(Input::Enter);
|
||||
let picker = editor.file_picker().unwrap();
|
||||
assert_eq!(picker.query, "module");
|
||||
assert!(picker.entries().nth(picker.selected).unwrap().expanded);
|
||||
assert!(
|
||||
picker
|
||||
.entries()
|
||||
.any(|row| row.path == Path::new("src/module/needle.txt"))
|
||||
);
|
||||
assert_eq!(editor.buffer_count(), 2);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user