| 99 | #[async_trait] |
| 100 | impl WorkspaceSearch for MemoryWorkspace { |
| 101 | async fn glob(&self, request: WorkspaceGlobRequest) -> Result<WorkspaceGlobResult> { |
| 102 | let pattern = |
| 103 | glob::Pattern::new(&request.pattern).map_err(|e| anyhow!("invalid glob: {}", e))?; |
| 104 | let base_prefix = if request.base.is_root() { |
| 105 | String::new() |
| 106 | } else { |
| 107 | format!("{}/", request.base.as_str()) |
| 108 | }; |
| 109 | let files = self.files.read().unwrap(); |
| 110 | let mut matches = Vec::new(); |
| 111 | |
| 112 | for file_path in files.keys() { |
| 113 | if !file_path.starts_with(&base_prefix) { |
| 114 | continue; |
| 115 | } |
| 116 | let remaining = &file_path[base_prefix.len()..]; |
| 117 | if pattern.matches(remaining) { |
| 118 | matches.push(WorkspacePath::from_normalized(file_path.clone())); |
| 119 | } |
| 120 | } |
| 121 | |
| 122 | matches.sort_by(|a, b| a.as_str().cmp(b.as_str())); |
| 123 | Ok(WorkspaceGlobResult { matches }) |
| 124 | } |
| 125 | |
| 126 | async fn grep(&self, request: WorkspaceGrepRequest) -> Result<WorkspaceGrepResult> { |
| 127 | let pattern = if request.case_insensitive { |