Add the first functionalities

This commit is contained in:
Peltoche 2018-11-12 13:33:47 +01:00
parent 1ca2645bc6
commit 3dc1689e65
No known key found for this signature in database
GPG key ID: CED68D0487156952
7 changed files with 524 additions and 0 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
/target
**/*.rs.bk

150
Cargo.lock generated Normal file
View file

@ -0,0 +1,150 @@
[[package]]
name = "ansi_term"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "atty"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
"termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bitflags"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "clap"
version = "2.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "lazy_static"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libc"
version = "0.2.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "lsd"
version = "0.1.0"
dependencies = [
"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)",
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "redox_syscall"
version = "0.1.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "redox_termios"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "strsim"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "termion"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "textwrap"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "time"
version = "0.1.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "unicode-width"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "vec_map"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
"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 libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d"
"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 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 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 unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
"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-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

10
Cargo.toml Normal file
View file

@ -0,0 +1,10 @@
[package]
authors = ["Peltoche <dev@halium.fr>"]
name = "lsd"
version = "0.1.0"
[dependencies]
ansi_term = "0.11.0"
clap = "2.32.0"
lazy_static = "1.2.0"
time = "0.1.40"

194
src/formatter.rs Normal file
View file

@ -0,0 +1,194 @@
use ansi_term::Colour;
use path_lister::Path;
use std::collections::HashMap;
use std::os::unix::fs::PermissionsExt;
use std::time::{Duration, SystemTime, UNIX_EPOCH};
use time::Timespec;
const HOURE: u64 = 3600; // 1 HOURE == 3600 seconds
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)]
#[derive(Hash, Debug, Eq, PartialEq, Copy, Clone)]
pub enum Elem {
/// Link
DeadLink,
Link,
/// File Size
FileLarge,
FileMedium,
FileSmall,
/// Random
Report,
User,
Tree,
Empty,
Error,
Normal,
/// Git
Addition,
Modification,
Deletion,
Untracked,
Unchanged,
}
pub struct Formatter {}
impl Formatter {
pub fn new() -> Formatter {
Formatter {}
}
pub fn format_path(&self, content: &str, path: &Path) -> String {
let color = match path.metadata.is_dir() {
true => PathKindColor[&PathKind::Dir],
false => PathKindColor[&PathKind::UnrecognizedFile],
};
Colour::RGB(color.0, color.1, color.2)
.paint(content)
.to_string()
}
pub fn format_date(&self, path: &Path) -> String {
let modified_time = path.metadata.modified().unwrap();
let now = SystemTime::now();
let color;
if modified_time > now - Duration::new(HOURE, 0) {
color = LastTimeModifiedColor[&LastTimeModified::HourOld];
} else if modified_time > now - Duration::new(DAY, 0) {
color = LastTimeModifiedColor[&LastTimeModified::DayOld];
} else {
color = LastTimeModifiedColor[&LastTimeModified::Older];
}
let modified_time_since_epoch = modified_time.duration_since(UNIX_EPOCH).unwrap();
let time = time::at(Timespec::new(
modified_time_since_epoch.as_secs() as i64,
modified_time_since_epoch.subsec_nanos() as i32,
));
Colour::RGB(color.0, color.1, color.2)
.paint(time.ctime().to_string())
.to_string()
}
pub fn format_permissions(&self, path: &Path) -> String {
let mut res = String::with_capacity(10);
let mode = path.metadata.permissions().mode();
let read_perm = Colour::RGB(0x5f, 0xD7, 0x5F)
.paint(String::from("r"))
.to_string();
let write_perm = Colour::RGB(0xD7, 0xD7, 0x87)
.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
match mode & 0o400 {
0 => res = res + no_access.as_str(),
_ => res = res + read_perm.as_str(),
}
// User Write Permisssions
match mode & 0o200 {
0 => res = res + no_access.as_str(),
_ => res = res + write_perm.as_str(),
}
// User Exec Permisssions
match mode & 0o100 {
0 => res = res + no_access.as_str(),
_ => res = res + exec_perm.as_str(),
}
// Group Read Permisssions
match mode & 0o040 {
0 => res = res + no_access.as_str(),
_ => res = res + read_perm.as_str(),
}
// Group Write Permisssions
match mode & 0o020 {
0 => res = res + no_access.as_str(),
_ => res = res + write_perm.as_str(),
}
// Group Exec Permisssions
match mode & 0o010 {
0 => res = res + no_access.as_str(),
_ => res = res + exec_perm.as_str(),
}
// Other Read Permisssions
match mode & 0o040 {
0 => res = res + no_access.as_str(),
_ => res = res + read_perm.as_str(),
}
// Other Write Permisssions
match mode & 0o020 {
0 => res = res + no_access.as_str(),
_ => res = res + write_perm.as_str(),
}
// Other Exec Permisssions
match mode & 0o010 {
0 => res = res + no_access.as_str(),
_ => res = res + exec_perm.as_str(),
}
res.to_string()
}
}

40
src/main.rs Normal file
View file

@ -0,0 +1,40 @@
extern crate clap;
#[macro_use]
extern crate lazy_static;
extern crate ansi_term;
extern crate time;
mod formatter;
mod path_lister;
mod presenter;
use clap::{App, Arg};
use path_lister::PathLister;
use presenter::Presenter;
pub struct Options {
pub display_long: bool,
pub display_all: bool,
}
fn main() {
let matches = App::new("lsd")
.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("long").short("l"))
.arg(Arg::with_name("all").short("a"))
.get_matches();
let options = Options {
display_long: matches.is_present("long"),
display_all: matches.is_present("all"),
};
let inputs: Vec<&str> = matches.values_of("FILE").unwrap().collect();
let path_lister = PathLister::new(&options);
let presenter = Presenter::new(&options);
presenter.print(path_lister.list_paths_to_print(inputs));
}

80
src/path_lister.rs Normal file
View file

@ -0,0 +1,80 @@
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,
});
}
}

48
src/presenter.rs Normal file
View file

@ -0,0 +1,48 @@
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)
);
}
}
}