Skip to content

Commit

Permalink
fix(lsp): handle importmaps properly (denoland#11496)
Browse files Browse the repository at this point in the history
  • Loading branch information
kitsonk committed Jul 25, 2021
1 parent 74c7559 commit 72ac9c3
Show file tree
Hide file tree
Showing 8 changed files with 331 additions and 27 deletions.
9 changes: 7 additions & 2 deletions cli/lsp/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,11 +122,16 @@ impl DiagnosticsServer {

pub(crate) async fn invalidate(&self, specifiers: Vec<ModuleSpecifier>) {
let mut collection = self.collection.lock().await;
for specifier in specifiers {
collection.versions.remove(&specifier);
for specifier in &specifiers {
collection.versions.remove(specifier);
}
}

pub(crate) async fn invalidate_all(&self) {
let mut collection = self.collection.lock().await;
collection.versions.clear();
}

pub(crate) fn start(
&mut self,
language_server: Arc<Mutex<language_server::Inner>>,
Expand Down
25 changes: 19 additions & 6 deletions cli/lsp/documents.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ pub struct DocumentData {
bytes: Option<Vec<u8>>,
dependencies: Option<HashMap<String, analysis::Dependency>>,
dependency_ranges: Option<analysis::DependencyRanges>,
language_id: LanguageId,
pub(crate) language_id: LanguageId,
line_index: Option<LineIndex>,
maybe_navigation_tree: Option<tsc::NavigationTree>,
specifier: ModuleSpecifier,
Expand Down Expand Up @@ -180,7 +180,7 @@ impl DocumentData {
#[derive(Debug, Clone, Default)]
pub struct DocumentCache {
dependents_graph: HashMap<ModuleSpecifier, HashSet<ModuleSpecifier>>,
pub docs: HashMap<ModuleSpecifier, DocumentData>,
pub(crate) docs: HashMap<ModuleSpecifier, DocumentData>,
}

impl DocumentCache {
Expand Down Expand Up @@ -272,16 +272,29 @@ impl DocumentCache {
&self,
specifier: &ModuleSpecifier,
) -> Option<HashMap<String, analysis::Dependency>> {
let doc = self.docs.get(specifier)?;
doc.dependencies.clone()
self
.docs
.get(specifier)
.map(|doc| doc.dependencies.clone())
.flatten()
}

pub fn get_language_id(
&self,
specifier: &ModuleSpecifier,
) -> Option<LanguageId> {
self.docs.get(specifier).map(|doc| doc.language_id.clone())
}

pub fn get_navigation_tree(
&self,
specifier: &ModuleSpecifier,
) -> Option<tsc::NavigationTree> {
let doc = self.docs.get(specifier)?;
doc.maybe_navigation_tree.clone()
self
.docs
.get(specifier)
.map(|doc| doc.maybe_navigation_tree.clone())
.flatten()
}

/// Determines if the specifier should be processed for diagnostics and other
Expand Down
54 changes: 47 additions & 7 deletions cli/lsp/language_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,15 +163,15 @@ impl Inner {
fn analyze_dependencies(
&mut self,
specifier: &ModuleSpecifier,
media_type: &MediaType,
source: &str,
) {
let media_type = MediaType::from(specifier);
if let Ok(parsed_module) =
analysis::parse_module(specifier, source, &media_type)
analysis::parse_module(specifier, source, media_type)
{
let (mut deps, _) = analysis::analyze_dependencies(
specifier,
&media_type,
media_type,
&parsed_module,
&self.maybe_import_map,
);
Expand All @@ -194,6 +194,24 @@ impl Inner {
}
}

/// Analyzes all dependencies for all documents that have been opened in the
/// editor and sets the dependencies property on the documents.
fn analyze_dependencies_all(&mut self) {
let docs: Vec<(ModuleSpecifier, String, MediaType)> = self
.documents
.docs
.iter()
.filter_map(|(s, doc)| {
let source = doc.content().ok().flatten()?;
let media_type = MediaType::from(&doc.language_id);
Some((s.clone(), source, media_type))
})
.collect();
for (specifier, source, media_type) in docs {
self.analyze_dependencies(&specifier, &media_type, &source);
}
}

/// Searches assets, open documents and external sources for a line_index,
/// which might be performed asynchronously, hydrating in memory caches for
/// subsequent requests.
Expand Down Expand Up @@ -445,8 +463,10 @@ impl Inner {
let import_map =
ImportMap::from_json(&import_map_url.to_string(), &import_map_json)?;
self.maybe_import_map_uri = Some(import_map_url);
self.maybe_import_map = Some(import_map);
self.maybe_import_map = Some(import_map.clone());
self.sources.set_import_map(Some(import_map));
} else {
self.sources.set_import_map(None);
self.maybe_import_map = None;
}
self.performance.measure(mark);
Expand Down Expand Up @@ -694,6 +714,7 @@ impl Inner {
LanguageId::TypeScript
}
};
let media_type = MediaType::from(&language_id);
self.documents.open(
specifier.clone(),
params.text_document.version,
Expand All @@ -702,7 +723,11 @@ impl Inner {
);

if self.documents.is_diagnosable(&specifier) {
self.analyze_dependencies(&specifier, &params.text_document.text);
self.analyze_dependencies(
&specifier,
&media_type,
&params.text_document.text,
);
self
.diagnostics_server
.invalidate(self.documents.dependents(&specifier))
Expand All @@ -724,7 +749,10 @@ impl Inner {
) {
Ok(Some(source)) => {
if self.documents.is_diagnosable(&specifier) {
self.analyze_dependencies(&specifier, &source);
let media_type = MediaType::from(
&self.documents.get_language_id(&specifier).unwrap(),
);
self.analyze_dependencies(&specifier, &media_type, &source);
self
.diagnostics_server
.invalidate(self.documents.dependents(&specifier))
Expand Down Expand Up @@ -825,12 +853,14 @@ impl Inner {
let mark = self
.performance
.mark("did_change_watched_files", Some(&params));
let mut touched = false;
// if the current import map has changed, we need to reload it
if let Some(import_map_uri) = &self.maybe_import_map_uri {
if params.changes.iter().any(|fe| *import_map_uri == fe.uri) {
if let Err(err) = self.update_import_map().await {
self.client.show_message(MessageType::Warning, err).await;
}
touched = true;
}
}
// if the current tsconfig has changed, we need to reload it
Expand All @@ -839,6 +869,14 @@ impl Inner {
if let Err(err) = self.update_tsconfig().await {
self.client.show_message(MessageType::Warning, err).await;
}
touched = true;
}
}
if touched {
self.analyze_dependencies_all();
self.diagnostics_server.invalidate_all().await;
if let Err(err) = self.diagnostics_server.update() {
error!("Cannot update diagnostics: {}", err);
}
}
self.performance.measure(mark);
Expand Down Expand Up @@ -2392,7 +2430,9 @@ impl Inner {
// invalidate some diagnostics
if self.documents.contains_key(&referrer) {
if let Some(source) = self.documents.content(&referrer).unwrap() {
self.analyze_dependencies(&referrer, &source);
let media_type =
MediaType::from(&self.documents.get_language_id(&referrer).unwrap());
self.analyze_dependencies(&referrer, &media_type, &source);
}
self.diagnostics_server.invalidate(vec![referrer]).await;
}
Expand Down
Loading

0 comments on commit 72ac9c3

Please sign in to comment.