1use anyhow::{bail, Result};
10use std::io::Write;
11
12use crate::config;
13use crate::db::{self, CommandRecord};
14
15pub fn run_show(id: i64) -> Result<()> {
17 let conn = db::open(&config::db_path()?)?;
18 match db::get_command(&conn, id)? {
19 Some(record) => {
20 let stdout = std::io::stdout();
23 let mut out = stdout.lock();
24 write!(out, "{}", format_record(&record))?;
25 Ok(())
26 }
27 None => bail!("Aucune commande avec l'ID {id}."),
28 }
29}
30
31pub fn run_print(id: i64) -> Result<()> {
37 let conn = db::open(&config::db_path()?)?;
38 match db::get_command(&conn, id)? {
39 Some(record) => {
40 let stdout = std::io::stdout();
41 let mut out = stdout.lock();
42 writeln!(out, "{}", record.command)?;
43 Ok(())
44 }
45 None => bail!("Aucune commande avec l'ID {id}."),
46 }
47}
48
49fn format_record(r: &CommandRecord) -> String {
55 let mut out = String::new();
56 out.push_str(&format!("Commande {}\n\n", r.id));
57 out.push_str(&format!("Date : {}\n", r.created_at));
58 if let Some(cwd) = field(&r.cwd) {
59 out.push_str(&format!("Dossier : {cwd}\n"));
60 }
61 if let Some(root) = field(&r.git_root) {
62 out.push_str(&format!("Projet Git : {root}\n"));
63 }
64 if let Some(branch) = field(&r.git_branch) {
65 out.push_str(&format!("Branche : {branch}\n"));
66 }
67 if let Some(remote) = field(&r.git_remote) {
68 out.push_str(&format!("Remote : {remote}\n"));
69 }
70 if let Some(shell) = field(&r.shell) {
71 out.push_str(&format!("Shell : {shell}\n"));
72 }
73 if let Some(session) = field(&r.session_id) {
74 out.push_str(&format!("Session : {session}\n"));
75 }
76 if let Some(code) = r.exit_code {
77 out.push_str(&format!("Code retour : {code}\n"));
78 }
79 out.push_str(&format!("\nCommande :\n{}\n", r.command));
80 out
81}
82
83fn field(value: &Option<String>) -> Option<&str> {
86 value.as_deref().filter(|s| !s.trim().is_empty())
87}
88
89#[cfg(test)]
90mod tests {
91 use super::*;
92
93 fn rec() -> CommandRecord {
94 CommandRecord {
95 id: 128,
96 command: "cargo test --locked".to_string(),
97 cwd: Some("/home/u/projects/mnemo".to_string()),
98 shell: Some("bash".to_string()),
99 hostname: None,
100 exit_code: Some(0),
101 created_at: "2026-06-23 14:22:10".to_string(),
102 git_root: Some("/home/u/projects/mnemo".to_string()),
103 git_branch: Some("main".to_string()),
104 git_remote: None,
105 session_id: Some("20260623T141200-12345".to_string()),
106 }
107 }
108
109 #[test]
110 fn format_affiche_les_champs_disponibles() {
111 let out = format_record(&rec());
112 assert!(out.contains("Commande 128"));
113 assert!(out.contains("Date : 2026-06-23 14:22:10"));
114 assert!(out.contains("Dossier : /home/u/projects/mnemo"));
115 assert!(out.contains("Projet Git : /home/u/projects/mnemo"));
116 assert!(out.contains("Branche : main"));
117 assert!(out.contains("Session : 20260623T141200-12345"));
118 assert!(out.contains("Code retour : 0"));
119 assert!(out.contains("Commande :\ncargo test --locked\n"));
120 }
121
122 #[test]
123 fn format_omet_les_champs_absents() {
124 let mut r = rec();
125 r.git_remote = None;
126 r.git_branch = None;
127 r.session_id = None;
128 r.git_root = Some(" ".to_string()); let out = format_record(&r);
130 assert!(!out.contains("Branche :"));
131 assert!(!out.contains("Remote :"));
132 assert!(!out.contains("Session :"));
133 assert!(!out.contains("Projet Git :"));
134 }
135
136 #[test]
137 fn format_preserve_une_commande_redactee() {
138 let mut r = rec();
139 r.command = "curl -H 'Authorization: Bearer [REDACTED]'".to_string();
140 let out = format_record(&r);
141 assert!(out.contains("[REDACTED]"));
142 }
143}