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