2019-02-09 10:41:42 +00:00
|
|
|
|
use crate::color::Colors;
|
2019-06-17 03:10:41 +00:00
|
|
|
|
use crate::flags::{Block, Display, Flags, Layout};
|
2019-02-09 10:41:42 +00:00
|
|
|
|
use crate::icon::Icons;
|
|
|
|
|
use crate::meta::{FileType, Meta};
|
2019-01-20 10:22:14 +00:00
|
|
|
|
use ansi_term::{ANSIString, ANSIStrings};
|
2018-12-02 16:22:51 +00:00
|
|
|
|
use term_grid::{Cell, Direction, Filling, Grid, GridOptions};
|
|
|
|
|
use terminal_size::terminal_size;
|
2018-12-19 04:50:55 +00:00
|
|
|
|
use unicode_width::UnicodeWidthStr;
|
2018-12-02 16:22:51 +00:00
|
|
|
|
|
2018-12-13 15:50:47 +00:00
|
|
|
|
const EDGE: &str = "\u{251c}\u{2500}\u{2500}"; // "├──"
|
|
|
|
|
const LINE: &str = "\u{2502} "; // "├ "
|
|
|
|
|
const CORNER: &str = "\u{2514}\u{2500}\u{2500}"; // "└──"
|
2019-01-23 17:02:36 +00:00
|
|
|
|
const BLANK: &str = " ";
|
2018-12-04 13:54:56 +00:00
|
|
|
|
|
2019-01-20 10:22:14 +00:00
|
|
|
|
#[derive(Debug, Copy, Clone)]
|
|
|
|
|
struct PaddingRules {
|
|
|
|
|
user: usize,
|
|
|
|
|
group: usize,
|
|
|
|
|
size: (usize, usize),
|
|
|
|
|
date: usize,
|
2019-05-04 10:43:25 +00:00
|
|
|
|
name: usize,
|
2019-05-04 10:56:27 +00:00
|
|
|
|
name_with_symlink: usize,
|
2019-01-20 10:22:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-03-30 10:58:36 +00:00
|
|
|
|
pub fn one_line(metas: Vec<Meta>, flags: &Flags, colors: &Colors, icons: &Icons) -> String {
|
|
|
|
|
inner_display_one_line(metas, &flags, colors, icons, 0)
|
2018-12-02 16:22:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-03-30 10:58:36 +00:00
|
|
|
|
pub fn grid(metas: Vec<Meta>, flags: &Flags, colors: &Colors, icons: &Icons) -> String {
|
2019-01-20 10:22:14 +00:00
|
|
|
|
let term_width = match terminal_size() {
|
2019-02-12 12:24:21 +00:00
|
|
|
|
Some((w, _)) => Some(w.0 as usize),
|
|
|
|
|
None => None,
|
2019-01-20 10:22:14 +00:00
|
|
|
|
};
|
|
|
|
|
|
2019-03-30 10:58:36 +00:00
|
|
|
|
inner_display_grid(metas, &flags, colors, icons, 0, term_width)
|
2019-01-20 10:22:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-03-30 10:58:36 +00:00
|
|
|
|
pub fn tree(metas: Vec<Meta>, flags: &Flags, colors: &Colors, icons: &Icons) -> String {
|
|
|
|
|
inner_display_tree(metas, &flags, colors, icons, 0, "")
|
2019-01-20 10:22:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn inner_display_one_line(
|
|
|
|
|
metas: Vec<Meta>,
|
2019-03-30 10:58:36 +00:00
|
|
|
|
flags: &Flags,
|
2019-01-20 10:22:14 +00:00
|
|
|
|
colors: &Colors,
|
|
|
|
|
icons: &Icons,
|
|
|
|
|
depth: usize,
|
|
|
|
|
) -> String {
|
|
|
|
|
let mut output = String::new();
|
|
|
|
|
|
|
|
|
|
let mut padding_rules = None;
|
2019-03-08 17:28:35 +00:00
|
|
|
|
if let Layout::OneLine { long: true } = flags.layout {
|
2019-01-20 10:22:14 +00:00
|
|
|
|
// Defining the padding rules is costly and so shouldn't be done several
|
|
|
|
|
// times. That's why it's done outside the loop.
|
|
|
|
|
padding_rules = Some(PaddingRules {
|
|
|
|
|
user: detect_user_length(&metas),
|
|
|
|
|
group: detect_group_length(&metas),
|
2019-03-30 10:58:36 +00:00
|
|
|
|
size: detect_size_lengths(&metas, &flags),
|
|
|
|
|
date: detect_date_length(&metas, &flags),
|
2019-06-17 06:42:03 +00:00
|
|
|
|
name: detect_name_length(&metas, &icons, &flags),
|
|
|
|
|
name_with_symlink: detect_name_with_symlink_length(&metas, &icons, &flags),
|
2019-01-20 10:22:14 +00:00
|
|
|
|
})
|
2018-12-02 16:22:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-05-24 13:30:36 +00:00
|
|
|
|
// The first iteration (depth == 0) corresponds to the inputs given by the
|
|
|
|
|
// user. We defer displaying directories given by the user unless we've been
|
|
|
|
|
// asked to display the directory itself (rather than its contents).
|
|
|
|
|
let skip_dirs = (depth == 0) && (flags.display != Display::DisplayDirectoryItself);
|
|
|
|
|
|
2019-01-20 10:22:14 +00:00
|
|
|
|
// print the files first.
|
|
|
|
|
for meta in &metas {
|
2019-05-24 13:30:36 +00:00
|
|
|
|
// Maybe skip showing the directory meta now; show its contents later.
|
|
|
|
|
if let (true, FileType::Directory { .. }) = (skip_dirs, meta.file_type) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-08 17:28:35 +00:00
|
|
|
|
if let Layout::OneLine { long: true } = flags.layout {
|
2019-03-30 10:58:36 +00:00
|
|
|
|
output += &get_long_output(&meta, &colors, &icons, &flags, padding_rules.unwrap());
|
2018-12-02 16:22:51 +00:00
|
|
|
|
} else {
|
2019-03-30 10:58:36 +00:00
|
|
|
|
output += &get_short_output(&meta, &colors, &icons, &flags);
|
2018-12-02 16:22:51 +00:00
|
|
|
|
}
|
2019-01-20 10:22:14 +00:00
|
|
|
|
|
|
|
|
|
output.push('\n');
|
2018-12-02 16:22:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-01-20 10:22:14 +00:00
|
|
|
|
let should_display_folder_path = should_display_folder_path(depth, &metas);
|
2018-12-02 16:22:51 +00:00
|
|
|
|
|
2019-01-20 10:22:14 +00:00
|
|
|
|
// print the folder content
|
|
|
|
|
for meta in metas {
|
|
|
|
|
if meta.content.is_some() {
|
|
|
|
|
if should_display_folder_path {
|
|
|
|
|
output += &display_folder_path(&meta);
|
|
|
|
|
}
|
2018-12-02 16:22:51 +00:00
|
|
|
|
|
2019-01-20 10:22:14 +00:00
|
|
|
|
output +=
|
2019-03-30 10:58:36 +00:00
|
|
|
|
&inner_display_one_line(meta.content.unwrap(), &flags, colors, icons, depth + 1);
|
2018-12-02 16:22:51 +00:00
|
|
|
|
}
|
2019-01-20 10:22:14 +00:00
|
|
|
|
}
|
2018-12-02 16:22:51 +00:00
|
|
|
|
|
2019-01-20 10:22:14 +00:00
|
|
|
|
output
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn inner_display_grid(
|
|
|
|
|
metas: Vec<Meta>,
|
2019-03-30 10:58:36 +00:00
|
|
|
|
flags: &Flags,
|
2019-01-20 10:22:14 +00:00
|
|
|
|
colors: &Colors,
|
|
|
|
|
icons: &Icons,
|
|
|
|
|
depth: usize,
|
2019-02-12 12:24:21 +00:00
|
|
|
|
term_width: Option<usize>,
|
2019-01-20 10:22:14 +00:00
|
|
|
|
) -> String {
|
|
|
|
|
let mut output = String::new();
|
|
|
|
|
|
|
|
|
|
let mut grid = Grid::new(GridOptions {
|
|
|
|
|
filling: Filling::Spaces(2),
|
|
|
|
|
direction: Direction::TopToBottom,
|
|
|
|
|
});
|
|
|
|
|
|
2019-05-24 13:30:36 +00:00
|
|
|
|
// The first iteration (depth == 0) corresponds to the inputs given by the
|
|
|
|
|
// user. We defer displaying directories given by the user unless we've been
|
|
|
|
|
// asked to display the directory itself (rather than its contents).
|
|
|
|
|
let skip_dirs = (depth == 0) && (flags.display != Display::DisplayDirectoryItself);
|
|
|
|
|
|
2019-01-20 10:22:14 +00:00
|
|
|
|
// print the files first.
|
|
|
|
|
for meta in &metas {
|
2019-05-24 13:30:36 +00:00
|
|
|
|
// Maybe skip showing the directory meta now; show its contents later.
|
|
|
|
|
if let (true, FileType::Directory { .. }) = (skip_dirs, meta.file_type) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-30 10:58:36 +00:00
|
|
|
|
let line_output = get_short_output(&meta, &colors, &icons, &flags);
|
2019-01-20 10:22:14 +00:00
|
|
|
|
grid.add(Cell {
|
|
|
|
|
width: get_visible_width(&line_output),
|
|
|
|
|
contents: line_output,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-12 12:24:21 +00:00
|
|
|
|
if let Some(tw) = term_width {
|
|
|
|
|
if let Some(gridded_output) = grid.fit_into_width(tw) {
|
|
|
|
|
output += &gridded_output.to_string();
|
|
|
|
|
} else {
|
|
|
|
|
//does not fit into grid, usually because (some) filename(s)
|
|
|
|
|
//are longer or almost as long as term_width
|
|
|
|
|
//print line by line instead!
|
|
|
|
|
output += &grid.fit_into_columns(1).to_string();
|
|
|
|
|
}
|
2019-01-20 10:22:14 +00:00
|
|
|
|
} else {
|
|
|
|
|
output += &grid.fit_into_columns(1).to_string();
|
2018-12-02 16:22:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-01-20 10:22:14 +00:00
|
|
|
|
let should_display_folder_path = should_display_folder_path(depth, &metas);
|
2019-01-12 15:17:40 +00:00
|
|
|
|
|
2019-01-20 10:22:14 +00:00
|
|
|
|
// print the folder content
|
|
|
|
|
for meta in metas {
|
|
|
|
|
if meta.content.is_some() {
|
|
|
|
|
if should_display_folder_path {
|
|
|
|
|
output += &display_folder_path(&meta);
|
2019-01-12 15:17:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-01-20 10:22:14 +00:00
|
|
|
|
output += &inner_display_grid(
|
|
|
|
|
meta.content.unwrap(),
|
2019-03-30 10:58:36 +00:00
|
|
|
|
&flags,
|
2019-01-20 10:22:14 +00:00
|
|
|
|
colors,
|
|
|
|
|
icons,
|
|
|
|
|
depth + 1,
|
|
|
|
|
term_width,
|
|
|
|
|
);
|
2019-01-12 15:17:40 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-20 10:22:14 +00:00
|
|
|
|
output
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn inner_display_tree(
|
|
|
|
|
metas: Vec<Meta>,
|
2019-03-30 10:58:36 +00:00
|
|
|
|
flags: &Flags,
|
2019-01-20 10:22:14 +00:00
|
|
|
|
colors: &Colors,
|
|
|
|
|
icons: &Icons,
|
|
|
|
|
depth: usize,
|
2019-01-23 17:02:36 +00:00
|
|
|
|
prefix: &str,
|
2019-01-20 10:22:14 +00:00
|
|
|
|
) -> String {
|
|
|
|
|
let mut output = String::new();
|
|
|
|
|
let last_idx = metas.len();
|
|
|
|
|
|
2019-05-25 16:47:34 +00:00
|
|
|
|
let mut padding_rules = None;
|
|
|
|
|
if let Layout::Tree { long: true } = flags.layout {
|
|
|
|
|
// Defining the padding rules is costly and so shouldn't be done several
|
|
|
|
|
// times. That's why it's done outside the loop.
|
|
|
|
|
padding_rules = Some(PaddingRules {
|
|
|
|
|
user: detect_user_length(&metas),
|
|
|
|
|
group: detect_group_length(&metas),
|
|
|
|
|
size: detect_size_lengths(&metas, flags),
|
|
|
|
|
date: detect_date_length(&metas, flags),
|
2019-06-17 06:42:03 +00:00
|
|
|
|
name: detect_name_length(&metas, &icons, &flags),
|
|
|
|
|
name_with_symlink: detect_name_with_symlink_length(&metas, &icons, &flags),
|
2019-05-25 16:47:34 +00:00
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-20 10:22:14 +00:00
|
|
|
|
for (idx, meta) in metas.into_iter().enumerate() {
|
|
|
|
|
let is_last_folder_elem = idx + 1 != last_idx;
|
2018-12-04 13:54:56 +00:00
|
|
|
|
|
2019-01-23 17:02:36 +00:00
|
|
|
|
if depth > 0 {
|
|
|
|
|
output += prefix;
|
2018-12-04 13:54:56 +00:00
|
|
|
|
|
2019-01-23 17:02:36 +00:00
|
|
|
|
if is_last_folder_elem {
|
|
|
|
|
output += EDGE;
|
|
|
|
|
} else {
|
|
|
|
|
output += CORNER;
|
|
|
|
|
}
|
|
|
|
|
output += " ";
|
2018-12-04 13:54:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-05-25 16:47:34 +00:00
|
|
|
|
if let Layout::Tree { long: true } = flags.layout {
|
2019-03-30 10:58:36 +00:00
|
|
|
|
output += &get_long_output(&meta, &colors, &icons, &flags, padding_rules.unwrap());
|
2019-05-25 16:47:34 +00:00
|
|
|
|
} else {
|
2019-03-30 10:58:36 +00:00
|
|
|
|
output += &get_short_output(&meta, &colors, &icons, &flags);
|
2019-05-25 16:47:34 +00:00
|
|
|
|
}
|
2019-01-20 10:22:14 +00:00
|
|
|
|
output += "\n";
|
2018-12-04 13:54:56 +00:00
|
|
|
|
|
2019-01-20 10:22:14 +00:00
|
|
|
|
if meta.content.is_some() {
|
2019-01-23 17:02:36 +00:00
|
|
|
|
let mut new_prefix = String::from(prefix);
|
|
|
|
|
|
|
|
|
|
if depth > 0 {
|
|
|
|
|
if is_last_folder_elem {
|
|
|
|
|
new_prefix += LINE;
|
|
|
|
|
} else {
|
|
|
|
|
new_prefix += BLANK;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
output += &inner_display_tree(
|
|
|
|
|
meta.content.unwrap(),
|
2019-03-30 10:58:36 +00:00
|
|
|
|
&flags,
|
2019-01-23 17:02:36 +00:00
|
|
|
|
colors,
|
|
|
|
|
icons,
|
|
|
|
|
depth + 1,
|
|
|
|
|
&new_prefix,
|
|
|
|
|
);
|
2019-01-20 10:22:14 +00:00
|
|
|
|
}
|
2018-12-04 13:54:56 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-01-20 10:22:14 +00:00
|
|
|
|
output
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn should_display_folder_path(depth: usize, metas: &[Meta]) -> bool {
|
|
|
|
|
if depth > 0 {
|
|
|
|
|
true
|
|
|
|
|
} else {
|
|
|
|
|
let folder_number = metas
|
|
|
|
|
.iter()
|
|
|
|
|
.filter(|x| match x.file_type {
|
|
|
|
|
FileType::Directory { .. } => true,
|
|
|
|
|
_ => false,
|
|
|
|
|
})
|
|
|
|
|
.count();
|
|
|
|
|
|
|
|
|
|
folder_number > 1 || folder_number < metas.len()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn display_folder_path(meta: &Meta) -> String {
|
|
|
|
|
let mut output = String::new();
|
|
|
|
|
output.push('\n');
|
|
|
|
|
output += &meta.path.to_string_lossy();
|
|
|
|
|
output += ":\n";
|
|
|
|
|
|
|
|
|
|
output
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-30 10:58:36 +00:00
|
|
|
|
fn get_short_output(meta: &Meta, colors: &Colors, icons: &Icons, flags: &Flags) -> String {
|
2019-01-20 10:22:14 +00:00
|
|
|
|
let strings: &[ANSIString] = &[
|
2019-05-18 14:32:29 +00:00
|
|
|
|
meta.name.render(colors, icons),
|
2019-03-30 10:58:36 +00:00
|
|
|
|
meta.indicator.render(&flags),
|
2019-01-20 10:22:14 +00:00
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
ANSIStrings(strings).to_string()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get_long_output(
|
|
|
|
|
meta: &Meta,
|
|
|
|
|
colors: &Colors,
|
|
|
|
|
icons: &Icons,
|
2019-03-30 10:58:36 +00:00
|
|
|
|
flags: &Flags,
|
2019-01-20 10:22:14 +00:00
|
|
|
|
padding_rules: PaddingRules,
|
|
|
|
|
) -> String {
|
2019-03-30 10:58:36 +00:00
|
|
|
|
let mut strings: Vec<ANSIString> = Vec::new();
|
|
|
|
|
for block in flags.blocks.iter() {
|
|
|
|
|
match block {
|
2019-05-04 10:59:11 +00:00
|
|
|
|
Block::Permission => {
|
|
|
|
|
strings.push(meta.file_type.render(colors));
|
|
|
|
|
strings.push(meta.permissions.render(colors));
|
|
|
|
|
}
|
2019-03-30 10:58:36 +00:00
|
|
|
|
Block::User => strings.push(meta.owner.render_user(colors, padding_rules.user)),
|
|
|
|
|
Block::Group => strings.push(meta.owner.render_group(colors, padding_rules.group)),
|
|
|
|
|
Block::Size => strings.push(meta.size.render(
|
|
|
|
|
colors,
|
|
|
|
|
padding_rules.size.0,
|
|
|
|
|
padding_rules.size.1,
|
2019-05-04 10:43:25 +00:00
|
|
|
|
&flags,
|
2019-03-30 10:58:36 +00:00
|
|
|
|
)),
|
|
|
|
|
Block::Date => strings.push(meta.date.render(colors, padding_rules.date, &flags)),
|
2019-05-18 13:49:29 +00:00
|
|
|
|
Block::Name => {
|
|
|
|
|
if flags.no_symlink {
|
2019-05-18 14:32:29 +00:00
|
|
|
|
strings.push(meta.name.render(colors, icons));
|
2019-06-17 06:42:03 +00:00
|
|
|
|
strings.push(meta.indicator.render(&flags));
|
|
|
|
|
strings.push(ANSIString::from(" ".to_string().repeat(
|
|
|
|
|
padding_rules.name
|
|
|
|
|
- meta.indicator.len(&flags)
|
|
|
|
|
- meta.name.name_string(icons).len(),
|
|
|
|
|
)))
|
2019-05-18 13:49:29 +00:00
|
|
|
|
} else {
|
|
|
|
|
match meta.symlink.symlink_string() {
|
2019-05-18 14:32:29 +00:00
|
|
|
|
Some(s) => {
|
|
|
|
|
strings.push(meta.name.render(colors, icons));
|
2019-05-18 13:49:29 +00:00
|
|
|
|
strings.push(meta.indicator.render(&flags));
|
2019-05-18 14:32:29 +00:00
|
|
|
|
strings.push(meta.symlink.render(colors));
|
|
|
|
|
strings.push(ANSIString::from(" ".to_string().repeat(
|
|
|
|
|
padding_rules.name_with_symlink
|
2019-06-17 06:42:03 +00:00
|
|
|
|
- 3 // 3 = ( arrow + 2 spaces) for symlink;
|
2019-05-18 14:32:29 +00:00
|
|
|
|
- meta.name.name_string(icons).len()
|
2019-06-17 08:22:56 +00:00
|
|
|
|
- meta.indicator.len(&flags)
|
2019-05-18 14:32:29 +00:00
|
|
|
|
- s.len(),
|
|
|
|
|
)))
|
2019-05-18 13:49:29 +00:00
|
|
|
|
}
|
|
|
|
|
None => {
|
2019-05-18 14:32:29 +00:00
|
|
|
|
strings.push(meta.name.render(colors, icons));
|
2019-05-18 13:49:29 +00:00
|
|
|
|
strings.push(meta.indicator.render(&flags));
|
2019-05-18 14:32:29 +00:00
|
|
|
|
strings.push(meta.symlink.render(colors));
|
|
|
|
|
strings.push(ANSIString::from(" ".to_string().repeat(
|
2019-06-17 06:42:03 +00:00
|
|
|
|
padding_rules.name_with_symlink
|
2019-06-17 03:10:41 +00:00
|
|
|
|
- meta.name.name_string(icons).len()
|
2019-06-17 08:22:56 +00:00
|
|
|
|
- meta.indicator.len(&flags),
|
2019-05-18 14:32:29 +00:00
|
|
|
|
)))
|
2019-05-18 13:49:29 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2019-05-04 11:17:33 +00:00
|
|
|
|
}
|
2019-05-18 13:49:29 +00:00
|
|
|
|
}
|
2019-03-30 10:58:36 +00:00
|
|
|
|
};
|
2019-06-09 03:24:45 +00:00
|
|
|
|
strings.push(ANSIString::from(" "));
|
2019-03-30 10:58:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-06-09 03:24:45 +00:00
|
|
|
|
strings.pop(); // remove the last space
|
|
|
|
|
|
2019-03-30 10:58:36 +00:00
|
|
|
|
ANSIStrings(&strings).to_string()
|
2019-01-20 10:22:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get_visible_width(input: &str) -> usize {
|
|
|
|
|
let mut nb_invisible_char = 0;
|
|
|
|
|
|
2019-03-12 06:20:57 +00:00
|
|
|
|
// If the input has color, do not compute the length contributed by the color to the actual length
|
|
|
|
|
if input.starts_with("\u{1b}[") {
|
|
|
|
|
let m_pos = input.find('m');
|
|
|
|
|
if let Some(len) = m_pos {
|
2019-05-05 17:35:47 +00:00
|
|
|
|
nb_invisible_char = len + 3 // 1 (index -> length) + 2 ( compensate for color reset chars )
|
2019-03-11 13:45:39 +00:00
|
|
|
|
}
|
2019-01-20 10:22:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UnicodeWidthStr::width(input) - nb_invisible_char
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn detect_user_length(metas: &[Meta]) -> usize {
|
|
|
|
|
let mut max: usize = 0;
|
|
|
|
|
|
|
|
|
|
for meta in metas {
|
|
|
|
|
let user = meta.owner.user();
|
|
|
|
|
if user.len() > max {
|
|
|
|
|
max = user.len();
|
2018-12-02 16:22:51 +00:00
|
|
|
|
}
|
2019-01-20 10:22:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
max
|
|
|
|
|
}
|
2018-12-02 17:16:02 +00:00
|
|
|
|
|
2019-01-20 10:22:14 +00:00
|
|
|
|
fn detect_group_length(metas: &[Meta]) -> usize {
|
|
|
|
|
let mut max: usize = 0;
|
|
|
|
|
|
|
|
|
|
for meta in metas {
|
|
|
|
|
let group = meta.owner.group();
|
|
|
|
|
if group.len() > max {
|
|
|
|
|
max = group.len();
|
|
|
|
|
}
|
2018-12-02 16:22:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-01-20 10:22:14 +00:00
|
|
|
|
max
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-30 10:58:36 +00:00
|
|
|
|
fn detect_date_length(metas: &[Meta], flags: &Flags) -> usize {
|
2019-01-20 10:22:14 +00:00
|
|
|
|
let mut max_value_length: usize = 0;
|
2018-12-02 16:22:51 +00:00
|
|
|
|
|
2019-01-20 10:22:14 +00:00
|
|
|
|
for meta in metas {
|
2019-03-30 10:58:36 +00:00
|
|
|
|
if meta.date.date_string(&flags).len() > max_value_length {
|
|
|
|
|
max_value_length = meta.date.date_string(&flags).len();
|
2018-12-02 16:22:51 +00:00
|
|
|
|
}
|
2019-01-20 10:22:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
max_value_length
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-30 10:58:36 +00:00
|
|
|
|
fn detect_size_lengths(metas: &[Meta], flags: &Flags) -> (usize, usize) {
|
2019-01-20 10:22:14 +00:00
|
|
|
|
let mut max_value_length: usize = 0;
|
|
|
|
|
let mut max_unit_size: usize = 0;
|
2018-12-02 16:22:51 +00:00
|
|
|
|
|
2019-01-20 10:22:14 +00:00
|
|
|
|
for meta in metas {
|
|
|
|
|
if meta.size.render_value().len() > max_value_length {
|
|
|
|
|
max_value_length = meta.size.render_value().len();
|
2018-12-20 13:09:01 +00:00
|
|
|
|
}
|
2018-12-02 16:22:51 +00:00
|
|
|
|
|
2019-03-30 10:58:36 +00:00
|
|
|
|
if meta.size.render_unit(&flags).len() > max_unit_size {
|
|
|
|
|
max_unit_size = meta.size.render_unit(&flags).len();
|
2019-01-20 10:22:14 +00:00
|
|
|
|
}
|
2018-12-02 16:22:51 +00:00
|
|
|
|
}
|
2019-01-20 10:22:14 +00:00
|
|
|
|
|
|
|
|
|
(max_value_length, max_unit_size)
|
2018-12-02 16:22:51 +00:00
|
|
|
|
}
|
2019-05-04 10:56:27 +00:00
|
|
|
|
|
2019-06-17 06:42:03 +00:00
|
|
|
|
fn detect_name_length(metas: &[Meta], icons: &Icons, flags: &Flags) -> usize {
|
2019-05-04 10:43:25 +00:00
|
|
|
|
let mut max_value_length: usize = 0;
|
|
|
|
|
|
|
|
|
|
for meta in metas {
|
2019-06-17 06:42:03 +00:00
|
|
|
|
let len = meta.name.name_string(&icons).len() + meta.indicator.len(&flags);
|
|
|
|
|
if len > max_value_length {
|
|
|
|
|
max_value_length = len;
|
2019-05-04 10:43:25 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
max_value_length
|
|
|
|
|
}
|
2018-12-20 02:03:58 +00:00
|
|
|
|
|
2019-06-17 06:42:03 +00:00
|
|
|
|
fn detect_name_with_symlink_length(metas: &[Meta], icons: &Icons, flags: &Flags) -> usize {
|
2019-05-04 10:56:27 +00:00
|
|
|
|
let mut max_value_length: usize = 0;
|
|
|
|
|
|
|
|
|
|
for meta in metas {
|
2019-06-17 06:42:03 +00:00
|
|
|
|
let mut len = meta.name.name_string(&icons).len() + meta.indicator.len(&flags);
|
2019-05-04 10:56:27 +00:00
|
|
|
|
if let Some(syml) = meta.symlink.symlink_string() {
|
2019-06-17 06:42:03 +00:00
|
|
|
|
len += syml.len() + 3 // 3 = ( arrow + 2 spaces) for symlink;
|
2019-05-04 10:56:27 +00:00
|
|
|
|
}
|
|
|
|
|
if len > max_value_length {
|
|
|
|
|
max_value_length = len;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
max_value_length
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-20 02:03:58 +00:00
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
|
|
|
|
use super::*;
|
2019-02-09 10:41:42 +00:00
|
|
|
|
use crate::color;
|
|
|
|
|
use crate::color::Colors;
|
|
|
|
|
use crate::icon;
|
|
|
|
|
use crate::icon::Icons;
|
|
|
|
|
use crate::meta::{FileType, Name};
|
2018-12-20 02:51:44 +00:00
|
|
|
|
use std::path::Path;
|
2018-12-20 02:03:58 +00:00
|
|
|
|
|
|
|
|
|
#[test]
|
2018-12-20 13:09:01 +00:00
|
|
|
|
fn test_display_get_visible_width_without_icons() {
|
2018-12-20 02:03:58 +00:00
|
|
|
|
for (s, l) in &[
|
|
|
|
|
("Hello,world!", 22),
|
|
|
|
|
("ASCII1234-_", 11),
|
|
|
|
|
("制作样本。", 10),
|
|
|
|
|
("日本語", 6),
|
|
|
|
|
("샘플은 무료로 드리겠습니다", 26),
|
|
|
|
|
("👩🐩", 4),
|
|
|
|
|
("🔬", 2),
|
|
|
|
|
] {
|
|
|
|
|
let path = Path::new(s);
|
2019-01-19 16:27:50 +00:00
|
|
|
|
let name = Name::new(
|
|
|
|
|
&path,
|
|
|
|
|
FileType::File {
|
|
|
|
|
exec: false,
|
|
|
|
|
uid: false,
|
|
|
|
|
},
|
|
|
|
|
);
|
2018-12-20 02:51:44 +00:00
|
|
|
|
let output = name.render(
|
2018-12-20 13:09:01 +00:00
|
|
|
|
&Colors::new(color::Theme::NoColor),
|
|
|
|
|
&Icons::new(icon::Theme::NoIcon),
|
2018-12-20 02:51:44 +00:00
|
|
|
|
);
|
2019-01-20 10:22:14 +00:00
|
|
|
|
|
|
|
|
|
assert_eq!(get_visible_width(&output), *l);
|
2018-12-20 02:03:58 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2018-12-20 13:09:01 +00:00
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_display_get_visible_width_with_icons() {
|
|
|
|
|
for (s, l) in &[
|
|
|
|
|
// Add 3 characters for the icons.
|
|
|
|
|
("Hello,world!", 25),
|
|
|
|
|
("ASCII1234-_", 14),
|
2019-03-11 15:12:16 +00:00
|
|
|
|
("File with space", 18),
|
2018-12-20 13:09:01 +00:00
|
|
|
|
("制作样本。", 13),
|
|
|
|
|
("日本語", 9),
|
|
|
|
|
("샘플은 무료로 드리겠습니다", 29),
|
|
|
|
|
("👩🐩", 7),
|
|
|
|
|
("🔬", 5),
|
|
|
|
|
] {
|
|
|
|
|
let path = Path::new(s);
|
2019-01-19 16:27:50 +00:00
|
|
|
|
let name = Name::new(
|
|
|
|
|
&path,
|
|
|
|
|
FileType::File {
|
|
|
|
|
exec: false,
|
|
|
|
|
uid: false,
|
|
|
|
|
},
|
|
|
|
|
);
|
2018-12-20 13:09:01 +00:00
|
|
|
|
let output = name
|
|
|
|
|
.render(
|
|
|
|
|
&Colors::new(color::Theme::NoColor),
|
2019-01-16 16:39:20 +00:00
|
|
|
|
&Icons::new(icon::Theme::Fancy),
|
2018-12-20 13:09:01 +00:00
|
|
|
|
)
|
|
|
|
|
.to_string();
|
2019-01-20 10:22:14 +00:00
|
|
|
|
|
|
|
|
|
assert_eq!(get_visible_width(&output), *l);
|
2018-12-20 13:09:01 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_display_get_visible_width_with_colors() {
|
|
|
|
|
for (s, l) in &[
|
2019-03-11 15:12:16 +00:00
|
|
|
|
("Hello,world!", 22),
|
2018-12-20 13:09:01 +00:00
|
|
|
|
("ASCII1234-_", 11),
|
2019-03-11 15:12:16 +00:00
|
|
|
|
("File with space", 15),
|
2018-12-20 13:09:01 +00:00
|
|
|
|
("制作样本。", 10),
|
|
|
|
|
("日本語", 6),
|
|
|
|
|
("샘플은 무료로 드리겠습니다", 26),
|
|
|
|
|
("👩🐩", 4),
|
|
|
|
|
("🔬", 2),
|
|
|
|
|
] {
|
|
|
|
|
let path = Path::new(s);
|
2019-01-19 16:27:50 +00:00
|
|
|
|
let name = Name::new(
|
|
|
|
|
&path,
|
|
|
|
|
FileType::File {
|
|
|
|
|
exec: false,
|
|
|
|
|
uid: false,
|
|
|
|
|
},
|
|
|
|
|
);
|
2018-12-20 13:09:01 +00:00
|
|
|
|
let output = name
|
|
|
|
|
.render(
|
2019-02-08 07:43:43 +00:00
|
|
|
|
&Colors::new(color::Theme::NoLscolors),
|
2018-12-20 13:09:01 +00:00
|
|
|
|
&Icons::new(icon::Theme::NoIcon),
|
|
|
|
|
)
|
|
|
|
|
.to_string();
|
|
|
|
|
|
|
|
|
|
// check if the color is present.
|
|
|
|
|
assert_eq!(true, output.starts_with("\u{1b}[38;5;"));
|
|
|
|
|
assert_eq!(true, output.ends_with("[0m"));
|
|
|
|
|
|
2019-03-11 15:12:16 +00:00
|
|
|
|
assert_eq!(get_visible_width(&output), *l);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_display_get_visible_width_without_colors() {
|
|
|
|
|
for (s, l) in &[
|
|
|
|
|
("Hello,world!", 22),
|
|
|
|
|
("ASCII1234-_", 11),
|
|
|
|
|
("File with space", 15),
|
|
|
|
|
("制作样本。", 10),
|
|
|
|
|
("日本語", 6),
|
|
|
|
|
("샘플은 무료로 드리겠습니다", 26),
|
|
|
|
|
("👩🐩", 4),
|
|
|
|
|
("🔬", 2),
|
|
|
|
|
] {
|
|
|
|
|
let path = Path::new(s);
|
|
|
|
|
let name = Name::new(
|
|
|
|
|
&path,
|
|
|
|
|
FileType::File {
|
|
|
|
|
exec: false,
|
|
|
|
|
uid: false,
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
let output = name
|
|
|
|
|
.render(
|
|
|
|
|
&Colors::new(color::Theme::NoColor),
|
|
|
|
|
&Icons::new(icon::Theme::NoIcon),
|
|
|
|
|
)
|
|
|
|
|
.to_string();
|
|
|
|
|
|
|
|
|
|
// check if the color is present.
|
|
|
|
|
assert_eq!(false, output.starts_with("\u{1b}[38;5;"));
|
|
|
|
|
assert_eq!(false, output.ends_with("[0m"));
|
|
|
|
|
|
2019-01-20 10:22:14 +00:00
|
|
|
|
assert_eq!(get_visible_width(&output), *l);
|
2018-12-20 13:09:01 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2018-12-20 02:03:58 +00:00
|
|
|
|
}
|