fix: skip omitted diff lines instead of expanding excerpts during navigation
This commit is contained in:
+31
-35
@@ -629,28 +629,24 @@ impl DiffState {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn reveal_after(&mut self, caret_row: usize) {
|
||||
let Some(index) = self
|
||||
.rows
|
||||
pub(crate) fn after_rows(&self) -> impl DoubleEndedIterator<Item = usize> + '_ {
|
||||
self.excerpt_ranges
|
||||
.iter()
|
||||
.position(|row| row.after == Some(caret_row))
|
||||
else {
|
||||
return;
|
||||
};
|
||||
if self.after_display_row(caret_row).is_some() {
|
||||
return;
|
||||
.flat_map(|&(start, end)| self.rows[start..end].iter().filter_map(|row| row.after))
|
||||
}
|
||||
|
||||
pub(crate) fn clamp_after_row(&self, row: usize) -> Option<usize> {
|
||||
let mut previous = None;
|
||||
for visible in self.after_rows() {
|
||||
if visible >= row {
|
||||
return Some(match previous {
|
||||
Some(previous) if row - previous < visible - row => previous,
|
||||
_ => visible,
|
||||
});
|
||||
}
|
||||
previous = Some(visible);
|
||||
}
|
||||
let anchor = self.display_rows.get(self.top).copied();
|
||||
self.excerpt_ranges.push((
|
||||
index.saturating_sub(self.context_lines),
|
||||
index
|
||||
.saturating_add(self.context_lines)
|
||||
.saturating_add(1)
|
||||
.min(self.rows.len()),
|
||||
));
|
||||
self.excerpt_ranges.sort_unstable();
|
||||
self.rebuild_display_rows();
|
||||
self.restore_top(anchor);
|
||||
previous
|
||||
}
|
||||
|
||||
fn restore_top(&mut self, anchor: Option<DisplayRow>) {
|
||||
@@ -670,12 +666,11 @@ impl DiffState {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn refresh_after(&mut self, lines: &[String], revision: u64, caret_row: usize) {
|
||||
pub fn refresh_after(&mut self, lines: &[String], revision: u64) {
|
||||
if !self.after_editable() {
|
||||
return;
|
||||
}
|
||||
if self.live_revision == Some(revision) {
|
||||
self.reveal_after(caret_row);
|
||||
return;
|
||||
}
|
||||
let file = &self.comparison.as_ref().unwrap().files[self.file];
|
||||
@@ -761,7 +756,6 @@ impl DiffState {
|
||||
{
|
||||
self.restore_top(Some(DisplayRow::Line(index)));
|
||||
}
|
||||
self.reveal_after(caret_row);
|
||||
if was_changed != changed {
|
||||
self.refresh_files();
|
||||
}
|
||||
@@ -2039,7 +2033,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn live_reflow_keeps_separate_hunks_expansion_and_caret_after_revert() {
|
||||
fn live_reflow_keeps_separate_hunks_and_expanded_context_after_revert() {
|
||||
let base = (0..100)
|
||||
.map(|row| format!("line {row}"))
|
||||
.collect::<Vec<_>>();
|
||||
@@ -2049,7 +2043,7 @@ mod tests {
|
||||
let mut state = live_state(base.clone(), changed.clone(), true);
|
||||
state.set_context_options(2, 5);
|
||||
changed.push(String::new());
|
||||
state.refresh_after(&changed, 1, 30);
|
||||
state.refresh_after(&changed, 1);
|
||||
assert_eq!(state.comparison.as_ref().unwrap().files[0].hunks.len(), 2);
|
||||
assert!(
|
||||
state
|
||||
@@ -2061,7 +2055,7 @@ mod tests {
|
||||
state.handle(Input::Char('['));
|
||||
assert!(state.after_display_row(23).is_some());
|
||||
changed.insert(10, "inserted outside excerpts".into());
|
||||
state.refresh_after(&changed, 2, 31);
|
||||
state.refresh_after(&changed, 2);
|
||||
assert!(state.after_display_row(24).is_some());
|
||||
assert_eq!(state.comparison.as_ref().unwrap().files[0].hunks.len(), 3);
|
||||
assert!(
|
||||
@@ -2071,14 +2065,15 @@ mod tests {
|
||||
);
|
||||
let mut reverted = base;
|
||||
reverted.push(String::new());
|
||||
state.refresh_after(&reverted, 3, 90);
|
||||
state.refresh_after(&reverted, 3);
|
||||
assert!(state.comparison.as_ref().unwrap().files[0].hunks.is_empty());
|
||||
assert!(state.rows.iter().all(|row| row.kind == RowKind::Equal));
|
||||
assert!(state.after_display_row(90).is_some());
|
||||
assert!(state.after_display_row(23).is_some());
|
||||
assert!(state.after_display_row(90).is_none());
|
||||
assert_eq!(state.files.as_ref().unwrap().entries().len(), 0);
|
||||
assert_eq!(state.file, 0);
|
||||
reverted[50] = "changed again".into();
|
||||
state.refresh_after(&reverted, 4, 50);
|
||||
state.refresh_after(&reverted, 4);
|
||||
assert_eq!(state.files.as_ref().unwrap().entries().len(), 1);
|
||||
assert!(state.after_display_row(50).is_some());
|
||||
}
|
||||
@@ -2086,12 +2081,13 @@ mod tests {
|
||||
#[test]
|
||||
fn live_empty_and_eof_rows_match_buffer_without_false_eof_highlights() {
|
||||
let mut state = live_state(vec!["same".into()], vec!["changed".into()], true);
|
||||
state.refresh_after(&["same".into(), "".into()], 1, 1);
|
||||
state.refresh_after(&["same".into(), "".into()], 1);
|
||||
assert!(state.comparison.as_ref().unwrap().files[0].hunks.is_empty());
|
||||
assert_eq!(state.rows.len(), 2);
|
||||
assert!(state.rows.iter().all(|row| row.kind == RowKind::Equal));
|
||||
assert!(state.after_display_row(1).is_some());
|
||||
state.refresh_after(&["same".into()], 2, 0);
|
||||
assert!(state.after_display_row(0).is_some());
|
||||
assert!(state.after_display_row(1).is_none());
|
||||
state.refresh_after(&["same".into()], 2);
|
||||
assert_eq!(state.rows[0].kind, RowKind::Changed);
|
||||
assert!(
|
||||
state.comparison.as_ref().unwrap().files[0]
|
||||
@@ -2100,17 +2096,17 @@ mod tests {
|
||||
.unwrap()
|
||||
.contains("After missing")
|
||||
);
|
||||
state.refresh_after(&["".into()], 3, 0);
|
||||
state.refresh_after(&["".into()], 3);
|
||||
assert!(state.after_display_row(0).is_some());
|
||||
assert_eq!(state.comparison.as_ref().unwrap().files[0].after, [""]);
|
||||
let mut empty = live_state(vec![], vec!["text".into()], false);
|
||||
empty.refresh_after(&["".into()], 1, 0);
|
||||
empty.refresh_after(&["".into()], 1);
|
||||
assert!(empty.comparison.as_ref().unwrap().files[0].hunks.is_empty());
|
||||
assert_eq!(empty.rows.len(), 1);
|
||||
assert_eq!(empty.rows[0].kind, RowKind::Equal);
|
||||
assert_eq!(empty.after_display_row(0), Some(0));
|
||||
empty.after.as_mut().unwrap().target = RevisionTarget::Commit("historic".into());
|
||||
empty.refresh_after(&["must not apply".into()], 2, 0);
|
||||
empty.refresh_after(&["must not apply".into()], 2);
|
||||
assert_eq!(empty.comparison.as_ref().unwrap().files[0].after, [""]);
|
||||
empty.handle(Input::Escape);
|
||||
assert_eq!(empty.phase, Phase::View);
|
||||
|
||||
Reference in New Issue
Block a user