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, short = 'p')]
27 pub exe_path: Option<String>,
28
29 #[arg(long)]
31 pub min_cpu: Option<f32>,
32
33 #[arg(long)]
35 pub min_mem: Option<f64>,
36
37 #[arg(long)]
39 pub status: Option<String>,
40
41 #[arg(long, short = 'j')]
43 pub json: bool,
44
45 #[arg(long, short = 'v')]
47 pub verbose: bool,
48
49 #[arg(long, short = 'n')]
51 pub limit: Option<usize>,
52
53 #[arg(long, short = 's', default_value = "cpu")]
55 pub sort: String,
56}
57
58impl InCommand {
59 fn expand_tilde(path: &str) -> PathBuf {
61 if let Some(stripped) = path.strip_prefix("~/") {
62 if let Ok(home) = std::env::var("HOME") {
63 return PathBuf::from(home).join(stripped);
64 }
65 } else if path == "~" {
66 if let Ok(home) = std::env::var("HOME") {
67 return PathBuf::from(home);
68 }
69 }
70 PathBuf::from(path)
71 }
72
73 pub fn execute(&self) -> Result<()> {
75 let format = if self.json {
76 OutputFormat::Json
77 } else {
78 OutputFormat::Human
79 };
80 let printer = Printer::new(format, self.verbose);
81
82 let mut processes = if let Some(ref name) = self.by_name {
84 Process::find_by_name(name)?
85 } else {
86 Process::find_all()?
87 };
88
89 let dir_filter = if self.path == "." {
91 std::env::current_dir().unwrap_or_else(|_| PathBuf::from("."))
92 } else {
93 let expanded = Self::expand_tilde(&self.path);
94 if expanded.is_relative() {
95 std::env::current_dir()
96 .unwrap_or_else(|_| PathBuf::from("."))
97 .join(expanded)
98 } else {
99 expanded
100 }
101 };
102
103 let exe_path_filter: Option<PathBuf> = self.exe_path.as_ref().map(|p| {
105 let path = PathBuf::from(p);
106 if path.is_relative() {
107 std::env::current_dir()
108 .unwrap_or_else(|_| PathBuf::from("."))
109 .join(path)
110 } else {
111 path
112 }
113 });
114
115 processes.retain(|p| {
117 if let Some(ref proc_cwd) = p.cwd {
119 let proc_path = PathBuf::from(proc_cwd);
120 if !proc_path.starts_with(&dir_filter) {
121 return false;
122 }
123 } else {
124 return false;
125 }
126
127 if let Some(ref exe_path) = exe_path_filter {
129 if let Some(ref proc_exe) = p.exe_path {
130 let proc_path = PathBuf::from(proc_exe);
131 if !proc_path.starts_with(exe_path) {
132 return false;
133 }
134 } else {
135 return false;
136 }
137 }
138
139 if let Some(min_cpu) = self.min_cpu {
141 if p.cpu_percent < min_cpu {
142 return false;
143 }
144 }
145
146 if let Some(min_mem) = self.min_mem {
148 if p.memory_mb < min_mem {
149 return false;
150 }
151 }
152
153 if let Some(ref status) = self.status {
155 let status_match = match status.to_lowercase().as_str() {
156 "running" => matches!(p.status, ProcessStatus::Running),
157 "sleeping" | "sleep" => matches!(p.status, ProcessStatus::Sleeping),
158 "stopped" | "stop" => matches!(p.status, ProcessStatus::Stopped),
159 "zombie" => matches!(p.status, ProcessStatus::Zombie),
160 _ => true,
161 };
162 if !status_match {
163 return false;
164 }
165 }
166
167 true
168 });
169
170 match self.sort.to_lowercase().as_str() {
172 "cpu" => processes.sort_by(|a, b| {
173 b.cpu_percent
174 .partial_cmp(&a.cpu_percent)
175 .unwrap_or(std::cmp::Ordering::Equal)
176 }),
177 "mem" | "memory" => processes.sort_by(|a, b| {
178 b.memory_mb
179 .partial_cmp(&a.memory_mb)
180 .unwrap_or(std::cmp::Ordering::Equal)
181 }),
182 "pid" => processes.sort_by_key(|p| p.pid),
183 "name" => processes.sort_by(|a, b| a.name.to_lowercase().cmp(&b.name.to_lowercase())),
184 _ => {} }
186
187 if let Some(limit) = self.limit {
189 processes.truncate(limit);
190 }
191
192 let mut context_parts = vec![format!("in {}", dir_filter.display())];
194 if let Some(ref name) = self.by_name {
195 context_parts.push(format!("by '{}'", name));
196 }
197 let context = Some(context_parts.join(" "));
198
199 printer.print_processes_with_context(&processes, context.as_deref());
200 Ok(())
201 }
202}