(&self, request: WorkspaceGrepRequest)
| 193 | } |
| 194 | |
| 195 | async fn grep(&self, request: WorkspaceGrepRequest) -> Result<WorkspaceGrepResult> { |
| 196 | if let Some(ref glob) = request.glob { |
| 197 | validate_relative_pattern(glob, "grep glob filter")?; |
| 198 | } |
| 199 | |
| 200 | let regex_pattern = if request.case_insensitive { |
| 201 | format!("(?i){}", request.pattern) |
| 202 | } else { |
| 203 | request.pattern.clone() |
| 204 | }; |
| 205 | let regex = regex::Regex::new(®ex_pattern) |
| 206 | .map_err(|e| anyhow!("Invalid regex pattern '{}': {}", request.pattern, e))?; |
| 207 | |
| 208 | let search_path = self.local_path_for_read(&request.base)?; |
| 209 | let mut builder = ignore::WalkBuilder::new(&search_path); |
| 210 | builder.hidden(false).git_ignore(true).git_global(true); |
| 211 | |
| 212 | if let Some(ref glob_pat) = request.glob { |
| 213 | let mut types = ignore::types::TypesBuilder::new(); |
| 214 | types.add("custom", glob_pat).ok(); |
| 215 | types.select("custom"); |
| 216 | if let Ok(built) = types.build() { |
| 217 | builder.types(built); |
| 218 | } |
| 219 | } |
| 220 | |
| 221 | let mut output = String::new(); |
| 222 | let mut match_count = 0; |
| 223 | let mut file_count = 0; |
| 224 | let mut total_size = 0; |
| 225 | |
| 226 | for entry in builder.build().flatten() { |
| 227 | if !entry.file_type().map(|ft| ft.is_file()).unwrap_or(false) { |
| 228 | continue; |
| 229 | } |
| 230 | |
| 231 | let file_path = entry.path(); |
| 232 | let content = match std::fs::read_to_string(file_path) { |
| 233 | Ok(content) => content, |
| 234 | Err(_) => continue, |
| 235 | }; |
| 236 | |
| 237 | let lines: Vec<&str> = content.lines().collect(); |
| 238 | let mut file_matches = Vec::new(); |
| 239 | for (line_idx, line) in lines.iter().enumerate() { |
| 240 | if regex.is_match(line) { |
| 241 | file_matches.push(line_idx); |
| 242 | } |
| 243 | } |
| 244 | |
| 245 | if file_matches.is_empty() { |
| 246 | continue; |
| 247 | } |
| 248 | |
| 249 | file_count += 1; |
| 250 | let rel_path = file_path |
| 251 | .strip_prefix(&self.root) |
| 252 | .unwrap_or(file_path) |
no test coverage detected