From 5a6a1eeb3918985ab003fd8d87faebb76410a242 Mon Sep 17 00:00:00 2001 From: Kitson Kelly Date: Tue, 29 Mar 2022 11:27:43 +1100 Subject: [PATCH] feat(lsp): support API for config file (#14139) Closes: #13910 --- cli/config_file.rs | 19 +++++++++++++ cli/lsp/capabilities.rs | 32 ++++----------------- cli/lsp/language_server.rs | 10 +++++++ cli/lsp/lsp_custom.rs | 1 + cli/tests/integration/lsp_tests.rs | 45 ++++++++++++++++++++++++++++++ 5 files changed, 80 insertions(+), 27 deletions(-) diff --git a/cli/config_file.rs b/cli/config_file.rs index 1563500646..2c1ec79074 100644 --- a/cli/config_file.rs +++ b/cli/config_file.rs @@ -649,6 +649,25 @@ impl ConfigFile { } } + /// Return any tasks that are defined in the configuration file as a sequence + /// of JSON objects providing the name of the task and the arguments of the + /// task in a detail field. + pub fn to_lsp_tasks(&self) -> Option { + let value = self.json.tasks.clone()?; + let tasks: BTreeMap = serde_json::from_value(value).ok()?; + Some( + tasks + .into_iter() + .map(|(key, value)| { + json!({ + "name": key, + "detail": value, + }) + }) + .collect(), + ) + } + pub fn to_tasks_config( &self, ) -> Result>, AnyError> { diff --git a/cli/lsp/capabilities.rs b/cli/lsp/capabilities.rs index 49adc961d9..ed371bab16 100644 --- a/cli/lsp/capabilities.rs +++ b/cli/lsp/capabilities.rs @@ -5,32 +5,8 @@ ///! language server, which helps determine what messages are sent from the ///! client. ///! -use lspower::lsp::CallHierarchyServerCapability; -use lspower::lsp::ClientCapabilities; -use lspower::lsp::CodeActionKind; -use lspower::lsp::CodeActionOptions; -use lspower::lsp::CodeActionProviderCapability; -use lspower::lsp::CodeLensOptions; -use lspower::lsp::CompletionOptions; -use lspower::lsp::DocumentSymbolOptions; -use lspower::lsp::FoldingRangeProviderCapability; -use lspower::lsp::HoverProviderCapability; -use lspower::lsp::ImplementationProviderCapability; -use lspower::lsp::OneOf; -use lspower::lsp::SaveOptions; -use lspower::lsp::SelectionRangeProviderCapability; -use lspower::lsp::SemanticTokensFullOptions; -use lspower::lsp::SemanticTokensOptions; -use lspower::lsp::SemanticTokensServerCapabilities; -use lspower::lsp::ServerCapabilities; -use lspower::lsp::SignatureHelpOptions; -use lspower::lsp::TextDocumentSyncCapability; -use lspower::lsp::TextDocumentSyncKind; -use lspower::lsp::TextDocumentSyncOptions; -use lspower::lsp::TypeDefinitionProviderCapability; -use lspower::lsp::WorkDoneProgressOptions; -use lspower::lsp::WorkspaceFoldersServerCapabilities; -use lspower::lsp::WorkspaceServerCapabilities; +use deno_core::serde_json::json; +use lspower::lsp::*; use super::refactor::ALL_KNOWN_REFACTOR_ACTION_KINDS; use super::semantic_tokens::get_legend; @@ -158,8 +134,10 @@ pub fn server_capabilities( }), file_operations: None, }), - experimental: None, linked_editing_range_provider: None, moniker_provider: None, + experimental: Some(json!({ + "denoConfigTasks": true, + })), } } diff --git a/cli/lsp/language_server.rs b/cli/lsp/language_server.rs index c2083bc480..1afcff8a64 100644 --- a/cli/lsp/language_server.rs +++ b/cli/lsp/language_server.rs @@ -2141,6 +2141,7 @@ impl Inner { lsp_custom::RELOAD_IMPORT_REGISTRIES_REQUEST => { self.reload_import_registries().await } + lsp_custom::TASK_REQUEST => self.get_tasks(), lsp_custom::VIRTUAL_TEXT_DOCUMENT => { match params.map(serde_json::from_value) { Some(Ok(params)) => Ok(Some( @@ -2831,6 +2832,15 @@ impl Inner { json!({ "averages": averages }) } + fn get_tasks(&self) -> LspResult> { + Ok( + self + .maybe_config_file + .as_ref() + .and_then(|cf| cf.to_lsp_tasks()), + ) + } + async fn reload_import_registries(&mut self) -> LspResult> { fs_util::remove_dir_all_if_exists(&self.module_registries_location) .await diff --git a/cli/lsp/lsp_custom.rs b/cli/lsp/lsp_custom.rs index 1d8c209846..eff55e2ead 100644 --- a/cli/lsp/lsp_custom.rs +++ b/cli/lsp/lsp_custom.rs @@ -6,6 +6,7 @@ use lspower::lsp; pub const CACHE_REQUEST: &str = "deno/cache"; pub const PERFORMANCE_REQUEST: &str = "deno/performance"; +pub const TASK_REQUEST: &str = "deno/task"; pub const RELOAD_IMPORT_REGISTRIES_REQUEST: &str = "deno/reloadImportRegistries"; pub const VIRTUAL_TEXT_DOCUMENT: &str = "deno/virtualTextDocument"; diff --git a/cli/tests/integration/lsp_tests.rs b/cli/tests/integration/lsp_tests.rs index b8f33ddcc5..63695634aa 100644 --- a/cli/tests/integration/lsp_tests.rs +++ b/cli/tests/integration/lsp_tests.rs @@ -579,6 +579,51 @@ fn lsp_import_map_config_file() { shutdown(&mut client); } +#[test] +fn lsp_deno_task() { + let temp_dir = TempDir::new().unwrap(); + let workspace_root = temp_dir.path().canonicalize().unwrap(); + let mut params: lsp::InitializeParams = + serde_json::from_value(load_fixture("initialize_params.json")).unwrap(); + fs::write( + workspace_root.join("deno.jsonc"), + r#"{ + "tasks": { + "build": "deno test", + "some:test": "deno bundle mod.ts" + } + }"#, + ) + .unwrap(); + + params.root_uri = Some(Url::from_file_path(workspace_root).unwrap()); + + let deno_exe = deno_exe_path(); + let mut client = LspClient::new(&deno_exe).unwrap(); + client + .write_request::<_, _, Value>("initialize", params) + .unwrap(); + + let (maybe_res, maybe_err) = client + .write_request::<_, _, Value>("deno/task", json!({})) + .unwrap(); + + assert!(maybe_err.is_none()); + assert_eq!( + maybe_res, + Some(json!([ + { + "name": "build", + "detail": "deno test" + }, + { + "name": "some:test", + "detail": "deno bundle mod.ts" + } + ])) + ); +} + #[test] fn lsp_import_assertions() { let mut client = init("initialize_params_import_map.json");