|
1 | 1 | use std::path::{Component, Path, PathBuf};
|
| 2 | +use std::str::FromStr; |
2 | 3 | use std::sync::Arc;
|
3 | 4 |
|
4 | 5 | use ignore::gitignore::Gitignore;
|
@@ -37,26 +38,44 @@ pub struct ServerLinter {
|
37 | 38 | ignore_matcher: LintIgnoreMatcher,
|
38 | 39 | gitignore_glob: Vec<Gitignore>,
|
39 | 40 | lint_on_run: Run,
|
40 |
| - diagnostics: Arc<ServerLinterDiagnostics>, |
| 41 | + diagnostics: ServerLinterDiagnostics, |
41 | 42 | pub extended_paths: Vec<PathBuf>,
|
42 | 43 | }
|
43 | 44 |
|
44 | 45 | #[derive(Debug, Default)]
|
45 | 46 | struct ServerLinterDiagnostics {
|
46 |
| - isolated_linter: Arc<ConcurrentHashMap<String, Vec<DiagnosticReport>>>, |
47 |
| - tsgo_linter: Arc<ConcurrentHashMap<String, Vec<DiagnosticReport>>>, |
| 47 | + isolated_linter: Arc<ConcurrentHashMap<String, Option<Vec<DiagnosticReport>>>>, |
| 48 | + tsgo_linter: Arc<ConcurrentHashMap<String, Option<Vec<DiagnosticReport>>>>, |
48 | 49 | }
|
49 | 50 |
|
50 | 51 | impl ServerLinterDiagnostics {
|
51 |
| - pub fn all_diagnostics(&self, path: &str) -> Vec<DiagnosticReport> { |
52 |
| - let mut diagnostics = Vec::new(); |
53 |
| - if let Some(reports) = self.isolated_linter.pin().get(path) { |
54 |
| - diagnostics.extend_from_slice(reports); |
| 52 | + pub fn get_diagnostics(&self, path: &str) -> Option<Vec<DiagnosticReport>> { |
| 53 | + let mut reports = Vec::new(); |
| 54 | + let mut found = false; |
| 55 | + if let Some(Some(diagnostics)) = self.isolated_linter.pin().get(path) { |
| 56 | + reports.extend(diagnostics.clone()); |
| 57 | + found = true; |
55 | 58 | }
|
56 |
| - if let Some(reports) = self.tsgo_linter.pin().get(path) { |
57 |
| - diagnostics.extend_from_slice(reports); |
| 59 | + if let Some(Some(diagnostics)) = self.tsgo_linter.pin().get(path) { |
| 60 | + reports.extend(diagnostics.clone()); |
| 61 | + found = true; |
58 | 62 | }
|
59 |
| - diagnostics |
| 63 | + if found { Some(reports) } else { None } |
| 64 | + } |
| 65 | + |
| 66 | + pub fn remove_diagnostics(&self, path: &str) { |
| 67 | + self.isolated_linter.pin().remove(path); |
| 68 | + self.tsgo_linter.pin().remove(path); |
| 69 | + } |
| 70 | + |
| 71 | + pub fn get_cached_files_of_diagnostics(&self) -> Vec<String> { |
| 72 | + let mut files = Vec::new(); |
| 73 | + let isolated_files = self.isolated_linter.pin().keys().cloned().collect::<Vec<_>>(); |
| 74 | + let tsgo_files = self.tsgo_linter.pin().keys().cloned().collect::<Vec<_>>(); |
| 75 | + files.extend(isolated_files); |
| 76 | + files.extend(tsgo_files); |
| 77 | + files.dedup(); |
| 78 | + files |
60 | 79 | }
|
61 | 80 | }
|
62 | 81 |
|
@@ -154,7 +173,7 @@ impl ServerLinter {
|
154 | 173 | gitignore_glob: Self::create_ignore_glob(&root_path),
|
155 | 174 | extended_paths,
|
156 | 175 | lint_on_run: options.run,
|
157 |
| - diagnostics: Arc::new(ServerLinterDiagnostics::default()), |
| 176 | + diagnostics: ServerLinterDiagnostics::default(), |
158 | 177 | tsgo_linter: if options.type_aware {
|
159 | 178 | Arc::new(Some(TsgoLinter::new(&root_path, config_store)))
|
160 | 179 | } else {
|
@@ -247,6 +266,35 @@ impl ServerLinter {
|
247 | 266 | gitignore_globs
|
248 | 267 | }
|
249 | 268 |
|
| 269 | + pub fn remove_diagnostics(&self, uri: &Uri) { |
| 270 | + self.diagnostics.remove_diagnostics(&uri.to_string()); |
| 271 | + } |
| 272 | + |
| 273 | + pub fn get_cached_diagnostics(&self, uri: &Uri) -> Option<Vec<DiagnosticReport>> { |
| 274 | + self.diagnostics.get_diagnostics(&uri.to_string()) |
| 275 | + } |
| 276 | + |
| 277 | + pub fn get_cached_files_of_diagnostics(&self) -> Vec<Uri> { |
| 278 | + self.diagnostics |
| 279 | + .get_cached_files_of_diagnostics() |
| 280 | + .into_iter() |
| 281 | + .filter_map(|s| Uri::from_str(&s).ok()) |
| 282 | + .collect() |
| 283 | + } |
| 284 | + |
| 285 | + pub async fn revalidate_diagnostics( |
| 286 | + &self, |
| 287 | + uris: Vec<Uri>, |
| 288 | + ) -> ConcurrentHashMap<String, Vec<DiagnosticReport>> { |
| 289 | + let map = ConcurrentHashMap::default(); |
| 290 | + for uri in uris { |
| 291 | + if let Some(diagnostics) = self.run_single(&uri, None, ServerLinterRun::Always).await { |
| 292 | + map.pin().insert(uri.to_string(), diagnostics); |
| 293 | + } |
| 294 | + } |
| 295 | + map |
| 296 | + } |
| 297 | + |
250 | 298 | fn is_ignored(&self, uri: &Uri) -> bool {
|
251 | 299 | let Some(uri_path) = uri.to_file_path() else {
|
252 | 300 | return true;
|
@@ -297,26 +345,22 @@ impl ServerLinter {
|
297 | 345 | return None;
|
298 | 346 | }
|
299 | 347 |
|
300 |
| - if oxlint |
301 |
| - && let Some(oxlint_reports) = |
302 |
| - self.isolated_linter.lock().await.run_single(uri, content.clone()) |
303 |
| - { |
304 |
| - self.diagnostics.isolated_linter.pin().insert(uri.to_string(), oxlint_reports); |
305 |
| - } |
306 |
| - |
307 |
| - if !tsgolint { |
308 |
| - return Some(self.diagnostics.all_diagnostics(&uri.to_string())); |
| 348 | + if oxlint { |
| 349 | + let diagnostics = { |
| 350 | + let mut isolated_linter = self.isolated_linter.lock().await; |
| 351 | + isolated_linter.run_single(uri, content.clone()) |
| 352 | + }; |
| 353 | + self.diagnostics.isolated_linter.pin().insert(uri.to_string(), diagnostics); |
309 | 354 | }
|
310 | 355 |
|
311 |
| - let Some(tsgo_linter) = &*self.tsgo_linter else { |
312 |
| - return Some(self.diagnostics.all_diagnostics(&uri.to_string())); |
313 |
| - }; |
314 |
| - |
315 |
| - if let Some(tsgo_reports) = tsgo_linter.lint_file(uri, content) { |
316 |
| - self.diagnostics.tsgo_linter.pin().insert(uri.to_string(), tsgo_reports); |
| 356 | + if tsgolint && let Some(tsgo_linter) = self.tsgo_linter.as_ref() { |
| 357 | + self.diagnostics |
| 358 | + .tsgo_linter |
| 359 | + .pin() |
| 360 | + .insert(uri.to_string(), tsgo_linter.lint_file(uri, content.clone())); |
317 | 361 | }
|
318 | 362 |
|
319 |
| - Some(self.diagnostics.all_diagnostics(&uri.to_string())) |
| 363 | + self.diagnostics.get_diagnostics(&uri.to_string()) |
320 | 364 | }
|
321 | 365 | }
|
322 | 366 |
|
|
0 commit comments