1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-28 16:20:57 -05:00

fix(lsp): don't normalize urls in cache command params (#22182)

This commit is contained in:
Nayeem Rahman 2024-01-30 17:17:34 +00:00 committed by GitHub
parent 0e1cae32b3
commit d730956f49
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 128 additions and 126 deletions

View file

@ -284,7 +284,8 @@ impl LanguageServer {
/// in the Deno cache, including any of their dependencies. /// in the Deno cache, including any of their dependencies.
pub async fn cache_request( pub async fn cache_request(
&self, &self,
params: Option<Value>, specifiers: Vec<ModuleSpecifier>,
referrer: ModuleSpecifier,
) -> LspResult<Option<Value>> { ) -> LspResult<Option<Value>> {
async fn create_graph_for_caching( async fn create_graph_for_caching(
cli_options: CliOptions, cli_options: CliOptions,
@ -330,12 +331,10 @@ impl LanguageServer {
Ok(()) Ok(())
} }
match params.map(serde_json::from_value) {
Some(Ok(params)) => {
// do as much as possible in a read, then do a write outside // do as much as possible in a read, then do a write outside
let maybe_prepare_cache_result = { let maybe_prepare_cache_result = {
let inner = self.0.read().await; // ensure dropped let inner = self.0.read().await; // ensure dropped
match inner.prepare_cache(params) { match inner.prepare_cache(specifiers, referrer) {
Ok(maybe_cache_result) => maybe_cache_result, Ok(maybe_cache_result) => maybe_cache_result,
Err(err) => { Err(err) => {
self self
@ -371,10 +370,6 @@ impl LanguageServer {
} }
Ok(Some(json!(true))) Ok(Some(json!(true)))
} }
Some(Err(err)) => Err(LspError::invalid_params(err.to_string())),
None => Err(LspError::invalid_params("Missing parameters")),
}
}
/// This request is only used by the lsp integration tests to /// This request is only used by the lsp integration tests to
/// coordinate the tests receiving the latest diagnostics. /// coordinate the tests receiving the latest diagnostics.
@ -396,12 +391,6 @@ impl LanguageServer {
Ok(Some(self.0.read().await.get_performance())) Ok(Some(self.0.read().await.get_performance()))
} }
pub async fn reload_import_registries_request(
&self,
) -> LspResult<Option<Value>> {
self.0.write().await.reload_import_registries().await
}
pub async fn task_definitions(&self) -> LspResult<Vec<TaskDefinition>> { pub async fn task_definitions(&self) -> LspResult<Vec<TaskDefinition>> {
self.0.read().await.task_definitions() self.0.read().await.task_definitions()
} }
@ -1081,24 +1070,18 @@ impl Inner {
compiler_options_obj.get("jsxImportSource") compiler_options_obj.get("jsxImportSource")
{ {
if let Some(jsx_import_source) = jsx_import_source.as_str() { if let Some(jsx_import_source) = jsx_import_source.as_str() {
let cache_params = lsp_custom::CacheParams { let specifiers = vec![Url::parse(&format!(
referrer: TextDocumentIdentifier {
uri: config_file.specifier.clone(),
},
uris: vec![TextDocumentIdentifier {
uri: Url::parse(&format!(
"data:application/typescript;base64,{}", "data:application/typescript;base64,{}",
base64::engine::general_purpose::STANDARD.encode( base64::engine::general_purpose::STANDARD.encode(format!(
format!("import '{jsx_import_source}/jsx-runtime';") "import '{jsx_import_source}/jsx-runtime';"
)
)) ))
.unwrap(), ))
}], .unwrap()];
}; let referrer = config_file.specifier.clone();
self.task_queue.queue_task(Box::new(|ls: LanguageServer| { self.task_queue.queue_task(Box::new(|ls: LanguageServer| {
spawn(async move { spawn(async move {
if let Err(err) = if let Err(err) =
ls.cache_request(Some(json!(cache_params))).await ls.cache_request(specifiers, referrer).await
{ {
lsp_warn!("{}", err); lsp_warn!("{}", err);
} }
@ -3222,24 +3205,13 @@ impl tower_lsp::LanguageServer for LanguageServer {
) -> LspResult<Option<Value>> { ) -> LspResult<Option<Value>> {
if params.command == "deno.cache" { if params.command == "deno.cache" {
let mut arguments = params.arguments.into_iter(); let mut arguments = params.arguments.into_iter();
let uris = serde_json::to_value(arguments.next()).unwrap(); let specifiers = serde_json::to_value(arguments.next()).unwrap();
let uris: Vec<Url> = serde_json::from_value(uris) let specifiers: Vec<Url> = serde_json::from_value(specifiers)
.map_err(|err| LspError::invalid_params(err.to_string()))?; .map_err(|err| LspError::invalid_params(err.to_string()))?;
let referrer = serde_json::to_value(arguments.next()).unwrap(); let referrer = serde_json::to_value(arguments.next()).unwrap();
let referrer: Url = serde_json::from_value(referrer) let referrer: Url = serde_json::from_value(referrer)
.map_err(|err| LspError::invalid_params(err.to_string()))?; .map_err(|err| LspError::invalid_params(err.to_string()))?;
self self.cache_request(specifiers, referrer).await
.cache_request(Some(
serde_json::to_value(lsp_custom::CacheParams {
referrer: TextDocumentIdentifier { uri: referrer },
uris: uris
.into_iter()
.map(|uri| TextDocumentIdentifier { uri })
.collect(),
})
.expect("well formed json"),
))
.await
} else if params.command == "deno.reloadImportRegistries" { } else if params.command == "deno.reloadImportRegistries" {
self.0.write().await.reload_import_registries().await self.0.write().await.reload_import_registries().await
} else { } else {
@ -3421,7 +3393,7 @@ impl tower_lsp::LanguageServer for LanguageServer {
async fn did_save(&self, params: DidSaveTextDocumentParams) { async fn did_save(&self, params: DidSaveTextDocumentParams) {
let uri = &params.text_document.uri; let uri = &params.text_document.uri;
{ let specifier = {
let mut inner = self.0.write().await; let mut inner = self.0.write().await;
let specifier = inner.url_map.normalize_url(uri, LspUrlKind::File); let specifier = inner.url_map.normalize_url(uri, LspUrlKind::File);
inner.documents.save(&specifier); inner.documents.save(&specifier);
@ -3438,18 +3410,10 @@ impl tower_lsp::LanguageServer for LanguageServer {
Ok(path) if is_importable_ext(&path) => {} Ok(path) if is_importable_ext(&path) => {}
_ => return, _ => return,
} }
} specifier
if let Err(err) = self };
.cache_request(Some( if let Err(err) = self.cache_request(vec![], specifier.clone()).await {
serde_json::to_value(lsp_custom::CacheParams { lsp_warn!("Failed to cache \"{}\" on save: {}", &specifier, err);
referrer: TextDocumentIdentifier { uri: uri.clone() },
uris: vec![TextDocumentIdentifier { uri: uri.clone() }],
})
.unwrap(),
))
.await
{
lsp_warn!("Failed to cache \"{}\" on save: {}", uri.to_string(), err);
} }
} }
@ -3693,22 +3657,17 @@ struct PrepareCacheResult {
impl Inner { impl Inner {
fn prepare_cache( fn prepare_cache(
&self, &self,
params: lsp_custom::CacheParams, specifiers: Vec<ModuleSpecifier>,
referrer: ModuleSpecifier,
) -> Result<Option<PrepareCacheResult>, AnyError> { ) -> Result<Option<PrepareCacheResult>, AnyError> {
let referrer = self let mark = self
.url_map .performance
.normalize_url(&params.referrer.uri, LspUrlKind::File); .mark_with_args("lsp.cache", (&specifiers, &referrer));
let mark = self.performance.mark_with_args("lsp.cache", &params); let roots = if !specifiers.is_empty() {
let roots = if !params.uris.is_empty() { specifiers
params
.uris
.iter()
.map(|t| self.url_map.normalize_url(&t.uri, LspUrlKind::File))
.collect()
} else { } else {
vec![referrer] vec![referrer]
}; };
let workspace_settings = self.config.workspace_settings(); let workspace_settings = self.config.workspace_settings();
let mut cli_options = CliOptions::new( let mut cli_options = CliOptions::new(
Flags { Flags {

View file

@ -4,26 +4,12 @@ use deno_core::serde::Deserialize;
use deno_core::serde::Serialize; use deno_core::serde::Serialize;
use tower_lsp::lsp_types as lsp; use tower_lsp::lsp_types as lsp;
pub const CACHE_REQUEST: &str = "deno/cache";
pub const PERFORMANCE_REQUEST: &str = "deno/performance"; pub const PERFORMANCE_REQUEST: &str = "deno/performance";
pub const TASK_REQUEST: &str = "deno/taskDefinitions"; pub const TASK_REQUEST: &str = "deno/taskDefinitions";
pub const RELOAD_IMPORT_REGISTRIES_REQUEST: &str =
"deno/reloadImportRegistries";
pub const VIRTUAL_TEXT_DOCUMENT: &str = "deno/virtualTextDocument"; pub const VIRTUAL_TEXT_DOCUMENT: &str = "deno/virtualTextDocument";
pub const LATEST_DIAGNOSTIC_BATCH_INDEX: &str = pub const LATEST_DIAGNOSTIC_BATCH_INDEX: &str =
"deno/internalLatestDiagnosticBatchIndex"; "deno/internalLatestDiagnosticBatchIndex";
#[derive(Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CacheParams {
/// The document currently open in the editor. If there are no `uris`
/// supplied, the referrer will be cached.
pub referrer: lsp::TextDocumentIdentifier,
/// Any documents that have been specifically asked to be cached via the
/// command.
pub uris: Vec<lsp::TextDocumentIdentifier>,
}
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct TaskDefinition { pub struct TaskDefinition {

View file

@ -48,20 +48,10 @@ pub async fn start() -> Result<(), AnyError> {
token.clone(), token.clone(),
) )
}) })
// TODO(nayeemrmn): The extension has replaced this with the `deno.cache`
// command as of vscode_deno 3.21.0 / 2023.09.05. Remove this eventually.
.custom_method(lsp_custom::CACHE_REQUEST, LanguageServer::cache_request)
.custom_method( .custom_method(
lsp_custom::PERFORMANCE_REQUEST, lsp_custom::PERFORMANCE_REQUEST,
LanguageServer::performance_request, LanguageServer::performance_request,
) )
// TODO(nayeemrmn): The extension has replaced this with the
// `deno.reloadImportRegistries` command as of vscode_deno
// 3.26.0 / 2023.10.10. Remove this eventually.
.custom_method(
lsp_custom::RELOAD_IMPORT_REGISTRIES_REQUEST,
LanguageServer::reload_import_registries_request,
)
.custom_method(lsp_custom::TASK_REQUEST, LanguageServer::task_definitions) .custom_method(lsp_custom::TASK_REQUEST, LanguageServer::task_definitions)
// TODO(nayeemrmn): Rename this to `deno/taskDefinitions` in vscode_deno and // TODO(nayeemrmn): Rename this to `deno/taskDefinitions` in vscode_deno and
// remove this alias. // remove this alias.

View file

@ -4945,6 +4945,73 @@ fn lsp_cache_on_save() {
client.shutdown(); client.shutdown();
} }
// Regression test for https://github.com/denoland/deno/issues/22122.
#[test]
fn lsp_cache_then_definition() {
let context = TestContextBuilder::new()
.use_http_server()
.use_temp_cwd()
.build();
let temp_dir = context.temp_dir();
let mut client = context.new_lsp_command().build();
client.initialize_default();
client.did_open(json!({
"textDocument": {
"uri": temp_dir.uri().join("file.ts").unwrap(),
"languageId": "typescript",
"version": 1,
"text": r#"import "http://localhost:4545/run/002_hello.ts";"#,
},
}));
// Prior to the fix, this would cause a faulty memoization that maps the
// URL "http://localhost:4545/run/002_hello.ts" to itself, preventing it from
// being reverse-mapped to "deno:/http/localhost%3A4545/run/002_hello.ts" on
// "textDocument/definition" request.
client.write_request(
"workspace/executeCommand",
json!({
"command": "deno.cache",
"arguments": [
["http://localhost:4545/run/002_hello.ts"],
temp_dir.uri().join("file.ts").unwrap(),
],
}),
);
let res = client.write_request(
"textDocument/definition",
json!({
"textDocument": { "uri": temp_dir.uri().join("file.ts").unwrap() },
"position": { "line": 0, "character": 8 },
}),
);
assert_eq!(
res,
json!([{
"targetUri": "deno:/http/localhost%3A4545/run/002_hello.ts",
"targetRange": {
"start": {
"line": 0,
"character": 0,
},
"end": {
"line": 1,
"character": 0,
},
},
"targetSelectionRange": {
"start": {
"line": 0,
"character": 0,
},
"end": {
"line": 1,
"character": 0,
},
},
}]),
);
}
#[test] #[test]
fn lsp_code_actions_imports() { fn lsp_code_actions_imports() {
let context = TestContextBuilder::new().use_temp_cwd().build(); let context = TestContextBuilder::new().use_temp_cwd().build();