use crate::color::{Colors, Elem};
use crate::flags::blocks::Block;
use crate::flags::{Display, Flags, HyperlinkOption, Layout};
use crate::git_theme::GitTheme;
use crate::icon::Icons;
use crate::meta::name::DisplayOption;
use crate::meta::{FileType, Meta};
use std::collections::HashMap;
use term_grid::{Alignment, Cell, Direction, Filling, Grid, GridOptions};
use terminal_size::terminal_size;
use unicode_width::UnicodeWidthStr;
const EDGE: &str = "\u{251c}\u{2500}\u{2500}"; // "├──"
const LINE: &str = "\u{2502} "; // "│ "
const CORNER: &str = "\u{2514}\u{2500}\u{2500}"; // "└──"
const BLANK: &str = " ";
pub fn grid(
metas: &[Meta],
flags: &Flags,
colors: &Colors,
icons: &Icons,
git_theme: &GitTheme,
) -> String {
let term_width = terminal_size().map(|(w, _)| w.0 as usize);
inner_display_grid(
&DisplayOption::None,
metas,
flags,
colors,
icons,
git_theme,
0,
term_width,
)
}
pub fn tree(
metas: &[Meta],
flags: &Flags,
colors: &Colors,
icons: &Icons,
git_theme: &GitTheme,
) -> String {
let mut grid = Grid::new(GridOptions {
filling: Filling::Spaces(1),
direction: Direction::LeftToRight,
});
let padding_rules = get_padding_rules(metas, flags);
let mut index = 0;
for (i, block) in flags.blocks.0.iter().enumerate() {
if block == &Block::Name {
index = i;
break;
}
}
for cell in inner_display_tree(
metas,
flags,
colors,
icons,
git_theme,
(0, ""),
&padding_rules,
index,
) {
grid.add(cell);
}
grid.fit_into_columns(flags.blocks.0.len()).to_string()
}
#[allow(clippy::too_many_arguments)] // should wrap flags, colors, icons, git_theme into one struct
fn inner_display_grid(
display_option: &DisplayOption,
metas: &[Meta],
flags: &Flags,
colors: &Colors,
icons: &Icons,
git_theme: &GitTheme,
depth: usize,
term_width: Option<usize>,
) -> String {
let mut output = String::new();
let mut cells = Vec::new();
let padding_rules = get_padding_rules(metas, flags);
let mut grid = match flags.layout {
Layout::OneLine => Grid::new(GridOptions {
filling: Filling::Spaces(1),
direction: Direction::LeftToRight,
}),
_ => Grid::new(GridOptions {
filling: Filling::Spaces(2),
direction: Direction::TopToBottom,
}),
};
// 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::DirectoryOnly);
// print the files first.
for meta in metas {
// Maybe skip showing the directory meta now; show its contents later.
if skip_dirs
&& (matches!(meta.file_type, FileType::Directory { .. })
|| (matches!(meta.file_type, FileType::SymLink { is_dir: true })
&& flags.layout != Layout::OneLine))
{
continue;
}
let blocks = get_output(
meta,
colors,
icons,
git_theme,
flags,
display_option,
&padding_rules,
(0, ""),
);
for block in blocks {
cells.push(Cell {
width: get_visible_width(&block, flags.hyperlink == HyperlinkOption::Always),
contents: block,
alignment: Alignment::Left,
});
}
}
// Print block headers
if flags.header.0 && flags.layout