proc_cli/commands/
find_in.rs1use crate::core::{Process, ProcessStatus};
10use crate::error::Result;
11use crate::ui::{OutputFormat, Printer};
12use clap::Args;
13use std::path::PathBuf;
14
15#[derive(Args, Debug)]
17pub struct InCommand {
18 pub path: String,
20
21 #[arg(long = "by", short = 'b')]
23 pub by_name: Option<String>,
24
25 #[arg(long)]
27 pub min_cpu: Option<f32>,
28
29 #[arg(long)]
31 pub min_mem: Option<f64>,
32
33 #[arg(long)]
35 pub status: Option<String>,
36
37 #[arg(long)]
39 pub min_uptime: Option<u64>,
40
41 #[arg(long)]
43 pub parent: Option<u32>,
44
45 #[arg(long, short = 'j')]
47 pub json: bool,
48
49 #[arg(long, short = 'v')]
51 pub verbose: bool,
52
53 #[arg(long, short = 'n')]
55 pub limit: Option<usize>,
56
57 #[arg(long, short = 's', default_value = "cpu")]
59 pub sort: String,
60}
61
62impl InCommand {
63 fn expand_tilde(path: &str) -> PathBuf {
65 if let Some(stripped) = path.strip_prefix("~/") {
66 if let Ok(home) = std::env::var("HOME") {
67 return PathBuf::from(home).join(stripped);
68 }
69 } else if path == "~" {
70 if let Ok(home) = std::env::var("HOME") {
71 return PathBuf::from(home);
72 }
73 }
74 PathBuf::from(path)
75 }
76
77 pub fn execute(&self) -> Result<()> {
79 let format = if self.json {
80 OutputFormat::Json
81 } else {
82 OutputFormat::Human
83 };
84 let printer = Printer::new(format, self.verbose);
85
86 let mut processes = if let Some(ref name) = self.by_name {
88 Process::find_by_name(name)?
89 } else {
90 Process::find_all()?
91 };
92
93 let dir_filter = if self.path == "." {
95 std::env::current_dir().unwrap_or_else(|_| PathBuf::from("."))
96 } else {
97 let expanded = Self::expand_tilde(&self.path);
98 if expanded.is_relative() {
99 std::env::current_dir()
100 .unwrap_or_else(|_| PathBuf::from("."))
101 .join(expanded)
102 } else {
103 expanded
104 }
105 };
106
107 processes.retain(|p| {
109 if let Some(ref proc_cwd) = p.cwd {
111 let proc_path = PathBuf::from(proc_cwd);
112 if !proc_path.starts_with(&dir_filter) {
113 return false;
114 }
115 } else {
116 return false;
117 }
118
119 if let Some(min_cpu) = self.min_cpu {
121 if p.cpu_percent < min_cpu {
122 return false;
123 }
124 }
125
126 if let Some(min_mem) = self.min_mem {
128 if p.memory_mb < min_mem {
129 return false;
130 }
131 }
132
133 if let Some(ref status) = self.status {
135 let status_match = match status.to_lowercase().as_str() {
136 "running" => matches!(p.status, ProcessStatus::Running),
137 "sleeping" | "sleep" => matches!(p.status, ProcessStatus::Sleeping),
138 "stopped" | "stop" => matches!(p.status, ProcessStatus::Stopped),
139 "zombie" => matches!(p.status, ProcessStatus::Zombie),
140 _ => true,
141 };
142 if !status_match {
143 return false;
144 }
145 }
146
147 if let Some(min_uptime) = self.min_uptime {
149 if let Some(start_time) = p.start_time {
150 let now = std::time::SystemTime::now()
151 .duration_since(std::time::UNIX_EPOCH)
152 .map(|d| d.as_secs())
153 .unwrap_or(0);
154 if now.saturating_sub(start_time) < min_uptime {
155 return false;
156 }
157 } else {
158 return false;
159 }
160 }
161
162 if let Some(ppid) = self.parent {
164 if p.parent_pid != Some(ppid) {
165 return false;
166 }
167 }
168
169 true
170 });
171
172 match self.sort.to_lowercase().as_str() {
174 "cpu" => processes.sort_by(|a, b| {
175 b.cpu_percent
176 .partial_cmp(&a.cpu_percent)
177 .unwrap_or(std::cmp::Ordering::Equal)
178 }),
179 "mem" | "memory" => processes.sort_by(|a, b| {
180 b.memory_mb
181 .partial_cmp(&a.memory_mb)
182 .unwrap_or(std::cmp::Ordering::Equal)
183 }),
184 "pid" => processes.sort_by_key(|p| p.pid),
185 "name" => processes.sort_by(|a, b| a.name.to_lowercase().cmp(&b.name.to_lowercase())),
186 _ => {} }
188
189 if let Some(limit) = self.limit {
191 processes.truncate(limit);
192 }
193
194 let mut context_parts = vec![format!("in {}", dir_filter.display())];
196 if let Some(ref name) = self.by_name {
197 context_parts.push(format!("by '{}'", name));
198 }
199 let context = Some(context_parts.join(" "));
200
201 printer.print_processes_with_context(&processes, context.as_deref());
202 Ok(())
203 }
204}