pub mod color;
pub mod columns;
pub mod csv;
pub mod format;
pub mod json;
pub mod jsonl;
pub mod long;
pub mod plain;
pub mod tree;
use crate::entry::Entry;
use crate::group;
use crate::walk::Stats;
pub use color::ColorMode;
use lscolors::LsColors;
use serde::Serialize;
use std::borrow::Borrow;
use std::io::{self, Write};
pub struct DisplayOptions {
pub short: bool,
pub classify: bool,
pub color_enabled: bool,
pub terminal_width: u16,
pub ls_colors: LsColors,
}
#[derive(Clone, Copy, clap::ValueEnum)]
pub enum Format {
Plain,
Tree,
Json,
Jsonl,
Csv,
}
#[derive(Clone, Copy, clap::ValueEnum)]
pub enum GroupBy {
Extension,
Directory,
Depth,
}
pub fn write_entries(
w: &mut impl Write,
entries: &[Entry],
format: Format,
group_by: Option<GroupBy>,
display: Option<&DisplayOptions>,
) -> io::Result<()> {
if let Some(gb) = group_by {
write_grouped(w, entries, format, gb, display)
} else {
write_flat(w, entries, format, display)
}
}
pub fn write_stats(w: &mut impl Write, stats: &Stats) -> io::Result<()> {
writeln!(
w,
"\n{} files, {} directories, {} bytes, {:.2?}",
stats.file_count, stats.dir_count, stats.total_size, stats.duration
)
}
fn write_flat<E: Borrow<Entry> + Serialize>(
w: &mut impl Write,
entries: &[E],
format: Format,
display: Option<&DisplayOptions>,
) -> io::Result<()> {
if let (Format::Plain, Some(opts)) = (format, display) {
if opts.short {
return columns::write(w, entries, opts);
}
return long::write(w, entries, opts);
}
match format {
Format::Plain => plain::write(w, entries),
Format::Tree => {
let refs: Vec<&Entry> = entries.iter().map(|e| e.borrow()).collect();
tree::write(w, &refs)
}
Format::Json => json::write(w, entries),
Format::Jsonl => jsonl::write(w, entries),
Format::Csv => csv::write(w, entries),
}
}
fn write_grouped(
w: &mut impl Write,
entries: &[Entry],
format: Format,
group_by: GroupBy,
display: Option<&DisplayOptions>,
) -> io::Result<()> {
match group_by {
GroupBy::Extension => {
let groups = group::group_by_extension(entries);
for (ext, group) in &groups {
writeln!(w, "\n[{}]", ext.unwrap_or("(no extension)"))?;
write_flat(w, group, format, display)?;
}
}
GroupBy::Directory => {
let groups = group::group_by_directory(entries);
for (dir, group) in &groups {
let label = if dir.is_empty() { "." } else { dir };
writeln!(w, "\n[{}]", label)?;
write_flat(w, group, format, display)?;
}
}
GroupBy::Depth => {
let groups = group::group_by_depth(entries);
for (depth, group) in &groups {
writeln!(w, "\n[depth {}]", depth)?;
write_flat(w, group, format, display)?;
}
}
}
Ok(())
}