pub mod dispatch;
pub mod items;
pub mod source;
pub mod tui;
use anyhow::Result;
use clap::Parser;
use std::io::IsTerminal;
use std::path::PathBuf;
#[derive(Debug, Parser)]
#[command(author, version, about, long_about = None)]
struct Args {
#[arg(long)]
config: Option<PathBuf>,
#[arg(long)]
snapshot: bool,
#[arg(long, default_value = "")]
query: String,
#[arg(long)]
shell: bool,
#[arg(long, default_value_t = 100)]
width: u16,
#[arg(long, default_value_t = 24)]
height: u16,
#[arg(long)]
debug_kinds: bool,
#[arg(long)]
debug_keys: bool,
}
fn main() -> Result<()> {
let args = Args::parse();
let data = source::collect(args.config)?;
if args.debug_keys {
use std::collections::BTreeMap;
let mut by_key: BTreeMap<String, Vec<&str>> = BTreeMap::new();
for it in &data.items {
if it.keys.is_empty() {
continue;
}
for k in &it.keys {
by_key.entry(k.clone()).or_default().push(it.title.as_str());
}
}
println!("occupied chords ({}):", by_key.len());
for (k, titles) in &by_key {
println!(" {k:<22} โ {}", titles.join(", "));
}
return Ok(());
}
if args.debug_kinds {
use std::collections::BTreeMap;
let mut counts: BTreeMap<&str, usize> = BTreeMap::new();
for it in &data.items {
*counts.entry(it.kind.category_label()).or_default() += 1;
}
println!("collected {} items:", data.items.len());
for (k, v) in &counts {
println!(" {k}: {v}");
}
return Ok(());
}
let header = format!("Herdr Palette ยท {}", data.theme_name);
if args.snapshot || !std::io::stdout().is_terminal() {
let out = tui::render_snapshot(
data.items,
data.palette,
&header,
&args.query,
args.width,
args.height,
)?;
print!("{out}");
return Ok(());
}
match tui::run(
data.items,
data.palette,
&header,
&args.query,
&data.config_path,
args.shell,
&data.cwd,
)? {
tui::Outcome::Selected(item) => {
if let Some(d) = item.dispatch.as_ref() {
dispatch::run(d, &data.cwd)?;
}
}
tui::Outcome::Cancelled => {}
}
Ok(())
}