proc_cli/commands/
kill.rs1use crate::core::{resolve_target, Process};
10use crate::error::{ProcError, Result};
11use crate::ui::{OutputFormat, Printer};
12use clap::Args;
13use dialoguer::Confirm;
14
15#[derive(Args, Debug)]
17pub struct KillCommand {
18 pub target: String,
20
21 #[arg(long, short = 'y')]
23 pub yes: bool,
24
25 #[arg(long)]
27 pub dry_run: bool,
28
29 #[arg(long, short = 'j')]
31 pub json: bool,
32
33 #[arg(long, short = 'v')]
35 pub verbose: bool,
36
37 #[arg(long, short = 'g')]
39 pub graceful: bool,
40}
41
42impl KillCommand {
43 pub fn execute(&self) -> Result<()> {
45 let format = if self.json {
46 OutputFormat::Json
47 } else {
48 OutputFormat::Human
49 };
50 let printer = Printer::new(format, self.verbose);
51
52 let processes = self.resolve_target_processes()?;
54
55 if processes.is_empty() {
56 return Err(ProcError::ProcessNotFound(self.target.clone()));
57 }
58
59 if self.dry_run {
61 printer.warning(&format!(
62 "Dry run: would kill {} process{}",
63 processes.len(),
64 if processes.len() == 1 { "" } else { "es" }
65 ));
66 printer.print_processes(&processes);
67 return Ok(());
68 }
69
70 if !self.yes && !self.json {
72 self.print_confirmation_prompt(&processes);
73
74 let confirmed = Confirm::new()
75 .with_prompt(format!(
76 "Kill {} process{}?",
77 processes.len(),
78 if processes.len() == 1 { "" } else { "es" }
79 ))
80 .default(false)
81 .interact()
82 .unwrap_or(false);
83
84 if !confirmed {
85 printer.warning("Cancelled");
86 return Ok(());
87 }
88 }
89
90 let mut killed = Vec::new();
92 let mut failed = Vec::new();
93
94 for proc in processes {
95 let result = if self.graceful {
96 proc.terminate()
97 } else {
98 proc.kill()
99 };
100
101 match result {
102 Ok(()) => killed.push(proc),
103 Err(e) => failed.push((proc, e.to_string())),
104 }
105 }
106
107 printer.print_kill_result(&killed, &failed);
108
109 if failed.is_empty() {
110 Ok(())
111 } else {
112 Err(ProcError::SignalError(format!(
113 "Failed to kill {} process(es)",
114 failed.len()
115 )))
116 }
117 }
118
119 fn resolve_target_processes(&self) -> Result<Vec<Process>> {
121 resolve_target(&self.target)
122 }
123
124 fn print_confirmation_prompt(&self, processes: &[Process]) {
125 use colored::*;
126
127 println!(
128 "\n{} Found {} process{} to kill:\n",
129 "⚠".yellow().bold(),
130 processes.len().to_string().cyan().bold(),
131 if processes.len() == 1 { "" } else { "es" }
132 );
133
134 for proc in processes {
135 println!(
136 " {} {} [PID {}] - CPU: {:.1}%, MEM: {:.1}MB",
137 "→".bright_black(),
138 proc.name.white().bold(),
139 proc.pid.to_string().cyan(),
140 proc.cpu_percent,
141 proc.memory_mb
142 );
143 }
144 println!();
145 }
146}