use crate::config::CliConfig;
use anyhow::{Result, anyhow};
use clap::Args;
use org_core::{CaptureEntry, OrgMode, PropertyPair};
#[derive(Args)]
pub struct CaptureCommand {
title: String,
#[arg(long)]
level: Option<usize>,
#[arg(short = 's', long)]
todo_state: Option<String>,
#[arg(short = 't', long, value_delimiter = ',')]
tags: Option<Vec<String>>,
#[arg(short = 'p', long)]
priority: Option<String>,
#[arg(short = 'b', long)]
body: Option<String>,
#[arg(short = 'F', long)]
file: Option<String>,
#[arg(long)]
target_heading: Option<String>,
#[arg(long)]
scheduled: Option<String>,
#[arg(long)]
deadline: Option<String>,
#[arg(long)]
closed: Option<String>,
#[arg(long = "property", value_name = "KEY=VALUE")]
properties: Vec<String>,
#[arg(long)]
datetree: bool,
#[arg(long, value_name = "YYYY-MM-DD")]
datetree_date: Option<String>,
#[arg(short = 'f', long)]
format: Option<OutputFormat>,
}
#[derive(clap::ValueEnum, Clone)]
enum OutputFormat {
Plain,
Json,
}
fn parse_property(arg: &str) -> Result<PropertyPair> {
let (key, value) = arg
.split_once('=')
.ok_or_else(|| anyhow!("property must be KEY=VALUE: '{arg}'"))?;
Ok(PropertyPair {
key: key.to_string(),
value: value.to_string(),
})
}
impl CaptureCommand {
pub fn execute(&self, org_mode: OrgMode, cli: CliConfig) -> Result<()> {
let properties = if self.properties.is_empty() {
None
} else {
Some(
self.properties
.iter()
.map(|s| parse_property(s))
.collect::<Result<Vec<_>>>()?,
)
};
let datetree = self.datetree || self.datetree_date.is_some();
let entry = CaptureEntry {
title: self.title.clone(),
level: self.level,
todo_state: self.todo_state.clone(),
tags: self.tags.clone(),
priority: self.priority.clone(),
body: self.body.clone(),
file: self.file.clone(),
target_heading: self.target_heading.clone(),
scheduled: self.scheduled.clone(),
deadline: self.deadline.clone(),
closed: self.closed.clone(),
properties,
datetree,
datetree_date: self.datetree_date.clone(),
};
let result = org_mode.capture_append(entry)?;
let format = self.format.as_ref().unwrap_or({
match cli.default_format.as_str() {
"json" => &OutputFormat::Json,
_ => &OutputFormat::Plain,
}
});
match format {
OutputFormat::Plain => {
println!("Captured to {}", result.file_path);
println!(" {}", result.heading_line);
}
OutputFormat::Json => {
println!("{}", serde_json::to_string_pretty(&result)?);
}
}
Ok(())
}
}