1use anyhow::{anyhow, Context, Result};
2use clap::Args;
3use gn_core::{Note, NotesEngine};
4use std::process::Command;
5
6#[derive(Args)]
7pub struct ReplyArgs {
8 pub id: Option<String>,
10
11 #[arg(short, long)]
13 pub message: String,
14}
15
16pub fn run(args: &ReplyArgs) -> Result<()> {
17 let engine = NotesEngine::new(".");
18 let namespaces = vec!["comments", "review", "todos"];
19
20 let mut all_notes = Vec::new();
21
22 for ns in &namespaces {
23 let namespace_enum = gn_core::Namespace::Custom(ns.to_string());
24 if let Ok(notes) = engine.read_notes(&namespace_enum) {
25 all_notes.extend(notes);
26 }
27 }
28
29 if all_notes.is_empty() {
30 return Err(anyhow!("No notes exist in the repository to reply to."));
31 }
32
33 let found_note = match &args.id {
35 None => match super::picker::pick_note("Select note to reply to:", &all_notes)? {
36 Some(n) => Some(n.clone()),
37 None => {
38 println!("Cancelled.");
39 return Ok(());
40 }
41 },
42 Some(raw_id) => {
43 let target = raw_id.trim().trim_start_matches('#');
44 if target.eq_ignore_ascii_case("latest") || target == "^" {
45 all_notes.last().cloned()
46 } else if let Ok(idx) = target.parse::<usize>() {
47 if idx >= 1 && idx <= all_notes.len() {
48 Some(all_notes[idx - 1].clone())
49 } else {
50 None
51 }
52 } else {
53 all_notes
54 .iter()
55 .find(|n| n.id.to_string().starts_with(target))
56 .cloned()
57 }
58 }
59 };
60
61 let parent_note =
62 found_note.ok_or_else(|| anyhow!("Target note not found"))?;
63
64 let name_output = Command::new("git")
65 .args(["config", "user.name"])
66 .output()
67 .context("Failed to read user.name")?;
68 let email_output = Command::new("git")
69 .args(["config", "user.email"])
70 .output()
71 .context("Failed to read user.email")?;
72
73 let author = format!(
74 "{} <{}>",
75 String::from_utf8_lossy(&name_output.stdout).trim(),
76 String::from_utf8_lossy(&email_output.stdout).trim()
77 );
78
79 let reply = Note::reply(&parent_note, args.message.clone(), author);
80
81 let id = engine.write_note(&reply)?;
82 println!(
83 "\x1b[32m✔\x1b[0m Reply added to thread \x1b[36m{}\x1b[0m (Note ID: \x1b[36m{}\x1b[0m)",
84 &parent_note.id.to_string()[..8],
85 &id[..8.min(id.len())]
86 );
87
88 Ok(())
89}