Recursive
This commit is contained in:
@@ -6,9 +6,11 @@ use std::{
|
|||||||
time::SystemTime,
|
time::SystemTime,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// use clap::builder::styling::Metadata;
|
||||||
|
|
||||||
use crate::utils::get_icon_file_type;
|
use crate::utils::get_icon_file_type;
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||||
pub enum TypeOfFile {
|
pub enum TypeOfFile {
|
||||||
File,
|
File,
|
||||||
Dir,
|
Dir,
|
||||||
@@ -22,7 +24,7 @@ pub struct Element {
|
|||||||
path: String,
|
path: String,
|
||||||
file_type: TypeOfFile,
|
file_type: TypeOfFile,
|
||||||
name: String,
|
name: String,
|
||||||
perms: fs::Permissions,
|
perms: Option<fs::Permissions>,
|
||||||
size: u64,
|
size: u64,
|
||||||
creation: SystemTime,
|
creation: SystemTime,
|
||||||
}
|
}
|
||||||
@@ -31,7 +33,19 @@ impl Element {
|
|||||||
pub fn new(path_str: &str) -> Element {
|
pub fn new(path_str: &str) -> Element {
|
||||||
let path_built = Path::new(path_str);
|
let path_built = Path::new(path_str);
|
||||||
// println!("{:?}", path_built);
|
// println!("{:?}", path_built);
|
||||||
let metadata = fs::metadata(path_str).unwrap();
|
let metadata: fs::Metadata; // = fs::metadata(path_str).unwrap();
|
||||||
|
if let Result::Ok(m) = fs::metadata(path_str) {
|
||||||
|
metadata = m;
|
||||||
|
} else {
|
||||||
|
return Self {
|
||||||
|
path: path_str.to_string(),
|
||||||
|
file_type: TypeOfFile::File,
|
||||||
|
name: path_str.split('/').last().unwrap().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();
|
||||||
|
|
||||||
let t: TypeOfFile;
|
let t: TypeOfFile;
|
||||||
@@ -66,7 +80,7 @@ impl Element {
|
|||||||
path: path_str.to_string(),
|
path: path_str.to_string(),
|
||||||
file_type: t,
|
file_type: t,
|
||||||
name,
|
name,
|
||||||
perms: metadata.permissions(),
|
perms: Some(metadata.permissions()),
|
||||||
size: metadata.len(),
|
size: metadata.len(),
|
||||||
creation: metadata.created().unwrap(),
|
creation: metadata.created().unwrap(),
|
||||||
}
|
}
|
||||||
@@ -84,7 +98,7 @@ impl Element {
|
|||||||
self.name.clone()
|
self.name.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_perms(&self) -> fs::Permissions {
|
pub fn get_perms(&self) -> Option<fs::Permissions> {
|
||||||
self.perms.clone()
|
self.perms.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,15 +120,15 @@ impl Display for Element {
|
|||||||
TypeOfFile::File => file_icon,
|
TypeOfFile::File => file_icon,
|
||||||
TypeOfFile::Dir => {
|
TypeOfFile::Dir => {
|
||||||
is_dir = true;
|
is_dir = true;
|
||||||
" "
|
" "
|
||||||
}
|
}
|
||||||
TypeOfFile::Link => " ",
|
TypeOfFile::Link => " ",
|
||||||
TypeOfFile::Block => " ",
|
TypeOfFile::Block => " ",
|
||||||
TypeOfFile::Socket => " ",
|
TypeOfFile::Socket => " ",
|
||||||
};
|
};
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"{}{}{} ",
|
"{}{}{} ",
|
||||||
icon,
|
icon,
|
||||||
self.name.as_str(),
|
self.name.as_str(),
|
||||||
if is_dir { "/" } else { "" }
|
if is_dir { "/" } else { "" }
|
||||||
|
|||||||
20
src/main.rs
20
src/main.rs
@@ -1,9 +1,8 @@
|
|||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use lsplus::{
|
use lsplus::{
|
||||||
element::Element,
|
|
||||||
out::{default::default, list::list},
|
out::{default::default, list::list},
|
||||||
|
utils::get_elements_from_path,
|
||||||
};
|
};
|
||||||
use std::fs;
|
|
||||||
|
|
||||||
// Needs to be defined in main
|
// Needs to be defined in main
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
@@ -17,6 +16,9 @@ pub struct Args {
|
|||||||
#[arg(short, long, default_value_t = false)]
|
#[arg(short, long, default_value_t = false)]
|
||||||
list: bool,
|
list: bool,
|
||||||
|
|
||||||
|
#[arg(short, long, default_value_t = 0)]
|
||||||
|
recursive: usize,
|
||||||
|
|
||||||
/// Path of the directory to list
|
/// Path of the directory to list
|
||||||
#[arg(default_value_t = String::from("."))]
|
#[arg(default_value_t = String::from("."))]
|
||||||
path: String,
|
path: String,
|
||||||
@@ -25,17 +27,17 @@ pub struct Args {
|
|||||||
fn main() {
|
fn main() {
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
|
|
||||||
let paths = fs::read_dir(args.path).unwrap();
|
let elements = get_elements_from_path(args.path, args.all);
|
||||||
|
|
||||||
let _max_width = 50;
|
// let paths = fs::read_dir(args.path).unwrap();
|
||||||
|
|
||||||
let elements: Vec<Element> = paths
|
// let elements: Vec<Element> = paths
|
||||||
.map(|e| Element::new(e.unwrap().path().to_str().unwrap()))
|
// .map(|e| Element::new(e.unwrap().path().to_str().unwrap()))
|
||||||
.filter(|element| args.all || !element.get_name().starts_with('.'))
|
// .filter(|element| args.all || !element.get_name().starts_with('.'))
|
||||||
.collect();
|
// .collect();
|
||||||
|
|
||||||
if args.list {
|
if args.list {
|
||||||
list(elements);
|
list(elements, args.recursive);
|
||||||
} else {
|
} else {
|
||||||
default(elements);
|
default(elements);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ pub fn default(mut elements: Vec<Element>) {
|
|||||||
let mut max_len = 0;
|
let mut max_len = 0;
|
||||||
for k in 0..i {
|
for k in 0..i {
|
||||||
if i * j + k < elements.len() {
|
if i * j + k < elements.len() {
|
||||||
let space = get_string_length(&elements[i * j + k].to_string());
|
let space = get_string_length(&elements[i * j + k].to_string()) + 1;
|
||||||
if space > max_len {
|
if space > max_len {
|
||||||
max_len = space;
|
max_len = space;
|
||||||
}
|
}
|
||||||
@@ -39,7 +39,7 @@ pub fn default(mut elements: Vec<Element>) {
|
|||||||
for j in 0..num_columns {
|
for j in 0..num_columns {
|
||||||
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)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
152
src/out/list.rs
152
src/out/list.rs
@@ -1,19 +1,16 @@
|
|||||||
use crate::element::Element;
|
use crate::element::{Element, TypeOfFile};
|
||||||
use crate::utils::{get_size_string, get_string_length, pad_string, system_time_to_string};
|
use crate::utils::{
|
||||||
|
get_elements_from_path, get_size_string, get_string_length, pad_string, system_time_to_string,
|
||||||
|
};
|
||||||
|
|
||||||
pub fn list(mut elements: Vec<Element>) {
|
pub fn list(mut elements: Vec<Element>, recursive_limit: usize) {
|
||||||
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().unwrap().0;
|
||||||
// ╭──────────────╼ 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 mut name_max_len = 0;
|
|
||||||
for e in &elements {
|
let name_max_len = get_max_width(&elements, recursive_limit, 0);
|
||||||
let length = get_string_length(e.to_string().as_str());
|
|
||||||
if length > name_max_len {
|
|
||||||
name_max_len = length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let name_length = name_max_len
|
let name_length = name_max_len
|
||||||
.max(14 + (elements.len() as f32).log10() as usize)
|
.max(14 + (elements.len() as f32).log10() as usize)
|
||||||
@@ -21,41 +18,69 @@ pub fn list(mut elements: Vec<Element>) {
|
|||||||
.min(width - 30);
|
.min(width - 30);
|
||||||
|
|
||||||
print_header(name_length);
|
print_header(name_length);
|
||||||
print_elements(&elements, name_length);
|
print_elements(&elements, name_length, recursive_limit, 0, &Vec::new());
|
||||||
print_footer(&elements, name_length);
|
print_footer(&elements, name_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_header(name_length: usize) {
|
fn print_header(name_length: usize) {
|
||||||
print!("╭");
|
print!("╭");
|
||||||
for _ in 0..((name_length - 13) as f32 / 2.0).floor() as usize {
|
for _ in 0..((name_length - 12) as f32 / 2.0).floor() as usize {
|
||||||
print!("─");
|
print!("─");
|
||||||
}
|
}
|
||||||
print!("╼ File name ╾");
|
print!("╼ File name ╾");
|
||||||
for _ in 0..((name_length - 13) as f32 / 2.0).ceil() as usize {
|
for _ in 0..((name_length - 12) as f32 / 2.0).ceil() as usize {
|
||||||
print!("─");
|
print!("─");
|
||||||
}
|
}
|
||||||
println!("┬─╼ Size ╾─┬──╼ Creation ╾──╮");
|
println!("┬─╼ Size ╾─┬──╼ Creation ╾──╮");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_elements(elements: &Vec<Element>, name_length: usize) {
|
fn print_elements(
|
||||||
for e in elements {
|
elements: &Vec<Element>,
|
||||||
|
name_length: usize,
|
||||||
|
recursive_limit: usize,
|
||||||
|
current_depth: usize,
|
||||||
|
is_last_element: &[bool],
|
||||||
|
) {
|
||||||
|
let mut new_is_last_element = is_last_element.to_owned();
|
||||||
|
|
||||||
|
// println!("{:?}", is_last_element);
|
||||||
|
|
||||||
|
for (i, e) in elements.iter().enumerate() {
|
||||||
let str_len = get_string_length(e.get_name().as_str());
|
let str_len = get_string_length(e.get_name().as_str());
|
||||||
print!("│");
|
print!("│ ");
|
||||||
if get_string_length(e.to_string().as_str()) > name_length {
|
if get_string_length(e.to_string().as_str()) > name_length {
|
||||||
|
let mut e_string = String::new();
|
||||||
|
if current_depth > 0 {
|
||||||
|
for &is_last in &new_is_last_element[1..] {
|
||||||
|
if is_last {
|
||||||
|
e_string.push_str(" ");
|
||||||
|
} else {
|
||||||
|
e_string.push_str("│ ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if i == elements.len() - 1 {
|
||||||
|
e_string.push_str("╰─");
|
||||||
|
} else {
|
||||||
|
e_string.push_str("├─");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
e_string.push_str(e.to_string().as_str());
|
||||||
print!(
|
print!(
|
||||||
"{}",
|
"{}",
|
||||||
pad_string(
|
pad_string(
|
||||||
e.to_string().as_str()[..=name_length].to_string(),
|
e_string.as_str()[..=name_length].to_string(),
|
||||||
name_length,
|
name_length - 2,
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
print!("│");
|
print_size_and_creation_date(e);
|
||||||
print!("{}", pad_string(get_size_string(e.get_size()), 10, false));
|
let mut e_name = String::new();
|
||||||
print!("│");
|
if current_depth > 0 {
|
||||||
print!(" {} ", system_time_to_string(e.get_creation()));
|
for _ in 0..current_depth {
|
||||||
println!("│");
|
e_name.push_str(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
e_name.push_str(e.get_name().as_str());
|
||||||
for i in 1..(str_len / (name_length - 5) + 1) {
|
for i in 1..(str_len / (name_length - 5) + 1) {
|
||||||
print!(
|
print!(
|
||||||
"│ {}",
|
"│ {}",
|
||||||
@@ -71,20 +96,59 @@ fn print_elements(elements: &Vec<Element>, name_length: usize) {
|
|||||||
println!("│ │ │");
|
println!("│ │ │");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
print!("{}", pad_string(e.to_string(), name_length, true));
|
let mut e_string = String::new();
|
||||||
print!("│");
|
if current_depth > 0 {
|
||||||
print!("{}", pad_string(get_size_string(e.get_size()), 10, false));
|
for &is_last in &new_is_last_element[1..] {
|
||||||
print!("│");
|
if is_last {
|
||||||
print!(" {} ", system_time_to_string(e.get_creation()));
|
e_string.push_str(" ");
|
||||||
println!("│");
|
} else {
|
||||||
|
e_string.push_str("│ ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if i == elements.len() - 1 {
|
||||||
|
e_string.push_str("╰─");
|
||||||
|
} else {
|
||||||
|
e_string.push_str("├─");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
e_string.push_str(e.to_string().as_str());
|
||||||
|
print!("{}", pad_string(e_string, name_length, true));
|
||||||
|
print_size_and_creation_date(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
if e.get_file_type() == TypeOfFile::Dir && current_depth < recursive_limit {
|
||||||
|
let dir_path = e.get_path_string();
|
||||||
|
new_is_last_element.push(i == elements.len() - 1);
|
||||||
|
print_elements(
|
||||||
|
&get_elements_from_path(dir_path, true),
|
||||||
|
name_length,
|
||||||
|
recursive_limit,
|
||||||
|
current_depth + 1,
|
||||||
|
&new_is_last_element,
|
||||||
|
);
|
||||||
|
new_is_last_element.pop();
|
||||||
|
// println!("{:?}", is_last_element);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn print_size_and_creation_date(e: &Element) {
|
||||||
|
print!("│");
|
||||||
|
if e.get_file_type() == TypeOfFile::Dir {
|
||||||
|
print!(" ");
|
||||||
|
} else {
|
||||||
|
print!("{}", pad_string(get_size_string(e.get_size()), 10, false));
|
||||||
|
}
|
||||||
|
print!("│");
|
||||||
|
print!(" {} ", system_time_to_string(e.get_creation()));
|
||||||
|
println!("│");
|
||||||
|
}
|
||||||
|
|
||||||
fn print_footer(elements: &Vec<Element>, name_length: usize) {
|
fn print_footer(elements: &Vec<Element>, name_length: usize) {
|
||||||
let num_elements = elements.len();
|
let num_elements = elements.len();
|
||||||
let num_elements_len = (num_elements as f32).log10() as usize;
|
let num_elements_len = (num_elements as f32).log10() as usize;
|
||||||
let name_length_fixed = name_length - (num_elements_len + 14);
|
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) as f32 / 2.0).floor() as usize {
|
||||||
print!("─");
|
print!("─");
|
||||||
@@ -93,8 +157,28 @@ fn print_footer(elements: &Vec<Element>, name_length: usize) {
|
|||||||
for _ in 0..((name_length_fixed) as f32 / 2.0).ceil() as usize {
|
for _ in 0..((name_length_fixed) as f32 / 2.0).ceil() as usize {
|
||||||
print!("─");
|
print!("─");
|
||||||
}
|
}
|
||||||
// for _ in 0..(name_length - (num_elements_len + 15)) {
|
|
||||||
// print!("─");
|
|
||||||
// }
|
|
||||||
println!("┴──────────┴────────────────╯");
|
println!("┴──────────┴────────────────╯");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_max_width(elements: &Vec<Element>, recursive_limit: usize, current_depth: usize) -> usize {
|
||||||
|
let mut name_max_len = 0;
|
||||||
|
for e in elements {
|
||||||
|
let mut length = get_string_length(e.to_string().as_str()) + 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),
|
||||||
|
recursive_limit,
|
||||||
|
current_depth + 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
if recursive_width > length {
|
||||||
|
length = recursive_width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if length > name_max_len {
|
||||||
|
name_max_len = length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
name_max_len
|
||||||
|
}
|
||||||
|
|||||||
45
src/utils.rs
45
src/utils.rs
@@ -1,10 +1,23 @@
|
|||||||
|
use std::fs;
|
||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
|
|
||||||
use chrono::offset::Utc;
|
use chrono::offset::Utc;
|
||||||
use chrono::DateTime;
|
use chrono::DateTime;
|
||||||
|
|
||||||
|
use crate::element::Element;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_elements_from_path(path: String, all: bool) -> Vec<Element> {
|
||||||
|
fs::read_dir(path)
|
||||||
|
.unwrap()
|
||||||
|
.map(|e| Element::new(e.unwrap().path().to_str().unwrap()))
|
||||||
|
.filter(|element| all || !element.get_name().starts_with('.'))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn pad_string(s: String, pad: usize, after: bool) -> String {
|
pub fn pad_string(s: String, pad: usize, after: bool) -> String {
|
||||||
let mut s2 = String::new();
|
let mut s2 = String::new();
|
||||||
|
// println!("{}, {}", s.len(), pad);
|
||||||
if after {
|
if after {
|
||||||
s2.push_str(s.as_str());
|
s2.push_str(s.as_str());
|
||||||
for _ in 0..(pad - get_string_length(&s)) {
|
for _ in 0..(pad - get_string_length(&s)) {
|
||||||
@@ -47,21 +60,21 @@ pub fn system_time_to_string(system_time: SystemTime) -> String {
|
|||||||
pub fn get_icon_file_type<'a>(filename: String) -> &'a str {
|
pub fn get_icon_file_type<'a>(filename: String) -> &'a str {
|
||||||
let extension = filename.split('.').collect::<Vec<&str>>()[1..].join(".");
|
let extension = filename.split('.').collect::<Vec<&str>>()[1..].join(".");
|
||||||
match extension.to_lowercase().as_str() {
|
match extension.to_lowercase().as_str() {
|
||||||
"zip" | "rar" | "7zip" | "tar" | "tar.gz" | "tgz" => " ",
|
"zip" | "rar" | "7zip" | "tar" | "tar.gz" | "tgz" => " ",
|
||||||
"rs" => " ",
|
"rs" => " ",
|
||||||
"jpg" | "jpeg" | "png" | "bmp" | "gif" | "webp" | "svg" => " ",
|
"jpg" | "jpeg" | "png" | "bmp" | "gif" | "webp" | "svg" => " ",
|
||||||
"flv" | "avi" | "mp4" | "webm" | "mov" => " ",
|
"flv" | "avi" | "mp4" | "webm" | "mov" => " ",
|
||||||
"exe" | "ini" | "bat" => " ",
|
"exe" | "ini" | "bat" => " ",
|
||||||
"py" => " ",
|
"py" => " ",
|
||||||
"c" => " ",
|
"c" => " ",
|
||||||
"cpp" => " ",
|
"cpp" => " ",
|
||||||
"json" => " ",
|
"json" => " ",
|
||||||
"pdf" => " ",
|
"pdf" => " ",
|
||||||
"java" | "jar" => " ",
|
"java" | "jar" => " ",
|
||||||
"js" => " ",
|
"js" => " ",
|
||||||
"html" => " ",
|
"html" => " ",
|
||||||
"css" => " ",
|
"css" => " ",
|
||||||
"csv" => " ",
|
"csv" => " ",
|
||||||
_ => " ",
|
_ => " ",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
0
test/dir/another_dir/deepest_secret.txt
Normal file
0
test/dir/another_dir/deepest_secret.txt
Normal file
0
test/dir/more_dirs/definetly_not_porn.zip
Normal file
0
test/dir/more_dirs/definetly_not_porn.zip
Normal file
0
test/dir/more_dirs/noodles.jpg
Normal file
0
test/dir/more_dirs/noodles.jpg
Normal file
0
test/dir/something_inside.txt
Normal file
0
test/dir/something_inside.txt
Normal file
Reference in New Issue
Block a user