DevelopmentNodeEnvironment_MicrosoftVSCodeDependency_22NodeVersion_Bundle_Clean_Debug_ElectronProfile_EsbuildCompiler_Mountain/ProcessManagement/
WorkspaceContainsGlob.rs1pub fn FindMatchingWorkspaceContainsPatterns(Folders:&[std::path::PathBuf], Patterns:&[String]) -> Vec<String> {
16 use std::collections::HashSet;
17
18 const MAX_DEPTH:usize = 3;
19
20 const MAX_ENTRIES_PER_ROOT:usize = 4096;
21
22 let mut Matched:HashSet<String> = HashSet::new();
23
24 for Folder in Folders {
25 if !Folder.is_dir() {
26 continue;
27 }
28
29 let mut Entries:Vec<String> = Vec::new();
30
31 let mut Stack:Vec<(std::path::PathBuf, usize)> = vec![(Folder.clone(), 0)];
32
33 while let Some((Current, Depth)) = Stack.pop() {
34 if Entries.len() >= MAX_ENTRIES_PER_ROOT {
35 break;
36 }
37
38 let ReadDir = match std::fs::read_dir(&Current) {
39 Ok(R) => R,
40
41 Err(_) => continue,
42 };
43
44 for Entry in ReadDir.flatten() {
45 if Entries.len() >= MAX_ENTRIES_PER_ROOT {
46 break;
47 }
48
49 let Path = Entry.path();
50
51 let Relative = match Path.strip_prefix(Folder) {
52 Ok(R) => R.to_string_lossy().replace('\\', "/"),
53
54 Err(_) => continue,
55 };
56
57 let IsDir = Entry.file_type().map(|T| T.is_dir()).unwrap_or(false);
58
59 Entries.push(Relative.clone());
60
61 if IsDir && Depth + 1 < MAX_DEPTH {
62 Stack.push((Path, Depth + 1));
63 }
64 }
65 }
66
67 for Pattern in Patterns {
68 if Matched.contains(Pattern) {
69 continue;
70 }
71
72 if PatternMatchesAnyEntry(Pattern, &Entries) {
73 Matched.insert(Pattern.clone());
74 }
75 }
76 }
77
78 Matched.into_iter().collect()
79}
80
81pub fn PatternMatchesAnyEntry(Pattern:&str, Entries:&[String]) -> bool {
85 let HasWildcard = Pattern.contains('*') || Pattern.contains('?');
86
87 if !HasWildcard {
88 return Entries.iter().any(|E| E == Pattern);
89 }
90
91 let PatternSegments:Vec<&str> = Pattern.split('/').collect();
92
93 Entries
94 .iter()
95 .any(|E| SegmentMatch(&PatternSegments, &E.split('/').collect::<Vec<_>>()))
96}
97
98pub fn SegmentMatch(Pattern:&[&str], Entry:&[&str]) -> bool {
101 if Pattern.is_empty() {
102 return Entry.is_empty();
103 }
104
105 let Head = Pattern[0];
106
107 if Head == "**" {
108 for Consumed in 0..=Entry.len() {
109 if SegmentMatch(&Pattern[1..], &Entry[Consumed..]) {
110 return true;
111 }
112 }
113
114 return false;
115 }
116
117 if Entry.is_empty() {
118 return false;
119 }
120
121 if SingleSegmentMatch(Head, Entry[0]) {
122 return SegmentMatch(&Pattern[1..], &Entry[1..]);
123 }
124
125 false
126}
127
128pub fn SingleSegmentMatch(Pattern:&str, Segment:&str) -> bool {
132 if Pattern == "*" {
133 return true;
134 }
135
136 if !Pattern.contains('*') && !Pattern.contains('?') {
137 return Pattern == Segment;
138 }
139
140 let Fragments:Vec<&str> = Pattern.split('*').collect();
141
142 let mut Cursor = 0usize;
143
144 for (Index, Fragment) in Fragments.iter().enumerate() {
145 if Fragment.is_empty() {
146 continue;
147 }
148
149 if Index == 0 {
150 if !Segment[Cursor..].starts_with(Fragment) {
151 return false;
152 }
153
154 Cursor += Fragment.len();
155
156 continue;
157 }
158
159 match Segment[Cursor..].find(Fragment) {
160 Some(Offset) => Cursor += Offset + Fragment.len(),
161
162 None => return false,
163 }
164 }
165
166 if let Some(Last) = Fragments.last()
167 && !Last.is_empty()
168 {
169 return Segment.ends_with(Last);
170 }
171
172 true
173}