1use std::path::PathBuf;
5
6use anyhow::{Context, Result};
7use glob::glob;
8use walkdir::WalkDir;
9
10pub fn collect_rust_files(paths: &[PathBuf]) -> Result<Vec<PathBuf>> {
11 collect_rust_files_with_exclusions(paths, &[])
12}
13
14pub fn collect_rust_files_with_exclusions(
15 paths: &[PathBuf],
16 exclude_patterns: &[String],
17) -> Result<Vec<PathBuf>> {
18 let mut files = Vec::new();
19
20 for path in paths {
21 let path_str = path.to_string_lossy();
22
23 if path_str.contains('*') || path_str.contains('?') || path_str.contains('[') {
24 for entry in glob(&path_str).context("Failed to parse glob pattern")? {
25 match entry {
26 Ok(file_path) => {
27 if file_path.is_file()
28 && file_path.extension().and_then(|s| s.to_str()) == Some("rs")
29 {
30 files.push(file_path);
31 }
32 }
33 Err(e) => eprintln!("Warning: Error reading glob entry: {}", e),
34 }
35 }
36 } else if path.is_file() {
37 if path.extension().and_then(|s| s.to_str()) == Some("rs") {
38 files.push(path.clone());
39 }
40 } else if path.is_dir() {
41 for entry in WalkDir::new(path)
42 .into_iter()
43 .filter_map(|e| e.ok())
44 .filter(|e| e.path().extension().and_then(|s| s.to_str()) == Some("rs"))
45 {
46 files.push(entry.path().to_path_buf());
47 }
48 }
49 }
50
51 if !exclude_patterns.is_empty() {
52 files.retain(|file| {
53 let file_str = file.to_string_lossy();
54 !exclude_patterns.iter().any(|pattern| {
55 if pattern.contains('*') || pattern.contains('?') || pattern.contains('[') {
56 glob::Pattern::new(pattern)
57 .map(|p| p.matches(&file_str))
58 .unwrap_or(false)
59 } else {
60 file_str.contains(pattern.as_str())
61 }
62 })
63 });
64 }
65
66 Ok(files)
67}
68
69pub fn expand_kind_to_node_types(kind: &str) -> Vec<&'static str> {
70 match kind {
71 "struct" => vec!["struct", "struct-literal"],
72 "function" => vec!["function", "function-call", "method-call", "impl-method", "trait-method"],
73 "enum" => vec!["enum", "enum-usage"],
74 "match" => vec!["match-arm"],
75 "identifier" => vec!["identifier"],
76 "type" => vec!["type-ref", "type-alias"],
77 "macro" => vec!["macro-call"],
78 "const" => vec!["const", "static"],
79 "trait" => vec!["trait", "trait-impl"],
80 "mod" => vec!["mod"],
81 "use" => vec!["use"],
82 _ => vec![],
83 }
84}