refactor: deepen conflict History alignment ownership

This commit is contained in:
Valdemar Lorenzen
2026-10-16 17:07:28 +02:00
parent 53c37e6209
commit a1fdc1e1b0
5 changed files with 250 additions and 153 deletions
+113
View File
@@ -240,6 +240,119 @@ pub enum DisplayRow {
Fold { start: usize, end: usize },
}
/// Immutable left/base/right conflict History, aligned at shared base rows.
pub(crate) struct HistoryComparison {
columns: [DiffState; 3],
}
/// A read-only projection for the existing diff painter.
pub(crate) struct HistoryColumn<'a> {
pub diff: &'a DiffState,
pub file: &'a ChangedFile,
pub focus: Focus,
pub lines: &'a [String],
}
impl HistoryColumn<'_> {
pub fn source_row(&self, display: usize) -> Option<usize> {
self.diff.display_source_row(self.focus, display)
}
pub fn display_row(&self, source: usize) -> Option<usize> {
self.diff.source_display_row(self.focus, source)
}
}
impl HistoryComparison {
pub fn new(sources: [&str; 3]) -> Self {
let [left, base, right] =
sources.map(|text| text.split('\n').map(str::to_owned).collect::<Vec<_>>());
let mut columns: [DiffState; 3] = std::array::from_fn(|_| DiffState::new());
columns[0].set_resolver_text(&base, &left);
columns[1].set_resolver_text(&base, &base);
columns[2].set_resolver_text(&base, &right);
let mut left = std::mem::take(&mut columns[0].rows).into_iter().peekable();
let mut right = std::mem::take(&mut columns[2].rows).into_iter().peekable();
columns[1].rows.clear();
// Stitch the existing pairwise alignments at their shared base rows.
while left.peek().is_some() || right.peek().is_some() {
let insertion = left.peek().is_some_and(|row| row.before.is_none())
|| right.peek().is_some_and(|row| row.before.is_none());
let take_left = left
.peek()
.is_some_and(|row| !insertion || row.before.is_none());
let take_right = right
.peek()
.is_some_and(|row| !insertion || row.before.is_none());
let empty = || AlignedRow {
before: None,
after: None,
kind: RowKind::Equal,
changes: Vec::new(),
};
let left_row = if take_left {
left.next().unwrap()
} else {
empty()
};
let right_row = if take_right {
right.next().unwrap()
} else {
empty()
};
let base = left_row.before.or(right_row.before);
let changed = left_row.kind != RowKind::Equal || right_row.kind != RowKind::Equal;
let changes = left_row
.changes
.iter()
.chain(&right_row.changes)
.map(|change| [change[0].clone(), change[0].clone()])
.collect();
columns[1].rows.push(AlignedRow {
before: base,
after: base,
kind: if changed {
RowKind::Changed
} else {
RowKind::Equal
},
changes,
});
columns[0].rows.push(left_row);
columns[2].rows.push(right_row);
}
for column in &mut columns {
column.display_rows = (0..column.rows.len()).map(DisplayRow::Line).collect();
}
Self { columns }
}
pub fn row_count(&self) -> usize {
self.columns[0].rows.len()
}
pub fn column(&self, index: usize) -> HistoryColumn<'_> {
let diff = &self.columns[index];
let file = &diff.comparison.as_ref().unwrap().files[0];
let focus = if index == 1 {
Focus::Before
} else {
Focus::After
};
let lines = if focus == Focus::Before {
&file.before
} else {
&file.after
};
HistoryColumn {
diff,
file,
focus,
lines,
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum RequestKind {
Catalog,