From 33bb9d86b7b46b475aa2d9cc8e004c321ca06819 Mon Sep 17 00:00:00 2001 From: Guilleag01 Date: Sat, 21 Mar 2026 14:26:19 +0100 Subject: [PATCH] Some refactoring and improvements for clippy --- src/element.rs | 42 ++++++++++++++++------ src/lib.rs | 4 +++ src/main.rs | 10 ++++-- src/out/default.rs | 9 +++-- src/out/list.rs | 86 +++++++++++++++++++++------------------------- src/utils.rs | 44 +++++++++++++++--------- 6 files changed, 116 insertions(+), 79 deletions(-) diff --git a/src/element.rs b/src/element.rs index ef206da..390e17a 100644 --- a/src/element.rs +++ b/src/element.rs @@ -28,7 +28,9 @@ pub struct Element { } impl Element { - pub fn new(path_str: &str) -> Element { + /// # Panics + #[must_use] + pub fn new(path_str: &str) -> Self { let path_built = Path::new(path_str); let metadata: fs::Metadata; if let Result::Ok(m) = fs::metadata(path_str) { @@ -37,13 +39,18 @@ impl Element { return Self { path: path_str.to_string(), file_type: TypeOfFile::File, - name: path_str.split('/').next_back().unwrap().to_string(), + name: path_str + .split('/') + .next_back() + .expect("Error splitting path") + .to_string(), perms: None, size: 0, creation: SystemTime::UNIX_EPOCH, }; } - let symlink_metadata = fs::symlink_metadata(path_str).unwrap(); + let symlink_metadata = fs::symlink_metadata(path_str) + .unwrap_or_else(|e| panic!("Error while getting metadata from file: {path_str}: {e}")); let t: TypeOfFile; @@ -63,14 +70,19 @@ impl Element { let mut name = path_built .file_name() - .unwrap() + .expect("Error getting os string from path") .to_str() - .unwrap() + .expect("Error ") .to_string(); if symlink_metadata.is_symlink() { name.push_str(" -> "); - name.push_str(read_link(path_built).unwrap().to_str().unwrap()) + name.push_str( + read_link(path_built) + .unwrap_or_else(|e| panic!("Error reading link from {path_str}: {e}")) + .to_str() + .expect("Error"), + ); } let s = if t == TypeOfFile::Dir { @@ -79,44 +91,52 @@ impl Element { metadata.len() }; + let now = SystemTime::now(); + Self { path: path_str.to_string(), file_type: t, name, perms: Some(metadata.permissions()), size: s, - creation: metadata.created().unwrap_or(SystemTime::now()), + creation: metadata.created().unwrap_or(now), } } + #[must_use] pub fn get_path_string(&self) -> String { self.path.clone() } - pub fn get_file_type(&self) -> TypeOfFile { + #[must_use] + pub const fn get_file_type(&self) -> TypeOfFile { self.file_type } + #[must_use] pub fn get_name(&self) -> String { self.name.clone() } + #[must_use] pub fn get_perms(&self) -> Option { self.perms.clone() } - pub fn get_size(&self) -> u64 { + #[must_use] + pub const fn get_size(&self) -> u64 { self.size } - pub fn get_creation(&self) -> SystemTime { + #[must_use] + pub const fn get_creation(&self) -> SystemTime { self.creation } } impl Display for Element { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let file_icon = get_icon_file_type(self.get_name()); + let file_icon = get_icon_file_type(&self.get_name()); let mut is_dir = false; let icon = match self.file_type { diff --git a/src/lib.rs b/src/lib.rs index 5667a22..e2fd059 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,7 @@ +#![warn(clippy::pedantic)] +#![warn(clippy::nursery)] +#![deny(clippy::unwrap_used)] + pub mod config; pub mod element; pub mod out; diff --git a/src/main.rs b/src/main.rs index 1474bd1..4b3179b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,3 @@ -#![warn(clippy::pedantic)] use clap::Parser; use lsplus::{ out::{default::default, list::list}, @@ -32,12 +31,17 @@ pub struct Args { } fn main() { + // 138 + // let a: usize = 100; + // let b = a as f32; + // println!("{}, {}", a.checked_ilog10().unwrap(), b.log10().floor()); + let args = Args::parse(); - let elements = get_elements_from_path(args.path, args.all); + let elements = get_elements_from_path(&args.path, args.all); if args.list { - list(elements, args.recursive, args.sort); + list(elements, args.recursive, &args.sort); } else { default(elements); } diff --git a/src/out/default.rs b/src/out/default.rs index 08810c1..9c32575 100644 --- a/src/out/default.rs +++ b/src/out/default.rs @@ -1,10 +1,13 @@ use crate::element::Element; use crate::utils::{get_string_length, pad_string}; +/// # Panics pub fn default(mut elements: Vec) { elements.sort_unstable_by_key(|a: &Element| a.get_name()); - let width = term_size::dimensions().unwrap().0; + let width = term_size::dimensions() + .expect("Error getting terminal width") + .0; let mut i = 1; @@ -14,7 +17,7 @@ pub fn default(mut elements: Vec) { let mut total = usize::MAX; while total >= width - 1 { total = 0; - num_columns = (elements.len() as f32 / i as f32).ceil() as usize; + num_columns = (elements.len() / i) + 1; column_widths = vec![0; num_columns]; for j in 0..num_columns { let mut max_len = 0; @@ -43,7 +46,7 @@ pub fn default(mut elements: Vec) { if i * j + k < elements.len() { print!( "{} ", - pad_string(elements[i * j + k].to_string(), column_widths[j], true) + pad_string(&elements[i * j + k].to_string(), column_widths[j], true) ); } } diff --git a/src/out/list.rs b/src/out/list.rs index 8f51a54..84e9bc1 100644 --- a/src/out/list.rs +++ b/src/out/list.rs @@ -4,16 +4,25 @@ use crate::utils::{ system_time_to_string, SortBy, }; -pub fn list(mut elements: Vec, recursive_limit: usize, sort_by: SortBy) { +/// # Panics +pub fn list(mut elements: Vec, recursive_limit: usize, sort_by: &SortBy) { // ╭──────────────╼ File name ╾──────────────┬─╼ Size ╾─┬──╼ Creation ╾──╮ // │ some_example_file │ 420.69 G │ 01-01-70 00:00 │ // ╰─────────────────────────────────────────┴──────────┴────────────────╯ - let width = term_size::dimensions().unwrap().0; + let width = term_size::dimensions() + .expect("Error getting terminal dimensions") + .0; let name_max_len = get_max_width(&elements, recursive_limit, 0); + #[allow(clippy::cast_possible_truncation)] + let elements_len = elements + .len() + .checked_ilog10() + .expect("Error while doing log10 of elements len"); + let name_length = name_max_len - .max(14 + (elements.len() as f32).log10() as usize) + .max(14_usize + elements_len as usize) .max(13) .min(width - 31); @@ -24,18 +33,18 @@ pub fn list(mut elements: Vec, recursive_limit: usize, sort_by: SortBy) recursive_limit, 0, &Vec::new(), - &sort_by, + sort_by, ); print_footer(num_elements, name_length); } fn print_header(name_length: usize) { print!("╭"); - for _ in 0..((name_length - 12) as f32 / 2.0).floor() as usize { + for _ in 0..((name_length - 12) / 2) { print!("─"); } print!("╼ File name ╾"); - for _ in 0..((name_length - 12) as f32 / 2.0).ceil() as usize { + for _ in 0..(((name_length + name_length % 2) - 12) / 2) { print!("─"); } println!("┬─╼ Size ╾─┬──╼ Creation ╾──╮"); @@ -71,35 +80,19 @@ fn print_elements( e_string.push_str(e.to_string().as_str()); let file_text = pad_string( - get_slice_of_string(e_string.as_str(), name_length - 1, 0, current_depth), + &get_slice_of_string(e_string.as_str(), name_length - 1, 0, current_depth), name_length, true, ); - print!( - "{}", - file_text // if e.get_file_type() == TypeOfFile::Dir { - // file_text.cyan().to_string() - // } else { - // file_text - // } - ); - - // text.push_str( - // pad_string( - // get_slice_of_string(e_string.as_str(), name_length - 1, 0, current_depth), - // name_length, - // true, - // ) - // .as_str(), - // ); + print!("{file_text}"); print_size_and_creation_date(e); let num_splits = get_string_length(e.get_name().as_str()) / (name_length - (2 + 2 * current_depth)); - for j in 1..num_splits + 1 { + for j in 1..=num_splits { let mut e_name = String::from("│ "); if current_depth > 0 { add_recursive_lines( @@ -108,19 +101,16 @@ fn print_elements( i == elements.len() - 1, " ", "│ ", - ) + ); } e_name.push_str(" "); - e_name.push_str( - get_slice_of_string( - e.get_name().as_str(), - name_length - (3 + 2 * current_depth), - j, - current_depth, - ) - .as_str(), - ); - print!("{}", pad_string(e_name, name_length + 2, true)); + e_name.push_str(&get_slice_of_string( + e.get_name().as_str(), + name_length - (3 + 2 * current_depth), + j, + current_depth, + )); + print!("{}", pad_string(&e_name, name_length + 2, true)); // text.push_str(pad_string(e_name, name_length + 2, true).as_str()); println!("│ │ │"); // text.push_str("│ │ │\n"); @@ -130,7 +120,7 @@ fn print_elements( let dir_path = e.get_path_string(); new_is_last_element.push(i == elements.len() - 1); num_elements += print_elements( - &mut get_elements_from_path(dir_path, true), + &mut get_elements_from_path(&dir_path, true), name_length, recursive_limit, current_depth + 1, @@ -167,9 +157,13 @@ fn add_recursive_lines( #[inline] fn get_slice_of_string(e: &str, name_length: usize, i: usize, _current_depth: usize) -> String { - e.chars().collect::>()[((name_length) * i).min(get_string_length(e)) - ..((name_length) * (i + 1)).min(get_string_length(e))] - .iter() + // e.chars().collect::>()[((name_length) * i).min(get_string_length(e)) + // ..((name_length) * (i + 1)).min(get_string_length(e))] + // .iter() + // .collect() + e.chars() + .skip(((name_length) * i).min(get_string_length(e))) + .take(((name_length) * (i + 1)).min(get_string_length(e))) .collect() } @@ -178,7 +172,7 @@ fn print_size_and_creation_date(e: &Element) { if e.get_file_type() == TypeOfFile::Dir { print!(" "); } else { - print!("{}", pad_string(get_size_string(e.get_size()), 10, false)); + print!("{}", pad_string(&get_size_string(e.get_size()), 10, false)); } print!("│"); print!(" {} ", system_time_to_string(e.get_creation())); @@ -186,14 +180,14 @@ fn print_size_and_creation_date(e: &Element) { } fn print_footer(num_elements: usize, name_length: usize) { - let num_elements_len = (num_elements as f32).log10() as usize; + let num_elements_len = num_elements.checked_ilog10().expect("Error") as usize; let name_length_fixed = name_length - (num_elements_len + 13); print!("╰"); - for _ in 0..((name_length_fixed) as f32 / 2.0).floor() as usize { + for _ in 0..((name_length_fixed) / 2) { print!("─"); } - print!("╼ {} Elements ╾", num_elements); - for _ in 0..((name_length_fixed) as f32 / 2.0).ceil() as usize { + print!("╼ {num_elements} Elements ╾"); + for _ in 0..usize::midpoint(name_length_fixed, name_length_fixed % 2) { print!("─"); } println!("┴──────────┴────────────────╯"); @@ -205,7 +199,7 @@ fn get_max_width(elements: &Vec, recursive_limit: usize, current_depth: let mut length = e.to_string().chars().count() + current_depth * 2; if e.get_file_type() == TypeOfFile::Dir && current_depth < recursive_limit { let recursive_width = get_max_width( - &get_elements_from_path(e.get_path_string(), true), + &get_elements_from_path(&e.get_path_string(), true), recursive_limit, current_depth + 1, ); diff --git a/src/utils.rs b/src/utils.rs index 756ae32..94cf769 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -20,24 +20,27 @@ impl Display for SortBy { Self::SIZE => "size", Self::CREATION => "creation", }; - write!(f, "{}", text) + write!(f, "{text}") } } +/// # Panics #[inline] -pub fn get_elements_from_path(path: String, all: bool) -> Vec { +#[must_use] +pub fn get_elements_from_path(path: &str, all: bool) -> Vec { fs::read_dir(path) - .unwrap() - .map(|e| Element::new(e.unwrap().path().to_str().unwrap())) + .unwrap_or_else(|e| panic!("Error reading directory {path}: {e}")) + .map(|e| Element::new(e.expect("Error").path().to_str().expect("Error"))) .filter(|element| all || !element.get_name().starts_with('.')) .collect() } -pub fn pad_string(s: String, pad: usize, after: bool) -> String { +#[must_use] +pub fn pad_string(s: &str, pad: usize, after: bool) -> String { let mut s2 = String::new(); - let s_length = get_string_length(&s); + let s_length = get_string_length(s); if after { - s2.push_str(s.as_str()); + s2.push_str(s); for _ in 0..(pad.saturating_sub(s_length)) { s2.push(' '); } @@ -45,7 +48,7 @@ pub fn pad_string(s: String, pad: usize, after: bool) -> String { for _ in 0..(pad.saturating_sub(s_length)) { s2.push(' '); } - s2.push_str(s.as_str()); + s2.push_str(s); } s2 } @@ -53,26 +56,30 @@ pub fn pad_string(s: String, pad: usize, after: bool) -> String { // Some characters like  counts for more than one // character when using .len() #[inline] +#[must_use] pub fn get_string_length(s: &str) -> usize { s.chars().count() } +/// # Panics +#[must_use] pub fn get_size_string(bytes: u64) -> String { if bytes == 0 { return String::from(" 0 B "); } - let bytes_f32 = bytes as f32; - let exp = bytes_f32.log(1024.0).floor(); - let divided_num = bytes_f32 / 1024.0_f32.powf(exp); + // let bytes_f32 = bytes as f32; + let exp = bytes.checked_ilog(1024).expect("Error"); + let divided_num = bytes / 1024_u64.pow(exp); let unit = ['B', 'K', 'M', 'G', 'T', 'P', 'Y', 'E'][exp as usize]; if unit == 'B' { - format!("{:.0} {} ", divided_num, unit) + format!("{divided_num:.0} {unit} ") } else { - format!("{:.2} {} ", divided_num, unit) + format!("{divided_num:.2} {unit} ") } } #[inline] +#[must_use] pub fn system_time_to_string(system_time: SystemTime) -> String { let datetime: DateTime = system_time.into(); datetime.format("%d-%m-%y %H:%M").to_string() @@ -87,9 +94,14 @@ pub fn sort_elements(elements: &mut [Element], sort_by: &SortBy) { } } -// ALL ICONS MUST BE FOLLOWED BY A SPACE -pub fn get_icon_file_type<'a>(filename: String) -> &'a str { - let extension = filename.split('.').next_back().unwrap(); +/// # Panics +#[must_use] +pub fn get_icon_file_type<'a>(filename: &str) -> &'a str { + // ALL ICONS MUST BE FOLLOWED BY A SPACE + let extension = filename + .split('.') + .next_back() + .expect("Error while sparating filename extension"); match extension.to_lowercase().as_str() { "jpg" | "jpeg" | "png" | "bmp" | "gif" | "webp" | "svg" => "󰋩 ", "zip" | "rar" | "7zip" | "tar" | "gz" | "tgz" => "󰗄 ",