Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(unstable/lsp): support navigating to deno_modules folder #20030

Merged
merged 3 commits into from
Aug 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
424 changes: 376 additions & 48 deletions cli/cache/http_cache/local.rs

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions cli/cache/http_cache/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ mod local;
pub use global::url_to_filename;
pub use global::GlobalHttpCache;
pub use local::LocalHttpCache;
pub use local::LocalLspHttpCache;

/// Cached metadata about a url.
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
Expand Down
1 change: 1 addition & 0 deletions cli/cache/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ pub use http_cache::CachedUrlMetadata;
pub use http_cache::GlobalHttpCache;
pub use http_cache::HttpCache;
pub use http_cache::LocalHttpCache;
pub use http_cache::LocalLspHttpCache;
pub use incremental::IncrementalCache;
pub use node::NodeAnalysisCache;
pub use parsed_source::ParsedSourceCache;
Expand Down
7 changes: 5 additions & 2 deletions cli/lsp/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,11 +154,14 @@ impl OutsideLockClient {

pub async fn publish_diagnostics(
&self,
uri: lsp::Url,
uri: LspClientUrl,
diags: Vec<lsp::Diagnostic>,
version: Option<i32>,
) {
self.0.publish_diagnostics(uri, diags, version).await;
self
.0
.publish_diagnostics(uri.into_url(), diags, version)
.await;
}
}

Expand Down
38 changes: 33 additions & 5 deletions cli/lsp/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ use super::language_server::StateSnapshot;
use super::performance::Performance;
use super::tsc;
use super::tsc::TsServer;
use super::urls::LspClientUrl;
use super::urls::LspUrlMap;

use crate::args::LintOptions;
use crate::graph_util;
Expand Down Expand Up @@ -54,6 +56,7 @@ pub struct DiagnosticServerUpdateMessage {
pub snapshot: Arc<StateSnapshot>,
pub config: Arc<ConfigSnapshot>,
pub lint_options: LintOptions,
pub url_map: LspUrlMap,
}

struct DiagnosticRecord {
Expand Down Expand Up @@ -107,6 +110,7 @@ impl DiagnosticsPublisher {
&self,
source: DiagnosticSource,
diagnostics: DiagnosticVec,
url_map: &LspUrlMap,
token: &CancellationToken,
) -> usize {
let mut diagnostics_by_specifier =
Expand Down Expand Up @@ -141,7 +145,9 @@ impl DiagnosticsPublisher {
.client
.when_outside_lsp_lock()
.publish_diagnostics(
record.specifier,
url_map
.normalize_specifier(&record.specifier)
.unwrap_or(LspClientUrl::new(record.specifier)),
all_specifier_diagnostics,
version,
)
Expand Down Expand Up @@ -169,7 +175,9 @@ impl DiagnosticsPublisher {
.client
.when_outside_lsp_lock()
.publish_diagnostics(
specifier.clone(),
url_map
.normalize_specifier(specifier)
.unwrap_or_else(|_| LspClientUrl::new(specifier.clone())),
Vec::new(),
removed_value.version,
)
Expand Down Expand Up @@ -366,9 +374,11 @@ impl DiagnosticsServer {
snapshot,
config,
lint_options,
url_map,
},
batch_index,
} = message;
let url_map = Arc::new(url_map);

// cancel the previous run
token.cancel();
Expand All @@ -383,6 +393,7 @@ impl DiagnosticsServer {
let ts_diagnostics_store = ts_diagnostics_store.clone();
let snapshot = snapshot.clone();
let config = config.clone();
let url_map = url_map.clone();
async move {
if let Some(previous_handle) = previous_ts_handle {
// Wait on the previous run to complete in order to prevent
Expand Down Expand Up @@ -419,7 +430,12 @@ impl DiagnosticsServer {
if !token.is_cancelled() {
ts_diagnostics_store.update(&diagnostics);
messages_len = diagnostics_publisher
.publish(DiagnosticSource::Ts, diagnostics, &token)
.publish(
DiagnosticSource::Ts,
diagnostics,
&url_map,
&token,
)
.await;

if !token.is_cancelled() {
Expand Down Expand Up @@ -447,6 +463,7 @@ impl DiagnosticsServer {
let token = token.clone();
let snapshot = snapshot.clone();
let config = config.clone();
let url_map = url_map.clone();
async move {
if let Some(previous_handle) = previous_deps_handle {
previous_handle.await;
Expand All @@ -463,7 +480,12 @@ impl DiagnosticsServer {
let mut messages_len = 0;
if !token.is_cancelled() {
messages_len = diagnostics_publisher
.publish(DiagnosticSource::Deno, diagnostics, &token)
.publish(
DiagnosticSource::Deno,
diagnostics,
&url_map,
&token,
)
.await;

if !token.is_cancelled() {
Expand Down Expand Up @@ -491,6 +513,7 @@ impl DiagnosticsServer {
let token = token.clone();
let snapshot = snapshot.clone();
let config = config.clone();
let url_map = url_map.clone();
async move {
if let Some(previous_handle) = previous_lint_handle {
previous_handle.await;
Expand All @@ -514,7 +537,12 @@ impl DiagnosticsServer {
let mut messages_len = 0;
if !token.is_cancelled() {
messages_len = diagnostics_publisher
.publish(DiagnosticSource::Lint, diagnostics, &token)
.publish(
DiagnosticSource::Lint,
diagnostics,
&url_map,
&token,
)
.await;

if !token.is_cancelled() {
Expand Down
9 changes: 8 additions & 1 deletion cli/lsp/documents.rs
Original file line number Diff line number Diff line change
Expand Up @@ -969,6 +969,13 @@ impl Documents {
}
}

pub fn resolve_redirected(
&self,
specifier: &ModuleSpecifier,
) -> Option<ModuleSpecifier> {
self.specifier_resolver.resolve(specifier)
}

/// Return `true` if the specifier can be resolved to a document.
pub fn exists(&self, specifier: &ModuleSpecifier) -> bool {
let specifier = self.specifier_resolver.resolve(specifier);
Expand Down Expand Up @@ -1498,7 +1505,7 @@ impl Documents {
self.resolve_dependency(specifier, maybe_node_resolver)
} else {
let media_type = doc.media_type();
Some((specifier.clone(), media_type))
Some((doc.specifier().clone(), media_type))
}
}

Expand Down
21 changes: 12 additions & 9 deletions cli/lsp/language_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ use crate::cache::DenoDir;
use crate::cache::FastInsecureHasher;
use crate::cache::GlobalHttpCache;
use crate::cache::HttpCache;
use crate::cache::LocalHttpCache;
use crate::cache::LocalLspHttpCache;
use crate::factory::CliFactory;
use crate::file_fetcher::FileFetcher;
use crate::graph_util;
Expand Down Expand Up @@ -204,7 +204,7 @@ pub struct Inner {
/// An abstraction that handles interactions with TypeScript.
pub ts_server: Arc<TsServer>,
/// A map of specifiers and URLs used to translate over the LSP.
pub url_map: Arc<urls::LspUrlMap>,
pub url_map: urls::LspUrlMap,
}

impl LanguageServer {
Expand Down Expand Up @@ -905,16 +905,18 @@ impl Inner {
self.module_registries_location = module_registries_location;
// update the cache path
let global_cache = Arc::new(GlobalHttpCache::new(dir.deps_folder_path()));
let cache: Arc<dyn HttpCache> =
match self.config.maybe_deno_modules_dir_path() {
Some(local_path) => {
Arc::new(LocalHttpCache::new(local_path, global_cache))
}
None => global_cache,
};
let maybe_local_cache =
self.config.maybe_deno_modules_dir_path().map(|local_path| {
Arc::new(LocalLspHttpCache::new(local_path, global_cache.clone()))
});
let cache: Arc<dyn HttpCache> = maybe_local_cache
.clone()
.map(|c| c as Arc<dyn HttpCache>)
.unwrap_or(global_cache);
self.deps_http_cache = cache.clone();
self.documents.set_cache(cache.clone());
self.cache_metadata.set_cache(cache);
self.url_map.set_cache(maybe_local_cache);
self.maybe_global_cache_path = new_cache_path;
Ok(())
}
Expand Down Expand Up @@ -2946,6 +2948,7 @@ impl Inner {
snapshot: self.snapshot(),
config: self.config.snapshot(),
lint_options: self.lint_options.clone(),
url_map: self.url_map.clone(),
};
if let Err(err) = self.diagnostics_server.update(snapshot) {
error!("Cannot update diagnostics: {}", err);
Expand Down
10 changes: 7 additions & 3 deletions cli/lsp/tsc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3214,9 +3214,13 @@ fn op_script_names(state: &mut OpState) -> Vec<String> {
.filter_map(|dep| dep.get_type().or_else(|| dep.get_code())),
);
for specifier in specifiers {
if seen.insert(specifier.as_str()) && documents.exists(specifier) {
// only include dependencies we know to exist otherwise typescript will error
result.push(specifier.to_string());
if seen.insert(specifier.as_str()) {
if let Some(specifier) = documents.resolve_redirected(specifier) {
// only include dependencies we know to exist otherwise typescript will error
if documents.exists(&specifier) {
result.push(specifier.to_string());
}
}
}
}
}
Expand Down
33 changes: 29 additions & 4 deletions cli/lsp/urls.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.

use crate::cache::LocalLspHttpCache;
use crate::file_fetcher::map_content_type;

use data_url::DataUrl;
Expand All @@ -12,6 +13,7 @@ use deno_core::url::Url;
use deno_core::ModuleSpecifier;
use once_cell::sync::Lazy;
use std::collections::HashMap;
use std::sync::Arc;

/// Used in situations where a default URL needs to be used where otherwise a
/// panic is undesired.
Expand Down Expand Up @@ -119,17 +121,31 @@ pub enum LspUrlKind {
/// A bi-directional map of URLs sent to the LSP client and internal module
/// specifiers. We need to map internal specifiers into `deno:` schema URLs
/// to allow the Deno language server to manage these as virtual documents.
#[derive(Debug, Default)]
pub struct LspUrlMap(Mutex<LspUrlMapInner>);
#[derive(Debug, Default, Clone)]
pub struct LspUrlMap {
local_http_cache: Option<Arc<LocalLspHttpCache>>,
inner: Arc<Mutex<LspUrlMapInner>>,
}

impl LspUrlMap {
pub fn set_cache(&mut self, http_cache: Option<Arc<LocalLspHttpCache>>) {
self.local_http_cache = http_cache;
}

/// Normalize a specifier that is used internally within Deno (or tsc) to a
/// URL that can be handled as a "virtual" document by an LSP client.
pub fn normalize_specifier(
&self,
specifier: &ModuleSpecifier,
) -> Result<LspClientUrl, AnyError> {
let mut inner = self.0.lock();
if let Some(cache) = &self.local_http_cache {
if matches!(specifier.scheme(), "http" | "https") {
if let Some(file_url) = cache.get_file_url(specifier) {
return Ok(LspClientUrl(file_url));
}
}
}
let mut inner = self.inner.lock();
if let Some(url) = inner.get_url(specifier).cloned() {
Ok(url)
} else {
Expand Down Expand Up @@ -183,7 +199,16 @@ impl LspUrlMap {
/// so we need to force it to in the mapping and nee to explicitly state whether
/// this is a file or directory url.
pub fn normalize_url(&self, url: &Url, kind: LspUrlKind) -> ModuleSpecifier {
let mut inner = self.0.lock();
if let Some(cache) = &self.local_http_cache {
if url.scheme() == "file" {
if let Ok(path) = url.to_file_path() {
if let Some(remote_url) = cache.get_remote_url(&path) {
return remote_url;
}
}
}
}
let mut inner = self.inner.lock();
if let Some(specifier) = inner.get_specifier(url).cloned() {
specifier
} else {
Expand Down
Loading
Loading