fn new_rhei_write(
target: &Path,
options: &NewOptions,
description: Option<&str>,
) -> MietteResult<NewWrite> {
let Some(project_dir) = workspace::panta_project_dir(target) else {
return Err(miette!(
help = "create a project first: `rhei init` writes index.panta.md, and `rhei new` fills it.",
"{} is not a Panta project, so there is nowhere to add a rhei: a project is a \
directory holding {}, and its rheis live beside that manifest",
display_path(target),
workspace::PANTA_INDEX_FILE
));
};
let id = resolve_new_rhei_id(&options.title, options.id.as_deref())?;
reject_existing_rhei(&project_dir, &id)?;
let header = RheiHeader {
title: &options.title,
states: options.states.as_deref(),
max_levels: options.max_levels,
node_kinds: &options.node_kinds,
description,
};
let (path, contents, dirs) = if options.dir {
let rhei_dir = project_dir.join(&id);
let tasks_dir = rhei_dir.join("tasks");
let contents = render_rhei_file(&header, false);
(rhei_dir.join("index.rhei.md"), contents, vec![rhei_dir, tasks_dir])
} else {
let contents = render_rhei_file(&header, true);
(project_dir.join(format!("{id}.rhei.md")), contents, Vec::new())
};
Ok(NewWrite {
kind: "rhei",
id: id.clone(),
title: options.title.trim().to_string(),
path,
state: None,
preview: contents.clone(),
contents,
dirs,
next_hint: Some(format!("`rhei new \"<first ticket>\" --under {id}`")),
notes: Vec::new(),
})
}
fn reject_existing_rhei(project_dir: &Path, id: &str) -> MietteResult<()> {
let file = project_dir.join(format!("{id}.rhei.md"));
let dir = project_dir.join(id);
let taken = if file.is_file() {
Some(file)
} else if dir.is_dir() {
Some(dir)
} else {
None
};
match taken {
Some(path) => Err(miette!(
help = "pick another id with --id, or add a ticket to the existing rhei with `--under`.",
"rhei '{id}' already exists at {}",
display_path(&path)
)),
None => Ok(()),
}
}