feat: add editor tabs

This commit is contained in:
Valdemar Lorenzen
2026-10-12 09:34:54 +02:00
parent b72a3e206f
commit fc382529c5
11 changed files with 1241 additions and 105 deletions
+101
View File
@@ -184,6 +184,107 @@ fn typed_diff_edits_unsaved_working_after_and_preserves_undo_on_explicit_close()
assert_eq!(fixture.git(&["status", "--porcelain"]), "M buffer.rs");
}
#[test]
fn tabs_keep_repository_workers_and_hidden_comparisons_independent() {
let first = Fixture::new();
let second = Fixture::new();
for (fixture, before, after) in [
(&first, "first before\n", "first after\n"),
(&second, "second before\n", "second after\n"),
] {
fixture.git(&["init", "-q"]);
fs::write(fixture.0.join("repo/source.txt"), before).unwrap();
fixture.git(&["add", "source.txt"]);
fixture.git(&["commit", "-qm", "base"]);
fs::write(fixture.0.join("repo/source.txt"), after).unwrap();
}
let first_path = first.0.join("repo/source.txt");
let second_path = second.0.join("repo/source.txt");
let config = first.0.join("config.rb");
fs::write(
&config,
"Vamp.configure do |config|\n config.bind 'ctrl+option+n', config.core.tab.new\n config.bind 'ctrl+option+w', config.core.tab.close\nend\n",
)
.unwrap();
let mut session =
EditorSession::open(Some(first_path.clone()), vec!["text".into()], Some(&config)).unwrap();
assert!(session.editor().startup_diagnostic().is_none());
session.execute("diff");
session.handle(Input::CtrlAlt('n'));
session.execute(&format!("edit {}", second_path.display()));
session.execute("diff");
wait_until(&mut session, |session| {
session
.editor()
.diff()
.is_some_and(|diff| diff.catalog.is_some() && !diff.loading)
});
session.handle(Input::CtrlAlt('h'));
assert_eq!(session.editor().tab_index(), 0);
wait_until(&mut session, |session| {
session
.editor()
.diff()
.is_some_and(|diff| diff.catalog.is_some() && !diff.loading)
});
type_query(&mut session, &first.git(&["rev-parse", "HEAD"]));
session.handle(Input::Down);
session.handle(Input::Enter);
session.handle(Input::Enter);
session.handle(Input::CtrlAlt('l'));
assert_eq!(session.editor().tab_index(), 1);
type_query(&mut session, &second.git(&["rev-parse", "HEAD"]));
session.handle(Input::Down);
session.handle(Input::Enter);
session.handle(Input::Enter);
wait_until(&mut session, |session| {
session
.editor()
.diff()
.is_some_and(|diff| diff.phase == Phase::View && diff.selected_file_loaded())
});
let comparison = session
.editor()
.diff()
.unwrap()
.comparison
.as_ref()
.unwrap();
assert_eq!(
comparison.root,
second.0.join("repo").canonicalize().unwrap()
);
assert_eq!(comparison.files[0].before, ["second before"]);
assert_eq!(comparison.files[0].after, ["second after", ""]);
session.handle(Input::CtrlAlt('h'));
wait_until(&mut session, |session| {
session
.editor()
.diff()
.is_some_and(|diff| diff.phase == Phase::View && diff.selected_file_loaded())
});
let comparison = session
.editor()
.diff()
.unwrap()
.comparison
.as_ref()
.unwrap();
assert_eq!(
comparison.root,
first.0.join("repo").canonicalize().unwrap()
);
assert_eq!(comparison.files[0].before, ["first before"]);
assert_eq!(comparison.files[0].after, ["first after", ""]);
session.handle(Input::CtrlAlt('l'));
session.handle(Input::CtrlAlt('w'));
assert_eq!(session.editor().tab_count(), 1);
assert!(session.editor().diff().is_some());
session.execute("diff.close");
assert_eq!(session.editor().path(), Some(first_path.as_path()));
assert_eq!(session.editor().lines(), ["first after", ""]);
}
#[test]
fn editable_diff_navigation_skips_omitted_lines_without_expanding_excerpts() {
use vamp::diff::DisplayRow;