refactor: deepen conflict History alignment ownership
This commit is contained in:
+113
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user