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)
| 1018 | /// `FileDiff` into the serializable [`DiffFileView`] mirror. Best-effort: on any |
| 1019 | /// error this returns an empty vec (the report still carries message/files). |
| 1020 | fn build_change_diff(repo: &Repository, change: &Change, hash: &Hash) -> Vec<DiffFileView> { |
| 1021 | // Sensible review defaults: unified, a few context lines, no color/word-diff. |
| 1022 | let config = DiffOutputConfig::new().with_color(false); |
| 1023 | debug_assert_eq!(config.format, DiffFormat::Unified); |
| 1024 | |
| 1025 | let file_diffs = match change_file_diffs(repo, change, hash, &config) { |
| 1026 | Ok((file_diffs, _stats)) => file_diffs, |
| 1027 | Err(_) => return Vec::new(), |
| 1028 | }; |
| 1029 | |
| 1030 | let mut out = Vec::with_capacity(file_diffs.len()); |
| 1031 | for fd in file_diffs { |
| 1032 | let status = match fd.status { |
| 1033 | FileChangeStatus::Added => "added", |
| 1034 | FileChangeStatus::Deleted => "deleted", |
| 1035 | _ => "modified", |
| 1036 | } |
| 1037 | .to_string(); |
| 1038 | let path = if !fd.new_path.is_empty() { |
| 1039 | fd.new_path.clone() |
| 1040 | } else { |
| 1041 | fd.old_path.clone() |
| 1042 | }; |
| 1043 | |
| 1044 | let total_lines: usize = fd.hunks.iter().map(|h| h.lines.len()).sum(); |
| 1045 | let hunks = if total_lines > MAX_DIFF_LINES_PER_FILE { |
| 1046 | // Too large to embed: leave a note pointing at the full command. |
| 1047 | vec![DiffHunkView { |
| 1048 | header: format!("@@ {path} @@"), |
| 1049 | lines: vec![DiffLineView { |
| 1050 | tag: " ".to_string(), |
| 1051 | content: format!( |
| 1052 | "[diff omitted: {total_lines} lines exceed embed cap; run: atomic change {} --show-hunks]", |
| 1053 | hash.to_base32() |
| 1054 | ), |
| 1055 | }], |
| 1056 | }] |
| 1057 | } else { |
| 1058 | fd.hunks |
| 1059 | .iter() |
| 1060 | .map(|h| DiffHunkView { |
| 1061 | header: h.header(), |
| 1062 | lines: h |
| 1063 | .lines |
| 1064 | .iter() |
| 1065 | .map(|l| DiffLineView { |
| 1066 | tag: l.status.prefix().to_string(), |
| 1067 | content: l.content.clone(), |
| 1068 | }) |
| 1069 | .collect(), |
| 1070 | }) |
| 1071 | .collect() |
| 1072 | }; |
| 1073 | |
| 1074 | out.push(DiffFileView { |
| 1075 | path, |
| 1076 | status, |
| 1077 | hunks, |
no test coverage detected