| 579 | /// omitted. Read-only. |
| 580 | #[allow(clippy::type_complexity)] |
| 581 | pub fn list_conflicts( |
| 582 | &self, |
| 583 | ) -> Result<Vec<(String, Vec<atomic_core::pristine::StoredConflict>)>, RepositoryError> { |
| 584 | let txn = self |
| 585 | .pristine |
| 586 | .read_txn() |
| 587 | .map_err(|e| RepositoryError::Database(e.to_string()))?; |
| 588 | let view = match txn |
| 589 | .get_view(&self.current_view) |
| 590 | .map_err(|e| RepositoryError::Database(e.to_string()))? |
| 591 | { |
| 592 | Some(v) => v, |
| 593 | None => return Ok(Vec::new()), |
| 594 | }; |
| 595 | let mut out = Vec::new(); |
| 596 | for (_inode, records) in txn |
| 597 | .iter_conflicts(view.id) |
| 598 | .map_err(|e| RepositoryError::Database(e.to_string()))? |
| 599 | { |
| 600 | let Some(first) = records.first() else { |
| 601 | continue; |
| 602 | }; |
| 603 | let abs_path = self.root.join(&first.path); |
| 604 | let still_conflicted = std::fs::read(&abs_path) |
| 605 | .ok() |
| 606 | .and_then(|c| super::materialize::first_conflict_marker_line(&c)) |
| 607 | .is_some(); |
| 608 | if !still_conflicted { |
| 609 | continue; |
| 610 | } |
| 611 | out.push((first.path.clone(), records)); |
| 612 | } |
| 613 | out.sort_by(|a, b| a.0.cmp(&b.0)); |
| 614 | Ok(out) |
| 615 | } |
| 616 | |
| 617 | /// Quick status check — uses default options. |
| 618 | /// |