feat: close focused docked file lists with pane actions
This commit is contained in:
+294
@@ -11258,6 +11258,300 @@ end
|
||||
assert!(screen_text(&terminal).contains(editor.selection_navigation_hint()));
|
||||
}
|
||||
|
||||
const PANE_CLOSE_CONFIG: &str = r#"
|
||||
Vamp.configure do |config|
|
||||
config.file_explorer_view = "list"
|
||||
config.file_explorer_side = "right"
|
||||
config.file_picker_view = "tree"
|
||||
config.bind "ctrl+o", config.core.file_picker
|
||||
config.bind "ctrl+x", config.core.pane.close
|
||||
config.bind "ctrl+y", config.core.pane.force_close
|
||||
end
|
||||
"#;
|
||||
|
||||
#[test]
|
||||
fn bound_pane_close_reclaims_focused_dock_without_losing_dirty_source_or_diff() {
|
||||
let directory = Directory::new();
|
||||
let path = directory.file("source.txt", "SOURCE\nsecond");
|
||||
let config = directory.file("config.rb", PANE_CLOSE_CONFIG);
|
||||
for comparison in [false, true] {
|
||||
for key in ['x', 'y'] {
|
||||
let mut session =
|
||||
EditorSession::open(Some(path.clone()), vec![], Some(&config)).unwrap();
|
||||
session.editor_mut().set_project_root(directory.0.clone());
|
||||
let source = session.editor().buffer_id();
|
||||
session.handle(Input::Char('i'));
|
||||
session.handle(Input::Paste("DIRTY ".into()));
|
||||
session.handle(Input::Escape);
|
||||
let text = session.editor().lines().to_vec();
|
||||
if comparison {
|
||||
install_readonly_diff(
|
||||
session.editor_mut(),
|
||||
syntax_diff_file("history.txt", "OLD", "NEW"),
|
||||
);
|
||||
} else {
|
||||
session.handle(Input::Char(' '));
|
||||
session.handle(Input::Char('e'));
|
||||
}
|
||||
let pane = session.editor().pane_id();
|
||||
let tab = session.editor().tab_id();
|
||||
let buffers = session.editor().buffer_count();
|
||||
let comparison_id = session.editor().diff().and_then(|diff| diff.comparison_id);
|
||||
let picker = session.editor().file_picker().unwrap();
|
||||
assert!(picker.focused);
|
||||
assert_eq!(picker.presentation, FilePresentation::Docked);
|
||||
let mut terminal =
|
||||
Terminal::new(ratatui::backend::TestBackend::new(120, 20)).unwrap();
|
||||
let mut views = BufferViewports::default();
|
||||
terminal
|
||||
.draw(|frame| views.draw_session(frame, &mut session))
|
||||
.unwrap();
|
||||
let dock = views.panels.files.unwrap().0;
|
||||
let workspace = views.rects[0].1;
|
||||
let regions = views.panels.diff.as_ref().map(|geometry| geometry.regions);
|
||||
assert_eq!(workspace.width + dock.width, 120);
|
||||
assert!(dock.contains(terminal.get_cursor_position().unwrap()));
|
||||
|
||||
session.handle(
|
||||
translate(KeyEvent::new(KeyCode::Char(key), KeyModifiers::CONTROL)).unwrap(),
|
||||
);
|
||||
terminal
|
||||
.draw(|frame| views.draw_session(frame, &mut session))
|
||||
.unwrap();
|
||||
assert!(!session.editor().should_quit(), "{comparison} Ctrl+{key}");
|
||||
assert_eq!(session.editor().pane_id(), pane);
|
||||
assert_eq!(session.editor().tab_id(), tab);
|
||||
assert_eq!(session.editor().pane_layout().len(), 1);
|
||||
assert_eq!(session.editor().tab_count(), 1);
|
||||
assert_eq!(session.editor().buffer_count(), buffers);
|
||||
assert!(session.editor().file_picker().is_none());
|
||||
assert!(views.panels.files.is_none());
|
||||
assert_eq!(views.rects[0].1.width, 120);
|
||||
assert!(!screen_text(&terminal).contains("Explorer"));
|
||||
assert!(
|
||||
session
|
||||
.editor()
|
||||
.buffers()
|
||||
.find(|buffer| buffer.id == source)
|
||||
.unwrap()
|
||||
.dirty
|
||||
);
|
||||
assert_eq!(
|
||||
session
|
||||
.editor()
|
||||
.documents()
|
||||
.find(|document| document.id == source)
|
||||
.unwrap()
|
||||
.lines,
|
||||
text
|
||||
);
|
||||
let (caret_area, caret) = views.panels.caret.unwrap();
|
||||
assert!(caret_area.contains(caret));
|
||||
assert_eq!(terminal.get_cursor_position().unwrap(), caret);
|
||||
if comparison {
|
||||
let diff = session.editor().diff().unwrap();
|
||||
assert_eq!(diff.comparison_id, comparison_id);
|
||||
assert!(!diff.files_visible);
|
||||
assert!(!diff.files.as_ref().unwrap().focused);
|
||||
let expanded = views.panels.diff.as_ref().unwrap().regions;
|
||||
assert_eq!(expanded[0].0, Rect::default());
|
||||
for index in [1, 2] {
|
||||
assert!(expanded[index].0.width > regions.unwrap()[index].0.width);
|
||||
assert_eq!(
|
||||
terminal.backend().buffer()[(expanded[index].0.x, expanded[index].0.y)]
|
||||
.symbol(),
|
||||
"┌"
|
||||
);
|
||||
}
|
||||
let screen = screen_text(&terminal);
|
||||
assert!(screen.contains("Before") && screen.contains("After"));
|
||||
assert!(screen.contains("OLD") && screen.contains("NEW"));
|
||||
session.execute("diff.close");
|
||||
}
|
||||
assert_eq!(session.editor().buffer_id(), source);
|
||||
assert_eq!(session.editor().lines(), text);
|
||||
session.handle(Input::Char('u'));
|
||||
assert_eq!(session.editor().lines(), ["SOURCE", "second"]);
|
||||
assert!(!session.editor().dirty());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bound_pane_close_with_unfocused_dock_removes_editor_leaf_not_the_list() {
|
||||
let directory = Directory::new();
|
||||
let path = directory.file("source.txt", "SOURCE");
|
||||
let config = directory.file("config.rb", PANE_CLOSE_CONFIG);
|
||||
for comparison in [false, true] {
|
||||
let mut session =
|
||||
EditorSession::open(Some(path.clone()), vec![], Some(&config)).unwrap();
|
||||
session.editor_mut().set_project_root(directory.0.clone());
|
||||
let root = session.editor().pane_id();
|
||||
let source = session.editor().buffer_id();
|
||||
session.handle(Input::Char('i'));
|
||||
session.handle(Input::Paste("DIRTY ".into()));
|
||||
session.handle(Input::Escape);
|
||||
session.execute("pane.split_vertical");
|
||||
let closing = session.editor().pane_id();
|
||||
if comparison {
|
||||
install_readonly_diff(
|
||||
session.editor_mut(),
|
||||
syntax_diff_file("history.txt", "OLD", "NEW"),
|
||||
);
|
||||
} else {
|
||||
session.handle(Input::Char(' '));
|
||||
session.handle(Input::Char('e'));
|
||||
}
|
||||
session.handle(Input::Char('\t'));
|
||||
assert!(!session.editor().file_picker().unwrap().focused);
|
||||
let mut terminal = Terminal::new(ratatui::backend::TestBackend::new(120, 20)).unwrap();
|
||||
let mut views = BufferViewports::default();
|
||||
terminal
|
||||
.draw(|frame| views.draw_session(frame, &mut session))
|
||||
.unwrap();
|
||||
assert_eq!(views.rects.len(), 2);
|
||||
let dock = views.panels.files.unwrap().0;
|
||||
session.handle(Input::Ctrl('x'));
|
||||
terminal
|
||||
.draw(|frame| views.draw_session(frame, &mut session))
|
||||
.unwrap();
|
||||
assert!(!session.editor().should_quit());
|
||||
assert_eq!(session.editor().pane_id(), root);
|
||||
assert!(!session.editor().pane_layout().contains(closing));
|
||||
assert_eq!(views.rects.len(), 1);
|
||||
assert_eq!(session.editor().buffer_id(), source);
|
||||
assert_eq!(session.editor().lines(), ["DIRTY SOURCE"]);
|
||||
assert!(session.editor().dirty());
|
||||
assert!(session.editor().diff().is_none());
|
||||
assert!(!screen_text(&terminal).contains("Before"));
|
||||
if comparison {
|
||||
assert!(views.panels.files.is_none());
|
||||
assert_eq!(views.rects[0].1.width, 120);
|
||||
} else {
|
||||
assert!(!session.editor().file_picker().unwrap().focused);
|
||||
assert_eq!(views.panels.files.unwrap().0, dock);
|
||||
assert_eq!(views.rects[0].1.width + dock.width, 120);
|
||||
assert!(screen_text(&terminal).contains("Explorer"));
|
||||
}
|
||||
assert!(
|
||||
views.rects[0]
|
||||
.1
|
||||
.contains(terminal.get_cursor_position().unwrap())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bound_pane_close_under_floating_picker_obeys_dirty_guard_force_and_escape() {
|
||||
let directory = Directory::new();
|
||||
let source = directory.file("source.txt", "SURVIVING DOCUMENT");
|
||||
let owner = directory.file("owner.txt", "POPUP OWNER");
|
||||
let config = directory.file("config.rb", PANE_CLOSE_CONFIG);
|
||||
for comparison in [false, true] {
|
||||
for dirty in [false, true] {
|
||||
let mut session =
|
||||
EditorSession::open(Some(source.clone()), vec![], Some(&config)).unwrap();
|
||||
session.editor_mut().set_project_root(directory.0.clone());
|
||||
let root = session.editor().pane_id();
|
||||
let source_buffer = session.editor().buffer_id();
|
||||
session.execute("tab.new");
|
||||
session.execute(&format!("edit {}", owner.display()));
|
||||
let owner_buffer = session.editor().buffer_id();
|
||||
let owner_pane = session.editor().pane_id();
|
||||
let owner_tab = session.editor().tab_id();
|
||||
if dirty {
|
||||
session.handle(Input::Char('i'));
|
||||
session.handle(Input::Paste("DIRTY ".into()));
|
||||
session.handle(Input::Escape);
|
||||
}
|
||||
let text = session.editor().lines().to_vec();
|
||||
if comparison {
|
||||
install_readonly_diff(
|
||||
session.editor_mut(),
|
||||
syntax_diff_file("history.txt", "OLD", "NEW"),
|
||||
);
|
||||
}
|
||||
let comparison_id = session.editor().diff().and_then(|diff| diff.comparison_id);
|
||||
session.handle(Input::Ctrl('o'));
|
||||
let mut terminal =
|
||||
Terminal::new(ratatui::backend::TestBackend::new(120, 20)).unwrap();
|
||||
let mut views = BufferViewports::default();
|
||||
terminal
|
||||
.draw(|frame| views.draw_session(frame, &mut session))
|
||||
.unwrap();
|
||||
let popup = views.panels.files.unwrap().0;
|
||||
assert_eq!(
|
||||
session.editor().file_picker().unwrap().presentation,
|
||||
FilePresentation::Floating
|
||||
);
|
||||
assert!(popup.contains(terminal.get_cursor_position().unwrap()));
|
||||
session.handle(Input::Ctrl('x'));
|
||||
if dirty {
|
||||
terminal
|
||||
.draw(|frame| views.draw_session(frame, &mut session))
|
||||
.unwrap();
|
||||
assert_eq!(session.editor().tab_count(), 2);
|
||||
assert_eq!(session.editor().tab_id(), owner_tab);
|
||||
assert_eq!(session.editor().pane_id(), owner_pane);
|
||||
assert!(!session.editor().should_quit());
|
||||
assert!(session.editor().message().contains("Unsaved changes"));
|
||||
assert!(session.editor().file_picker().unwrap().focused);
|
||||
assert_eq!(views.panels.files.unwrap().0, popup);
|
||||
assert!(popup.contains(terminal.get_cursor_position().unwrap()));
|
||||
assert_eq!(
|
||||
session
|
||||
.editor()
|
||||
.documents()
|
||||
.find(|document| document.id == owner_buffer)
|
||||
.unwrap()
|
||||
.lines,
|
||||
text
|
||||
);
|
||||
session.handle(Input::Escape);
|
||||
assert!(session.editor().file_picker().unwrap().focused);
|
||||
assert!(!session.editor().file_picker().unwrap().searching);
|
||||
session.handle(Input::Escape);
|
||||
terminal
|
||||
.draw(|frame| views.draw_session(frame, &mut session))
|
||||
.unwrap();
|
||||
assert!(session.editor().file_picker().is_none());
|
||||
assert!(views.panels.files.is_none());
|
||||
assert_eq!(session.editor().pane_id(), owner_pane);
|
||||
assert_eq!(session.editor().tab_count(), 2);
|
||||
assert_eq!(
|
||||
session.editor().diff().and_then(|diff| diff.comparison_id),
|
||||
comparison_id
|
||||
);
|
||||
if comparison {
|
||||
assert!(screen_text(&terminal).contains("Before"));
|
||||
} else {
|
||||
assert!(screen_text(&terminal).contains("DIRTY POPUP OWNER"));
|
||||
}
|
||||
session.handle(Input::Ctrl('o'));
|
||||
session.handle(Input::Ctrl('y'));
|
||||
}
|
||||
terminal
|
||||
.draw(|frame| views.draw_session(frame, &mut session))
|
||||
.unwrap();
|
||||
assert!(!session.editor().should_quit());
|
||||
assert_eq!(session.editor().tab_count(), 1);
|
||||
assert_eq!(session.editor().pane_id(), root);
|
||||
assert_eq!(session.editor().buffer_id(), source_buffer);
|
||||
assert!(!session.editor().has_buffer(owner_buffer));
|
||||
assert_eq!(session.editor().lines(), ["SURVIVING DOCUMENT"]);
|
||||
assert!(session.editor().diff().is_none());
|
||||
assert!(session.editor().file_picker().is_none());
|
||||
assert!(views.panels.files.is_none());
|
||||
assert_eq!(views.rects.len(), 1);
|
||||
assert_eq!(views.rects[0].1.width, 120);
|
||||
assert!(screen_text(&terminal).contains("SURVIVING DOCUMENT"));
|
||||
let (caret_area, caret) = views.panels.caret.unwrap();
|
||||
assert!(caret_area.contains(caret));
|
||||
assert_eq!(terminal.get_cursor_position().unwrap(), caret);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn all_dock_sides_clip_editor_gutter_selection_carets_and_cursor() {
|
||||
let mut editor = Editor::open(None, vec![]).unwrap();
|
||||
|
||||
Reference in New Issue
Block a user