1use std::fmt::Write;
2
3use crate::diff::RowKind;
4use crate::moves::detect;
5use crate::project::LayerMode;
6use crate::review::{Detection, DiffModes, FileReview, Layers, Summary};
7
8pub fn plain(files: &[FileReview], layers: Layers) -> String {
11 print(files, layers, false)
12}
13
14pub fn plain_numbered(files: &[FileReview], layers: Layers) -> String {
18 print(files, layers, true)
19}
20
21fn print(files: &[FileReview], layers: Layers, numbered: bool) -> String {
22 let mut out = String::new();
23 let listed: Vec<&FileReview> = files
24 .iter()
25 .filter(|file| file.is_visible(layers.tests))
26 .collect();
27 let moves = detect(&listed, layers.into());
28 for (file_index, file) in listed.iter().enumerate() {
29 let view = file.view(layers);
30 let _ = writeln!(out, "{} [{}]", file_title(file), file.tag());
31 if file.detection == Detection::Binary {
32 let _ = writeln!(out, " (binary file not shown)");
33 } else if view.hunks.is_empty() {
34 let _ = writeln!(out, " ({})", empty_message(file, layers.into()));
35 }
36 for (hunk_index, hunk) in view.hunks.iter().enumerate() {
37 let _ = writeln!(out, "{}", hunk.header());
38 for (row_index, row) in hunk.rows.iter().enumerate() {
39 if let Some(moved) = moves.get(&(file_index, hunk_index, row_index))
40 && moved.starts_block
41 {
42 let _ = writeln!(out, "{}", moved.describe(&file.path));
43 }
44 let sign = match row.kind {
45 RowKind::Context => ' ',
46 RowKind::Removed => '-',
47 RowKind::Added => '+',
48 };
49 if numbered {
50 let number =
51 |line: Option<usize>| line.map_or(String::new(), |n| n.to_string());
52 let _ = write!(
53 out,
54 "{:>5} {:>5} ",
55 number(row.old_line),
56 number(row.new_line)
57 );
58 }
59 let _ = writeln!(out, "{sign}{}", row.text);
60 }
61 }
62 let _ = writeln!(out);
63 }
64 let _ = writeln!(out, "{}", Summary::new(files, layers).status_line(layers));
65 out
66}
67
68pub fn file_title(file: &FileReview) -> String {
69 match &file.old_path {
70 Some(old) => format!("{} {old} → {}", file.status.letter(), file.path),
71 None => format!("{} {}", file.status.letter(), file.path),
72 }
73}
74
75pub fn empty_message(file: &FileReview, modes: DiffModes) -> String {
77 let hidden = file.view(modes).hidden_hunks;
78 let adjective = modes.adjective();
79 match modes.outcome().0 {
80 _ if file.total_hunks() == 0 => "no textual changes".to_string(),
81 LayerMode::Hidden => format!(
82 "{adjective}-only changes: {hidden} hunk{} hidden",
83 if hidden == 1 { "" } else { "s" }
84 ),
85 LayerMode::Only => format!("no {adjective} changes"),
86 LayerMode::Shown => "no changes".to_string(),
87 }
88}