Something went wrong. Try again.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199use nu_ansi_term::Color::{self, Green, Red, Yellow};use std::collections::BTreeMap;use terminal_light::luma;
use super::{ color, package::{DiffType, Package, SizeDelta}, parser::DiffRoot,};
#[derive(Debug)]pub struct PackageExtra { name: String, base_package: Package,}
#[derive(Debug)]pub struct PackageListDiff { all: Vec<PackageExtra>, added: BTreeMap<String, Package>, removed: BTreeMap<String, Package>, changed: BTreeMap<String, Package>, size_delta: SizeDelta, longest_name: usize,
// Whether to sort by size difference when displaying pub by_size: bool,}
impl PackageListDiff { pub fn new() -> Self { PackageListDiff { all: Vec::new(), added: BTreeMap::new(), removed: BTreeMap::new(), changed: BTreeMap::new(), size_delta: SizeDelta(0), longest_name: 0, by_size: false, } }
pub fn is_empty(&self) -> bool { self.added.is_empty() && self.removed.is_empty() && self.changed.is_empty() }}
impl std::fmt::Display for PackageListDiff { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { if self.by_size { self.display_by_size(f)?; } else { if self.added.is_empty() && self.removed.is_empty() && self.changed.is_empty() { return write!(f, "No differences found."); }
self.display_by_category(f)?; }
{ let delta = &self.size_delta; writeln!(f, "size diff: {delta}")?; }
Ok(()) }}
impl PackageListDiff { fn display_by_size(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let all = { let mut v: Vec<_> = self.all.iter().collect(); v.sort_by_key(|pkg| -pkg.base_package.size_delta.0); v };
let name_width = self.longest_name + 2; let package_width = all .iter() .map(|pkg| strip_ansi_escapes::strip(format!("{}", pkg.base_package)).len()) .max() .map(|width| width.min(120));
for package in &all { let name = &package.name; let package = &package.base_package; let delta = &package.size_delta; let versions = format!("{package}"); let visual_len = strip_ansi_escapes::strip(&versions).len(); let package_width = package_width.expect("At least one package exists"); let padding = " ".repeat(package_width.saturating_sub(visual_len)); writeln!(f, "{name:name_width$}{versions}{padding} {delta}")?; }
writeln!(f)?;
Ok(()) }
fn display_by_category(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let name_width = self.longest_name + 2;
if color::color_enabled() { let text_color = if luma().is_ok_and(|luma| luma > 0.6) { Color::DarkGray } else { Color::LightGray }; let title_style = nu_ansi_term::Style::new().underline().bold().fg(text_color);
if !self.changed.is_empty() { writeln!(f, "{}", &title_style.paint("Changed"))?; for (name, package) in &self.changed { writeln!(f, "[{}] {name:name_width$}{package}", Yellow.paint("C"))?; } writeln!(f)?; }
if !self.added.is_empty() { writeln!(f, "{}", &title_style.paint("Added"))?; for (name, package) in &self.added { write!(f, "[{}] {name:name_width$}{package}", Green.paint("A"))?; writeln!(f)?; } writeln!(f)?; }
if !self.removed.is_empty() { writeln!(f, "{}", &title_style.paint("Removed"))?; for (name, package) in &self.removed { writeln!(f, "[{}] {name:name_width$}{package}", Red.paint("R"))?; } writeln!(f)?; } } else { if !self.changed.is_empty() { writeln!(f, "Changed")?; for (name, package) in &self.changed { writeln!(f, "[C] {name:name_width$}{package}")?; } writeln!(f)?; }
if !self.added.is_empty() { writeln!(f, "Added")?; for (name, package) in &self.added { writeln!(f, "[A] {name:name_width$}{package}")?; } writeln!(f)?; }
if !self.removed.is_empty() { writeln!(f, "Removed")?; for (name, package) in &self.removed { writeln!(f, "[R] {name:name_width$}{package}")?; } writeln!(f)?; } }
Ok(()) }
#[allow(clippy::wrong_self_convention)] pub fn from_diff_root(&mut self, diff_root: DiffRoot) { for (name, diff_package) in diff_root.packages { let package = Package::from(diff_package);
self.size_delta.0 += package.size_delta.0; self.longest_name = self.longest_name.max(name.len());
if self.by_size { self.all.push(PackageExtra { name, base_package: package, });
continue; }
match package.diff_type { DiffType::Added => { self.added.insert(name, package); } DiffType::Removed => { self.removed.insert(name, package); } DiffType::Changed => { self.changed.insert(name, package); } DiffType::Unknown => { // This should never happen, but just in case eprintln!("Unknown diff type for package: {name}"); } } } }}