feat: show line change counts in diff tabs
This commit is contained in:
+5
-3
@@ -3381,9 +3381,11 @@ impl Editor {
|
||||
}
|
||||
|
||||
pub fn tab_is_diff(&self, index: usize) -> bool {
|
||||
self.tab_order
|
||||
.get(index)
|
||||
.is_some_and(|id| self.tab_diff(*id).is_some())
|
||||
self.tab_diff_at(index).is_some()
|
||||
}
|
||||
|
||||
pub(crate) fn tab_diff_at(&self, index: usize) -> Option<&DiffState> {
|
||||
self.tab_diff(*self.tab_order.get(index)?)
|
||||
}
|
||||
|
||||
pub(crate) fn tab_diff(&self, id: usize) -> Option<&DiffState> {
|
||||
|
||||
+113
-26
@@ -1626,7 +1626,7 @@ fn chrome_title(
|
||||
index: usize,
|
||||
path: Option<&std::path::Path>,
|
||||
dirty: bool,
|
||||
is_diff: bool,
|
||||
diff: Option<&DiffState>,
|
||||
) -> String {
|
||||
let name = path
|
||||
.map(|path| {
|
||||
@@ -1645,7 +1645,23 @@ fn chrome_title(
|
||||
};
|
||||
match field {
|
||||
"index" => write!(title, "{index}").unwrap(),
|
||||
"view" if is_diff => title.push_str("Diff · "),
|
||||
"view" if diff.is_some() => {
|
||||
title.push_str("Diff · ");
|
||||
if let Some(diff) = diff
|
||||
&& diff.phase == Phase::View
|
||||
&& let Some(file) = diff
|
||||
.comparison
|
||||
.as_ref()
|
||||
.and_then(|comparison| comparison.files.get(diff.file))
|
||||
&& file.loaded
|
||||
{
|
||||
let (added, removed) =
|
||||
file.hunks.iter().fold((0, 0), |(added, removed), hunk| {
|
||||
(added + hunk.after_len, removed + hunk.before_len)
|
||||
});
|
||||
write!(title, "+{added} -{removed} · ").unwrap();
|
||||
}
|
||||
}
|
||||
"name" => title.push_str(&name),
|
||||
"path" => title.push_str(&path),
|
||||
"modified" if dirty => title.push_str(" [+]"),
|
||||
@@ -1680,7 +1696,7 @@ fn chrome_items<'a>(
|
||||
index + 1,
|
||||
buffer.as_ref().and_then(|buffer| buffer.path),
|
||||
buffer.is_some_and(|buffer| buffer.dirty),
|
||||
editor.tab_is_diff(index),
|
||||
editor.tab_diff_at(index),
|
||||
)),
|
||||
config,
|
||||
tab: Some(index),
|
||||
@@ -1705,7 +1721,7 @@ fn chrome_items<'a>(
|
||||
editor.tab_index() + 1,
|
||||
editor.path(),
|
||||
editor.dirty(),
|
||||
editor.tab_is_diff(editor.tab_index()),
|
||||
editor.tab_diff_at(editor.tab_index()),
|
||||
)),
|
||||
"position" => Cow::Owned(format!(
|
||||
"{}:{}",
|
||||
@@ -1780,7 +1796,7 @@ fn chrome_items<'a>(
|
||||
editor.tab_index() + 1,
|
||||
editor.path(),
|
||||
editor.dirty(),
|
||||
editor.tab_is_diff(editor.tab_index()),
|
||||
editor.tab_diff_at(editor.tab_index()),
|
||||
));
|
||||
} else if text.chars().any(char::is_control) {
|
||||
text = Cow::Owned(display_text(&text));
|
||||
@@ -10728,7 +10744,7 @@ mod tests {
|
||||
let path = directory.file("λ\t{index}.rs", "source");
|
||||
let editor = Editor::open(Some(path.clone()), vec![]).unwrap();
|
||||
let groups = chrome_groups(&editor, editor.bottom_bar_config(), &SyntaxCache::new());
|
||||
let title = chrome_title("{path}", 2, Some(&path), false, false);
|
||||
let title = chrome_title("{path}", 2, Some(&path), false, None);
|
||||
assert_eq!(title, display_text(&display_path(&path)));
|
||||
assert!(groups.iter().flatten().any(|item| item.text == title));
|
||||
assert_eq!(editor.path(), Some(path.as_path()));
|
||||
@@ -11411,10 +11427,10 @@ end
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn comparison_titles_distinguish_same_named_tabs_and_follow_current_context() {
|
||||
fn comparison_titles_follow_loaded_counts_and_each_tabs_context() {
|
||||
let directory = Directory::new();
|
||||
let path = directory.file("source.rs", "fn main() {}");
|
||||
for phase in ["loading", "before", "after", "view"] {
|
||||
for phase in ["loading", "before", "after", "unloaded", "view"] {
|
||||
let mut editor = Editor::open(Some(path.clone()), vec![]).unwrap();
|
||||
editor.execute("tab.new");
|
||||
editor.execute("diff");
|
||||
@@ -11422,14 +11438,26 @@ end
|
||||
let (id, _) = editor.take_diff_request().unwrap();
|
||||
editor.apply_diff_result(id, Ok(crate::diff::Outcome::Catalog(diff_catalog())));
|
||||
}
|
||||
if matches!(phase, "after" | "view") {
|
||||
if matches!(phase, "after" | "unloaded" | "view") {
|
||||
editor.handle(Input::Down);
|
||||
editor.handle(Input::Enter);
|
||||
}
|
||||
if phase == "view" {
|
||||
if matches!(phase, "unloaded" | "view") {
|
||||
editor.handle(Input::Down);
|
||||
editor.handle(Input::Enter);
|
||||
let (id, _) = editor.take_diff_request().unwrap();
|
||||
let mut file = syntax_diff_file(
|
||||
"source.rs",
|
||||
"old\ncontext\nremove",
|
||||
"new\ncontext\nextra\nmore",
|
||||
);
|
||||
file.hunks = crate::diff::line_hunks(&file.before, false, &file.after, false);
|
||||
if phase == "unloaded" {
|
||||
file.loaded = false;
|
||||
file.before.clear();
|
||||
file.after.clear();
|
||||
file.hunks.clear();
|
||||
}
|
||||
editor.apply_diff_result(
|
||||
id,
|
||||
Ok(crate::diff::Outcome::Comparison(crate::diff::Comparison {
|
||||
@@ -11437,24 +11465,24 @@ end
|
||||
editable_paths: Default::default(),
|
||||
before: "baseline".into(),
|
||||
after: "historic".into(),
|
||||
files: vec![syntax_diff_file("source.rs", "fn old() {}", "fn main() {}")],
|
||||
files: vec![file],
|
||||
})),
|
||||
);
|
||||
}
|
||||
let view = if phase == "view" {
|
||||
"Diff · +3 -2 · "
|
||||
} else {
|
||||
"Diff · "
|
||||
};
|
||||
let default_tabs = editor.top_bar_config().segment("tabs").clone();
|
||||
for (template, ordinary, comparison, marker_count) in [
|
||||
(None, "1 source.rs", "2 Diff · source.rs", 1),
|
||||
(
|
||||
Some("{index} {name}{modified}"),
|
||||
"1 source.rs",
|
||||
"2 source.rs",
|
||||
0,
|
||||
),
|
||||
for (template, ordinary, prefix, uses_view) in [
|
||||
(None, "1 source.rs", "2 ", true),
|
||||
(Some("{index} {name}{modified}"), "1 source.rs", "2 ", false),
|
||||
(
|
||||
Some("T{index}:{view}{name}{modified}"),
|
||||
"T1:source.rs",
|
||||
"T2:Diff · source.rs",
|
||||
1,
|
||||
"T2:",
|
||||
true,
|
||||
),
|
||||
] {
|
||||
configure_chrome(&mut editor, |top, bottom| {
|
||||
@@ -11486,19 +11514,21 @@ end
|
||||
.unwrap();
|
||||
let titles = pane_screen(&terminal, Rect::new(0, 0, 160, 1));
|
||||
assert!(titles.contains(ordinary), "{phase}: {titles}");
|
||||
assert!(titles.contains(comparison), "{phase}: {titles}");
|
||||
let comparison =
|
||||
format!("{prefix}{}source.rs", if uses_view { view } else { "" });
|
||||
assert!(titles.contains(&comparison), "{phase}: {titles}");
|
||||
assert_eq!(
|
||||
titles.matches("Diff · ").count(),
|
||||
marker_count,
|
||||
usize::from(uses_view),
|
||||
"{phase}: {titles}"
|
||||
);
|
||||
let current = pane_screen(&terminal, Rect::new(0, 1, 160, 1));
|
||||
let expected = if comparison_active {
|
||||
"Current:Diff · source.rs"
|
||||
format!("Current:{view}source.rs")
|
||||
} else {
|
||||
"Current:source.rs"
|
||||
"Current:source.rs".into()
|
||||
};
|
||||
assert!(current.contains(expected), "{phase}: {current}");
|
||||
assert!(current.contains(&expected), "{phase}: {current}");
|
||||
editor.execute(if comparison_active {
|
||||
"tab.previous"
|
||||
} else {
|
||||
@@ -11509,6 +11539,63 @@ end
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn comparison_title_counts_follow_live_edits_and_undo_in_hidden_tabs() {
|
||||
let directory = Directory::new();
|
||||
let path = directory.file("live.rs", "new");
|
||||
let mut editor = Editor::open(Some(path), vec![]).unwrap();
|
||||
editor.execute("diff");
|
||||
let (id, _) = editor.take_diff_request().unwrap();
|
||||
editor.apply_diff_result(id, Ok(crate::diff::Outcome::Catalog(diff_catalog())));
|
||||
editor.handle(Input::Down);
|
||||
editor.handle(Input::Enter);
|
||||
editor.handle(Input::Enter);
|
||||
let (id, _) = editor.take_diff_request().unwrap();
|
||||
editor.apply_diff_result(
|
||||
id,
|
||||
Ok(crate::diff::Outcome::Comparison(crate::diff::Comparison {
|
||||
root: directory.0.clone(),
|
||||
editable_paths: ["live.rs".into()].into(),
|
||||
before: "baseline".into(),
|
||||
after: "Working checkout".into(),
|
||||
files: vec![syntax_diff_file("live.rs", "old", "new")],
|
||||
})),
|
||||
);
|
||||
editor.handle(Input::Char('\t'));
|
||||
editor.handle(Input::Char('\t'));
|
||||
assert!(editor.diff_editing());
|
||||
editor.execute("tab.new");
|
||||
let mut terminal = Terminal::new(ratatui::backend::TestBackend::new(120, 14)).unwrap();
|
||||
let mut views = BufferViewports::default();
|
||||
for (inputs, counts) in [
|
||||
(vec![], "+1 -1"),
|
||||
(
|
||||
vec![
|
||||
Input::Char('i'),
|
||||
Input::Paste("extra\n".into()),
|
||||
Input::Escape,
|
||||
],
|
||||
"+2 -1",
|
||||
),
|
||||
(vec![Input::Char('u')], "+1 -1"),
|
||||
(vec![Input::Char('U')], "+2 -1"),
|
||||
] {
|
||||
for input in inputs {
|
||||
editor.handle(input);
|
||||
}
|
||||
editor.refresh_live_diff();
|
||||
terminal
|
||||
.draw(|frame| views.draw(frame, &mut editor))
|
||||
.unwrap();
|
||||
let titles = pane_screen(&terminal, Rect::new(0, 0, 120, 1));
|
||||
assert!(
|
||||
titles.contains(&format!("1 Diff · {counts} · live.rs")),
|
||||
"{titles}"
|
||||
);
|
||||
assert!(titles.contains("2 live.rs"), "{titles}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tab_titles_update_templates_without_reinterpreting_file_names() {
|
||||
let directory = Directory::new();
|
||||
|
||||
Reference in New Issue
Block a user