1use crate::{Cli, ClientType, detect_client, detect_installed_clients};
4use std::path::PathBuf;
5
6#[derive(Debug, Clone)]
8pub enum ScanMode {
9 Paths(Vec<PathBuf>),
11 AllClients,
13 SingleClient(ClientType),
15}
16
17impl ScanMode {
18 pub fn from_cli(cli: &Cli) -> Self {
20 if cli.all_clients {
21 ScanMode::AllClients
22 } else if let Some(client) = cli.client {
23 ScanMode::SingleClient(client)
24 } else {
25 ScanMode::Paths(cli.paths.clone())
26 }
27 }
28}
29
30pub fn resolve_scan_paths(cli: &Cli) -> Vec<PathBuf> {
32 let mode = ScanMode::from_cli(cli);
33
34 match mode {
35 ScanMode::Paths(paths) => {
36 if paths.is_empty() {
37 vec![PathBuf::from(".")]
39 } else {
40 paths
41 }
42 }
43 ScanMode::AllClients => {
44 let clients = detect_installed_clients();
45 if clients.is_empty() {
46 eprintln!("No AI coding clients detected on this system.");
47 return Vec::new();
48 }
49
50 let mut paths = Vec::new();
51 for client in &clients {
52 eprintln!(
53 "Detected {}: {}",
54 client.client_type.display_name(),
55 client.home_dir.display()
56 );
57 paths.extend(client.all_configs());
58 }
59 paths
60 }
61 ScanMode::SingleClient(client_type) => match detect_client(client_type) {
62 Some(client) => {
63 eprintln!(
64 "Scanning {}: {}",
65 client.client_type.display_name(),
66 client.home_dir.display()
67 );
68 client.all_configs()
69 }
70 None => {
71 eprintln!(
72 "{} is not installed or has no configuration files.",
73 client_type.display_name()
74 );
75 Vec::new()
76 }
77 },
78 }
79}
80
81pub fn detect_client_for_path(path: &str) -> Option<String> {
83 for client_type in ClientType::all() {
84 if let Some(home) = client_type.home_dir() {
85 let home_str = home.display().to_string();
86 if path.starts_with(&home_str) {
87 return Some(client_type.display_name().to_string());
88 }
89 }
90 }
91 None
92}
93
94#[cfg(test)]
95mod tests {
96 use super::*;
97
98 #[test]
99 fn test_scan_mode_from_cli_paths() {
100 let cli = crate::Cli {
101 paths: vec![PathBuf::from("/test/path")],
102 all_clients: false,
103 client: None,
104 ..Default::default()
105 };
106 match ScanMode::from_cli(&cli) {
107 ScanMode::Paths(paths) => assert_eq!(paths, vec![PathBuf::from("/test/path")]),
108 _ => panic!("Expected ScanMode::Paths"),
109 }
110 }
111
112 #[test]
113 fn test_scan_mode_from_cli_all_clients() {
114 let cli = crate::Cli {
115 paths: vec![],
116 all_clients: true,
117 client: None,
118 ..Default::default()
119 };
120 assert!(matches!(ScanMode::from_cli(&cli), ScanMode::AllClients));
121 }
122
123 #[test]
124 fn test_scan_mode_from_cli_single_client() {
125 let cli = crate::Cli {
126 paths: vec![],
127 all_clients: false,
128 client: Some(ClientType::Claude),
129 ..Default::default()
130 };
131 match ScanMode::from_cli(&cli) {
132 ScanMode::SingleClient(client) => assert_eq!(client, ClientType::Claude),
133 _ => panic!("Expected ScanMode::SingleClient"),
134 }
135 }
136}