feat: show jj ancestry in the floating diff picker
This commit is contained in:
+176
-4
@@ -394,6 +394,7 @@ fn revision(
|
||||
fn catalog() -> Catalog {
|
||||
Catalog {
|
||||
kind: RepoKind::Git,
|
||||
graph: Default::default(),
|
||||
entries: vec![
|
||||
revision(
|
||||
RevisionTarget::Working,
|
||||
@@ -1573,7 +1574,7 @@ fn revision_matches_rank_later_contiguous_boundaries_and_tight_subsequences() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn jujutsu_fuzzy_selectors_rank_labels_above_descriptions_in_both_stages() {
|
||||
fn jujutsu_fuzzy_selectors_preserve_catalog_order_in_both_stages() {
|
||||
for phase in [Phase::Before, Phase::After] {
|
||||
for (category_index, &category) in RepoKind::Jujutsu.categories().iter().enumerate() {
|
||||
let mut state = DiffState::new();
|
||||
@@ -1581,6 +1582,7 @@ fn jujutsu_fuzzy_selectors_rank_labels_above_descriptions_in_both_stages() {
|
||||
1,
|
||||
Ok(Outcome::Catalog(Catalog {
|
||||
kind: RepoKind::Jujutsu,
|
||||
graph: Default::default(),
|
||||
entries: vec![
|
||||
revision(
|
||||
RevisionTarget::Working,
|
||||
@@ -1621,15 +1623,185 @@ fn jujutsu_fuzzy_selectors_rank_labels_above_descriptions_in_both_stages() {
|
||||
.map(|entry| &entry.target)
|
||||
.collect::<Vec<_>>(),
|
||||
[
|
||||
&RevisionTarget::Commit("immutable-exact-target".into()),
|
||||
&RevisionTarget::Commit("immutable-fuzzy-target".into()),
|
||||
&RevisionTarget::Commit("description-target".into()),
|
||||
&RevisionTarget::Commit("immutable-fuzzy-target".into()),
|
||||
&RevisionTarget::Commit("immutable-exact-target".into()),
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn graph_state() -> DiffState {
|
||||
let mut catalog = Catalog {
|
||||
kind: RepoKind::Jujutsu,
|
||||
graph: Default::default(),
|
||||
notice: None,
|
||||
entries: vec![revision(
|
||||
RevisionTarget::Working,
|
||||
"Working",
|
||||
"",
|
||||
Category::Revisions,
|
||||
)],
|
||||
};
|
||||
for (id, parents) in [
|
||||
("merge", vec!["left", "right"]),
|
||||
("left", vec!["hidden"]),
|
||||
("hidden", vec!["root"]),
|
||||
("right", vec!["root"]),
|
||||
("root", vec![]),
|
||||
] {
|
||||
catalog.entries.push(revision(
|
||||
RevisionTarget::Commit(id.into()),
|
||||
id,
|
||||
"needle",
|
||||
Category::Revisions,
|
||||
));
|
||||
catalog.graph.insert(
|
||||
id.into(),
|
||||
RevisionGraph {
|
||||
parents: parents.into_iter().map(String::from).collect(),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
}
|
||||
catalog.entries.push(revision(
|
||||
RevisionTarget::Bookmark {
|
||||
name: "topic".into(),
|
||||
remote: None,
|
||||
},
|
||||
"topic",
|
||||
"change merge needle",
|
||||
Category::Bookmarks,
|
||||
));
|
||||
catalog.entries.push(revision(
|
||||
RevisionTarget::Bookmark {
|
||||
name: "base".into(),
|
||||
remote: None,
|
||||
},
|
||||
"base",
|
||||
"change root needle",
|
||||
Category::Bookmarks,
|
||||
));
|
||||
let mut state = DiffState::new();
|
||||
state.apply_result(1, Ok(Outcome::Catalog(catalog)));
|
||||
state
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn picker_graph_preserves_forks_merges_and_marks_filtered_ancestry() {
|
||||
let mut state = graph_state();
|
||||
let graph = state.picker_graph();
|
||||
assert_eq!(graph.len(), 5);
|
||||
assert_eq!(graph["merge"][1].trim_end(), "├─┐");
|
||||
assert_eq!(graph["right"][1].trim_end(), "├─┘");
|
||||
assert!(!graph.values().flatten().any(|prefix| prefix.contains('~')));
|
||||
state.category = 1;
|
||||
state.refilter();
|
||||
assert_eq!(state.entries().len(), 3);
|
||||
let graph = state.picker_graph();
|
||||
assert_eq!(
|
||||
graph.keys().map(String::as_str).collect::<Vec<_>>(),
|
||||
["merge", "root"]
|
||||
);
|
||||
assert!(graph["merge"][1].contains('~'));
|
||||
assert_eq!(
|
||||
state
|
||||
.graph_revision(state.entries().nth(1).unwrap())
|
||||
.unwrap()
|
||||
.0,
|
||||
"merge"
|
||||
);
|
||||
assert!(matches!(
|
||||
state.entries().nth(1).unwrap().target,
|
||||
RevisionTarget::Bookmark { .. }
|
||||
));
|
||||
state.category = 0;
|
||||
state.query = "left root".into();
|
||||
state.refilter();
|
||||
assert!(state.picker_graph().is_empty());
|
||||
assert_eq!(state.entries().len(), 1);
|
||||
state.before = Some(state.catalog.as_ref().unwrap().entries[1].clone());
|
||||
state.query = "right".into();
|
||||
state.refilter();
|
||||
assert_eq!(state.picker_graph().len(), 2);
|
||||
assert!(state.picker_graph()["merge"][1].contains('~'));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn graph_crossings_do_not_join_unrelated_ancestry() {
|
||||
let mut state = DiffState::new();
|
||||
let mut catalog = Catalog {
|
||||
kind: RepoKind::Jujutsu,
|
||||
entries: Vec::new(),
|
||||
graph: Default::default(),
|
||||
notice: None,
|
||||
};
|
||||
for (id, parents) in [
|
||||
("a", vec!["x"]),
|
||||
("b", vec!["y"]),
|
||||
("merge", vec!["x", "z"]),
|
||||
("x", vec![]),
|
||||
("y", vec![]),
|
||||
("z", vec![]),
|
||||
] {
|
||||
catalog.entries.push(revision(
|
||||
RevisionTarget::Commit(id.into()),
|
||||
id,
|
||||
"",
|
||||
Category::Revisions,
|
||||
));
|
||||
catalog.graph.insert(
|
||||
id.into(),
|
||||
RevisionGraph {
|
||||
parents: parents.into_iter().map(String::from).collect(),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
}
|
||||
state.apply_result(1, Ok(Outcome::Catalog(catalog)));
|
||||
assert_eq!(state.picker_graph()["merge"][1].trim_end(), "├─╪─┤");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn before_identity_survives_query_and_category_without_duplicate_graph_nodes() {
|
||||
let mut state = graph_state();
|
||||
state.category = 1;
|
||||
state.refilter();
|
||||
state.selected = 1;
|
||||
state.choose();
|
||||
let before = state.before.clone().unwrap();
|
||||
assert!(matches!(before.target, RevisionTarget::Bookmark { .. }));
|
||||
state.category = 0;
|
||||
state.refilter();
|
||||
assert_eq!(
|
||||
state
|
||||
.entries()
|
||||
.filter(|entry| state
|
||||
.graph_revision(entry)
|
||||
.is_some_and(|(id, _)| id == "merge"))
|
||||
.count(),
|
||||
1
|
||||
);
|
||||
for category in 0..2 {
|
||||
state.category = category;
|
||||
state.query = "unmatched".into();
|
||||
state.refilter();
|
||||
assert_eq!(state.entries().len(), 2);
|
||||
let retained = state
|
||||
.entries()
|
||||
.find(|entry| entry.target == before.target)
|
||||
.unwrap();
|
||||
assert_eq!(retained.target, before.target);
|
||||
assert_eq!(state.before.as_ref(), Some(&before));
|
||||
state.selected = 1;
|
||||
assert_eq!(
|
||||
state.entries().nth(state.selected).unwrap().target,
|
||||
before.target
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn selector_filters_literal_unicode_tokens_and_pins_working_in_each_category() {
|
||||
let mut editor = editor();
|
||||
@@ -1746,7 +1918,7 @@ fn loader_preserves_after_step_query_category_and_selection_then_compares() {
|
||||
state.entries().nth(state.selected).unwrap().target,
|
||||
RevisionTarget::FetchRemote("origin".into())
|
||||
);
|
||||
assert_eq!(state.entries().len(), 3);
|
||||
assert_eq!(state.entries().len(), 4);
|
||||
let remote_position = state
|
||||
.entries()
|
||||
.position(
|
||||
|
||||
Reference in New Issue
Block a user