feat: add guarded and forceful editor restart actions
This commit is contained in:
@@ -150,6 +150,144 @@ fn buffer_next_and_bnext_preserve_each_buffers_dirty_text_and_undo() {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn restart_closes_clean_buffers_across_tabs_and_panes_but_preserves_dirty_history() {
|
||||
let fixture = Fixture::new();
|
||||
let mut editor = fixture.editor("first.txt", "first\n");
|
||||
let first_id = editor.buffer_id();
|
||||
insert(&mut editor, "changed ");
|
||||
editor.handle(Input::Char('0'));
|
||||
insert(&mut editor, "extra ");
|
||||
let first_redo_text = editor.context().text;
|
||||
editor.handle(Input::Char('u'));
|
||||
assert_eq!(editor.context().text, "changed first\n");
|
||||
|
||||
editor.execute("pane.split_vertical");
|
||||
let clean_path = fixture.0.join("clean.txt");
|
||||
fs::write(&clean_path, "clean\n").unwrap();
|
||||
editor.execute(&format!("edit {}", clean_path.display()));
|
||||
let clean_id = editor.buffer_id();
|
||||
editor.execute("tab.new");
|
||||
let second_path = fixture.0.join("second.txt");
|
||||
fs::write(&second_path, "second\n").unwrap();
|
||||
editor.execute(&format!("edit {}", second_path.display()));
|
||||
let second_id = editor.buffer_id();
|
||||
insert(&mut editor, "edited ");
|
||||
editor.execute("pane.split_horizontal");
|
||||
let active_clean_path = fixture.0.join("active-clean.txt");
|
||||
fs::write(&active_clean_path, "active clean\n").unwrap();
|
||||
editor.execute(&format!("edit {}", active_clean_path.display()));
|
||||
let active_clean_id = editor.buffer_id();
|
||||
assert_eq!(editor.tab_count(), 2);
|
||||
assert_eq!(editor.pane_layout().len(), 2);
|
||||
|
||||
editor.execute(":restart");
|
||||
|
||||
assert!(!editor.should_restart());
|
||||
assert!(!editor.should_quit());
|
||||
assert!(editor.message().to_lowercase().contains("unsaved"));
|
||||
assert_eq!(editor.buffer_count(), 2);
|
||||
assert!(!editor.has_buffer(clean_id));
|
||||
assert!(!editor.has_buffer(active_clean_id));
|
||||
assert!(editor.has_buffer(first_id));
|
||||
assert!(editor.has_buffer(second_id));
|
||||
editor.execute(&format!("buffer {first_id}"));
|
||||
assert_eq!(editor.buffer_id(), first_id);
|
||||
assert_eq!(editor.context().text, "changed first\n");
|
||||
assert!(editor.dirty());
|
||||
editor.handle(Input::Char('U'));
|
||||
assert_eq!(editor.context().text, first_redo_text);
|
||||
editor.handle(Input::Char('u'));
|
||||
assert_eq!(editor.context().text, "changed first\n");
|
||||
editor.handle(Input::Char('u'));
|
||||
assert_eq!(editor.context().text, "first\n");
|
||||
editor.handle(Input::Char('U'));
|
||||
assert_eq!(editor.context().text, "changed first\n");
|
||||
editor.execute("save");
|
||||
editor.execute(&format!("buffer {second_id}"));
|
||||
assert_eq!(editor.buffer_id(), second_id);
|
||||
assert_eq!(editor.context().text, "edited second\n");
|
||||
assert!(editor.dirty());
|
||||
editor.handle(Input::Char('u'));
|
||||
assert_eq!(editor.context().text, "second\n");
|
||||
editor.handle(Input::Char('U'));
|
||||
assert_eq!(editor.context().text, "edited second\n");
|
||||
editor.execute("save");
|
||||
|
||||
editor.execute(":restart");
|
||||
|
||||
assert!(editor.should_restart());
|
||||
assert!(editor.should_quit());
|
||||
assert_eq!(
|
||||
fs::read_to_string(fixture.0.join("first.txt")).unwrap(),
|
||||
"changed first\n"
|
||||
);
|
||||
assert_eq!(fs::read_to_string(second_path).unwrap(), "edited second\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn restart_commands_validate_arguments_before_closing_or_discarding_buffers() {
|
||||
for command in ["restart", "force_restart", "restart!"] {
|
||||
let fixture = Fixture::new();
|
||||
let mut editor = fixture.editor("dirty.txt", "original\n");
|
||||
let dirty_id = editor.buffer_id();
|
||||
insert(&mut editor, "changed ");
|
||||
let clean_path = fixture.0.join("clean.txt");
|
||||
fs::write(&clean_path, "clean\n").unwrap();
|
||||
editor.execute(&format!("edit {}", clean_path.display()));
|
||||
let clean_id = editor.buffer_id();
|
||||
|
||||
editor.execute(&format!(":{command} unexpected argument"));
|
||||
|
||||
assert!(!editor.should_restart(), "{command}");
|
||||
assert!(!editor.should_quit(), "{command}");
|
||||
assert_eq!(editor.buffer_count(), 2, "{command}");
|
||||
assert_eq!(editor.buffer_id(), clean_id, "{command}");
|
||||
assert!(editor.has_buffer(dirty_id), "{command}");
|
||||
editor.execute(&format!("buffer {dirty_id}"));
|
||||
assert_eq!(editor.context().text, "changed original\n", "{command}");
|
||||
assert!(editor.dirty(), "{command}");
|
||||
editor.handle(Input::Char('u'));
|
||||
assert_eq!(editor.context().text, "original\n", "{command}");
|
||||
editor.handle(Input::Char('U'));
|
||||
assert_eq!(editor.context().text, "changed original\n", "{command}");
|
||||
|
||||
if command != "restart" {
|
||||
editor.execute(&format!(":{command}"));
|
||||
assert!(editor.should_restart(), "{command}");
|
||||
assert!(editor.should_quit(), "{command}");
|
||||
}
|
||||
assert_eq!(
|
||||
fs::read_to_string(fixture.0.join("dirty.txt")).unwrap(),
|
||||
"original\n",
|
||||
"{command}"
|
||||
);
|
||||
assert_eq!(fs::read_to_string(clean_path).unwrap(), "clean\n");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn configured_restart_bindings_execute_directly_without_force_confirmation() {
|
||||
for action in ["core.restart", "core.force_restart"] {
|
||||
let fixture = Fixture::new();
|
||||
let mut editor = fixture.editor("file.txt", "original\n");
|
||||
editor.bind("normal", "x", Some(action.into())).unwrap();
|
||||
if action == "core.force_restart" {
|
||||
insert(&mut editor, "changed ");
|
||||
}
|
||||
|
||||
editor.handle(Input::Char('x'));
|
||||
|
||||
assert!(editor.should_restart(), "{action}");
|
||||
assert!(editor.should_quit(), "{action}");
|
||||
assert_eq!(
|
||||
fs::read_to_string(fixture.0.join("file.txt")).unwrap(),
|
||||
"original\n",
|
||||
"{action}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn builtin_canonical_and_alias_collisions_reject_the_entire_feature() {
|
||||
for reserved in ["save", "w", "quit", "q"] {
|
||||
|
||||
Reference in New Issue
Block a user