Some refactoring and improvements for clippy

This commit is contained in:
Guilleag01
2026-03-21 14:26:19 +01:00
parent a4cf1c1973
commit 33bb9d86b7
6 changed files with 116 additions and 79 deletions

View File

@@ -28,7 +28,9 @@ pub struct Element {
} }
impl 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 path_built = Path::new(path_str);
let metadata: fs::Metadata; let metadata: fs::Metadata;
if let Result::Ok(m) = fs::metadata(path_str) { if let Result::Ok(m) = fs::metadata(path_str) {
@@ -37,13 +39,18 @@ impl Element {
return Self { return Self {
path: path_str.to_string(), path: path_str.to_string(),
file_type: TypeOfFile::File, 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, perms: None,
size: 0, size: 0,
creation: SystemTime::UNIX_EPOCH, 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; let t: TypeOfFile;
@@ -63,14 +70,19 @@ impl Element {
let mut name = path_built let mut name = path_built
.file_name() .file_name()
.unwrap() .expect("Error getting os string from path")
.to_str() .to_str()
.unwrap() .expect("Error ")
.to_string(); .to_string();
if symlink_metadata.is_symlink() { if symlink_metadata.is_symlink() {
name.push_str(" -> "); 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 { let s = if t == TypeOfFile::Dir {
@@ -79,44 +91,52 @@ impl Element {
metadata.len() metadata.len()
}; };
let now = SystemTime::now();
Self { Self {
path: path_str.to_string(), path: path_str.to_string(),
file_type: t, file_type: t,
name, name,
perms: Some(metadata.permissions()), perms: Some(metadata.permissions()),
size: s, size: s,
creation: metadata.created().unwrap_or(SystemTime::now()), creation: metadata.created().unwrap_or(now),
} }
} }
#[must_use]
pub fn get_path_string(&self) -> String { pub fn get_path_string(&self) -> String {
self.path.clone() self.path.clone()
} }
pub fn get_file_type(&self) -> TypeOfFile { #[must_use]
pub const fn get_file_type(&self) -> TypeOfFile {
self.file_type self.file_type
} }
#[must_use]
pub fn get_name(&self) -> String { pub fn get_name(&self) -> String {
self.name.clone() self.name.clone()
} }
#[must_use]
pub fn get_perms(&self) -> Option<fs::Permissions> { pub fn get_perms(&self) -> Option<fs::Permissions> {
self.perms.clone() self.perms.clone()
} }
pub fn get_size(&self) -> u64 { #[must_use]
pub const fn get_size(&self) -> u64 {
self.size self.size
} }
pub fn get_creation(&self) -> SystemTime { #[must_use]
pub const fn get_creation(&self) -> SystemTime {
self.creation self.creation
} }
} }
impl Display for Element { impl Display for Element {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 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 mut is_dir = false;
let icon = match self.file_type { let icon = match self.file_type {

View File

@@ -1,3 +1,7 @@
#![warn(clippy::pedantic)]
#![warn(clippy::nursery)]
#![deny(clippy::unwrap_used)]
pub mod config; pub mod config;
pub mod element; pub mod element;
pub mod out; pub mod out;

View File

@@ -1,4 +1,3 @@
#![warn(clippy::pedantic)]
use clap::Parser; use clap::Parser;
use lsplus::{ use lsplus::{
out::{default::default, list::list}, out::{default::default, list::list},
@@ -32,12 +31,17 @@ pub struct Args {
} }
fn main() { 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 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 { if args.list {
list(elements, args.recursive, args.sort); list(elements, args.recursive, &args.sort);
} else { } else {
default(elements); default(elements);
} }

View File

@@ -1,10 +1,13 @@
use crate::element::Element; use crate::element::Element;
use crate::utils::{get_string_length, pad_string}; use crate::utils::{get_string_length, pad_string};
/// # Panics
pub fn default(mut elements: Vec<Element>) { pub fn default(mut elements: Vec<Element>) {
elements.sort_unstable_by_key(|a: &Element| a.get_name()); 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; let mut i = 1;
@@ -14,7 +17,7 @@ pub fn default(mut elements: Vec<Element>) {
let mut total = usize::MAX; let mut total = usize::MAX;
while total >= width - 1 { while total >= width - 1 {
total = 0; 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]; column_widths = vec![0; num_columns];
for j in 0..num_columns { for j in 0..num_columns {
let mut max_len = 0; let mut max_len = 0;
@@ -43,7 +46,7 @@ pub fn default(mut elements: Vec<Element>) {
if i * j + k < elements.len() { if i * j + k < elements.len() {
print!( 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)
); );
} }
} }

View File

@@ -4,16 +4,25 @@ use crate::utils::{
system_time_to_string, SortBy, system_time_to_string, SortBy,
}; };
pub fn list(mut elements: Vec<Element>, recursive_limit: usize, sort_by: SortBy) { /// # Panics
pub fn list(mut elements: Vec<Element>, recursive_limit: usize, sort_by: &SortBy) {
// ╭──────────────╼ File name ╾──────────────┬─╼ Size ╾─┬──╼ Creation ╾──╮ // ╭──────────────╼ File name ╾──────────────┬─╼ Size ╾─┬──╼ Creation ╾──╮
// │ some_example_file │ 420.69 G │ 01-01-70 00:00 │ // │ 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); 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 let name_length = name_max_len
.max(14 + (elements.len() as f32).log10() as usize) .max(14_usize + elements_len as usize)
.max(13) .max(13)
.min(width - 31); .min(width - 31);
@@ -24,18 +33,18 @@ pub fn list(mut elements: Vec<Element>, recursive_limit: usize, sort_by: SortBy)
recursive_limit, recursive_limit,
0, 0,
&Vec::new(), &Vec::new(),
&sort_by, sort_by,
); );
print_footer(num_elements, name_length); print_footer(num_elements, name_length);
} }
fn print_header(name_length: usize) { fn print_header(name_length: usize) {
print!(""); print!("");
for _ in 0..((name_length - 12) as f32 / 2.0).floor() as usize { for _ in 0..((name_length - 12) / 2) {
print!(""); print!("");
} }
print!("╼ File name ╾"); 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!(""); print!("");
} }
println!("┬─╼ Size ╾─┬──╼ Creation ╾──╮"); println!("┬─╼ Size ╾─┬──╼ Creation ╾──╮");
@@ -71,35 +80,19 @@ fn print_elements(
e_string.push_str(e.to_string().as_str()); e_string.push_str(e.to_string().as_str());
let file_text = pad_string( 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, name_length,
true, true,
); );
print!( print!("{file_text}");
"{}",
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_size_and_creation_date(e); print_size_and_creation_date(e);
let num_splits = let num_splits =
get_string_length(e.get_name().as_str()) / (name_length - (2 + 2 * current_depth)); 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(""); let mut e_name = String::from("");
if current_depth > 0 { if current_depth > 0 {
add_recursive_lines( add_recursive_lines(
@@ -108,19 +101,16 @@ fn print_elements(
i == elements.len() - 1, i == elements.len() - 1,
" ", " ",
"", "",
) );
} }
e_name.push_str(" "); e_name.push_str(" ");
e_name.push_str( e_name.push_str(&get_slice_of_string(
get_slice_of_string(
e.get_name().as_str(), e.get_name().as_str(),
name_length - (3 + 2 * current_depth), name_length - (3 + 2 * current_depth),
j, j,
current_depth, current_depth,
) ));
.as_str(), print!("{}", pad_string(&e_name, name_length + 2, true));
);
print!("{}", pad_string(e_name, name_length + 2, true));
// text.push_str(pad_string(e_name, name_length + 2, true).as_str()); // text.push_str(pad_string(e_name, name_length + 2, true).as_str());
println!("│ │ │"); println!("│ │ │");
// text.push_str("│ │ │\n"); // text.push_str("│ │ │\n");
@@ -130,7 +120,7 @@ fn print_elements(
let dir_path = e.get_path_string(); let dir_path = e.get_path_string();
new_is_last_element.push(i == elements.len() - 1); new_is_last_element.push(i == elements.len() - 1);
num_elements += print_elements( num_elements += print_elements(
&mut get_elements_from_path(dir_path, true), &mut get_elements_from_path(&dir_path, true),
name_length, name_length,
recursive_limit, recursive_limit,
current_depth + 1, current_depth + 1,
@@ -167,9 +157,13 @@ fn add_recursive_lines(
#[inline] #[inline]
fn get_slice_of_string(e: &str, name_length: usize, i: usize, _current_depth: usize) -> String { fn get_slice_of_string(e: &str, name_length: usize, i: usize, _current_depth: usize) -> String {
e.chars().collect::<Vec<char>>()[((name_length) * i).min(get_string_length(e)) // e.chars().collect::<Vec<char>>()[((name_length) * i).min(get_string_length(e))
..((name_length) * (i + 1)).min(get_string_length(e))] // ..((name_length) * (i + 1)).min(get_string_length(e))]
.iter() // .iter()
// .collect()
e.chars()
.skip(((name_length) * i).min(get_string_length(e)))
.take(((name_length) * (i + 1)).min(get_string_length(e)))
.collect() .collect()
} }
@@ -178,7 +172,7 @@ fn print_size_and_creation_date(e: &Element) {
if e.get_file_type() == TypeOfFile::Dir { if e.get_file_type() == TypeOfFile::Dir {
print!(" "); print!(" ");
} else { } 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!("");
print!(" {} ", system_time_to_string(e.get_creation())); 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) { 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); let name_length_fixed = name_length - (num_elements_len + 13);
print!(""); print!("");
for _ in 0..((name_length_fixed) as f32 / 2.0).floor() as usize { for _ in 0..((name_length_fixed) / 2) {
print!(""); print!("");
} }
print!("{} Elements", num_elements); print!("{num_elements} Elements");
for _ in 0..((name_length_fixed) as f32 / 2.0).ceil() as usize { for _ in 0..usize::midpoint(name_length_fixed, name_length_fixed % 2) {
print!(""); print!("");
} }
println!("┴──────────┴────────────────╯"); println!("┴──────────┴────────────────╯");
@@ -205,7 +199,7 @@ fn get_max_width(elements: &Vec<Element>, recursive_limit: usize, current_depth:
let mut length = e.to_string().chars().count() + current_depth * 2; let mut length = e.to_string().chars().count() + current_depth * 2;
if e.get_file_type() == TypeOfFile::Dir && current_depth < recursive_limit { if e.get_file_type() == TypeOfFile::Dir && current_depth < recursive_limit {
let recursive_width = get_max_width( 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, recursive_limit,
current_depth + 1, current_depth + 1,
); );

View File

@@ -20,24 +20,27 @@ impl Display for SortBy {
Self::SIZE => "size", Self::SIZE => "size",
Self::CREATION => "creation", Self::CREATION => "creation",
}; };
write!(f, "{}", text) write!(f, "{text}")
} }
} }
/// # Panics
#[inline] #[inline]
pub fn get_elements_from_path(path: String, all: bool) -> Vec<Element> { #[must_use]
pub fn get_elements_from_path(path: &str, all: bool) -> Vec<Element> {
fs::read_dir(path) fs::read_dir(path)
.unwrap() .unwrap_or_else(|e| panic!("Error reading directory {path}: {e}"))
.map(|e| Element::new(e.unwrap().path().to_str().unwrap())) .map(|e| Element::new(e.expect("Error").path().to_str().expect("Error")))
.filter(|element| all || !element.get_name().starts_with('.')) .filter(|element| all || !element.get_name().starts_with('.'))
.collect() .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 mut s2 = String::new();
let s_length = get_string_length(&s); let s_length = get_string_length(s);
if after { if after {
s2.push_str(s.as_str()); s2.push_str(s);
for _ in 0..(pad.saturating_sub(s_length)) { for _ in 0..(pad.saturating_sub(s_length)) {
s2.push(' '); 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)) { for _ in 0..(pad.saturating_sub(s_length)) {
s2.push(' '); s2.push(' ');
} }
s2.push_str(s.as_str()); s2.push_str(s);
} }
s2 s2
} }
@@ -53,26 +56,30 @@ pub fn pad_string(s: String, pad: usize, after: bool) -> String {
// Some characters like  counts for more than one // Some characters like  counts for more than one
// character when using .len() // character when using .len()
#[inline] #[inline]
#[must_use]
pub fn get_string_length(s: &str) -> usize { pub fn get_string_length(s: &str) -> usize {
s.chars().count() s.chars().count()
} }
/// # Panics
#[must_use]
pub fn get_size_string(bytes: u64) -> String { pub fn get_size_string(bytes: u64) -> String {
if bytes == 0 { if bytes == 0 {
return String::from(" 0 B "); return String::from(" 0 B ");
} }
let bytes_f32 = bytes as f32; // let bytes_f32 = bytes as f32;
let exp = bytes_f32.log(1024.0).floor(); let exp = bytes.checked_ilog(1024).expect("Error");
let divided_num = bytes_f32 / 1024.0_f32.powf(exp); let divided_num = bytes / 1024_u64.pow(exp);
let unit = ['B', 'K', 'M', 'G', 'T', 'P', 'Y', 'E'][exp as usize]; let unit = ['B', 'K', 'M', 'G', 'T', 'P', 'Y', 'E'][exp as usize];
if unit == 'B' { if unit == 'B' {
format!("{:.0} {} ", divided_num, unit) format!("{divided_num:.0} {unit} ")
} else { } else {
format!("{:.2} {} ", divided_num, unit) format!("{divided_num:.2} {unit} ")
} }
} }
#[inline] #[inline]
#[must_use]
pub fn system_time_to_string(system_time: SystemTime) -> String { pub fn system_time_to_string(system_time: SystemTime) -> String {
let datetime: DateTime<Utc> = system_time.into(); let datetime: DateTime<Utc> = system_time.into();
datetime.format("%d-%m-%y %H:%M").to_string() datetime.format("%d-%m-%y %H:%M").to_string()
@@ -87,9 +94,14 @@ pub fn sort_elements(elements: &mut [Element], sort_by: &SortBy) {
} }
} }
/// # Panics
#[must_use]
pub fn get_icon_file_type<'a>(filename: &str) -> &'a str {
// ALL ICONS MUST BE FOLLOWED BY A SPACE // ALL ICONS MUST BE FOLLOWED BY A SPACE
pub fn get_icon_file_type<'a>(filename: String) -> &'a str { let extension = filename
let extension = filename.split('.').next_back().unwrap(); .split('.')
.next_back()
.expect("Error while sparating filename extension");
match extension.to_lowercase().as_str() { match extension.to_lowercase().as_str() {
"jpg" | "jpeg" | "png" | "bmp" | "gif" | "webp" | "svg" => "󰋩 ", "jpg" | "jpeg" | "png" | "bmp" | "gif" | "webp" | "svg" => "󰋩 ",
"zip" | "rar" | "7zip" | "tar" | "gz" | "tgz" => "󰗄 ", "zip" | "rar" | "7zip" | "tar" | "gz" | "tgz" => "󰗄 ",