Build the real per-file unified diff for a change by reusing the exact `atomic diff -c ` builder ([`change_file_diffs`]), then converting each `FileDiff` into the serializable [`DiffFileView`] mirror. Best-effort: on any error this returns an empty vec (the report still carries message/files).
(repo: &Repository, change: &Change, hash: &Hash)
| 766 | /// `FileDiff` into the serializable [`DiffFileView`] mirror. Best-effort: on any |
| 767 | /// error this returns an empty vec (the report still carries message/files). |
| 768 | fn build_change_diff(repo: &Repository, change: &Change, hash: &Hash) -> Vec<DiffFileView> { |
| 769 | // Sensible review defaults: unified, a few context lines, no color/word-diff. |
| 770 | let config = DiffOutputConfig::new().with_color(false); |
| 771 | debug_assert_eq!(config.format, DiffFormat::Unified); |
| 772 | |
| 773 | let file_diffs = match change_file_diffs(repo, change, hash, &config) { |
| 774 | Ok((file_diffs, _stats)) => file_diffs, |
| 775 | Err(_) => return Vec::new(), |
| 776 | }; |
| 777 | |
| 778 | let mut out = Vec::with_capacity(file_diffs.len()); |
| 779 | for fd in file_diffs { |
| 780 | let status = match fd.status { |
| 781 | FileChangeStatus::Added => "added", |
| 782 | FileChangeStatus::Deleted => "deleted", |
| 783 | _ => "modified", |
| 784 | } |
| 785 | .to_string(); |
| 786 | let path = if !fd.new_path.is_empty() { |
| 787 | fd.new_path.clone() |
| 788 | } else { |
| 789 | fd.old_path.clone() |
| 790 | }; |
| 791 | |
| 792 | let total_lines: usize = fd.hunks.iter().map(|h| h.lines.len()).sum(); |
| 793 | let hunks = if total_lines > MAX_DIFF_LINES_PER_FILE { |
| 794 | // Too large to embed: leave a note pointing at the full command. |
| 795 | vec![DiffHunkView { |
| 796 | header: format!("@@ {path} @@"), |
| 797 | lines: vec![DiffLineView { |
| 798 | tag: " ".to_string(), |
| 799 | content: format!( |
| 800 | "[diff omitted: {total_lines} lines exceed embed cap; run: atomic change {} --show-hunks]", |
| 801 | hash.to_base32() |
| 802 | ), |
| 803 | }], |
| 804 | }] |
| 805 | } else { |
| 806 | fd.hunks |
| 807 | .iter() |
| 808 | .map(|h| DiffHunkView { |
| 809 | header: h.header(), |
| 810 | lines: h |
| 811 | .lines |
| 812 | .iter() |
| 813 | .map(|l| DiffLineView { |
| 814 | tag: l.status.prefix().to_string(), |
| 815 | content: l.content.clone(), |
| 816 | }) |
| 817 | .collect(), |
| 818 | }) |
| 819 | .collect() |
| 820 | }; |
| 821 | |
| 822 | out.push(DiffFileView { |
| 823 | path, |
| 824 | status, |
| 825 | hunks, |
no test coverage detected