feat: show jj ancestry in the floating diff picker
This commit is contained in:
@@ -629,10 +629,6 @@ fn branch_changes_default_and_mode_switches_compare_the_selected_divergent_tips(
|
||||
session.editor().diff().unwrap().comparison_mode,
|
||||
ComparisonMode::Snapshots
|
||||
);
|
||||
assert_eq!(
|
||||
session.editor().message(),
|
||||
"Working checkout requires Snapshots"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -1367,6 +1367,31 @@ fn jj_private_fetch_discovers_never_fetched_bookmark_and_searchable_remote_chang
|
||||
);
|
||||
assert_eq!(changed(&comparison, Path::new("file")).after, ["local"]);
|
||||
let loaded = repository.fetch_remote("origin").unwrap();
|
||||
assert_eq!(loaded.graph[&tip].parents, [ancestor.clone()]);
|
||||
assert_eq!(
|
||||
loaded.graph[&ancestor].description,
|
||||
"remote historic needle"
|
||||
);
|
||||
assert!(!loaded.graph[&tip].current);
|
||||
let positions: std::collections::BTreeMap<_, _> = loaded
|
||||
.entries
|
||||
.iter()
|
||||
.filter(|entry| entry.category == Category::Revisions)
|
||||
.enumerate()
|
||||
.filter_map(|(index, entry)| match &entry.target {
|
||||
RevisionTarget::Commit(id) => Some((id.as_str(), index)),
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
for (id, metadata) in &loaded.graph {
|
||||
for parent in &metadata.parents {
|
||||
if let (Some(child), Some(parent)) =
|
||||
(positions.get(id.as_str()), positions.get(parent.as_str()))
|
||||
{
|
||||
assert!(child < parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
let historic = loaded
|
||||
.entries
|
||||
.iter()
|
||||
|
||||
+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(
|
||||
|
||||
@@ -1836,6 +1836,7 @@ fn hidden_tab_diff_results_restore_visible_insert_interaction_and_route_request_
|
||||
let catalog = || {
|
||||
Outcome::Catalog(Catalog {
|
||||
kind: RepoKind::Git,
|
||||
graph: Default::default(),
|
||||
entries: [
|
||||
RevisionTarget::Commit("base".into()),
|
||||
RevisionTarget::Working,
|
||||
@@ -2627,6 +2628,7 @@ fn diff_results_bind_the_owning_pane_without_disturbing_focused_document_or_mode
|
||||
id,
|
||||
Ok(Outcome::Catalog(Catalog {
|
||||
kind: RepoKind::Git,
|
||||
graph: Default::default(),
|
||||
entries: vec![Revision {
|
||||
target: RevisionTarget::Working,
|
||||
label: "Working".into(),
|
||||
@@ -3039,6 +3041,7 @@ fn working_diff_with_revisions(
|
||||
id,
|
||||
Ok(Outcome::Catalog(Catalog {
|
||||
kind: RepoKind::Git,
|
||||
graph: Default::default(),
|
||||
entries: vec![
|
||||
revision(RevisionTarget::Commit("base".into()), "base"),
|
||||
revision(RevisionTarget::Working, "Working"),
|
||||
@@ -3113,6 +3116,7 @@ fn historical_diff_with_revisions(
|
||||
id,
|
||||
Ok(Outcome::Catalog(Catalog {
|
||||
kind: RepoKind::Git,
|
||||
graph: Default::default(),
|
||||
entries: vec![revision("base"), revision("head")],
|
||||
notice: None,
|
||||
})),
|
||||
|
||||
@@ -463,6 +463,80 @@ fn working_jj_conflicted_parent_uses_cli_projection_without_snapshotting() {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn jj_catalog_exposes_fixed_metadata_and_merge_parents_without_snapshotting() {
|
||||
let temp = Temporary::new().unwrap();
|
||||
let root = &temp.0;
|
||||
fixture_command(root, "jj", &["git", "init", "--no-colocate", "."]);
|
||||
fixture_command(root, "jj", &["describe", "-m", "Base"]);
|
||||
let id = |root: &Path| {
|
||||
fixture_command(
|
||||
root,
|
||||
"jj",
|
||||
&[
|
||||
"--ignore-working-copy",
|
||||
"log",
|
||||
"--no-graph",
|
||||
"-r",
|
||||
"@",
|
||||
"-T",
|
||||
"commit_id",
|
||||
],
|
||||
)
|
||||
};
|
||||
let base = id(root);
|
||||
fixture_command(root, "jj", &["bookmark", "create", "base"]);
|
||||
fixture_command(root, "jj", &["new", &base, "-m", "Left"]);
|
||||
let left = id(root);
|
||||
fixture_command(root, "jj", &["new", &base, "-m", "Right"]);
|
||||
let right = id(root);
|
||||
fixture_command(root, "jj", &["new", &left, &right, "-m", "Merge"]);
|
||||
let current = id(root);
|
||||
let operation = fixture_command(
|
||||
root,
|
||||
"jj",
|
||||
&[
|
||||
"--ignore-working-copy",
|
||||
"op",
|
||||
"log",
|
||||
"--no-graph",
|
||||
"-n",
|
||||
"1",
|
||||
"-T",
|
||||
"id",
|
||||
],
|
||||
);
|
||||
let mut repository = Repository::open(root, Arc::new(AtomicBool::new(false))).unwrap();
|
||||
let catalog = repository.catalog().unwrap();
|
||||
let merge = &catalog.graph[¤t];
|
||||
assert_eq!(merge.parents, [left, right]);
|
||||
assert_eq!(merge.author, "Picker Author");
|
||||
assert_eq!(merge.timestamp, "2001-01-01 00:00");
|
||||
assert_eq!(merge.description, "Merge");
|
||||
assert!(!merge.change_id.is_empty());
|
||||
assert!(merge.current);
|
||||
assert_eq!(catalog.graph[&base].bookmarks, "base");
|
||||
assert!(!catalog.graph[&base].current);
|
||||
assert!(catalog.graph[&"0".repeat(40)].immutable);
|
||||
assert_eq!(
|
||||
fixture_command(
|
||||
root,
|
||||
"jj",
|
||||
&[
|
||||
"--ignore-working-copy",
|
||||
"op",
|
||||
"log",
|
||||
"--no-graph",
|
||||
"-n",
|
||||
"1",
|
||||
"-T",
|
||||
"id"
|
||||
]
|
||||
),
|
||||
operation
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cancellation_kills_pipe_holding_children_and_drains_both_streams() {
|
||||
let temp = Temporary::new().unwrap();
|
||||
|
||||
@@ -556,6 +556,7 @@ fn checkout_diff_polling_uses_injected_interval_independently_of_endpoint_follow
|
||||
id,
|
||||
Ok(DiffOutcome::Catalog(Catalog {
|
||||
kind: RepoKind::Git,
|
||||
graph: Default::default(),
|
||||
notice: None,
|
||||
entries: [
|
||||
RevisionTarget::Working,
|
||||
@@ -3725,6 +3726,7 @@ fn async_responses_edit_only_current_bound_working_after_and_refresh_projection(
|
||||
id,
|
||||
Ok(DiffOutcome::Catalog(Catalog {
|
||||
kind: RepoKind::Git,
|
||||
graph: Default::default(),
|
||||
notice: None,
|
||||
entries: vec![
|
||||
revision(RevisionTarget::Commit("base".into()), "base"),
|
||||
|
||||
+129
-5
@@ -1951,6 +1951,7 @@ fn diff_catalog() -> crate::diff::Catalog {
|
||||
Catalog {
|
||||
kind: RepoKind::Git,
|
||||
entries,
|
||||
graph: Default::default(),
|
||||
notice: None,
|
||||
}
|
||||
}
|
||||
@@ -3501,7 +3502,7 @@ fn diff_picker_keeps_working_pinned_while_windowing_searching_and_changing_stage
|
||||
assert!(text.contains("Choose Before"));
|
||||
assert!(text.contains("Tab categories"));
|
||||
assert!(text.contains("Enter select"));
|
||||
assert!(text.contains("Working checkout · pinned"));
|
||||
assert!(text.contains("Checkout snapshot · pinned"));
|
||||
assert!(text.contains("> commit-19"));
|
||||
assert!(!text.contains("commit-00"));
|
||||
for ch in "needle".chars() {
|
||||
@@ -3511,13 +3512,14 @@ fn diff_picker_keeps_working_pinned_while_windowing_searching_and_changing_stage
|
||||
render_diff(&mut terminal, &diff, &mut panels);
|
||||
let text = screen_text(&terminal);
|
||||
assert!(text.contains("> needle"));
|
||||
assert!(text.contains("Working checkout · pinned"));
|
||||
assert!(text.contains("Checkout snapshot · pinned"));
|
||||
assert!(text.contains("> commit-19"));
|
||||
diff.handle(Input::Enter);
|
||||
render_diff(&mut terminal, &diff, &mut panels);
|
||||
let text = screen_text(&terminal);
|
||||
assert!(text.contains("Choose After"));
|
||||
assert!(text.contains("Branch changes · Ctrl+b toggle · Before: commit-19"));
|
||||
assert!(text.contains("Branch changes · Ctrl+b toggle"));
|
||||
assert!(!text.contains("Before:"));
|
||||
assert!(screen_text(&terminal).contains("Tab categories"));
|
||||
assert!(screen_text(&terminal).contains("Enter select"));
|
||||
diff.handle(Input::Ctrl('u'));
|
||||
@@ -3525,8 +3527,8 @@ fn diff_picker_keeps_working_pinned_while_windowing_searching_and_changing_stage
|
||||
render_diff(&mut terminal, &diff, &mut panels);
|
||||
let text = screen_text(&terminal);
|
||||
assert!(text.contains("feature-branch"));
|
||||
assert!(!text.contains("ordinary change"));
|
||||
assert!(text.contains("Working checkout · pinned"));
|
||||
assert!(text.contains("commit-19 [Before]"));
|
||||
assert!(text.contains("Checkout snapshot · pinned"));
|
||||
let buffer = terminal.backend().buffer();
|
||||
assert!(
|
||||
buffer
|
||||
@@ -3536,6 +3538,128 @@ fn diff_picker_keeps_working_pinned_while_windowing_searching_and_changing_stage
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn checkout_picker_labels_follow_the_configured_stage() {
|
||||
let mut diff = DiffState::new();
|
||||
diff.follow_working_copy = true;
|
||||
diff.take_request();
|
||||
diff.apply_result(1, Ok(crate::diff::Outcome::Catalog(diff_catalog())));
|
||||
let mut terminal = Terminal::new(ratatui::backend::TestBackend::new(100, 16)).unwrap();
|
||||
let mut panels = WheelPanels::default();
|
||||
render_diff(&mut terminal, &diff, &mut panels);
|
||||
assert!(
|
||||
screen_text(&terminal).contains("Checkout snapshot · pinned · Live files at this checkout")
|
||||
);
|
||||
diff.handle(Input::Enter);
|
||||
render_diff(&mut terminal, &diff, &mut panels);
|
||||
assert!(screen_text(&terminal).contains("Follow checkout [Before] · pinned"));
|
||||
assert!(screen_text(&terminal).contains("follows descendant checkouts"));
|
||||
diff.follow_working_copy = false;
|
||||
render_diff(&mut terminal, &diff, &mut panels);
|
||||
assert!(screen_text(&terminal).contains("Checkout snapshot [Before] · pinned"));
|
||||
assert!(!screen_text(&terminal).contains("Follow checkout"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn jj_picker_renders_graph_before_badge_and_compacts_without_losing_controls() {
|
||||
use crate::diff::{Category, RepoKind, Revision, RevisionGraph, RevisionTarget};
|
||||
let mut catalog = diff_catalog();
|
||||
catalog.kind = RepoKind::Jujutsu;
|
||||
catalog.entries.truncate(1);
|
||||
for (id, change, parent, current, immutable) in [
|
||||
("aaaa1111", "change-a", Some("bbbb2222"), true, false),
|
||||
("bbbb2222", "change-b", None, false, true),
|
||||
] {
|
||||
catalog.entries.push(Revision {
|
||||
target: RevisionTarget::Commit(id.into()),
|
||||
label: change.into(),
|
||||
description: format!("{change} description"),
|
||||
category: Category::Revisions,
|
||||
});
|
||||
catalog.graph.insert(
|
||||
id.into(),
|
||||
RevisionGraph {
|
||||
change_id: change.into(),
|
||||
description: format!("{change} description"),
|
||||
parents: parent.into_iter().map(str::to_owned).collect(),
|
||||
author: "alice".into(),
|
||||
timestamp: "2026-10-23".into(),
|
||||
bookmarks: if current {
|
||||
"main".into()
|
||||
} else {
|
||||
String::new()
|
||||
},
|
||||
current,
|
||||
immutable,
|
||||
},
|
||||
);
|
||||
}
|
||||
for name in ["main", "topic"] {
|
||||
catalog.entries.push(Revision {
|
||||
target: RevisionTarget::Bookmark {
|
||||
name: name.into(),
|
||||
remote: None,
|
||||
},
|
||||
label: name.into(),
|
||||
description: "change-a aaaa1111 change-a description".into(),
|
||||
category: Category::Bookmarks,
|
||||
});
|
||||
}
|
||||
let mut diff = DiffState::new();
|
||||
diff.take_request();
|
||||
diff.apply_result(1, Ok(crate::diff::Outcome::Catalog(catalog)));
|
||||
diff.handle(Input::Down);
|
||||
diff.handle(Input::Enter);
|
||||
diff.handle(Input::Down);
|
||||
diff.handle(Input::Down);
|
||||
let mut panels = WheelPanels::default();
|
||||
let mut terminal = Terminal::new(ratatui::backend::TestBackend::new(100, 24)).unwrap();
|
||||
render_diff(&mut terminal, &diff, &mut panels);
|
||||
let text = screen_text(&terminal);
|
||||
assert!(text.contains("Choose After"));
|
||||
assert!(text.contains("@"));
|
||||
assert!(text.contains("change-a [Before] alice 2026-10-23 [main] aaaa1111"));
|
||||
assert!(text.contains("change-a description"));
|
||||
assert!(!text.contains("Before:"));
|
||||
let buffer = terminal.backend().buffer();
|
||||
let selected_rows: Vec<_> = (0..buffer.area.height)
|
||||
.filter(|&y| (0..buffer.area.width).any(|x| buffer[(x, y)].bg == Color::Blue))
|
||||
.collect();
|
||||
assert_eq!(selected_rows.len(), 2);
|
||||
assert_eq!(selected_rows[1], selected_rows[0] + 1);
|
||||
let before_row = (0..buffer.area.height)
|
||||
.find(|&y| {
|
||||
(0..buffer.area.width)
|
||||
.map(|x| buffer[(x, y)].symbol())
|
||||
.collect::<String>()
|
||||
.contains("[Before]")
|
||||
})
|
||||
.unwrap();
|
||||
assert!((0..buffer.area.width).all(|x| buffer[(x, before_row)].bg != Color::Blue));
|
||||
for (width, height) in [(44, 12), (20, 8)] {
|
||||
let mut terminal =
|
||||
Terminal::new(ratatui::backend::TestBackend::new(width, height)).unwrap();
|
||||
render_diff(&mut terminal, &diff, &mut panels);
|
||||
let text = screen_text(&terminal);
|
||||
assert!(text.contains("Choose After"));
|
||||
assert!(text.contains("[Before]"));
|
||||
assert!(text.contains("> "));
|
||||
let buffer = terminal.backend().buffer();
|
||||
assert_eq!(
|
||||
(0..height)
|
||||
.filter(|&y| { (0..width).any(|x| buffer[(x, y)].bg == Color::Blue) })
|
||||
.count(),
|
||||
1
|
||||
);
|
||||
}
|
||||
diff.handle(Input::Char('\t'));
|
||||
render_diff(&mut terminal, &diff, &mut panels);
|
||||
let text = screen_text(&terminal);
|
||||
assert!(text.contains("[main] change-a"));
|
||||
assert!(text.contains("[topic] change-a"));
|
||||
assert_eq!(text.matches("change-a description").count(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pull_request_picker_renders_all_rows_without_a_pinned_offset() {
|
||||
use crate::diff::{Category, PullRequestPage, RepoKind, Revision, RevisionTarget};
|
||||
|
||||
Reference in New Issue
Block a user