(
root: &Path,
file_tree: &Arc<FileTree>,
pattern: &str,
max_matches: usize,
context_lines: usize,
scope: GrepScope,
file_filter: Option<&str>,
)
| 102 | } |
| 103 | |
| 104 | pub fn grep_with_scope( |
| 105 | root: &Path, |
| 106 | file_tree: &Arc<FileTree>, |
| 107 | pattern: &str, |
| 108 | max_matches: usize, |
| 109 | context_lines: usize, |
| 110 | scope: GrepScope, |
| 111 | file_filter: Option<&str>, |
| 112 | ) -> Result<GrepResponse, String> { |
| 113 | let re = Regex::new(pattern).map_err(|e| format!("Invalid regex: {}", e))?; |
| 114 | |
| 115 | let mut matches = Vec::new(); |
| 116 | let mut total = 0; |
| 117 | |
| 118 | let mut paths: Vec<(String, Language)> = file_tree |
| 119 | .files |
| 120 | .iter() |
| 121 | .filter(|e| { |
| 122 | if let Some(filter) = file_filter { |
| 123 | let key = e.key(); |
| 124 | key == filter || key.contains(filter) || key.ends_with(filter) |
| 125 | } else { |
| 126 | true |
| 127 | } |
| 128 | }) |
| 129 | .map(|e| (e.key().clone(), e.value().language)) |
| 130 | .collect(); |
| 131 | paths.sort_by(|a, b| a.0.cmp(&b.0)); |
| 132 | |
| 133 | for (rel_path, language) in &paths { |
| 134 | let abs_path = root.join(rel_path); |
| 135 | let source = match std::fs::read_to_string(&abs_path) { |
| 136 | Ok(s) => s, |
| 137 | Err(_) => continue, |
| 138 | }; |
| 139 | |
| 140 | // For scope=code, build a set of byte ranges that are inside comments/strings |
| 141 | let excluded_ranges = if scope == GrepScope::Code && language.has_tree_sitter_support() { |
| 142 | compute_non_code_ranges(&source, *language) |
| 143 | } else { |
| 144 | Vec::new() |
| 145 | }; |
| 146 | |
| 147 | let lines: Vec<&str> = source.lines().collect(); |
| 148 | |
| 149 | // Pre-compute line byte offsets for scope filtering |
| 150 | let line_offsets: Vec<usize> = if scope == GrepScope::Code { |
| 151 | let mut offsets = Vec::with_capacity(lines.len()); |
| 152 | let mut offset = 0; |
| 153 | for line in &lines { |
| 154 | offsets.push(offset); |
| 155 | offset += line.len() + 1; // +1 for newline |
| 156 | } |
| 157 | offsets |
| 158 | } else { |
| 159 | Vec::new() |
| 160 | }; |
| 161 |
no test coverage detected