diff options
Diffstat (limited to 'cli/lsp/documents.rs')
-rw-r--r-- | cli/lsp/documents.rs | 61 |
1 files changed, 61 insertions, 0 deletions
diff --git a/cli/lsp/documents.rs b/cli/lsp/documents.rs index 048e4bedb..5fbfcdf52 100644 --- a/cli/lsp/documents.rs +++ b/cli/lsp/documents.rs @@ -12,6 +12,7 @@ use deno_core::error::Context; use deno_core::ModuleSpecifier; use lspower::lsp::TextDocumentContentChangeEvent; use std::collections::HashMap; +use std::collections::HashSet; use std::ops::Range; use std::str::FromStr; @@ -138,10 +139,42 @@ impl DocumentData { #[derive(Debug, Clone, Default)] pub struct DocumentCache { + dependents_graph: HashMap<ModuleSpecifier, HashSet<ModuleSpecifier>>, docs: HashMap<ModuleSpecifier, DocumentData>, } impl DocumentCache { + /// Calculate a graph of dependents and set it on the structure. + fn calculate_dependents(&mut self) { + let mut dependents_graph: HashMap< + ModuleSpecifier, + HashSet<ModuleSpecifier>, + > = HashMap::new(); + for (specifier, data) in &self.docs { + if let Some(dependencies) = &data.dependencies { + for dependency in dependencies.values() { + if let Some(analysis::ResolvedDependency::Resolved(dep_specifier)) = + &dependency.maybe_code + { + dependents_graph + .entry(dep_specifier.clone()) + .or_default() + .insert(specifier.clone()); + } + if let Some(analysis::ResolvedDependency::Resolved(dep_specifier)) = + &dependency.maybe_type + { + dependents_graph + .entry(dep_specifier.clone()) + .or_default() + .insert(specifier.clone()); + } + } + } + } + self.dependents_graph = dependents_graph; + } + pub fn change( &mut self, specifier: &ModuleSpecifier, @@ -166,6 +199,7 @@ impl DocumentCache { pub fn close(&mut self, specifier: &ModuleSpecifier) { self.docs.remove(specifier); + self.calculate_dependents(); } pub fn contains_key(&self, specifier: &ModuleSpecifier) -> bool { @@ -183,6 +217,17 @@ impl DocumentCache { } } + // For a given specifier, get all open documents which directly or indirectly + // depend upon the specifier. + pub fn dependents( + &self, + specifier: &ModuleSpecifier, + ) -> Vec<ModuleSpecifier> { + let mut dependents = HashSet::new(); + self.recurse_dependents(specifier, &mut dependents); + dependents.into_iter().collect() + } + pub fn dependencies( &self, specifier: &ModuleSpecifier, @@ -260,6 +305,21 @@ impl DocumentCache { .collect() } + fn recurse_dependents( + &self, + specifier: &ModuleSpecifier, + dependents: &mut HashSet<ModuleSpecifier>, + ) { + if let Some(deps) = self.dependents_graph.get(specifier) { + for dep in deps { + if !dependents.contains(dep) { + dependents.insert(dep.clone()); + self.recurse_dependents(dep, dependents); + } + } + } + } + pub fn set_dependencies( &mut self, specifier: &ModuleSpecifier, @@ -267,6 +327,7 @@ impl DocumentCache { ) -> Result<(), AnyError> { if let Some(doc) = self.docs.get_mut(specifier) { doc.dependencies = maybe_dependencies; + self.calculate_dependents(); Ok(()) } else { Err(custom_error( |