use crate::entry::SortOrder;
use clap::{ArgGroup, Parser};
use std::path::PathBuf;
#[derive(Parser)]
#[command(
name = "duvis",
version,
about = "duvis (/ˈduːvɪs/) is a fast, read-only disk usage analyzer for both AI agents and humans. \
Default output is a colorized terminal tree; pass --analyze for a per-category summary, --json for \
structured output, or --ui for an interactive browser treemap. Strictly read-only — duvis never \
deletes anything and never recommends what to delete.",
after_help = "EXAMPLES:
Tree view, depth-limited
$ duvis ~/projects --depth 2 --top 10
Per-category summary
$ duvis ~/projects --analyze
Structured JSON for scripts and agents
$ duvis ~/projects --json | jq '.children[] | {name, size_human, category}'
Browser UI
$ duvis ~/projects --ui"
)]
#[command(group(
ArgGroup::new("output")
.multiple(false)
.args(["json", "analyze", "ui"])
))]
pub struct Cli {
#[arg(default_value = ".", value_name = "PATH")]
pub path: PathBuf,
#[arg(long, help_heading = "Output Format")]
pub json: bool,
#[arg(long, help_heading = "Output Format")]
pub analyze: bool,
#[arg(long, help_heading = "Output Format")]
pub ui: bool,
#[arg(
short,
long,
value_parser = positive_usize,
value_name = "N",
help_heading = "Display Options"
)]
pub depth: Option<usize>,
#[arg(
short = 'n',
long,
value_parser = positive_usize,
value_name = "N",
help_heading = "Display Options"
)]
pub top: Option<usize>,
#[arg(
long,
default_value = "size",
value_name = "size|name",
help_heading = "Display Options"
)]
pub sort: SortOrder,
#[arg(long, help_heading = "Display Options")]
pub reverse: bool,
#[arg(
long,
default_value = "7515",
value_name = "PORT",
help_heading = "UI Server Options"
)]
pub port: u16,
}
fn positive_usize(s: &str) -> Result<usize, String> {
let n: usize = s
.parse()
.map_err(|e: std::num::ParseIntError| e.to_string())?;
if n == 0 {
Err("must be ≥ 1".to_string())
} else {
Ok(n)
}
}