use crate::client::Client;
use crate::protocol::Request;
pub fn run(args: &[String]) {
match args.first().map(String::as_str) {
Some("add") => cmd_add(&args[1..]),
Some("list" | "ls") => cmd_list(),
Some("done") => cmd_done(&args[1..]),
Some("remove" | "rm") => cmd_remove(&args[1..]),
Some("clear") => cmd_clear(),
Some("service") => crate::service::run_cli(&args[1..]),
Some("help" | "--help" | "-h") => print_help(),
Some(other) => {
eprintln!("Unknown command: {other}");
print_help();
std::process::exit(1);
}
None => unreachable!(),
}
}
fn send_or_exit(request: &Request) -> crate::protocol::Response {
match Client::send(request) {
Ok(resp) => {
if !resp.ok {
if let Some(msg) = &resp.message {
eprintln!("Error: {msg}");
}
std::process::exit(1);
}
resp
}
Err(e) => {
eprintln!("{e}");
std::process::exit(1);
}
}
}
fn cmd_add(args: &[String]) {
if args.is_empty() {
eprintln!("Usage: hyperfocus add <name> [duration_minutes]");
eprintln!(" duration defaults to 25 minutes if omitted");
std::process::exit(1);
}
let (name, duration) = if args.len() >= 2 {
if let Ok(d) = args.last().unwrap().parse::<u32>() {
(args[..args.len() - 1].join(" "), d)
} else {
(args.join(" "), 25)
}
} else {
(args[0].clone(), 25)
};
send_or_exit(&Request::AddTask {
name: name.clone(),
duration_minutes: duration,
});
println!("Added: \"{name}\" ({duration}m)");
}
fn cmd_list() {
let resp = send_or_exit(&Request::ListTasks);
let tasks = resp.tasks.unwrap_or_default();
if tasks.is_empty() {
println!("No tasks. Add one with: hyperfocus add <name> [duration]");
return;
}
println!("{:<4} {:<6} {:<8} Name", "#", "Done", "Minutes");
println!("{}", "-".repeat(40));
for (i, task) in tasks.iter().enumerate() {
let check = if task.completed { "\u{2713}" } else { " " };
println!(
"{:<4} [{}] {:<8} {}",
i + 1,
check,
task.duration_minutes,
task.name
);
}
}
fn cmd_done(args: &[String]) {
let Some(idx_str) = args.first() else {
eprintln!("Usage: hyperfocus done <task_number>");
std::process::exit(1);
};
let Ok(idx) = idx_str.parse::<usize>() else {
eprintln!("Invalid task number: {idx_str}");
std::process::exit(1);
};
if idx == 0 {
eprintln!("Task numbers start at 1");
std::process::exit(1);
}
let resp = send_or_exit(&Request::MarkDone { index: idx - 1 });
if let Some(msg) = resp.message {
println!("{msg}");
}
}
fn cmd_remove(args: &[String]) {
let Some(idx_str) = args.first() else {
eprintln!("Usage: hyperfocus remove <task_number>");
std::process::exit(1);
};
let Ok(idx) = idx_str.parse::<usize>() else {
eprintln!("Invalid task number: {idx_str}");
std::process::exit(1);
};
if idx == 0 {
eprintln!("Task numbers start at 1");
std::process::exit(1);
}
let resp = send_or_exit(&Request::RemoveTask { index: idx - 1 });
if let Some(msg) = resp.message {
println!("{msg}");
}
}
fn cmd_clear() {
let resp = send_or_exit(&Request::ClearCompleted);
if let Some(msg) = resp.message {
println!("{msg}");
}
}
fn print_help() {
println!("Hyperfocus - Focus timer & task manager");
println!();
println!("USAGE:");
println!(" hyperfocus Launch the GUI");
println!(" hyperfocus <command> Run a CLI command");
println!();
println!("COMMANDS:");
println!(" add <name> [minutes] Add a task (default: 25 minutes)");
println!(" list, ls List all tasks");
println!(" done <number> Mark a task as completed");
println!(" remove, rm <number> Remove a task");
println!(" clear Remove all completed tasks");
println!(" service <start|stop|status>");
println!(" Manage the background service");
println!(" help Show this help");
}