mirror of
https://github.com/lsd-rs/lsd
synced 2024-09-20 14:22:01 +00:00
Change a lot of stuff
This is a shitty comment, I know...
This commit is contained in:
parent
3dc1689e65
commit
4b9568510c
7 changed files with 382 additions and 220 deletions
26
Cargo.lock
generated
26
Cargo.lock
generated
|
@ -52,9 +52,16 @@ dependencies = [
|
||||||
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"size 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
"time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"users 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.2.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.1.40"
|
version = "0.1.40"
|
||||||
|
@ -68,6 +75,14 @@ dependencies = [
|
||||||
"redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
"redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "size"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
|
@ -106,6 +121,14 @@ name = "unicode-width"
|
||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "users"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vec_map"
|
name = "vec_map"
|
||||||
version = "0.8.1"
|
version = "0.8.1"
|
||||||
|
@ -137,13 +160,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e"
|
"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e"
|
||||||
"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1"
|
"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1"
|
||||||
"checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d"
|
"checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d"
|
||||||
|
"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"
|
||||||
"checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1"
|
"checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1"
|
||||||
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
|
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
|
||||||
|
"checksum size 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "baf1794b187cb1fd42cbe074cafc027be10b275c68aa7d039dcbef41e94d01d4"
|
||||||
"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
|
"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
|
||||||
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
|
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
|
||||||
"checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6"
|
"checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6"
|
||||||
"checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b"
|
"checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b"
|
||||||
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
|
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
|
||||||
|
"checksum users 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb3c80625ae5e77e1b402f8a0fa89afbd50622a6cae65128844720bd4e26b657"
|
||||||
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
|
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
|
||||||
"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
|
"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
|
||||||
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||||
|
|
|
@ -7,4 +7,6 @@ version = "0.1.0"
|
||||||
ansi_term = "0.11.0"
|
ansi_term = "0.11.0"
|
||||||
clap = "2.32.0"
|
clap = "2.32.0"
|
||||||
lazy_static = "1.2.0"
|
lazy_static = "1.2.0"
|
||||||
|
size = "0.1.1"
|
||||||
time = "0.1.40"
|
time = "0.1.40"
|
||||||
|
users = "0.8.0"
|
||||||
|
|
206
src/core.rs
Normal file
206
src/core.rs
Normal file
|
@ -0,0 +1,206 @@
|
||||||
|
use formatter::*;
|
||||||
|
use size::*;
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
use std::fs::{read_link, Metadata};
|
||||||
|
use std::os::unix::fs::MetadataExt;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
use users::{get_group_by_gid, get_user_by_uid};
|
||||||
|
use Options;
|
||||||
|
|
||||||
|
pub struct Core<'a> {
|
||||||
|
formatter: Formatter,
|
||||||
|
options: &'a Options,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Meta {
|
||||||
|
pub path: PathBuf,
|
||||||
|
pub metadata: Metadata,
|
||||||
|
pub group: String,
|
||||||
|
pub user: String,
|
||||||
|
pub symlink: Option<String>,
|
||||||
|
pub size_value: String,
|
||||||
|
pub size_unit: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Core<'a> {
|
||||||
|
pub fn new(options: &'a Options) -> Core<'a> {
|
||||||
|
Core {
|
||||||
|
options: options,
|
||||||
|
formatter: Formatter::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn print(&self, inputs: Vec<&str>) {
|
||||||
|
let print_folder_name: bool = inputs.len() > 1;
|
||||||
|
|
||||||
|
let mut dirs = Vec::new();
|
||||||
|
let mut files = Vec::new();
|
||||||
|
|
||||||
|
for input in inputs {
|
||||||
|
let path = Path::new(input);
|
||||||
|
|
||||||
|
if path.is_dir() {
|
||||||
|
dirs.push(path);
|
||||||
|
} else {
|
||||||
|
files.push(self.path_to_meta(&path).unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
files.sort_unstable_by(sort_by_meta);
|
||||||
|
dirs.sort_unstable();
|
||||||
|
|
||||||
|
if files.len() > 0 {
|
||||||
|
self.print_long(&mut files);
|
||||||
|
}
|
||||||
|
|
||||||
|
for dir in dirs {
|
||||||
|
let folder_metas = self.list_folder_content(dir);
|
||||||
|
if print_folder_name {
|
||||||
|
println!("\n{}:", dir.display())
|
||||||
|
}
|
||||||
|
self.print_long(&folder_metas);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn list_folder_content(&self, folder: &Path) -> Vec<Meta> {
|
||||||
|
let mut content: Vec<Meta> = Vec::new();
|
||||||
|
|
||||||
|
for entry in folder.read_dir().expect("read_dir call failed") {
|
||||||
|
if let Ok(entry) = entry {
|
||||||
|
if let Some(meta) = self.path_to_meta(entry.path().as_path()) {
|
||||||
|
content.push(meta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
content.sort_unstable_by(sort_by_meta);
|
||||||
|
|
||||||
|
content
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn path_to_meta(&self, path: &Path) -> Option<Meta> {
|
||||||
|
let mut name: Option<&str> = None;
|
||||||
|
if let Some(os_str_name) = path.file_name() {
|
||||||
|
if let Some(name_str) = os_str_name.to_str() {
|
||||||
|
name = Some(name_str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if name.is_none() {
|
||||||
|
println!("failed to retrieve file name for {}", path.display());
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip the hidden files if the 'display_all' option is not set.
|
||||||
|
if name.unwrap().starts_with(".") && !self.options.display_all {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let meta;
|
||||||
|
let mut symlink = None;
|
||||||
|
if let Ok(res) = read_link(path) {
|
||||||
|
meta = path.symlink_metadata().unwrap();
|
||||||
|
symlink = Some(res.to_str().unwrap().to_string());
|
||||||
|
} else {
|
||||||
|
meta = path.metadata().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let user = get_user_by_uid(meta.uid())
|
||||||
|
.unwrap()
|
||||||
|
.name()
|
||||||
|
.to_str()
|
||||||
|
.unwrap()
|
||||||
|
.to_string();
|
||||||
|
|
||||||
|
let group = get_group_by_gid(meta.gid())
|
||||||
|
.unwrap()
|
||||||
|
.name()
|
||||||
|
.to_str()
|
||||||
|
.unwrap()
|
||||||
|
.to_string();
|
||||||
|
|
||||||
|
let size = Size::Bytes(meta.len()).to_string(Base::Base10, Style::Abbreviated);
|
||||||
|
let size_parts: Vec<&str> = size.split(' ').collect();
|
||||||
|
|
||||||
|
Some(Meta {
|
||||||
|
path: path.to_path_buf(),
|
||||||
|
metadata: meta,
|
||||||
|
user: user,
|
||||||
|
group: group,
|
||||||
|
symlink: symlink,
|
||||||
|
size_value: size_parts[0].to_string(),
|
||||||
|
size_unit: size_parts[1].to_string(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_long(&self, metas: &Vec<Meta>) {
|
||||||
|
let max_user_length = self.detect_user_lenght(metas);
|
||||||
|
let max_group_length = self.detect_group_lenght(metas);
|
||||||
|
let (max_size_value_length, max_size_unit_length) = self.detect_size_lenghts(metas);
|
||||||
|
|
||||||
|
for meta in metas {
|
||||||
|
print!(
|
||||||
|
" {} {} {} {} {} {}\n",
|
||||||
|
self.formatter.format_permissions(&meta),
|
||||||
|
self.formatter.format_user(&meta.user, max_user_length),
|
||||||
|
self.formatter.format_group(&meta.group, max_group_length),
|
||||||
|
self.formatter
|
||||||
|
.format_size(&meta, max_size_value_length, max_size_unit_length),
|
||||||
|
self.formatter.format_date(&meta),
|
||||||
|
self.formatter.format_name(&meta),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn detect_user_lenght(&self, paths: &Vec<Meta>) -> usize {
|
||||||
|
let mut max: usize = 0;
|
||||||
|
|
||||||
|
for path in paths {
|
||||||
|
if path.user.len() > max {
|
||||||
|
max = path.user.len();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
max
|
||||||
|
}
|
||||||
|
|
||||||
|
fn detect_group_lenght(&self, paths: &Vec<Meta>) -> usize {
|
||||||
|
let mut max: usize = 0;
|
||||||
|
|
||||||
|
for path in paths {
|
||||||
|
if path.group.len() > max {
|
||||||
|
max = path.group.len();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
max
|
||||||
|
}
|
||||||
|
|
||||||
|
fn detect_size_lenghts(&self, paths: &Vec<Meta>) -> (usize, usize) {
|
||||||
|
let mut max_value_length: usize = 0;
|
||||||
|
let mut max_unit_size: usize = 0;
|
||||||
|
|
||||||
|
for path in paths {
|
||||||
|
if path.size_value.len() > max_value_length {
|
||||||
|
max_value_length = path.size_value.len();
|
||||||
|
}
|
||||||
|
|
||||||
|
if path.size_unit.len() > max_unit_size {
|
||||||
|
max_unit_size = path.size_unit.len();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(max_value_length, max_unit_size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sort_by_meta(a: &Meta, b: &Meta) -> Ordering {
|
||||||
|
if a.path.is_dir() == b.path.is_dir() {
|
||||||
|
a.path.cmp(&b.path)
|
||||||
|
} else if a.path.is_dir() && b.path.is_file() {
|
||||||
|
Ordering::Less
|
||||||
|
} else {
|
||||||
|
Ordering::Greater
|
||||||
|
}
|
||||||
|
}
|
223
src/formatter.rs
223
src/formatter.rs
|
@ -1,5 +1,5 @@
|
||||||
use ansi_term::Colour;
|
use ansi_term::Colour;
|
||||||
use path_lister::Path;
|
use core::Meta;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::os::unix::fs::PermissionsExt;
|
use std::os::unix::fs::PermissionsExt;
|
||||||
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||||
|
@ -8,70 +8,72 @@ use time::Timespec;
|
||||||
const HOURE: u64 = 3600; // 1 HOURE == 3600 seconds
|
const HOURE: u64 = 3600; // 1 HOURE == 3600 seconds
|
||||||
const DAY: u64 = HOURE * 24; // 1 DAY == 25 HOURE
|
const DAY: u64 = HOURE * 24; // 1 DAY == 25 HOURE
|
||||||
|
|
||||||
#[derive(Hash, Debug, Eq, PartialEq, Copy, Clone)]
|
|
||||||
pub enum PathKind {
|
|
||||||
UnrecognizedFile,
|
|
||||||
RecognizedFile,
|
|
||||||
Dir,
|
|
||||||
}
|
|
||||||
|
|
||||||
lazy_static! {
|
|
||||||
pub static ref PathKindColor: HashMap<PathKind, (u8, u8, u8)> = {
|
|
||||||
let mut m = HashMap::new();
|
|
||||||
|
|
||||||
m.insert(PathKind::UnrecognizedFile, (0xFF, 0xFF, 0x04)); // gold
|
|
||||||
m.insert(PathKind::RecognizedFile, (0x04, 0xFF, 0x04)); // limon
|
|
||||||
m.insert(PathKind::Dir, (0x00, 0xAF, 0xFF)); // dodgerblue
|
|
||||||
|
|
||||||
m
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Hash, Debug, Eq, PartialEq, Copy, Clone)]
|
|
||||||
pub enum LastTimeModified {
|
|
||||||
DayOld,
|
|
||||||
HourOld,
|
|
||||||
Older,
|
|
||||||
}
|
|
||||||
|
|
||||||
lazy_static! {
|
|
||||||
pub static ref LastTimeModifiedColor: HashMap<LastTimeModified, (u8, u8, u8)> = {
|
|
||||||
let mut m = HashMap::new();
|
|
||||||
|
|
||||||
m.insert(LastTimeModified::HourOld, (0x2C, 0xFF, 0x2C));
|
|
||||||
m.insert(LastTimeModified::DayOld, (0x1C, 0xFF, 0xB7));
|
|
||||||
m.insert(LastTimeModified::Older, (0x63, 0xB1, 0x8A));
|
|
||||||
|
|
||||||
m
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Hash, Debug, Eq, PartialEq, Copy, Clone)]
|
#[derive(Hash, Debug, Eq, PartialEq, Copy, Clone)]
|
||||||
pub enum Elem {
|
pub enum Elem {
|
||||||
|
/// Path Kind
|
||||||
|
UnrecognizedFile,
|
||||||
|
RecognizedFile,
|
||||||
|
Dir,
|
||||||
|
|
||||||
|
/// Permissions
|
||||||
|
Read,
|
||||||
|
Write,
|
||||||
|
Exec,
|
||||||
|
NoAccess,
|
||||||
|
|
||||||
|
/// Last Time Modified
|
||||||
|
DayOld,
|
||||||
|
HourOld,
|
||||||
|
Older,
|
||||||
|
|
||||||
/// Link
|
/// Link
|
||||||
DeadLink,
|
DeadLink,
|
||||||
Link,
|
Link,
|
||||||
|
|
||||||
|
/// User / Group Name
|
||||||
|
User,
|
||||||
|
Group,
|
||||||
|
|
||||||
/// File Size
|
/// File Size
|
||||||
FileLarge,
|
FileLarge,
|
||||||
FileMedium,
|
FileMedium,
|
||||||
FileSmall,
|
FileSmall,
|
||||||
|
}
|
||||||
|
|
||||||
/// Random
|
lazy_static! {
|
||||||
Report,
|
pub static ref Colors: HashMap<Elem, Colour> = {
|
||||||
User,
|
let mut m = HashMap::new();
|
||||||
Tree,
|
// User / Group
|
||||||
Empty,
|
m.insert(Elem::User, Colour::RGB(0xFF, 0xFF, 0xD8));
|
||||||
Error,
|
m.insert(Elem::Group, Colour::RGB(0xD9, 0xD9, 0x8F));
|
||||||
Normal,
|
|
||||||
|
|
||||||
/// Git
|
// Permissions
|
||||||
Addition,
|
m.insert(Elem::Read, Colour::RGB(0x5f, 0xD7, 0x5F));
|
||||||
Modification,
|
m.insert(Elem::Write, Colour::RGB(0xD7, 0xD7, 0x87));
|
||||||
Deletion,
|
m.insert(Elem::Exec, Colour::RGB(0xCD, 0x3A, 0x3A));
|
||||||
Untracked,
|
m.insert(Elem::NoAccess, Colour::RGB(0xD7, 0x89, 0x89));
|
||||||
Unchanged,
|
|
||||||
|
// Path Kind
|
||||||
|
m.insert(Elem::UnrecognizedFile, Colour::RGB(0xFF, 0xFF, 0x04)); // gold
|
||||||
|
m.insert(Elem::RecognizedFile, Colour::RGB(0x04, 0xFF, 0x04)); // limon
|
||||||
|
m.insert(Elem::Dir, Colour::RGB(0x00, 0xAF, 0xFF)); // dodgerblue
|
||||||
|
|
||||||
|
// Last Time Modified
|
||||||
|
m.insert(Elem::HourOld, Colour::RGB(0x2C, 0xFF, 0x2C));
|
||||||
|
m.insert(Elem::DayOld, Colour::RGB(0x1C, 0xFF, 0xB7));
|
||||||
|
m.insert(Elem::Older, Colour::RGB(0x63, 0xB1, 0x8A));
|
||||||
|
|
||||||
|
// Last Time Modified
|
||||||
|
m.insert(Elem::FileSmall, Colour::RGB(0xFF, 0xFF, 0xD9));
|
||||||
|
m.insert(Elem::FileMedium, Colour::RGB(0x1C, 0xFF, 0xB7));
|
||||||
|
m.insert(Elem::FileLarge, Colour::RGB(0xFF, 0xB0, 0x00));
|
||||||
|
|
||||||
|
// Link
|
||||||
|
m.insert(Elem::Link, Colour::RGB(0x3B, 0xCE, 0xCe));
|
||||||
|
|
||||||
|
m
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Formatter {}
|
pub struct Formatter {}
|
||||||
|
@ -81,29 +83,38 @@ impl Formatter {
|
||||||
Formatter {}
|
Formatter {}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn format_path(&self, content: &str, path: &Path) -> String {
|
pub fn format_name(&self, meta: &Meta) -> String {
|
||||||
let color = match path.metadata.is_dir() {
|
let mut content = String::new();
|
||||||
true => PathKindColor[&PathKind::Dir],
|
|
||||||
false => PathKindColor[&PathKind::UnrecognizedFile],
|
let color = match meta.metadata.is_dir() {
|
||||||
|
true => Colors[&Elem::Dir],
|
||||||
|
false => Colors[&Elem::UnrecognizedFile],
|
||||||
};
|
};
|
||||||
|
|
||||||
Colour::RGB(color.0, color.1, color.2)
|
let file_name = meta.path.file_name().unwrap().to_str().unwrap();
|
||||||
.paint(content)
|
content = content + &color.paint(file_name).to_string();
|
||||||
.to_string()
|
|
||||||
|
let color = Colors[&Elem::Link];
|
||||||
|
if let Some(ref link) = meta.symlink {
|
||||||
|
content =
|
||||||
|
content + &color.paint(String::from(" ⇒ ") + &color.paint(link).to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
content
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn format_date(&self, path: &Path) -> String {
|
pub fn format_date(&self, meta: &Meta) -> String {
|
||||||
let modified_time = path.metadata.modified().unwrap();
|
let modified_time = meta.metadata.modified().unwrap();
|
||||||
|
|
||||||
let now = SystemTime::now();
|
let now = SystemTime::now();
|
||||||
|
|
||||||
let color;
|
let color;
|
||||||
if modified_time > now - Duration::new(HOURE, 0) {
|
if modified_time > now - Duration::new(HOURE, 0) {
|
||||||
color = LastTimeModifiedColor[&LastTimeModified::HourOld];
|
color = Colors[&Elem::HourOld];
|
||||||
} else if modified_time > now - Duration::new(DAY, 0) {
|
} else if modified_time > now - Duration::new(DAY, 0) {
|
||||||
color = LastTimeModifiedColor[&LastTimeModified::DayOld];
|
color = Colors[&Elem::DayOld];
|
||||||
} else {
|
} else {
|
||||||
color = LastTimeModifiedColor[&LastTimeModified::Older];
|
color = Colors[&Elem::Older];
|
||||||
}
|
}
|
||||||
|
|
||||||
let modified_time_since_epoch = modified_time.duration_since(UNIX_EPOCH).unwrap();
|
let modified_time_since_epoch = modified_time.duration_since(UNIX_EPOCH).unwrap();
|
||||||
|
@ -112,28 +123,18 @@ impl Formatter {
|
||||||
modified_time_since_epoch.subsec_nanos() as i32,
|
modified_time_since_epoch.subsec_nanos() as i32,
|
||||||
));
|
));
|
||||||
|
|
||||||
Colour::RGB(color.0, color.1, color.2)
|
color.paint(time.ctime().to_string()).to_string()
|
||||||
.paint(time.ctime().to_string())
|
|
||||||
.to_string()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn format_permissions(&self, path: &Path) -> String {
|
pub fn format_permissions(&self, meta: &Meta) -> String {
|
||||||
let mut res = String::with_capacity(10);
|
let mut res = String::with_capacity(10);
|
||||||
|
|
||||||
let mode = path.metadata.permissions().mode();
|
let mode = meta.metadata.permissions().mode();
|
||||||
|
|
||||||
let read_perm = Colour::RGB(0x5f, 0xD7, 0x5F)
|
let read_perm = Colors[&Elem::Read].paint(String::from("r")).to_string();
|
||||||
.paint(String::from("r"))
|
let write_perm = Colors[&Elem::Write].paint(String::from("w")).to_string();
|
||||||
.to_string();
|
let exec_perm = Colors[&Elem::Exec].paint(String::from("x")).to_string();
|
||||||
let write_perm = Colour::RGB(0xD7, 0xD7, 0x87)
|
let no_access = Colors[&Elem::NoAccess].paint(String::from("-")).to_string();
|
||||||
.paint(String::from("w"))
|
|
||||||
.to_string();
|
|
||||||
let exec_perm = Colour::RGB(0xCD, 0x3A, 0x3A)
|
|
||||||
.paint(String::from("x"))
|
|
||||||
.to_string();
|
|
||||||
let no_access = Colour::RGB(0xD7, 0x89, 0x89)
|
|
||||||
.paint(String::from("-"))
|
|
||||||
.to_string();
|
|
||||||
|
|
||||||
// User Read Permisssions
|
// User Read Permisssions
|
||||||
match mode & 0o400 {
|
match mode & 0o400 {
|
||||||
|
@ -191,4 +192,64 @@ impl Formatter {
|
||||||
|
|
||||||
res.to_string()
|
res.to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn format_user(&self, user_name: &String, max_user_size: usize) -> String {
|
||||||
|
if user_name.len() == max_user_size {
|
||||||
|
return Colors[&Elem::User].paint(user_name).to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut content = String::with_capacity(max_user_size);
|
||||||
|
|
||||||
|
content = content + user_name;
|
||||||
|
|
||||||
|
for _ in 0..(max_user_size - user_name.len()) {
|
||||||
|
content.push(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
content
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn format_group(&self, group_name: &String, max_group_size: usize) -> String {
|
||||||
|
if group_name.len() == max_group_size {
|
||||||
|
return Colors[&Elem::Group].paint(group_name).to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut content = String::with_capacity(max_group_size);
|
||||||
|
content = content + group_name;
|
||||||
|
|
||||||
|
for _ in 0..(max_group_size - group_name.len()) {
|
||||||
|
content.push(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
content
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn format_size(
|
||||||
|
&self,
|
||||||
|
meta: &Meta,
|
||||||
|
max_value_length: usize,
|
||||||
|
max_unit_size: usize,
|
||||||
|
) -> String {
|
||||||
|
let mut content = String::with_capacity(max_value_length + max_unit_size + 1);
|
||||||
|
|
||||||
|
for _ in 0..(max_value_length - meta.size_value.len()) {
|
||||||
|
content.push(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
content = content + meta.size_value.as_str();
|
||||||
|
content.push(' ');
|
||||||
|
content = content + meta.size_unit.as_str();
|
||||||
|
|
||||||
|
for _ in 0..(max_unit_size - meta.size_unit.len()) {
|
||||||
|
content.push(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
if meta.metadata.len() < 10 * 1044 * 1024 {
|
||||||
|
return Colors[&Elem::FileSmall].paint(content).to_string();
|
||||||
|
} else if meta.metadata.len() < 100 * 1044 * 1024 {
|
||||||
|
return Colors[&Elem::FileMedium].paint(content).to_string();
|
||||||
|
} else {
|
||||||
|
return Colors[&Elem::FileLarge].paint(content).to_string();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
17
src/main.rs
17
src/main.rs
|
@ -2,18 +2,17 @@ extern crate clap;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
extern crate ansi_term;
|
extern crate ansi_term;
|
||||||
|
extern crate size;
|
||||||
extern crate time;
|
extern crate time;
|
||||||
|
extern crate users;
|
||||||
|
|
||||||
|
mod core;
|
||||||
mod formatter;
|
mod formatter;
|
||||||
mod path_lister;
|
|
||||||
mod presenter;
|
|
||||||
|
|
||||||
use clap::{App, Arg};
|
use clap::{App, Arg};
|
||||||
use path_lister::PathLister;
|
use core::Core;
|
||||||
use presenter::Presenter;
|
|
||||||
|
|
||||||
pub struct Options {
|
pub struct Options {
|
||||||
pub display_long: bool,
|
|
||||||
pub display_all: bool,
|
pub display_all: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,20 +20,16 @@ fn main() {
|
||||||
let matches = App::new("lsd")
|
let matches = App::new("lsd")
|
||||||
.about("A ls comment with a lot of pretty colors and some other stuff.")
|
.about("A ls comment with a lot of pretty colors and some other stuff.")
|
||||||
.arg(Arg::with_name("FILE").multiple(true).default_value("."))
|
.arg(Arg::with_name("FILE").multiple(true).default_value("."))
|
||||||
.arg(Arg::with_name("long").short("l"))
|
|
||||||
.arg(Arg::with_name("all").short("a"))
|
.arg(Arg::with_name("all").short("a"))
|
||||||
.get_matches();
|
.get_matches();
|
||||||
|
|
||||||
let options = Options {
|
let options = Options {
|
||||||
display_long: matches.is_present("long"),
|
|
||||||
display_all: matches.is_present("all"),
|
display_all: matches.is_present("all"),
|
||||||
};
|
};
|
||||||
|
|
||||||
let inputs: Vec<&str> = matches.values_of("FILE").unwrap().collect();
|
let inputs: Vec<&str> = matches.values_of("FILE").unwrap().collect();
|
||||||
|
|
||||||
let path_lister = PathLister::new(&options);
|
let core = Core::new(&options);
|
||||||
|
|
||||||
let presenter = Presenter::new(&options);
|
core.print(inputs);
|
||||||
|
|
||||||
presenter.print(path_lister.list_paths_to_print(inputs));
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,80 +0,0 @@
|
||||||
use std::fs::Metadata;
|
|
||||||
use std::io::ErrorKind;
|
|
||||||
use std::path::{self, PathBuf};
|
|
||||||
use Options;
|
|
||||||
|
|
||||||
pub struct Path {
|
|
||||||
pub path: PathBuf,
|
|
||||||
pub metadata: Metadata,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct PathLister<'a> {
|
|
||||||
options: &'a Options,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> PathLister<'a> {
|
|
||||||
pub fn new(options: &'a Options) -> PathLister<'a> {
|
|
||||||
PathLister { options: options }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn list_paths_to_print(&self, inputs: Vec<&'a str>) -> Vec<Path> {
|
|
||||||
let mut res = Vec::new();
|
|
||||||
|
|
||||||
for input in inputs.iter() {
|
|
||||||
let path = path::Path::new(input);
|
|
||||||
|
|
||||||
let res_meta = path.metadata();
|
|
||||||
|
|
||||||
if let Err(err) = res_meta {
|
|
||||||
match err.kind() {
|
|
||||||
ErrorKind::NotFound => println!("Specified path \"{}\" doesn't exists.", input),
|
|
||||||
ErrorKind::PermissionDenied => {
|
|
||||||
println!("Cannot open \"{}\": Permission denied", input)
|
|
||||||
}
|
|
||||||
_ => println!("Cannot open \"{}\": {}", input, err),
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Ok(meta) = res_meta {
|
|
||||||
let file_type = meta.file_type();
|
|
||||||
|
|
||||||
if file_type.is_file() {
|
|
||||||
self.add_path_to_list(&mut res, path.to_path_buf(), meta);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if file_type.is_dir() {
|
|
||||||
self.read_paths_from_dir(&mut res, path.to_path_buf());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if file_type.is_symlink() {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
res
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_paths_from_dir(&self, path_list: &mut Vec<Path>, path: PathBuf) {
|
|
||||||
for entry in path.read_dir().expect("read_dir call failed") {
|
|
||||||
if let Ok(entry) = entry {
|
|
||||||
self.add_path_to_list(path_list, entry.path(), entry.metadata().unwrap());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_path_to_list(&self, path_list: &mut Vec<Path>, path: PathBuf, meta: Metadata) {
|
|
||||||
// Skip the hidden files if the 'display_all' option is not set.
|
|
||||||
if path.file_name().unwrap().to_str().unwrap().starts_with(".") && !self.options.display_all
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
path_list.push(Path {
|
|
||||||
path: path.to_path_buf(),
|
|
||||||
metadata: meta,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,48 +0,0 @@
|
||||||
use formatter::*;
|
|
||||||
use path_lister::Path;
|
|
||||||
use Options;
|
|
||||||
|
|
||||||
pub struct Presenter<'a> {
|
|
||||||
formatter: Formatter,
|
|
||||||
options: &'a Options,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Presenter<'a> {
|
|
||||||
pub fn new(options: &'a Options) -> Presenter<'a> {
|
|
||||||
Presenter {
|
|
||||||
options: options,
|
|
||||||
formatter: Formatter::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn print(&self, paths: Vec<Path>) {
|
|
||||||
if self.options.display_long {
|
|
||||||
self.print_long(&paths);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.print_simple(&paths)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn print_long(&self, paths: &Vec<Path>) {
|
|
||||||
for path in paths {
|
|
||||||
print!(
|
|
||||||
" {} {} {}\n",
|
|
||||||
self.formatter.format_permissions(path),
|
|
||||||
self.formatter.format_date(path),
|
|
||||||
self.formatter
|
|
||||||
.format_path(path.path.file_name().unwrap().to_str().unwrap(), &path)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn print_simple(&self, paths: &Vec<Path>) {
|
|
||||||
for path in paths {
|
|
||||||
print!(
|
|
||||||
"{}\n",
|
|
||||||
self.formatter
|
|
||||||
.format_path(path.path.file_name().unwrap().to_str().unwrap(), &path)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue