use crate::cli::StepCommand;
use crate::error::{Error, Result};
use crate::storage;
use super::task::active_library_root;
pub fn run(command: StepCommand) -> Result<()> {
match command {
StepCommand::Get { id } => get(&id),
StepCommand::Add { id, title } => add(&id, &title),
StepCommand::Done { id, step } => done(&id, &step),
StepCommand::Remove { id, step } => remove(&id, &step),
}
}
fn get(id: &str) -> Result<()> {
let root = active_library_root()?;
let st = storage::resolve_task(&root, id)?;
if st.task.steps.is_empty() {
println!("#{} {} has no steps", st.task.meta.seq, st.task.meta.title);
return Ok(());
}
println!("#{} {}", st.task.meta.seq, st.task.meta.title);
for (i, step) in st.task.steps.iter().enumerate() {
let mark = if step.done { "x" } else { " " };
println!(" s{} [{mark}] {}", i + 1, step.title);
}
print_progress(&st.task);
Ok(())
}
fn parse_step_index(step: &str, total: usize) -> Result<usize> {
let n = step
.strip_prefix('s')
.and_then(|n| n.parse::<usize>().ok())
.filter(|n| *n >= 1 && *n <= total)
.ok_or_else(|| {
Error::TaskNotFound(format!("step {step} (task has {total} steps: s1..s{total})"))
})?;
Ok(n - 1)
}
fn add(id: &str, title: &str) -> Result<()> {
let root = active_library_root()?;
let mut st = storage::resolve_task(&root, id)?;
st.task.body = crate::checkbox::append(&st.task.body, title);
st.task.steps = crate::checkbox::parse_checkboxes(&st.task.body);
storage::write_task(&st.path, &st.task)?;
println!("added step s{} to #{}", st.task.steps.len(), st.task.meta.seq);
print_progress(&st.task);
Ok(())
}
fn done(id: &str, step: &str) -> Result<()> {
let root = active_library_root()?;
let mut st = storage::resolve_task(&root, id)?;
let idx = parse_step_index(step, st.task.steps.len())?;
st.task.body = crate::checkbox::set_done(&st.task.body, idx).map_err(Error::InvalidTaskFile)?;
st.task.steps = crate::checkbox::parse_checkboxes(&st.task.body);
storage::write_task(&st.path, &st.task)?;
println!("step {step} -> done");
print_progress(&st.task);
Ok(())
}
fn remove(id: &str, step: &str) -> Result<()> {
let root = active_library_root()?;
let mut st = storage::resolve_task(&root, id)?;
let idx = parse_step_index(step, st.task.steps.len())?;
st.task.body =
crate::checkbox::remove_line(&st.task.body, idx).map_err(Error::InvalidTaskFile)?;
st.task.steps = crate::checkbox::parse_checkboxes(&st.task.body);
storage::write_task(&st.path, &st.task)?;
println!("removed step {step} from #{}", st.task.meta.seq);
Ok(())
}
fn print_progress(task: &crate::model::Task) {
let done = task.steps.iter().filter(|s| s.done).count();
println!("progress: {done}/{}", task.steps.len());
}