this repo has no description
1use nu_ansi_term::Color::{self, Green, Red, Yellow};
2use std::collections::BTreeMap;
3use terminal_light::luma;
4
5use super::{
6 package::{DiffType, Package, SizeDelta},
7 parser::DiffRoot,
8};
9
10#[derive(Debug)]
11pub struct PackageExtra {
12 name: String,
13 base_package: Package,
14}
15
16#[derive(Debug)]
17pub struct PackageListDiff {
18 all: Vec<PackageExtra>,
19 added: BTreeMap<String, Package>,
20 removed: BTreeMap<String, Package>,
21 changed: BTreeMap<String, Package>,
22 size_delta: SizeDelta,
23 longest_name: usize,
24
25 // Whether to sort by size difference when displaying
26 pub by_size: bool,
27}
28
29impl PackageListDiff {
30 pub fn new() -> Self {
31 PackageListDiff {
32 all: Vec::new(),
33 added: BTreeMap::new(),
34 removed: BTreeMap::new(),
35 changed: BTreeMap::new(),
36 size_delta: SizeDelta(0),
37 longest_name: 0,
38 by_size: false,
39 }
40 }
41}
42
43impl std::fmt::Display for PackageListDiff {
44 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
45 if self.by_size {
46 self.display_by_size(f)?;
47 } else {
48 if self.added.is_empty() && self.removed.is_empty() && self.changed.is_empty() {
49 return write!(f, "No differences found.");
50 }
51
52 self.display_by_category(f)?;
53 }
54
55 {
56 let delta = &self.size_delta;
57 writeln!(f, "size diff: {delta}")?;
58 }
59
60 Ok(())
61 }
62}
63
64impl PackageListDiff {
65 fn display_by_size(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
66 let all = {
67 let mut v: Vec<_> = self.all.iter().collect();
68 v.sort_by_key(|pkg| -pkg.base_package.size_delta.0);
69 v
70 };
71
72 let name_width = self.longest_name + 2;
73 let package_width = (all
74 .iter()
75 .map(|pkg| strip_ansi_escapes::strip(format!("{}", pkg.base_package)).len())
76 .max()
77 .expect("At least one package exists"))
78 .min(120);
79
80 for package in &all {
81 let name = &package.name;
82 let package = &package.base_package;
83 let delta = &package.size_delta;
84 let versions = format!("{package}");
85 let visual_len = strip_ansi_escapes::strip(&versions).len();
86 let padding = " ".repeat(package_width.saturating_sub(visual_len));
87 writeln!(f, "{name:name_width$}{versions}{padding} {delta}")?;
88 }
89
90 writeln!(f)?;
91
92 Ok(())
93 }
94
95 fn display_by_category(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
96 let text_color = if luma().is_ok_and(|luma| luma > 0.6) {
97 Color::DarkGray
98 } else {
99 Color::LightGray
100 };
101 let title_style = nu_ansi_term::Style::new().underline().bold().fg(text_color);
102
103 let name_width = self.longest_name + 2;
104
105 if !self.changed.is_empty() {
106 writeln!(f, "{}", &title_style.paint("Changed"))?;
107 for (name, package) in &self.changed {
108 writeln!(f, "[{}] {name:name_width$}{package}", Yellow.paint("C"))?;
109 }
110 writeln!(f)?;
111 }
112
113 if !self.added.is_empty() {
114 writeln!(f, "{}", &title_style.paint("Added"))?;
115 for (name, package) in &self.added {
116 write!(f, "[{}] {name:name_width$}{package}", Green.paint("A"))?;
117 writeln!(f)?;
118 }
119 writeln!(f)?;
120 }
121
122 if !self.removed.is_empty() {
123 writeln!(f, "{}", &title_style.paint("Removed"))?;
124 for (name, package) in &self.removed {
125 writeln!(f, "[{}] {name:name_width$}{package}", Red.paint("R"))?;
126 }
127 writeln!(f)?;
128 }
129
130 Ok(())
131 }
132
133 #[allow(clippy::wrong_self_convention)]
134 pub fn from_diff_root(&mut self, diff_root: DiffRoot) {
135 for (name, diff_package) in diff_root.packages {
136 let package = Package::from(diff_package);
137
138 self.size_delta.0 += package.size_delta.0;
139 self.longest_name = self.longest_name.max(name.len());
140
141 if self.by_size {
142 self.all.push(PackageExtra {
143 name,
144 base_package: package,
145 });
146
147 continue;
148 }
149
150 match package.diff_type {
151 DiffType::Added => {
152 self.added.insert(name, package);
153 }
154 DiffType::Removed => {
155 self.removed.insert(name, package);
156 }
157 DiffType::Changed => {
158 self.changed.insert(name, package);
159 }
160 DiffType::Unknown => {
161 // This should never happen, but just in case
162 eprintln!("Unknown diff type for package: {name}");
163 }
164 }
165 }
166 }
167}