2018-12-02 14:05:27 +00:00
|
|
|
use batch::Batch;
|
2018-12-13 13:51:31 +00:00
|
|
|
use color::{self, Colors};
|
2018-12-02 16:22:51 +00:00
|
|
|
use display::Display;
|
2019-01-16 16:39:20 +00:00
|
|
|
use flags::{Flags, IconTheme, WhenFlag};
|
2018-12-13 13:51:31 +00:00
|
|
|
use icon::{self, Icons};
|
2018-12-04 12:29:54 +00:00
|
|
|
use meta::{FileType, Meta};
|
|
|
|
use std::path::{Path, PathBuf};
|
2018-12-05 19:32:25 +00:00
|
|
|
use terminal_size::terminal_size;
|
2018-11-16 13:19:07 +00:00
|
|
|
|
2018-12-05 19:54:17 +00:00
|
|
|
pub struct Core {
|
2018-12-08 13:00:42 +00:00
|
|
|
flags: Flags,
|
2018-12-08 18:52:56 +00:00
|
|
|
icons: Icons,
|
2018-12-05 19:54:17 +00:00
|
|
|
display: Display,
|
2018-12-05 19:12:33 +00:00
|
|
|
colors: Colors,
|
2018-11-16 13:19:07 +00:00
|
|
|
}
|
|
|
|
|
2018-12-05 19:54:17 +00:00
|
|
|
impl Core {
|
2018-12-13 15:50:47 +00:00
|
|
|
pub fn new(flags: Flags) -> Self {
|
2018-12-05 19:32:25 +00:00
|
|
|
// terminal_size allows us to know if the stdout is a tty or not.
|
2018-12-05 19:54:17 +00:00
|
|
|
let tty_available = terminal_size().is_some();
|
2018-12-05 19:32:25 +00:00
|
|
|
|
2018-12-08 13:00:42 +00:00
|
|
|
let mut inner_flags = flags;
|
2018-12-05 19:54:17 +00:00
|
|
|
|
2018-12-13 13:51:31 +00:00
|
|
|
let color_theme = match (tty_available, flags.color) {
|
2019-01-16 16:39:20 +00:00
|
|
|
(_, WhenFlag::Never) | (false, WhenFlag::Auto) => color::Theme::NoColor,
|
2018-12-13 13:51:31 +00:00
|
|
|
_ => color::Theme::Default,
|
|
|
|
};
|
|
|
|
|
2019-01-14 19:58:14 +00:00
|
|
|
let icon_theme = match (tty_available, flags.icon, flags.icon_theme) {
|
|
|
|
(_, WhenFlag::Never, _) | (false, WhenFlag::Auto, _) => icon::Theme::NoIcon,
|
2019-01-16 16:39:20 +00:00
|
|
|
(_, _, IconTheme::Fancy) => icon::Theme::Fancy,
|
|
|
|
(_, _, IconTheme::Unicode) => icon::Theme::Unicode,
|
2018-12-08 13:21:32 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
if !tty_available {
|
2018-12-05 19:54:17 +00:00
|
|
|
// The output is not a tty, this means the command is piped. (ex: lsd -l | less)
|
|
|
|
//
|
|
|
|
// Most of the programs does not handle correctly the ansi colors
|
|
|
|
// or require a raw output (like the `wc` command).
|
2018-12-08 13:00:42 +00:00
|
|
|
inner_flags.display_online = true;
|
2018-12-05 19:32:25 +00:00
|
|
|
};
|
|
|
|
|
2018-12-13 15:50:47 +00:00
|
|
|
Self {
|
2018-12-08 13:00:42 +00:00
|
|
|
flags,
|
|
|
|
display: Display::new(inner_flags),
|
2018-12-13 13:51:31 +00:00
|
|
|
colors: Colors::new(color_theme),
|
|
|
|
icons: Icons::new(icon_theme),
|
2018-12-04 13:54:56 +00:00
|
|
|
}
|
2018-11-16 13:19:07 +00:00
|
|
|
}
|
|
|
|
|
2018-12-04 13:54:56 +00:00
|
|
|
pub fn run(self, paths: Vec<PathBuf>) {
|
|
|
|
self.run_inner(paths, 0);
|
|
|
|
}
|
2018-12-02 16:22:51 +00:00
|
|
|
|
2018-12-04 13:54:56 +00:00
|
|
|
fn run_inner(&self, paths: Vec<PathBuf>, depth: usize) {
|
2018-12-19 18:00:21 +00:00
|
|
|
if depth > self.flags.recursion_depth {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-11-16 13:19:07 +00:00
|
|
|
let mut dirs = Vec::new();
|
|
|
|
let mut files = Vec::new();
|
|
|
|
|
2018-12-04 12:29:54 +00:00
|
|
|
for path in paths {
|
2018-11-16 13:19:07 +00:00
|
|
|
if path.is_dir() {
|
|
|
|
dirs.push(path);
|
2018-12-04 12:29:54 +00:00
|
|
|
} else if let Some(meta) = Meta::from_path(&path) {
|
|
|
|
files.push(meta);
|
2018-11-16 13:19:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-02 14:05:27 +00:00
|
|
|
let print_folder_name: bool = dirs.len() + files.len() > 1;
|
2018-11-16 13:19:07 +00:00
|
|
|
|
2018-12-08 13:00:42 +00:00
|
|
|
if !files.is_empty() && !self.flags.display_tree {
|
2018-12-02 16:22:51 +00:00
|
|
|
let mut file_batch = Batch::from(files);
|
2018-12-15 13:44:36 +00:00
|
|
|
file_batch.sort(self.flags);
|
2018-12-04 13:54:56 +00:00
|
|
|
self.display
|
|
|
|
.print_outputs(self.get_batch_outputs(&file_batch));
|
2018-12-02 16:22:51 +00:00
|
|
|
}
|
2018-12-02 14:05:27 +00:00
|
|
|
|
|
|
|
dirs.sort_unstable();
|
2018-11-16 13:19:07 +00:00
|
|
|
|
|
|
|
for dir in dirs {
|
2018-12-04 12:29:54 +00:00
|
|
|
if let Some(folder_batch) = self.list_folder_content(dir.as_path()) {
|
2018-12-08 13:00:42 +00:00
|
|
|
if (print_folder_name || self.flags.recursive) && !self.flags.display_tree {
|
2018-12-02 14:05:27 +00:00
|
|
|
println!("\n{}:", dir.display())
|
|
|
|
}
|
2018-11-24 11:02:39 +00:00
|
|
|
|
2018-12-08 13:00:42 +00:00
|
|
|
if self.flags.display_tree {
|
2018-12-04 13:54:56 +00:00
|
|
|
self.display_as_tree(folder_batch, depth);
|
2018-12-08 13:00:42 +00:00
|
|
|
} else if self.flags.recursive {
|
2018-12-04 13:54:56 +00:00
|
|
|
self.display
|
|
|
|
.print_outputs(self.get_batch_outputs(&folder_batch));
|
2018-12-04 12:29:54 +00:00
|
|
|
|
|
|
|
let folder_dirs = folder_batch
|
|
|
|
.into_iter()
|
|
|
|
.filter_map(|x| {
|
2019-01-19 16:27:50 +00:00
|
|
|
if let FileType::Directory { .. } = x.file_type {
|
2018-12-04 12:29:54 +00:00
|
|
|
Some(x.path)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
2018-12-12 10:17:32 +00:00
|
|
|
})
|
|
|
|
.collect();
|
2018-12-04 12:29:54 +00:00
|
|
|
|
2018-12-19 18:00:21 +00:00
|
|
|
self.run_inner(folder_dirs, depth + 1);
|
2018-12-04 13:54:56 +00:00
|
|
|
} else {
|
|
|
|
self.display
|
|
|
|
.print_outputs(self.get_batch_outputs(&folder_batch));
|
2018-12-04 12:29:54 +00:00
|
|
|
}
|
2018-11-16 13:19:07 +00:00
|
|
|
}
|
2018-11-24 16:42:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-04 13:54:56 +00:00
|
|
|
pub fn display_as_tree(&self, batch: Batch, depth: usize) {
|
|
|
|
let last_idx = batch.len();
|
|
|
|
|
2019-01-12 15:17:40 +00:00
|
|
|
let mut output = String::new();
|
2018-12-04 13:54:56 +00:00
|
|
|
for (idx, elem) in batch.into_iter().enumerate() {
|
2018-12-05 19:12:33 +00:00
|
|
|
let last = idx + 1 != last_idx;
|
2018-12-04 13:54:56 +00:00
|
|
|
|
2019-01-19 16:27:50 +00:00
|
|
|
if let FileType::Directory { .. } = elem.file_type {
|
2019-01-12 15:17:40 +00:00
|
|
|
output += &self.display.print_tree_row(
|
2018-12-13 15:50:47 +00:00
|
|
|
&elem.name.render(&self.colors, &self.icons),
|
2018-12-05 19:12:33 +00:00
|
|
|
depth,
|
|
|
|
last,
|
|
|
|
);
|
2018-12-04 13:54:56 +00:00
|
|
|
self.run_inner(vec![elem.path], depth + 1);
|
|
|
|
} else {
|
2019-01-12 15:17:40 +00:00
|
|
|
output += &self.display.print_tree_row(
|
2018-12-13 15:50:47 +00:00
|
|
|
&elem.name.render(&self.colors, &self.icons),
|
2018-12-05 19:12:33 +00:00
|
|
|
depth,
|
|
|
|
last,
|
|
|
|
);
|
2018-12-04 13:54:56 +00:00
|
|
|
}
|
|
|
|
}
|
2019-01-12 15:17:40 +00:00
|
|
|
|
|
|
|
self.display.print_output(&output);
|
2018-12-04 13:54:56 +00:00
|
|
|
}
|
|
|
|
|
2018-12-02 16:22:51 +00:00
|
|
|
pub fn get_batch_outputs<'b>(&self, batch: &'b Batch) -> Vec<String> {
|
2018-12-08 13:00:42 +00:00
|
|
|
if self.flags.display_long {
|
2018-12-10 17:26:34 +00:00
|
|
|
batch.get_long_output(&self.colors, &self.icons, self.flags)
|
2018-11-24 16:42:39 +00:00
|
|
|
} else {
|
2018-12-10 17:26:34 +00:00
|
|
|
batch.get_short_output(&self.colors, &self.icons, self.flags)
|
2018-11-24 16:42:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-02 14:05:27 +00:00
|
|
|
pub fn list_folder_content(&self, folder: &Path) -> Option<Batch> {
|
|
|
|
let mut metas: Vec<Meta> = Vec::new();
|
2018-11-16 13:19:07 +00:00
|
|
|
|
2018-11-24 11:02:39 +00:00
|
|
|
let dir = match folder.read_dir() {
|
|
|
|
Ok(dir) => dir,
|
|
|
|
Err(err) => {
|
|
|
|
println!("cannot open directory'{}': {}", folder.display(), err);
|
2018-12-02 14:05:27 +00:00
|
|
|
return None;
|
2018-11-24 11:02:39 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
for entry in dir {
|
2018-11-16 13:19:07 +00:00
|
|
|
if let Ok(entry) = entry {
|
2018-12-04 12:29:54 +00:00
|
|
|
if let Some(meta) = Meta::from_path(&entry.path()) {
|
2018-12-08 13:00:42 +00:00
|
|
|
if !meta.name.is_hidden() || self.flags.display_all {
|
2018-12-04 10:15:05 +00:00
|
|
|
metas.push(meta);
|
|
|
|
}
|
2018-11-16 13:19:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-02 14:05:27 +00:00
|
|
|
let mut batch = Batch::from(metas);
|
2018-12-15 13:44:36 +00:00
|
|
|
batch.sort(self.flags);
|
2018-11-16 13:19:07 +00:00
|
|
|
|
2018-12-02 14:05:27 +00:00
|
|
|
Some(batch)
|
2018-11-16 13:19:07 +00:00
|
|
|
}
|
|
|
|
}
|