2024-01-01 14:58:21 -05:00
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
2020-12-21 08:44:26 -05:00
2024-01-02 18:48:34 -05:00
use base64 ::Engine ;
2021-10-28 19:56:01 -04:00
use deno_ast ::MediaType ;
2021-11-16 09:02:28 -05:00
use deno_core ::anyhow ::anyhow ;
2020-12-21 08:44:26 -05:00
use deno_core ::error ::AnyError ;
2023-10-02 17:53:55 -04:00
use deno_core ::parking_lot ::Mutex ;
2021-02-17 13:47:18 -05:00
use deno_core ::resolve_url ;
2020-12-21 08:44:26 -05:00
use deno_core ::serde_json ;
use deno_core ::serde_json ::json ;
use deno_core ::serde_json ::Value ;
2023-08-23 19:03:05 -04:00
use deno_core ::unsync ::spawn ;
2024-03-04 10:48:23 -05:00
use deno_core ::url ;
2020-12-21 08:44:26 -05:00
use deno_core ::ModuleSpecifier ;
2023-06-06 17:07:46 -04:00
use deno_graph ::GraphKind ;
2024-03-04 10:48:23 -05:00
use deno_graph ::Resolution ;
2023-05-22 21:28:36 -04:00
use deno_lockfile ::Lockfile ;
2023-05-17 17:38:50 -04:00
use deno_npm ::NpmSystemInfo ;
2023-05-05 12:44:24 -04:00
use deno_runtime ::deno_fs ;
2023-04-21 21:02:46 -04:00
use deno_runtime ::deno_node ::NodeResolver ;
2023-05-01 16:42:05 -04:00
use deno_runtime ::deno_tls ::rustls ::RootCertStore ;
use deno_runtime ::deno_tls ::RootCertStoreProvider ;
2024-03-04 10:48:23 -05:00
use deno_semver ::jsr ::JsrPackageReqReference ;
2023-10-12 11:07:27 -04:00
use indexmap ::IndexSet ;
2021-03-26 12:34:25 -04:00
use log ::error ;
2024-02-28 22:54:16 -05:00
use serde ::Deserialize ;
2021-02-04 13:53:02 -05:00
use serde_json ::from_value ;
2024-03-21 00:29:52 -04:00
use std ::collections ::BTreeSet ;
2022-10-20 13:23:21 -04:00
use std ::collections ::HashMap ;
2023-02-23 10:58:10 -05:00
use std ::collections ::HashSet ;
2024-03-21 00:29:52 -04:00
use std ::collections ::VecDeque ;
2020-12-21 08:44:26 -05:00
use std ::env ;
2022-07-01 09:28:06 -04:00
use std ::fmt ::Write as _ ;
2024-01-18 15:57:30 -05:00
use std ::path ::Path ;
2020-12-21 08:44:26 -05:00
use std ::path ::PathBuf ;
use std ::sync ::Arc ;
2024-01-02 18:48:34 -05:00
use tokio ::sync ::mpsc ::unbounded_channel ;
use tokio ::sync ::mpsc ::UnboundedReceiver ;
use tokio ::sync ::mpsc ::UnboundedSender ;
2023-11-21 23:08:48 -05:00
use tokio_util ::sync ::CancellationToken ;
2022-04-03 00:17:30 -04:00
use tower_lsp ::jsonrpc ::Error as LspError ;
use tower_lsp ::jsonrpc ::Result as LspResult ;
use tower_lsp ::lsp_types ::request ::* ;
use tower_lsp ::lsp_types ::* ;
2020-12-21 08:44:26 -05:00
2021-05-29 07:21:11 -04:00
use super ::analysis ::fix_ts_import_changes ;
2021-02-05 15:10:53 -05:00
use super ::analysis ::ts_changes_to_edit ;
2021-02-04 13:53:02 -05:00
use super ::analysis ::CodeActionCollection ;
2021-02-05 15:10:53 -05:00
use super ::analysis ::CodeActionData ;
2023-07-01 21:07:57 -04:00
use super ::analysis ::TsResponseImportMapper ;
2022-02-01 21:04:26 -05:00
use super ::cache ;
2020-12-21 08:44:26 -05:00
use super ::capabilities ;
2021-12-15 13:23:43 -05:00
use super ::client ::Client ;
2021-06-04 17:31:44 -04:00
use super ::code_lens ;
2021-03-24 20:13:37 -04:00
use super ::completions ;
2020-12-21 08:44:26 -05:00
use super ::config ::Config ;
2023-09-09 14:37:01 -04:00
use super ::config ::ConfigSnapshot ;
2023-09-25 22:54:07 -04:00
use super ::config ::UpdateImportsOnFileMoveEnabled ;
2023-09-21 01:46:39 -04:00
use super ::config ::WorkspaceSettings ;
2021-05-09 21:16:04 -04:00
use super ::config ::SETTINGS_SECTION ;
2020-12-21 08:44:26 -05:00
use super ::diagnostics ;
2023-09-24 18:33:52 -04:00
use super ::diagnostics ::DiagnosticDataSpecifier ;
2023-05-26 02:10:18 -04:00
use super ::diagnostics ::DiagnosticServerUpdateMessage ;
2022-01-17 17:09:43 -05:00
use super ::diagnostics ::DiagnosticsServer ;
2023-09-24 18:33:52 -04:00
use super ::diagnostics ::DiagnosticsState ;
2021-10-28 19:56:01 -04:00
use super ::documents ::to_lsp_range ;
2021-11-12 11:42:04 -05:00
use super ::documents ::AssetOrDocument ;
2022-02-02 18:02:59 -05:00
use super ::documents ::Document ;
2021-10-28 19:56:01 -04:00
use super ::documents ::Documents ;
2023-03-29 16:25:48 -04:00
use super ::documents ::DocumentsFilter ;
2021-06-02 06:29:58 -04:00
use super ::documents ::LanguageId ;
2024-02-28 22:54:16 -05:00
use super ::jsr ::CliJsrSearchApi ;
2022-01-19 16:05:19 -05:00
use super ::logging ::lsp_log ;
2023-03-30 10:43:16 -04:00
use super ::logging ::lsp_warn ;
2021-06-01 07:53:08 -04:00
use super ::lsp_custom ;
2023-10-12 11:07:27 -04:00
use super ::lsp_custom ::TaskDefinition ;
2023-08-29 11:22:05 -04:00
use super ::npm ::CliNpmSearchApi ;
2021-06-22 21:48:01 -04:00
use super ::parent_process_checker ;
2021-01-26 19:32:49 -05:00
use super ::performance ::Performance ;
2022-12-19 20:22:17 -05:00
use super ::performance ::PerformanceMark ;
2021-08-05 21:46:32 -04:00
use super ::refactor ;
2022-01-23 19:27:52 -05:00
use super ::registries ::ModuleRegistry ;
2022-03-29 18:59:27 -04:00
use super ::testing ;
2020-12-21 08:44:26 -05:00
use super ::text ;
use super ::tsc ;
2021-02-12 06:49:42 -05:00
use super ::tsc ::Assets ;
2022-01-18 16:28:47 -05:00
use super ::tsc ::AssetsSnapshot ;
2023-08-17 10:46:11 -04:00
use super ::tsc ::GetCompletionDetailsArgs ;
2020-12-21 08:44:26 -05:00
use super ::tsc ::TsServer ;
2021-02-17 23:37:05 -05:00
use super ::urls ;
2022-11-28 17:28:54 -05:00
use crate ::args ::get_root_cert_store ;
2023-01-17 19:18:24 -05:00
use crate ::args ::CaData ;
2022-11-28 17:28:54 -05:00
use crate ::args ::CacheSetting ;
2022-07-01 11:50:16 -04:00
use crate ::args ::CliOptions ;
2022-06-27 16:54:09 -04:00
use crate ::args ::ConfigFile ;
2022-07-01 11:50:16 -04:00
use crate ::args ::Flags ;
2022-11-25 19:04:30 -05:00
use crate ::cache ::DenoDir ;
2023-05-22 21:28:36 -04:00
use crate ::cache ::FastInsecureHasher ;
2023-08-01 20:49:09 -04:00
use crate ::cache ::GlobalHttpCache ;
2023-01-25 16:51:04 -05:00
use crate ::cache ::HttpCache ;
2023-08-02 16:57:25 -04:00
use crate ::cache ::LocalLspHttpCache ;
2023-05-01 14:35:23 -04:00
use crate ::factory ::CliFactory ;
2023-01-25 16:51:04 -05:00
use crate ::file_fetcher ::FileFetcher ;
2023-02-15 11:30:54 -05:00
use crate ::graph_util ;
2022-11-18 17:28:14 -05:00
use crate ::http_util ::HttpClient ;
2024-03-26 11:52:20 -04:00
use crate ::lsp ::config ::ConfigWatchedFileType ;
2023-12-08 12:04:56 -05:00
use crate ::lsp ::logging ::init_log_file ;
2023-08-25 20:50:47 -04:00
use crate ::lsp ::tsc ::file_text_changes_to_workspace_edit ;
2023-03-15 10:34:23 -04:00
use crate ::lsp ::urls ::LspUrlKind ;
2023-10-02 17:53:55 -04:00
use crate ::npm ::create_cli_npm_resolver_for_lsp ;
2023-04-21 21:02:46 -04:00
use crate ::npm ::CliNpmResolver ;
2023-10-25 14:39:00 -04:00
use crate ::npm ::CliNpmResolverByonmCreateOptions ;
2023-10-02 17:53:55 -04:00
use crate ::npm ::CliNpmResolverCreateOptions ;
use crate ::npm ::CliNpmResolverManagedCreateOptions ;
use crate ::npm ::CliNpmResolverManagedPackageJsonInstallerOption ;
use crate ::npm ::CliNpmResolverManagedSnapshotOption ;
2024-03-05 19:23:51 -05:00
use crate ::resolver ::CliNodeResolver ;
2021-05-18 02:35:46 -04:00
use crate ::tools ::fmt ::format_file ;
2021-10-21 10:18:18 -04:00
use crate ::tools ::fmt ::format_parsed_source ;
2023-11-14 17:10:51 -05:00
use crate ::tools ::upgrade ::check_for_upgrades_for_lsp ;
use crate ::tools ::upgrade ::upgrade_check_enabled ;
2022-11-28 17:28:54 -05:00
use crate ::util ::fs ::remove_dir_all_if_exists ;
2023-09-24 12:59:42 -04:00
use crate ::util ::path ::is_importable_ext ;
2022-11-28 17:28:54 -05:00
use crate ::util ::path ::specifier_to_file_path ;
2024-03-27 11:58:18 -04:00
use crate ::util ::path ::to_percent_decoded_str ;
2022-11-28 17:28:54 -05:00
use crate ::util ::progress_bar ::ProgressBar ;
2022-12-12 20:52:10 -05:00
use crate ::util ::progress_bar ::ProgressBarStyle ;
2020-12-21 08:44:26 -05:00
2023-05-01 16:42:05 -04:00
struct LspRootCertStoreProvider ( RootCertStore ) ;
impl RootCertStoreProvider for LspRootCertStoreProvider {
fn get_or_try_init ( & self ) -> Result < & RootCertStore , AnyError > {
Ok ( & self . 0 )
}
}
2023-05-22 21:28:36 -04:00
#[ derive(Debug) ]
struct LspNpmServices {
/// When this hash changes, the services need updating
config_hash : LspNpmConfigHash ,
2023-08-29 11:22:05 -04:00
/// Npm's search api.
search_api : CliNpmSearchApi ,
2023-10-25 14:39:00 -04:00
/// Node resolver.
2024-03-05 19:23:51 -05:00
node_resolver : Option < Arc < CliNodeResolver > > ,
2023-05-22 21:28:36 -04:00
/// Resolver for npm packages.
2023-10-02 17:53:55 -04:00
resolver : Option < Arc < dyn CliNpmResolver > > ,
2023-05-22 21:28:36 -04:00
}
#[ derive(Debug, PartialEq, Eq) ]
struct LspNpmConfigHash ( u64 ) ;
impl LspNpmConfigHash {
pub fn from_inner ( inner : & Inner ) -> Self {
2024-03-26 11:52:20 -04:00
let config_data = inner . config . tree . root_data ( ) ;
let node_modules_dir = config_data
. as_ref ( )
. and_then ( | d | d . node_modules_dir . as_ref ( ) ) ;
let lockfile = config_data . as_ref ( ) . and_then ( | d | d . lockfile . as_ref ( ) ) ;
2023-05-22 21:28:36 -04:00
let mut hasher = FastInsecureHasher ::new ( ) ;
2024-03-26 11:52:20 -04:00
hasher . write_hashable ( node_modules_dir ) ;
2023-08-01 20:49:09 -04:00
hasher . write_hashable ( & inner . maybe_global_cache_path ) ;
2024-03-26 11:52:20 -04:00
if let Some ( lockfile ) = lockfile {
2023-07-10 17:45:09 -04:00
hasher . write_hashable ( & * lockfile . lock ( ) ) ;
2023-05-22 21:28:36 -04:00
}
2023-07-10 17:45:09 -04:00
Self ( hasher . finish ( ) )
2023-05-22 21:28:36 -04:00
}
}
2020-12-21 08:44:26 -05:00
#[ derive(Debug, Clone) ]
2023-11-21 23:08:48 -05:00
pub struct LanguageServer ( Arc < tokio ::sync ::RwLock < Inner > > , CancellationToken ) ;
2020-12-21 08:44:26 -05:00
2024-01-11 12:07:44 -05:00
#[ derive(Clone, Debug) ]
2023-09-28 16:43:45 -04:00
pub struct StateNpmSnapshot {
2024-03-05 19:23:51 -05:00
pub node_resolver : Arc < CliNodeResolver > ,
2023-09-29 09:26:25 -04:00
pub npm_resolver : Arc < dyn CliNpmResolver > ,
2023-09-28 16:43:45 -04:00
}
2022-01-19 17:10:14 -05:00
/// Snapshot of the state used by TSC.
2024-01-11 12:07:44 -05:00
#[ derive(Clone, Debug) ]
2022-03-23 09:54:22 -04:00
pub struct StateSnapshot {
2022-01-18 16:28:47 -05:00
pub assets : AssetsSnapshot ,
2022-02-01 21:04:26 -05:00
pub cache_metadata : cache ::CacheMetadata ,
2023-09-09 14:37:01 -04:00
pub config : Arc < ConfigSnapshot > ,
2021-10-28 19:56:01 -04:00
pub documents : Documents ,
2023-09-28 16:43:45 -04:00
pub npm : Option < StateNpmSnapshot > ,
2021-01-26 04:55:04 -05:00
}
2024-01-02 18:48:34 -05:00
type LanguageServerTaskFn = Box < dyn FnOnce ( LanguageServer ) + Send + Sync > ;
/// Used to queue tasks from inside of the language server lock that must be
/// commenced from outside of it. For example, queue a request to cache a module
/// after having loaded a config file which references it.
#[ derive(Debug) ]
struct LanguageServerTaskQueue {
task_tx : UnboundedSender < LanguageServerTaskFn > ,
/// This is moved out to its own task after initializing.
task_rx : Option < UnboundedReceiver < LanguageServerTaskFn > > ,
}
impl Default for LanguageServerTaskQueue {
fn default ( ) -> Self {
let ( task_tx , task_rx ) = unbounded_channel ( ) ;
Self {
task_tx ,
task_rx : Some ( task_rx ) ,
}
}
}
impl LanguageServerTaskQueue {
fn queue_task ( & self , task_fn : LanguageServerTaskFn ) -> bool {
self . task_tx . send ( task_fn ) . is_ok ( )
}
/// Panics if called more than once.
fn start ( & mut self , ls : LanguageServer ) {
let mut task_rx = self . task_rx . take ( ) . unwrap ( ) ;
spawn ( async move {
while let Some ( task_fn ) = task_rx . recv ( ) . await {
task_fn ( ls . clone ( ) ) ;
}
} ) ;
}
}
2021-01-26 04:55:04 -05:00
#[ derive(Debug) ]
2022-03-23 09:54:22 -04:00
pub struct Inner {
2021-02-04 13:53:02 -05:00
/// Cached versions of "fixed" assets that can either be inlined in Rust or
/// are part of the TypeScript snapshot and have to be fetched out.
2021-02-12 06:49:42 -05:00
assets : Assets ,
2022-02-01 21:04:26 -05:00
/// A representation of metadata associated with specifiers in the DENO_DIR
/// which is used by the language server
cache_metadata : cache ::CacheMetadata ,
2021-02-04 13:53:02 -05:00
/// The LSP client that this LSP server is connected to.
2022-03-23 09:54:22 -04:00
pub client : Client ,
2021-02-04 13:53:02 -05:00
/// Configuration information.
2022-03-23 09:54:22 -04:00
pub config : Config ,
2023-08-01 20:49:09 -04:00
deps_http_cache : Arc < dyn HttpCache > ,
2023-09-24 18:33:52 -04:00
diagnostics_state : Arc < diagnostics ::DiagnosticsState > ,
2021-03-09 21:41:35 -05:00
diagnostics_server : diagnostics ::DiagnosticsServer ,
2021-10-28 19:56:01 -04:00
/// The collection of documents that the server is currently handling, either
/// on disk or "open" within the client.
2022-03-23 09:54:22 -04:00
pub documents : Documents ,
2024-01-18 15:57:30 -05:00
initial_cwd : PathBuf ,
2024-02-28 22:54:16 -05:00
jsr_search_api : CliJsrSearchApi ,
2023-05-01 16:42:05 -04:00
http_client : Arc < HttpClient > ,
2024-01-02 18:48:34 -05:00
task_queue : LanguageServerTaskQueue ,
2021-04-08 21:27:27 -04:00
/// Handles module registries, which allow discovery of modules
2022-01-23 19:27:52 -05:00
module_registries : ModuleRegistry ,
2021-04-08 21:27:27 -04:00
/// The path to the module registries cache
module_registries_location : PathBuf ,
2021-07-27 17:25:09 -04:00
/// An optional path to the DENO_DIR which has been specified in the client
/// options.
2023-08-01 20:49:09 -04:00
maybe_global_cache_path : Option < PathBuf > ,
2022-03-29 18:59:27 -04:00
/// A lazily create "server" for handling test run requests.
maybe_testing_server : Option < testing ::TestServer > ,
2023-05-22 21:28:36 -04:00
/// Services used for dealing with npm related functionality.
npm : LspNpmServices ,
2021-02-04 13:53:02 -05:00
/// A collection of measurements which instrument that performance of the LSP.
2022-01-17 17:09:43 -05:00
performance : Arc < Performance > ,
2021-02-04 13:53:02 -05:00
/// A memoized version of fixable diagnostic codes retrieved from TypeScript.
ts_fixable_diagnostics : Vec < String > ,
/// An abstraction that handles interactions with TypeScript.
2022-03-23 09:54:22 -04:00
pub ts_server : Arc < TsServer > ,
2021-02-17 23:37:05 -05:00
/// A map of specifiers and URLs used to translate over the LSP.
2023-08-02 16:57:25 -04:00
pub url_map : urls ::LspUrlMap ,
2024-03-21 00:29:52 -04:00
workspace_files : BTreeSet < ModuleSpecifier > ,
/// Set to `self.config.settings.enable_settings_hash()` after
/// refreshing `self.workspace_files`.
workspace_files_hash : u64 ,
2020-12-21 08:44:26 -05:00
}
impl LanguageServer {
2023-11-21 23:08:48 -05:00
pub fn new ( client : Client , token : CancellationToken ) -> Self {
Self (
Arc ::new ( tokio ::sync ::RwLock ::new ( Inner ::new ( client ) ) ) ,
token ,
)
2021-01-26 04:55:04 -05:00
}
2022-04-03 00:17:30 -04:00
2022-12-19 20:22:17 -05:00
/// Similar to `deno cache` on the command line, where modules will be cached
/// in the Deno cache, including any of their dependencies.
2024-02-28 22:54:16 -05:00
pub async fn cache (
2022-04-03 00:17:30 -04:00
& self ,
2024-01-30 12:17:34 -05:00
specifiers : Vec < ModuleSpecifier > ,
referrer : ModuleSpecifier ,
2024-02-28 22:54:16 -05:00
force_global_cache : bool ,
2022-04-03 00:17:30 -04:00
) -> LspResult < Option < Value > > {
2022-12-19 20:22:17 -05:00
async fn create_graph_for_caching (
cli_options : CliOptions ,
2023-01-24 08:23:19 -05:00
roots : Vec < ModuleSpecifier > ,
2022-12-19 20:22:17 -05:00
open_docs : Vec < Document > ,
) -> Result < ( ) , AnyError > {
let open_docs = open_docs
. into_iter ( )
. map ( | d | ( d . specifier ( ) . clone ( ) , d ) )
. collect ::< HashMap < _ , _ > > ( ) ;
2023-05-22 21:28:36 -04:00
let cli_options = Arc ::new ( cli_options ) ;
let factory = CliFactory ::from_cli_options ( cli_options . clone ( ) ) ;
2023-05-01 14:35:23 -04:00
let module_graph_builder = factory . module_graph_builder ( ) . await ? ;
2024-02-20 16:29:57 -05:00
let module_graph_creator = factory . module_graph_creator ( ) . await ? ;
2023-05-01 14:35:23 -04:00
let mut inner_loader = module_graph_builder . create_graph_loader ( ) ;
2022-12-19 20:22:17 -05:00
let mut loader = crate ::lsp ::documents ::OpenDocumentsGraphLoader {
inner_loader : & mut inner_loader ,
open_docs : & open_docs ,
2023-12-06 19:03:18 -05:00
unstable_sloppy_imports : cli_options . unstable_sloppy_imports ( ) ,
2022-12-19 20:22:17 -05:00
} ;
2024-02-20 16:29:57 -05:00
let graph = module_graph_creator
2023-06-06 17:07:46 -04:00
. create_graph_with_loader ( GraphKind ::All , roots . clone ( ) , & mut loader )
2023-02-09 22:00:23 -05:00
. await ? ;
2023-02-15 11:30:54 -05:00
graph_util ::graph_valid (
2023-02-09 22:00:23 -05:00
& graph ,
2023-12-08 09:57:06 -05:00
factory . fs ( ) . as_ref ( ) ,
2023-02-09 22:00:23 -05:00
& roots ,
2023-02-15 11:30:54 -05:00
graph_util ::GraphValidOptions {
is_vendoring : false ,
2023-02-09 22:00:23 -05:00
follow_type_only : true ,
check_js : false ,
} ,
) ? ;
2023-05-22 21:28:36 -04:00
// Update the lockfile on the file system with anything new
// found after caching
if let Some ( lockfile ) = cli_options . maybe_lockfile ( ) {
let lockfile = lockfile . lock ( ) ;
if let Err ( err ) = lockfile . write ( ) {
2024-03-01 21:25:38 -05:00
lsp_warn! ( " Error writing lockfile: {:#} " , err ) ;
2023-05-22 21:28:36 -04:00
}
}
2022-12-19 20:22:17 -05:00
Ok ( ( ) )
}
2024-01-30 12:17:34 -05:00
// do as much as possible in a read, then do a write outside
let maybe_prepare_cache_result = {
let inner = self . 0. read ( ) . await ; // ensure dropped
2024-03-26 11:52:20 -04:00
match inner . prepare_cache (
specifiers ,
referrer . clone ( ) ,
force_global_cache ,
) {
2024-01-30 12:17:34 -05:00
Ok ( maybe_cache_result ) = > maybe_cache_result ,
Err ( err ) = > {
2024-03-01 21:25:38 -05:00
lsp_warn! ( " Error preparing caching: {:#} " , err ) ;
2024-01-30 12:17:34 -05:00
self
. 0
. read ( )
. await
. client
. show_message ( MessageType ::WARNING , err ) ;
return Err ( LspError ::internal_error ( ) ) ;
2022-12-19 20:22:17 -05:00
}
}
2024-01-30 12:17:34 -05:00
} ;
if let Some ( result ) = maybe_prepare_cache_result {
let cli_options = result . cli_options ;
let roots = result . roots ;
let open_docs = result . open_docs ;
let handle = spawn ( async move {
create_graph_for_caching ( cli_options , roots , open_docs ) . await
} ) ;
if let Err ( err ) = handle . await . unwrap ( ) {
2024-03-01 21:25:38 -05:00
lsp_warn! ( " Error caching: {:#} " , err ) ;
2024-01-30 12:17:34 -05:00
self
. 0
. read ( )
. await
. client
. show_message ( MessageType ::WARNING , err ) ;
}
2024-02-14 17:48:39 -05:00
{
let mut inner = self . 0. write ( ) . await ;
2024-03-26 11:52:20 -04:00
let lockfile = inner . config . tree . lockfile_for_specifier ( & referrer ) ;
2024-02-14 17:48:39 -05:00
inner . documents . refresh_jsr_resolver ( lockfile ) ;
inner . refresh_npm_specifiers ( ) . await ;
2024-02-12 17:12:49 -05:00
}
2024-01-30 12:17:34 -05:00
// now refresh the data in a read
self . 0. read ( ) . await . post_cache ( result . mark ) . await ;
2022-04-03 00:17:30 -04:00
}
2024-01-30 12:17:34 -05:00
Ok ( Some ( json! ( true ) ) )
2022-04-03 00:17:30 -04:00
}
2023-05-26 02:10:18 -04:00
/// This request is only used by the lsp integration tests to
/// coordinate the tests receiving the latest diagnostics.
pub async fn latest_diagnostic_batch_index_request (
& self ,
) -> LspResult < Option < Value > > {
Ok (
self
. 0
. read ( )
. await
. diagnostics_server
. latest_batch_index ( )
. map ( | v | v . into ( ) ) ,
)
}
2022-04-03 00:17:30 -04:00
pub async fn performance_request ( & self ) -> LspResult < Option < Value > > {
2022-12-19 20:22:17 -05:00
Ok ( Some ( self . 0. read ( ) . await . get_performance ( ) ) )
2022-04-03 00:17:30 -04:00
}
2023-10-12 11:07:27 -04:00
pub async fn task_definitions ( & self ) -> LspResult < Vec < TaskDefinition > > {
self . 0. read ( ) . await . task_definitions ( )
2022-04-03 00:17:30 -04:00
}
pub async fn test_run_request (
& self ,
params : Option < Value > ,
) -> LspResult < Option < Value > > {
2022-12-19 20:22:17 -05:00
let inner = self . 0. read ( ) . await ;
2022-04-03 00:17:30 -04:00
if let Some ( testing_server ) = & inner . maybe_testing_server {
match params . map ( serde_json ::from_value ) {
Some ( Ok ( params ) ) = > testing_server
2023-05-11 17:17:14 -04:00
. run_request ( params , inner . config . workspace_settings ( ) . clone ( ) ) ,
2022-04-03 00:17:30 -04:00
Some ( Err ( err ) ) = > Err ( LspError ::invalid_params ( err . to_string ( ) ) ) ,
None = > Err ( LspError ::invalid_params ( " Missing parameters " ) ) ,
}
} else {
Err ( LspError ::invalid_request ( ) )
}
}
pub async fn test_run_cancel_request (
& self ,
params : Option < Value > ,
) -> LspResult < Option < Value > > {
2022-12-19 20:22:17 -05:00
if let Some ( testing_server ) = & self . 0. read ( ) . await . maybe_testing_server {
2022-04-03 00:17:30 -04:00
match params . map ( serde_json ::from_value ) {
Some ( Ok ( params ) ) = > testing_server . run_cancel_request ( params ) ,
Some ( Err ( err ) ) = > Err ( LspError ::invalid_params ( err . to_string ( ) ) ) ,
None = > Err ( LspError ::invalid_params ( " Missing parameters " ) ) ,
}
} else {
Err ( LspError ::invalid_request ( ) )
}
}
pub async fn virtual_text_document (
& self ,
params : Option < Value > ,
) -> LspResult < Option < Value > > {
match params . map ( serde_json ::from_value ) {
Some ( Ok ( params ) ) = > Ok ( Some (
serde_json ::to_value (
2022-12-19 20:22:17 -05:00
self . 0. read ( ) . await . virtual_text_document ( params ) ? ,
2022-04-03 00:17:30 -04:00
)
. map_err ( | err | {
error! (
2024-03-01 21:25:38 -05:00
" Failed to serialize virtual_text_document response: {:#} " ,
2022-04-03 00:17:30 -04:00
err
) ;
LspError ::internal_error ( )
} ) ? ,
) ) ,
Some ( Err ( err ) ) = > Err ( LspError ::invalid_params ( err . to_string ( ) ) ) ,
None = > Err ( LspError ::invalid_params ( " Missing parameters " ) ) ,
}
}
2023-03-15 10:34:23 -04:00
2023-10-24 16:27:27 -04:00
pub async fn refresh_configuration ( & self ) {
let ( client , folders , capable ) = {
2023-09-09 10:04:21 -04:00
let ls = self . 0. read ( ) . await ;
2023-10-24 16:27:27 -04:00
(
ls . client . clone ( ) ,
ls . config . workspace_folders . clone ( ) ,
ls . config . client_capabilities . workspace_configuration ,
)
2023-09-09 10:04:21 -04:00
} ;
2023-10-24 16:27:27 -04:00
if capable {
let mut scopes = Vec ::with_capacity ( folders . len ( ) + 1 ) ;
scopes . push ( None ) ;
for ( _ , folder ) in & folders {
scopes . push ( Some ( folder . uri . clone ( ) ) ) ;
}
let configs = client
2023-03-15 10:34:23 -04:00
. when_outside_lsp_lock ( )
2023-10-24 16:27:27 -04:00
. workspace_configuration ( scopes )
2023-03-15 10:34:23 -04:00
. await ;
2023-10-24 16:27:27 -04:00
if let Ok ( configs ) = configs {
if configs . len ( ) ! = folders . len ( ) + 1 {
lsp_warn! ( " Incorrect number of configurations received. " ) ;
return ;
2023-03-15 10:34:23 -04:00
}
2023-10-24 16:27:27 -04:00
let mut configs = configs . into_iter ( ) ;
let unscoped = configs . next ( ) . unwrap ( ) ;
2024-03-21 00:29:52 -04:00
let mut folder_settings = Vec ::with_capacity ( folders . len ( ) ) ;
2023-10-24 16:27:27 -04:00
for ( folder_uri , _ ) in & folders {
2024-03-21 00:29:52 -04:00
folder_settings . push ( ( folder_uri . clone ( ) , configs . next ( ) . unwrap ( ) ) ) ;
2023-10-24 16:27:27 -04:00
}
let mut ls = self . 0. write ( ) . await ;
2024-03-21 00:29:52 -04:00
ls . config . set_workspace_settings ( unscoped , folder_settings ) ;
2023-03-15 10:34:23 -04:00
}
}
}
2021-01-26 04:55:04 -05:00
}
impl Inner {
fn new ( client : Client ) -> Self {
2023-05-25 14:27:45 -04:00
let dir = DenoDir ::new ( None ) . expect ( " could not access DENO_DIR " ) ;
2022-11-25 19:04:30 -05:00
let module_registries_location = dir . registries_folder_path ( ) ;
2023-05-01 16:42:05 -04:00
let http_client = Arc ::new ( HttpClient ::new ( None , None ) ) ;
2023-06-10 11:09:45 -04:00
let module_registries = ModuleRegistry ::new (
module_registries_location . clone ( ) ,
http_client . clone ( ) ,
) ;
2024-03-27 12:02:05 -04:00
let jsr_search_api =
CliJsrSearchApi ::new ( module_registries . file_fetcher . clone ( ) ) ;
let npm_search_api =
CliNpmSearchApi ::new ( module_registries . file_fetcher . clone ( ) ) ;
2023-08-08 10:23:02 -04:00
let deps_http_cache = Arc ::new ( GlobalHttpCache ::new (
2024-03-27 12:02:05 -04:00
dir . deps_folder_path ( ) ,
2023-08-08 10:23:02 -04:00
crate ::cache ::RealDenoCacheEnv ,
) ) ;
2023-07-08 16:06:45 -04:00
let documents = Documents ::new ( deps_http_cache . clone ( ) ) ;
2023-01-25 16:51:04 -05:00
let cache_metadata = cache ::CacheMetadata ::new ( deps_http_cache . clone ( ) ) ;
2022-01-17 17:09:43 -05:00
let performance = Arc ::new ( Performance ::default ( ) ) ;
2024-03-26 11:52:20 -04:00
let config = Config ::default ( ) ;
let ts_server = Arc ::new ( TsServer ::new (
performance . clone ( ) ,
deps_http_cache . clone ( ) ,
config . tree . clone ( ) ,
) ) ;
2023-09-24 18:33:52 -04:00
let diagnostics_state = Arc ::new ( DiagnosticsState ::default ( ) ) ;
2022-01-17 17:09:43 -05:00
let diagnostics_server = DiagnosticsServer ::new (
client . clone ( ) ,
performance . clone ( ) ,
ts_server . clone ( ) ,
2023-09-24 18:33:52 -04:00
diagnostics_state . clone ( ) ,
2022-01-17 17:09:43 -05:00
) ;
2022-01-18 16:28:47 -05:00
let assets = Assets ::new ( ts_server . clone ( ) ) ;
2024-01-18 15:57:30 -05:00
let initial_cwd = std ::env ::current_dir ( ) . unwrap_or_else ( | _ | {
panic! ( " Could not resolve current working directory " )
} ) ;
2020-12-21 08:44:26 -05:00
2021-01-26 04:55:04 -05:00
Self {
2022-01-18 16:28:47 -05:00
assets ,
2022-02-01 21:04:26 -05:00
cache_metadata ,
2020-12-21 08:44:26 -05:00
client ,
2021-05-20 05:56:48 -04:00
config ,
2023-01-25 16:51:04 -05:00
deps_http_cache ,
2023-09-24 18:33:52 -04:00
diagnostics_state ,
2022-01-17 17:09:43 -05:00
diagnostics_server ,
2021-10-28 19:56:01 -04:00
documents ,
2023-01-25 16:51:04 -05:00
http_client ,
2024-01-18 15:57:30 -05:00
initial_cwd : initial_cwd . clone ( ) ,
2024-02-28 22:54:16 -05:00
jsr_search_api ,
2023-08-01 20:49:09 -04:00
maybe_global_cache_path : None ,
2024-01-02 18:48:34 -05:00
task_queue : Default ::default ( ) ,
2022-03-29 18:59:27 -04:00
maybe_testing_server : None ,
2021-04-08 21:27:27 -04:00
module_registries ,
module_registries_location ,
2023-05-22 21:28:36 -04:00
npm : LspNpmServices {
config_hash : LspNpmConfigHash ( 0 ) , // this will be updated in initialize
2023-08-29 11:22:05 -04:00
search_api : npm_search_api ,
2023-10-25 14:39:00 -04:00
node_resolver : None ,
2023-10-02 17:53:55 -04:00
resolver : None ,
2023-05-22 21:28:36 -04:00
} ,
2022-01-17 17:09:43 -05:00
performance ,
2021-02-04 13:53:02 -05:00
ts_fixable_diagnostics : Default ::default ( ) ,
2021-03-09 21:41:35 -05:00
ts_server ,
2021-02-17 23:37:05 -05:00
url_map : Default ::default ( ) ,
2024-03-21 00:29:52 -04:00
workspace_files : Default ::default ( ) ,
workspace_files_hash : 0 ,
2020-12-21 08:44:26 -05:00
}
}
2022-04-25 11:23:24 -04:00
/// Searches assets and documents for the provided
/// specifier erroring if it doesn't exist.
pub fn get_asset_or_document (
2022-01-18 16:28:47 -05:00
& self ,
2021-11-12 11:42:04 -05:00
specifier : & ModuleSpecifier ,
) -> LspResult < AssetOrDocument > {
2023-03-15 17:46:36 -04:00
self
. get_maybe_asset_or_document ( specifier )
. map ( Ok )
. unwrap_or_else ( | | {
2022-04-25 11:23:24 -04:00
Err ( LspError ::invalid_params ( format! (
2023-01-27 10:43:16 -05:00
" Unable to find asset or document for: {specifier} "
2022-04-25 11:23:24 -04:00
) ) )
2023-03-15 17:46:36 -04:00
} )
2021-11-12 11:42:04 -05:00
}
2022-04-25 11:23:24 -04:00
/// Searches assets and documents for the provided specifier.
pub fn get_maybe_asset_or_document (
2021-11-12 11:42:04 -05:00
& self ,
specifier : & ModuleSpecifier ,
) -> Option < AssetOrDocument > {
2021-04-02 02:21:07 -04:00
if specifier . scheme ( ) = = " asset " {
2022-04-25 11:23:24 -04:00
self . assets . get ( specifier ) . map ( AssetOrDocument ::Asset )
2021-04-02 02:21:07 -04:00
} else {
2021-11-12 11:42:04 -05:00
self . documents . get ( specifier ) . map ( AssetOrDocument ::Document )
2021-04-02 02:21:07 -04:00
}
}
2022-03-23 09:54:22 -04:00
pub async fn get_navigation_tree (
2022-12-19 20:22:17 -05:00
& self ,
2021-01-31 22:30:41 -05:00
specifier : & ModuleSpecifier ,
2021-10-28 19:56:01 -04:00
) -> Result < Arc < tsc ::NavigationTree > , AnyError > {
2023-11-30 21:54:59 -05:00
let mark = self . performance . mark_with_args (
" lsp.get_navigation_tree " ,
json! ( { " specifier " : specifier } ) ,
2021-05-11 00:54:10 -04:00
) ;
2022-04-25 11:23:24 -04:00
let asset_or_doc = self . get_asset_or_document ( specifier ) ? ;
2021-11-12 11:42:04 -05:00
let navigation_tree =
if let Some ( navigation_tree ) = asset_or_doc . maybe_navigation_tree ( ) {
navigation_tree
2021-06-04 17:31:44 -04:00
} else {
2021-11-12 11:42:04 -05:00
let navigation_tree : tsc ::NavigationTree = self
. ts_server
2023-05-12 19:07:40 -04:00
. get_navigation_tree ( self . snapshot ( ) , specifier . clone ( ) )
2021-11-12 11:42:04 -05:00
. await ? ;
let navigation_tree = Arc ::new ( navigation_tree ) ;
2021-11-18 13:50:24 -05:00
match asset_or_doc {
AssetOrDocument ::Asset ( _ ) = > self
2021-11-12 11:42:04 -05:00
. assets
2021-11-18 13:50:24 -05:00
. cache_navigation_tree ( specifier , navigation_tree . clone ( ) ) ? ,
AssetOrDocument ::Document ( doc ) = > {
self . documents . try_cache_navigation_tree (
specifier ,
& doc . script_version ( ) ,
navigation_tree . clone ( ) ,
) ?
}
2021-11-12 11:42:04 -05:00
}
navigation_tree
} ;
2021-06-04 17:31:44 -04:00
self . performance . measure ( mark ) ;
Ok ( navigation_tree )
2021-01-31 22:30:41 -05:00
}
2021-10-28 19:56:01 -04:00
fn is_diagnosable ( & self , specifier : & ModuleSpecifier ) -> bool {
if specifier . scheme ( ) = = " asset " {
matches! (
2023-03-21 11:46:40 -04:00
MediaType ::from_specifier ( specifier ) ,
2021-10-28 19:56:01 -04:00
MediaType ::JavaScript
| MediaType ::Jsx
2021-12-09 17:12:21 -05:00
| MediaType ::Mjs
| MediaType ::Cjs
2021-10-28 19:56:01 -04:00
| MediaType ::TypeScript
| MediaType ::Tsx
2021-12-09 17:12:21 -05:00
| MediaType ::Mts
| MediaType ::Cts
2021-10-28 19:56:01 -04:00
| MediaType ::Dts
2021-12-09 17:12:21 -05:00
| MediaType ::Dmts
| MediaType ::Dcts
2021-10-28 19:56:01 -04:00
)
} else {
2021-11-12 11:42:04 -05:00
self
. documents
. get ( specifier )
. map ( | d | d . is_diagnosable ( ) )
. unwrap_or ( false )
2021-10-28 19:56:01 -04:00
}
}
2022-03-23 09:54:22 -04:00
pub fn snapshot ( & self ) -> Arc < StateSnapshot > {
2023-10-02 17:53:55 -04:00
let maybe_state_npm_snapshot = self
. npm
. resolver
. as_ref ( )
. map ( | resolver | resolver . clone_snapshotted ( ) )
. map ( | resolver | {
let fs = Arc ::new ( deno_fs ::RealFs ) ;
2024-03-05 19:23:51 -05:00
let node_resolver = Arc ::new ( NodeResolver ::new (
fs . clone ( ) ,
resolver . clone ( ) . into_npm_resolver ( ) ,
) ) ;
let cli_node_resolver = Arc ::new ( CliNodeResolver ::new (
None ,
fs ,
2023-10-02 17:53:55 -04:00
node_resolver ,
2024-03-05 19:23:51 -05:00
resolver . clone ( ) ,
) ) ;
StateNpmSnapshot {
node_resolver : cli_node_resolver ,
2023-10-02 17:53:55 -04:00
npm_resolver : resolver ,
}
} ) ;
2022-01-19 17:10:14 -05:00
Arc ::new ( StateSnapshot {
2022-01-18 16:28:47 -05:00
assets : self . assets . snapshot ( ) ,
2022-02-01 21:04:26 -05:00
cache_metadata : self . cache_metadata . clone ( ) ,
2023-09-09 14:37:01 -04:00
config : self . config . snapshot ( ) ,
2021-01-26 04:55:04 -05:00
documents : self . documents . clone ( ) ,
2023-10-02 17:53:55 -04:00
npm : maybe_state_npm_snapshot ,
2022-01-19 17:10:14 -05:00
} )
2020-12-21 08:44:26 -05:00
}
2024-03-11 23:48:00 -04:00
pub fn update_cache ( & mut self ) -> Result < ( ) , AnyError > {
2023-11-30 21:54:59 -05:00
let mark = self . performance . mark ( " lsp.update_cache " ) ;
2021-07-27 17:25:09 -04:00
self . performance . measure ( mark ) ;
2023-05-11 17:17:14 -04:00
let maybe_cache = & self . config . workspace_settings ( ) . cache ;
2023-08-01 20:49:09 -04:00
let maybe_global_cache_path = if let Some ( cache_str ) = maybe_cache {
lsp_log! ( " Setting global cache path from: \" {} \" " , cache_str ) ;
2021-07-27 17:25:09 -04:00
let cache_url = if let Ok ( url ) = Url ::from_file_path ( cache_str ) {
Ok ( url )
2023-09-09 10:04:21 -04:00
} else if let Some ( root_uri ) = self . config . root_uri ( ) {
2022-11-28 17:28:54 -05:00
let root_path = specifier_to_file_path ( root_uri ) ? ;
2021-07-27 17:25:09 -04:00
let cache_path = root_path . join ( cache_str ) ;
Url ::from_file_path ( cache_path ) . map_err ( | _ | {
anyhow! ( " Bad file path for import path: {:?} " , cache_str )
} )
} else {
Err ( anyhow! (
" The path to the cache path ( \" {} \" ) is not resolvable. " ,
cache_str
) )
} ? ;
2022-11-28 17:28:54 -05:00
let cache_path = specifier_to_file_path ( & cache_url ) ? ;
2021-12-15 13:23:43 -05:00
lsp_log! (
2023-08-01 20:49:09 -04:00
" Resolved global cache path: \" {} \" " ,
2021-07-27 17:25:09 -04:00
cache_path . to_string_lossy ( )
) ;
Some ( cache_path )
} else {
None
} ;
2023-08-01 20:49:09 -04:00
if self . maybe_global_cache_path ! = maybe_global_cache_path {
2024-03-11 23:48:00 -04:00
self . set_new_global_cache_path ( maybe_global_cache_path ) ? ;
2021-07-27 17:25:09 -04:00
}
Ok ( ( ) )
}
2024-03-11 23:48:00 -04:00
fn recreate_http_client_and_dependents ( & mut self ) -> Result < ( ) , AnyError > {
self . set_new_global_cache_path ( self . maybe_global_cache_path . clone ( ) )
2023-08-01 20:49:09 -04:00
}
/// Recreates the http client and all dependent structs.
2024-03-11 23:48:00 -04:00
fn set_new_global_cache_path (
2023-08-01 20:49:09 -04:00
& mut self ,
2022-11-18 17:28:14 -05:00
new_cache_path : Option < PathBuf > ,
) -> Result < ( ) , AnyError > {
2023-05-25 14:27:45 -04:00
let dir = DenoDir ::new ( new_cache_path . clone ( ) ) ? ;
2023-05-11 17:17:14 -04:00
let workspace_settings = self . config . workspace_settings ( ) ;
2022-11-18 17:28:14 -05:00
let maybe_root_path = self
. config
2023-09-09 10:04:21 -04:00
. root_uri ( )
2022-11-28 17:28:54 -05:00
. and_then ( | uri | specifier_to_file_path ( uri ) . ok ( ) ) ;
2023-05-01 16:42:05 -04:00
let root_cert_store = get_root_cert_store (
2022-11-18 17:28:14 -05:00
maybe_root_path ,
2023-05-11 17:17:14 -04:00
workspace_settings . certificate_stores . clone ( ) ,
workspace_settings . tls_certificate . clone ( ) . map ( CaData ::File ) ,
2023-05-01 16:42:05 -04:00
) ? ;
let root_cert_store_provider =
Arc ::new ( LspRootCertStoreProvider ( root_cert_store ) ) ;
self . http_client = Arc ::new ( HttpClient ::new (
Some ( root_cert_store_provider ) ,
2023-05-11 17:17:14 -04:00
workspace_settings
. unsafely_ignore_certificate_errors
. clone ( ) ,
2023-05-01 16:42:05 -04:00
) ) ;
2024-03-27 12:02:05 -04:00
self . module_registries_location = dir . registries_folder_path ( ) ;
2023-01-25 16:51:04 -05:00
self . module_registries = ModuleRegistry ::new (
2024-03-27 12:02:05 -04:00
self . module_registries_location . clone ( ) ,
2023-01-25 16:51:04 -05:00
self . http_client . clone ( ) ,
2023-05-01 16:42:05 -04:00
) ;
2024-03-27 12:02:05 -04:00
self . jsr_search_api =
CliJsrSearchApi ::new ( self . module_registries . file_fetcher . clone ( ) ) ;
self . npm . search_api =
CliNpmSearchApi ::new ( self . module_registries . file_fetcher . clone ( ) ) ;
2022-11-18 17:28:14 -05:00
// update the cache path
2023-08-08 10:23:02 -04:00
let global_cache = Arc ::new ( GlobalHttpCache ::new (
dir . deps_folder_path ( ) ,
crate ::cache ::RealDenoCacheEnv ,
) ) ;
2023-08-02 16:57:25 -04:00
let maybe_local_cache =
2024-03-26 11:52:20 -04:00
self . config . tree . root_vendor_dir ( ) . map ( | local_path | {
2023-08-02 16:57:25 -04:00
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 ) ;
2023-08-01 20:49:09 -04:00
self . deps_http_cache = cache . clone ( ) ;
self . documents . set_cache ( cache . clone ( ) ) ;
self . cache_metadata . set_cache ( cache ) ;
2023-08-02 16:57:25 -04:00
self . url_map . set_cache ( maybe_local_cache ) ;
2023-08-01 20:49:09 -04:00
self . maybe_global_cache_path = new_cache_path ;
2022-11-18 17:28:14 -05:00
Ok ( ( ) )
}
2023-05-22 21:28:36 -04:00
async fn recreate_npm_services_if_necessary ( & mut self ) {
2023-08-01 20:49:09 -04:00
let deno_dir = match DenoDir ::new ( self . maybe_global_cache_path . clone ( ) ) {
2023-05-22 21:28:36 -04:00
Ok ( deno_dir ) = > deno_dir ,
Err ( err ) = > {
2024-03-01 21:25:38 -05:00
lsp_warn! ( " Error getting deno dir: {:#} " , err ) ;
2023-05-22 21:28:36 -04:00
return ;
}
} ;
let config_hash = LspNpmConfigHash ::from_inner ( self ) ;
if config_hash = = self . npm . config_hash {
return ; // no need to do anything
}
2024-03-26 11:52:20 -04:00
let config_data = self . config . tree . root_data ( ) ;
2023-10-25 14:39:00 -04:00
let npm_resolver = create_npm_resolver (
& deno_dir ,
2024-01-18 15:57:30 -05:00
& self . initial_cwd ,
2023-10-25 14:39:00 -04:00
& self . http_client ,
2024-03-26 11:52:20 -04:00
config_data . as_ref ( ) . and_then ( | d | d . config_file . as_deref ( ) ) ,
config_data . as_ref ( ) . and_then ( | d | d . lockfile . as_ref ( ) ) ,
config_data
. as_ref ( )
. and_then ( | d | d . node_modules_dir . clone ( ) ) ,
2023-10-25 14:39:00 -04:00
)
. await ;
2024-03-05 19:23:51 -05:00
let node_resolver = Arc ::new ( NodeResolver ::new (
2023-10-25 14:39:00 -04:00
Arc ::new ( deno_fs ::RealFs ) ,
npm_resolver . clone ( ) . into_npm_resolver ( ) ,
2024-03-05 19:23:51 -05:00
) ) ;
self . npm . node_resolver = Some ( Arc ::new ( CliNodeResolver ::new (
None ,
Arc ::new ( deno_fs ::RealFs ) ,
node_resolver ,
npm_resolver . clone ( ) ,
2023-10-25 14:39:00 -04:00
) ) ) ;
self . npm . resolver = Some ( npm_resolver ) ;
2023-05-22 21:28:36 -04:00
// update the hash
self . npm . config_hash = config_hash ;
}
2023-01-25 16:51:04 -05:00
fn create_file_fetcher ( & self , cache_setting : CacheSetting ) -> FileFetcher {
let mut file_fetcher = FileFetcher ::new (
self . deps_http_cache . clone ( ) ,
cache_setting ,
true ,
self . http_client . clone ( ) ,
2023-07-01 18:52:30 -04:00
Default ::default ( ) ,
2023-01-25 16:51:04 -05:00
None ,
) ;
file_fetcher . set_download_log_level ( super ::logging ::lsp_log_level ( ) ) ;
file_fetcher
}
2023-01-25 15:13:40 -05:00
fn resolve_import_map_specifier (
& self ,
2024-03-26 11:52:20 -04:00
referrer : & ModuleSpecifier ,
2023-01-25 15:13:40 -05:00
) -> Result < Option < ModuleSpecifier > , AnyError > {
2024-02-24 00:21:09 -05:00
let Some ( import_map_str ) = self
. config
2024-03-26 11:52:20 -04:00
. settings
. get_for_specifier ( referrer )
. 0
2024-02-24 00:21:09 -05:00
. import_map
. clone ( )
. and_then ( | s | if s . is_empty ( ) { None } else { Some ( s ) } )
else {
return Ok ( None ) ;
} ;
lsp_log! (
2024-03-01 21:13:04 -05:00
" Using import map from workspace settings: \" {} \" " ,
2024-02-24 00:21:09 -05:00
import_map_str
) ;
2024-03-26 11:52:20 -04:00
if let Some ( config_file ) =
self . config . tree . config_file_for_specifier ( referrer )
{
2024-02-24 00:21:09 -05:00
if let Some ( import_map_path ) = & config_file . json . import_map {
lsp_log! ( " Warning: Import map \" {} \" configured in \" {} \" being ignored due to an import map being explicitly configured in workspace settings. " , import_map_path , config_file . specifier ) ;
}
}
if let Ok ( url ) = Url ::parse ( & import_map_str ) {
Ok ( Some ( url ) )
} else if let Some ( root_uri ) = self . config . root_uri ( ) {
let root_path = specifier_to_file_path ( root_uri ) ? ;
let import_map_path = root_path . join ( & import_map_str ) ;
let import_map_url =
Url ::from_file_path ( import_map_path ) . map_err ( | _ | {
anyhow! ( " Bad file path for import map: {} " , import_map_str )
} ) ? ;
Ok ( Some ( import_map_url ) )
} else {
Err ( anyhow! (
" The path to the import map ( \" {} \" ) is not resolvable. " ,
import_map_str
) )
}
2023-01-25 15:13:40 -05:00
}
2021-12-15 13:23:43 -05:00
pub fn update_debug_flag ( & self ) {
2023-05-11 17:17:14 -04:00
let internal_debug = self . config . workspace_settings ( ) . internal_debug ;
2021-12-15 13:23:43 -05:00
super ::logging ::set_lsp_debug_flag ( internal_debug )
2021-05-11 00:54:10 -04:00
}
2021-04-08 21:27:27 -04:00
async fn update_registries ( & mut self ) -> Result < ( ) , AnyError > {
2023-11-30 21:54:59 -05:00
let mark = self . performance . mark ( " lsp.update_registries " ) ;
2024-03-11 23:48:00 -04:00
self . recreate_http_client_and_dependents ( ) ? ;
2023-05-11 17:17:14 -04:00
let workspace_settings = self . config . workspace_settings ( ) ;
2022-01-23 19:27:52 -05:00
for ( registry , enabled ) in workspace_settings . suggest . imports . hosts . iter ( ) {
2021-04-08 21:27:27 -04:00
if * enabled {
2021-12-15 13:23:43 -05:00
lsp_log! ( " Enabling import suggestions for: {} " , registry ) ;
2021-04-08 21:27:27 -04:00
self . module_registries . enable ( registry ) . await ? ;
} else {
2024-03-11 23:48:00 -04:00
self . module_registries . disable ( registry ) ? ;
2021-04-08 21:27:27 -04:00
}
}
self . performance . measure ( mark ) ;
Ok ( ( ) )
}
2020-12-21 08:44:26 -05:00
}
2023-10-02 17:53:55 -04:00
async fn create_npm_resolver (
deno_dir : & DenoDir ,
2024-01-18 15:57:30 -05:00
initial_cwd : & Path ,
2023-10-02 17:53:55 -04:00
http_client : & Arc < HttpClient > ,
2023-10-25 14:39:00 -04:00
maybe_config_file : Option < & ConfigFile > ,
2023-10-02 17:53:55 -04:00
maybe_lockfile : Option < & Arc < Mutex < Lockfile > > > ,
maybe_node_modules_dir_path : Option < PathBuf > ,
) -> Arc < dyn CliNpmResolver > {
2023-10-25 14:39:00 -04:00
let is_byonm = std ::env ::var ( " DENO_UNSTABLE_BYONM " ) . as_deref ( ) = = Ok ( " 1 " )
| | maybe_config_file
. as_ref ( )
2023-12-06 19:03:18 -05:00
. map ( | c | c . has_unstable ( " byonm " ) )
2023-10-25 14:39:00 -04:00
. unwrap_or ( false ) ;
create_cli_npm_resolver_for_lsp ( if is_byonm {
CliNpmResolverCreateOptions ::Byonm ( CliNpmResolverByonmCreateOptions {
fs : Arc ::new ( deno_fs ::RealFs ) ,
2024-01-18 15:57:30 -05:00
root_node_modules_dir : initial_cwd . join ( " node_modules " ) ,
2023-10-25 14:39:00 -04:00
} )
} else {
CliNpmResolverCreateOptions ::Managed ( CliNpmResolverManagedCreateOptions {
2023-10-02 17:53:55 -04:00
http_client : http_client . clone ( ) ,
snapshot : match maybe_lockfile {
Some ( lockfile ) = > {
CliNpmResolverManagedSnapshotOption ::ResolveFromLockfile (
lockfile . clone ( ) ,
)
}
None = > CliNpmResolverManagedSnapshotOption ::Specified ( None ) ,
} ,
// Don't provide the lockfile. We don't want these resolvers
// updating it. Only the cache request should update the lockfile.
maybe_lockfile : None ,
fs : Arc ::new ( deno_fs ::RealFs ) ,
npm_global_cache_dir : deno_dir . npm_folder_path ( ) ,
// Use an "only" cache setting in order to make the
// user do an explicit "cache" command and prevent
// the cache from being filled with lots of packages while
// the user is typing.
cache_setting : CacheSetting ::Only ,
text_only_progress_bar : ProgressBar ::new ( ProgressBarStyle ::TextOnly ) ,
maybe_node_modules_path : maybe_node_modules_dir_path ,
// do not install while resolving in the lsp—leave that to the cache command
package_json_installer :
CliNpmResolverManagedPackageJsonInstallerOption ::NoInstall ,
2024-03-06 08:24:15 -05:00
npm_registry_url : crate ::args ::npm_registry_url ( ) . to_owned ( ) ,
2023-10-02 17:53:55 -04:00
npm_system_info : NpmSystemInfo ::default ( ) ,
2023-10-25 14:39:00 -04:00
} )
} )
2023-10-02 17:53:55 -04:00
. await
}
2021-01-26 04:55:04 -05:00
// lspower::LanguageServer methods. This file's LanguageServer delegates to us.
impl Inner {
2020-12-21 08:44:26 -05:00
async fn initialize (
2021-01-26 04:55:04 -05:00
& mut self ,
2020-12-21 08:44:26 -05:00
params : InitializeParams ,
2020-12-29 23:17:17 -05:00
) -> LspResult < InitializeResult > {
2021-12-15 13:23:43 -05:00
lsp_log! ( " Starting Deno language server... " ) ;
2023-11-30 21:54:59 -05:00
let mark = self . performance . mark_with_args ( " lsp.initialize " , & params ) ;
2020-12-21 08:44:26 -05:00
2021-06-22 21:48:01 -04:00
// exit this process when the parent is lost
if let Some ( parent_pid ) = params . process_id {
parent_process_checker ::start ( parent_pid )
}
2024-01-28 16:56:45 -05:00
let capabilities = capabilities ::server_capabilities ( & params . capabilities ) ;
2020-12-21 08:44:26 -05:00
let version = format! (
" {} ({}, {}) " ,
crate ::version ::deno ( ) ,
env! ( " PROFILE " ) ,
env! ( " TARGET " )
) ;
2021-12-15 13:23:43 -05:00
lsp_log! ( " version: {} " , version ) ;
2021-06-08 20:00:26 -04:00
if let Ok ( path ) = std ::env ::current_exe ( ) {
2021-12-15 13:23:43 -05:00
lsp_log! ( " executable: {} " , path . to_string_lossy ( ) ) ;
2021-06-08 20:00:26 -04:00
}
2020-12-21 08:44:26 -05:00
let server_info = ServerInfo {
name : " deno-language-server " . to_string ( ) ,
version : Some ( version ) ,
} ;
if let Some ( client_info ) = params . client_info {
2021-12-15 13:23:43 -05:00
lsp_log! (
2020-12-21 08:44:26 -05:00
" Connected to \" {} \" {} " ,
client_info . name ,
client_info . version . unwrap_or_default ( ) ,
) ;
}
{
2023-09-21 01:46:39 -04:00
if let Some ( options ) = params . initialization_options {
self . config . set_workspace_settings (
WorkspaceSettings ::from_initialization_options ( options ) ,
2024-03-21 00:29:52 -04:00
vec! [ ] ,
2023-09-21 01:46:39 -04:00
) ;
2020-12-21 08:44:26 -05:00
}
2024-03-21 00:29:52 -04:00
let mut workspace_folders = vec! [ ] ;
2023-09-09 10:04:21 -04:00
if let Some ( folders ) = params . workspace_folders {
2024-03-21 00:29:52 -04:00
workspace_folders = folders
2022-03-20 21:33:37 -04:00
. into_iter ( )
2023-03-15 10:34:23 -04:00
. map ( | folder | {
(
self . url_map . normalize_url ( & folder . uri , LspUrlKind ::Folder ) ,
folder ,
)
} )
2023-09-09 10:04:21 -04:00
. collect ( ) ;
}
// rootUri is deprecated by the LSP spec. If it's specified, merge it into
// workspace_folders.
if let Some ( root_uri ) = params . root_uri {
2024-03-21 00:29:52 -04:00
if ! workspace_folders . iter ( ) . any ( | ( _ , f ) | f . uri = = root_uri ) {
2023-09-09 10:04:21 -04:00
let name = root_uri . path_segments ( ) . and_then ( | s | s . last ( ) ) ;
let name = name . unwrap_or_default ( ) . to_string ( ) ;
2024-03-21 00:29:52 -04:00
workspace_folders . insert (
2023-09-09 10:04:21 -04:00
0 ,
(
self . url_map . normalize_url ( & root_uri , LspUrlKind ::Folder ) ,
WorkspaceFolder {
uri : root_uri ,
name ,
} ,
) ,
) ;
}
}
2024-03-21 00:29:52 -04:00
self . config . set_workspace_folders ( workspace_folders ) ;
2022-01-19 17:10:14 -05:00
self . config . update_capabilities ( & params . capabilities ) ;
2020-12-21 08:44:26 -05:00
}
2023-12-21 20:04:02 -05:00
self
. ts_server
. start ( self . config . internal_inspect ( ) . to_address ( ) ) ;
2021-05-11 00:54:10 -04:00
self . update_debug_flag ( ) ;
2024-03-26 11:52:20 -04:00
self . refresh_workspace_files ( ) ;
self . refresh_config_tree ( ) . await ;
2024-03-11 23:48:00 -04:00
if let Err ( err ) = self . update_cache ( ) {
2024-03-01 21:25:38 -05:00
lsp_warn! ( " Error updating cache: {:#} " , err ) ;
2023-03-15 10:34:23 -04:00
self . client . show_message ( MessageType ::WARNING , err ) ;
2021-07-27 17:25:09 -04:00
}
2020-12-21 08:44:26 -05:00
2021-02-04 13:53:02 -05:00
if capabilities . code_action_provider . is_some ( ) {
2023-05-12 19:07:40 -04:00
let fixable_diagnostics = self
2021-02-04 13:53:02 -05:00
. ts_server
2023-05-12 19:07:40 -04:00
. get_supported_code_fixes ( self . snapshot ( ) )
. await ? ;
2021-02-04 13:53:02 -05:00
self . ts_fixable_diagnostics = fixable_diagnostics ;
}
2021-04-08 21:27:27 -04:00
// Check to see if we need to setup any module registries
if let Err ( err ) = self . update_registries ( ) . await {
2024-03-01 21:25:38 -05:00
lsp_warn! ( " Error updating registries: {:#} " , err ) ;
2023-03-15 10:34:23 -04:00
self . client . show_message ( MessageType ::WARNING , err ) ;
2021-04-08 21:27:27 -04:00
}
2020-12-21 08:44:26 -05:00
2023-05-22 21:28:36 -04:00
self . recreate_npm_services_if_necessary ( ) . await ;
2023-06-26 09:10:27 -04:00
self . assets . initialize ( self . snapshot ( ) ) . await ;
2022-04-25 11:23:24 -04:00
2021-07-27 17:25:09 -04:00
self . performance . measure ( mark ) ;
Ok ( InitializeResult {
capabilities ,
server_info : Some ( server_info ) ,
2022-10-14 08:04:38 -04:00
offset_encoding : None ,
2021-07-27 17:25:09 -04:00
} )
}
2024-03-21 00:29:52 -04:00
fn walk_workspace ( config : & Config ) -> ( BTreeSet < ModuleSpecifier > , bool ) {
let mut workspace_files = Default ::default ( ) ;
let document_preload_limit =
config . workspace_settings ( ) . document_preload_limit ;
let mut pending = VecDeque ::new ( ) ;
let mut entry_count = 0 ;
let mut roots = config
. workspace_folders
. iter ( )
. filter_map ( | p | specifier_to_file_path ( & p . 0 ) . ok ( ) )
. collect ::< Vec < _ > > ( ) ;
roots . sort ( ) ;
for i in 0 .. roots . len ( ) {
if i = = 0 | | ! roots [ i ] . starts_with ( & roots [ i - 1 ] ) {
if let Ok ( read_dir ) = std ::fs ::read_dir ( & roots [ i ] ) {
pending . push_back ( ( roots [ i ] . clone ( ) , read_dir ) ) ;
}
}
}
while let Some ( ( parent_path , read_dir ) ) = pending . pop_front ( ) {
for entry in read_dir {
let Ok ( entry ) = entry else {
continue ;
} ;
if entry_count > = document_preload_limit {
return ( workspace_files , true ) ;
}
entry_count + = 1 ;
let path = parent_path . join ( entry . path ( ) ) ;
let Ok ( specifier ) = ModuleSpecifier ::from_file_path ( & path ) else {
continue ;
} ;
// TODO(nayeemrmn): Don't walk folders that are `None` here and aren't
// in a `deno.json` scope.
if config . settings . specifier_enabled ( & specifier ) = = Some ( false ) {
continue ;
}
let Ok ( file_type ) = entry . file_type ( ) else {
continue ;
} ;
let Some ( file_name ) = path . file_name ( ) else {
continue ;
} ;
if file_type . is_dir ( ) {
let dir_name = file_name . to_string_lossy ( ) . to_lowercase ( ) ;
// We ignore these directories by default because there is a
// high likelihood they aren't relevant. Someone can opt-into
// them by specifying one of them as an enabled path.
if matches! ( dir_name . as_str ( ) , " node_modules " | " .git " ) {
continue ;
}
// ignore cargo target directories for anyone using Deno with Rust
if dir_name = = " target "
& & path
. parent ( )
. map ( | p | p . join ( " Cargo.toml " ) . exists ( ) )
. unwrap_or ( false )
{
continue ;
}
if let Ok ( read_dir ) = std ::fs ::read_dir ( & path ) {
pending . push_back ( ( path , read_dir ) ) ;
}
} else if file_type . is_file ( )
| | file_type . is_symlink ( )
& & std ::fs ::metadata ( & path )
. ok ( )
. map ( | m | m . is_file ( ) )
. unwrap_or ( false )
{
if file_name . to_string_lossy ( ) . contains ( " .min. " ) {
continue ;
}
let media_type = MediaType ::from_specifier ( & specifier ) ;
match media_type {
MediaType ::JavaScript
| MediaType ::Jsx
| MediaType ::Mjs
| MediaType ::Cjs
| MediaType ::TypeScript
| MediaType ::Mts
| MediaType ::Cts
| MediaType ::Dts
| MediaType ::Dmts
| MediaType ::Dcts
| MediaType ::Json
| MediaType ::Tsx = > { }
MediaType ::Wasm
| MediaType ::SourceMap
| MediaType ::TsBuildInfo
| MediaType ::Unknown = > {
if path . extension ( ) . and_then ( | s | s . to_str ( ) ) ! = Some ( " jsonc " ) {
continue ;
}
}
}
workspace_files . insert ( specifier ) ;
}
}
}
( workspace_files , false )
}
fn refresh_workspace_files ( & mut self ) {
let enable_settings_hash = self . config . settings . enable_settings_hash ( ) ;
if self . workspace_files_hash = = enable_settings_hash {
return ;
}
let ( workspace_files , hit_limit ) = Self ::walk_workspace ( & self . config ) ;
if hit_limit {
let document_preload_limit =
self . config . workspace_settings ( ) . document_preload_limit ;
if document_preload_limit = = 0 {
log ::debug! ( " Skipped document preload. " ) ;
} else {
lsp_warn! (
concat! (
" Hit the language server document preload limit of {} file system entries. " ,
" You may want to use the \" deno.enablePaths \" configuration setting to only have Deno " ,
" partially enable a workspace or increase the limit via \" deno.documentPreloadLimit \" . " ,
" In cases where Deno ends up using too much memory, you may want to lower the limit. "
) ,
document_preload_limit ,
) ;
}
}
self . workspace_files = workspace_files ;
self . workspace_files_hash = enable_settings_hash ;
}
2024-03-26 11:52:20 -04:00
async fn refresh_config_tree ( & mut self ) {
let file_fetcher = self . create_file_fetcher ( CacheSetting ::RespectHeaders ) ;
if let Some ( root_uri ) = self . config . root_uri ( ) {
self
. config
. tree
. refresh (
& self . config . settings ,
root_uri ,
& self . workspace_files ,
& file_fetcher ,
)
. await ;
for config_file in self . config . tree . config_files ( ) {
if let Ok ( ( compiler_options , _ ) ) = config_file . to_compiler_options ( ) {
if let Some ( compiler_options_obj ) = compiler_options . as_object ( ) {
if let Some ( jsx_import_source ) =
compiler_options_obj . get ( " jsxImportSource " )
{
if let Some ( jsx_import_source ) = jsx_import_source . as_str ( ) {
let specifiers = vec! [ Url ::parse ( & format! (
" data:application/typescript;base64,{} " ,
base64 ::engine ::general_purpose ::STANDARD . encode ( format! (
" import '{jsx_import_source}/jsx-runtime'; "
) )
) )
. unwrap ( ) ] ;
let referrer = config_file . specifier . clone ( ) ;
self . task_queue . queue_task ( Box ::new ( | ls : LanguageServer | {
spawn ( async move {
if let Err ( err ) =
ls . cache ( specifiers , referrer , false ) . await
{
lsp_warn! ( " {:#} " , err ) ;
}
} ) ;
} ) ) ;
}
}
}
}
}
}
}
2023-07-26 18:52:31 -04:00
async fn refresh_documents_config ( & mut self ) {
2024-03-26 11:52:20 -04:00
self . documents . update_config (
& self . config ,
self . npm . node_resolver . clone ( ) ,
self . npm . resolver . clone ( ) ,
& self . workspace_files ,
) ;
2023-07-26 18:52:31 -04:00
// refresh the npm specifiers because it might have discovered
// a @types/node package and now's a good time to do that anyway
self . refresh_npm_specifiers ( ) . await ;
2020-12-21 08:44:26 -05:00
}
2024-03-11 23:48:00 -04:00
fn shutdown ( & self ) -> LspResult < ( ) > {
2020-12-21 08:44:26 -05:00
Ok ( ( ) )
}
2024-03-11 23:48:00 -04:00
fn did_open (
2022-01-25 10:30:38 -05:00
& mut self ,
specifier : & ModuleSpecifier ,
params : DidOpenTextDocumentParams ,
2022-02-02 18:02:59 -05:00
) -> Document {
2023-11-30 21:54:59 -05:00
let mark = self . performance . mark_with_args ( " lsp.did_open " , & params ) ;
2021-08-18 23:19:12 -04:00
let language_id =
params
. text_document
. language_id
. parse ( )
. unwrap_or_else ( | err | {
2024-03-01 21:25:38 -05:00
error! ( " {:#} " , err ) ;
2021-08-18 23:19:12 -04:00
LanguageId ::Unknown
} ) ;
if language_id = = LanguageId ::Unknown {
2023-03-30 10:43:16 -04:00
lsp_warn! (
2021-08-18 23:19:12 -04:00
" Unsupported language id \" {} \" received for document \" {} \" . " ,
2023-03-30 10:43:16 -04:00
params . text_document . language_id ,
params . text_document . uri
2021-08-18 23:19:12 -04:00
) ;
}
2021-11-12 11:42:04 -05:00
let document = self . documents . open (
2021-01-22 05:03:16 -05:00
specifier . clone ( ) ,
params . text_document . version ,
2021-10-28 19:56:01 -04:00
params . text_document . language_id . parse ( ) . unwrap ( ) ,
2022-05-20 16:40:55 -04:00
params . text_document . text . into ( ) ,
2021-01-22 05:03:16 -05:00
) ;
2021-02-09 17:46:12 -05:00
2021-06-02 06:29:58 -04:00
self . performance . measure ( mark ) ;
2022-02-02 18:02:59 -05:00
document
2020-12-21 08:44:26 -05:00
}
2021-01-26 04:55:04 -05:00
async fn did_change ( & mut self , params : DidChangeTextDocumentParams ) {
2023-11-30 21:54:59 -05:00
let mark = self . performance . mark_with_args ( " lsp.did_change " , & params ) ;
2023-03-15 10:34:23 -04:00
let specifier = self
. url_map
. normalize_url ( & params . text_document . uri , LspUrlKind ::File ) ;
2021-02-09 17:46:12 -05:00
match self . documents . change (
2021-01-22 05:03:16 -05:00
& specifier ,
params . text_document . version ,
params . content_changes ,
) {
2021-11-12 11:42:04 -05:00
Ok ( document ) = > {
if document . is_diagnosable ( ) {
2022-10-21 11:20:18 -04:00
self . refresh_npm_specifiers ( ) . await ;
2021-06-03 07:13:53 -04:00
self
. diagnostics_server
2022-02-02 18:02:59 -05:00
. invalidate ( & self . documents . dependents ( & specifier ) ) ;
self . send_diagnostics_update ( ) ;
2022-03-29 18:59:27 -04:00
self . send_testing_update ( ) ;
2021-06-02 06:29:58 -04:00
}
}
2024-03-01 21:25:38 -05:00
Err ( err ) = > error! ( " {:#} " , err ) ,
2020-12-21 08:44:26 -05:00
}
2021-01-26 19:32:49 -05:00
self . performance . measure ( mark ) ;
2020-12-21 08:44:26 -05:00
}
2022-10-21 11:20:18 -04:00
async fn refresh_npm_specifiers ( & mut self ) {
let package_reqs = self . documents . npm_package_reqs ( ) ;
2023-05-22 21:28:36 -04:00
let npm_resolver = self . npm . resolver . clone ( ) ;
2023-05-17 17:38:50 -04:00
// spawn to avoid the LSP's Send requirements
2023-09-29 09:26:25 -04:00
let handle = spawn ( async move {
2023-10-02 17:53:55 -04:00
if let Some ( npm_resolver ) =
npm_resolver . as_ref ( ) . and_then ( | r | r . as_managed ( ) )
{
2023-09-29 09:26:25 -04:00
npm_resolver . set_package_reqs ( & package_reqs ) . await
} else {
Ok ( ( ) )
}
} ) ;
2023-05-17 17:38:50 -04:00
if let Err ( err ) = handle . await . unwrap ( ) {
2023-03-30 10:43:16 -04:00
lsp_warn! ( " Could not set npm package requirements. {:#} " , err ) ;
2022-10-21 11:20:18 -04:00
}
}
2021-01-26 04:55:04 -05:00
async fn did_close ( & mut self , params : DidCloseTextDocumentParams ) {
2023-11-30 21:54:59 -05:00
let mark = self . performance . mark_with_args ( " lsp.did_close " , & params ) ;
2023-09-24 18:33:52 -04:00
self . diagnostics_state . clear ( & params . text_document . uri ) ;
2023-02-06 16:49:49 -05:00
if params . text_document . uri . scheme ( ) = = " deno " {
2021-07-26 17:40:12 -04:00
// we can ignore virtual text documents closing, as they don't need to
2020-12-21 08:44:26 -05:00
// be tracked in memory, as they are static assets that won't change
// already managed by the language service
return ;
}
2023-03-15 10:34:23 -04:00
let specifier = self
. url_map
. normalize_url ( & params . text_document . uri , LspUrlKind ::File ) ;
2021-10-28 19:56:01 -04:00
if self . is_diagnosable ( & specifier ) {
2022-10-21 11:20:18 -04:00
self . refresh_npm_specifiers ( ) . await ;
2021-07-26 17:40:12 -04:00
let mut specifiers = self . documents . dependents ( & specifier ) ;
2023-10-12 10:37:56 -04:00
specifiers . push ( specifier . clone ( ) ) ;
2022-02-02 18:02:59 -05:00
self . diagnostics_server . invalidate ( & specifiers ) ;
self . send_diagnostics_update ( ) ;
2022-03-29 18:59:27 -04:00
self . send_testing_update ( ) ;
2020-12-21 08:44:26 -05:00
}
2023-10-12 10:37:56 -04:00
if let Err ( err ) = self . documents . close ( & specifier ) {
2024-03-01 21:25:38 -05:00
error! ( " {:#} " , err ) ;
2023-10-12 10:37:56 -04:00
}
2021-06-02 06:29:58 -04:00
self . performance . measure ( mark ) ;
2020-12-21 08:44:26 -05:00
}
async fn did_change_configuration (
2021-01-26 04:55:04 -05:00
& mut self ,
2021-01-04 16:52:20 -05:00
params : DidChangeConfigurationParams ,
2020-12-21 08:44:26 -05:00
) {
2023-10-24 16:27:27 -04:00
if ! self . config . client_capabilities . workspace_configuration {
let config = params . settings . as_object ( ) . map ( | settings | {
let deno =
serde_json ::to_value ( settings . get ( SETTINGS_SECTION ) ) . unwrap ( ) ;
let javascript =
serde_json ::to_value ( settings . get ( " javascript " ) ) . unwrap ( ) ;
let typescript =
serde_json ::to_value ( settings . get ( " typescript " ) ) . unwrap ( ) ;
WorkspaceSettings ::from_raw_settings ( deno , javascript , typescript )
} ) ;
if let Some ( settings ) = config {
2024-03-21 00:29:52 -04:00
self . config . set_workspace_settings ( settings , vec! [ ] ) ;
2023-10-24 16:27:27 -04:00
}
} ;
2021-05-09 21:16:04 -04:00
2021-05-11 00:54:10 -04:00
self . update_debug_flag ( ) ;
2024-03-26 11:52:20 -04:00
self . refresh_workspace_files ( ) ;
self . refresh_config_tree ( ) . await ;
2024-03-11 23:48:00 -04:00
if let Err ( err ) = self . update_cache ( ) {
2024-03-01 21:25:38 -05:00
lsp_warn! ( " Error updating cache: {:#} " , err ) ;
2023-03-15 10:34:23 -04:00
self . client . show_message ( MessageType ::WARNING , err ) ;
2021-07-27 17:25:09 -04:00
}
2021-05-09 21:16:04 -04:00
if let Err ( err ) = self . update_registries ( ) . await {
2024-03-01 21:25:38 -05:00
lsp_warn! ( " Error updating registries: {:#} " , err ) ;
2023-03-15 10:34:23 -04:00
self . client . show_message ( MessageType ::WARNING , err ) ;
2021-05-09 21:16:04 -04:00
}
2023-05-22 21:28:36 -04:00
self . recreate_npm_services_if_necessary ( ) . await ;
2023-07-26 18:52:31 -04:00
self . refresh_documents_config ( ) . await ;
2023-05-22 21:28:36 -04:00
self . diagnostics_server . invalidate_all ( ) ;
2022-02-02 18:02:59 -05:00
self . send_diagnostics_update ( ) ;
2022-03-29 18:59:27 -04:00
self . send_testing_update ( ) ;
2020-12-21 08:44:26 -05:00
}
async fn did_change_watched_files (
2021-01-26 04:55:04 -05:00
& mut self ,
2020-12-21 08:44:26 -05:00
params : DidChangeWatchedFilesParams ,
) {
2021-05-11 00:54:10 -04:00
let mark = self
. performance
2023-11-30 21:54:59 -05:00
. mark_with_args ( " lsp.did_change_watched_files " , & params ) ;
2021-11-23 12:32:40 -05:00
2024-03-26 11:52:20 -04:00
let changes = params
. changes
. into_iter ( )
. map ( | e | ( self . url_map . normalize_url ( & e . uri , LspUrlKind ::File ) , e ) )
. collect ::< Vec < _ > > ( ) ;
if changes
2023-10-12 11:07:27 -04:00
. iter ( )
2024-03-26 11:52:20 -04:00
. any ( | ( s , _ ) | self . config . tree . is_watched_file ( s ) )
{
let mut deno_config_changes = IndexSet ::with_capacity ( changes . len ( ) ) ;
deno_config_changes . extend ( changes . iter ( ) . filter_map ( | ( s , e ) | {
self . config . tree . watched_file_type ( s ) . and_then ( | t | {
let configuration_type = match t . 1 {
ConfigWatchedFileType ::DenoJson = > {
lsp_custom ::DenoConfigurationType ::DenoJson
}
ConfigWatchedFileType ::PackageJson = > {
lsp_custom ::DenoConfigurationType ::PackageJson
}
_ = > return None ,
} ;
Some ( lsp_custom ::DenoConfigurationChangeEvent {
scope_uri : t . 0 ,
file_uri : e . uri . clone ( ) ,
typ : lsp_custom ::DenoConfigurationChangeType ::from_file_change_type (
e . typ ,
) ,
configuration_type ,
} )
} )
} ) ) ;
self . workspace_files_hash = 0 ;
self . refresh_workspace_files ( ) ;
self . refresh_config_tree ( ) . await ;
deno_config_changes . extend ( changes . iter ( ) . filter_map ( | ( s , e ) | {
self . config . tree . watched_file_type ( s ) . and_then ( | t | {
let configuration_type = match t . 1 {
ConfigWatchedFileType ::DenoJson = > {
lsp_custom ::DenoConfigurationType ::DenoJson
}
ConfigWatchedFileType ::PackageJson = > {
lsp_custom ::DenoConfigurationType ::PackageJson
}
_ = > return None ,
} ;
Some ( lsp_custom ::DenoConfigurationChangeEvent {
scope_uri : t . 0 ,
file_uri : e . uri . clone ( ) ,
typ : lsp_custom ::DenoConfigurationChangeType ::from_file_change_type (
e . typ ,
) ,
configuration_type ,
} )
} )
} ) ) ;
if ! deno_config_changes . is_empty ( ) {
self . client . send_did_change_deno_configuration_notification (
lsp_custom ::DidChangeDenoConfigurationNotificationParams {
changes : deno_config_changes . into_iter ( ) . collect ( ) ,
} ,
2024-01-23 01:12:41 -05:00
) ;
}
2023-05-22 21:28:36 -04:00
self . recreate_npm_services_if_necessary ( ) . await ;
2023-07-26 18:52:31 -04:00
self . refresh_documents_config ( ) . await ;
2022-02-02 18:02:59 -05:00
self . diagnostics_server . invalidate_all ( ) ;
2023-05-12 19:07:40 -04:00
self . ts_server . restart ( self . snapshot ( ) ) . await ;
2022-02-02 18:02:59 -05:00
self . send_diagnostics_update ( ) ;
2022-03-29 18:59:27 -04:00
self . send_testing_update ( ) ;
2020-12-30 22:33:44 -05:00
}
2021-01-26 19:32:49 -05:00
self . performance . measure ( mark ) ;
2020-12-21 08:44:26 -05:00
}
2023-03-15 10:34:23 -04:00
fn did_change_workspace_folders (
2022-03-20 21:33:37 -04:00
& mut self ,
params : DidChangeWorkspaceFoldersParams ,
) {
let mut workspace_folders = params
. event
. added
. into_iter ( )
2023-03-15 10:34:23 -04:00
. map ( | folder | {
(
self . url_map . normalize_url ( & folder . uri , LspUrlKind ::Folder ) ,
folder ,
)
} )
2022-03-20 21:33:37 -04:00
. collect ::< Vec < ( ModuleSpecifier , WorkspaceFolder ) > > ( ) ;
2023-09-09 10:04:21 -04:00
for ( specifier , folder ) in & self . config . workspace_folders {
if ! params . event . removed . is_empty ( )
& & params . event . removed . iter ( ) . any ( | f | f . uri = = folder . uri )
{
continue ;
2022-03-20 21:33:37 -04:00
}
2023-09-09 10:04:21 -04:00
workspace_folders . push ( ( specifier . clone ( ) , folder . clone ( ) ) ) ;
2022-03-20 21:33:37 -04:00
}
2024-03-21 00:29:52 -04:00
self . config . set_workspace_folders ( workspace_folders ) ;
2022-03-20 21:33:37 -04:00
}
2021-04-19 21:29:27 -04:00
async fn document_symbol (
2022-12-19 20:22:17 -05:00
& self ,
2021-04-19 21:29:27 -04:00
params : DocumentSymbolParams ,
) -> LspResult < Option < DocumentSymbolResponse > > {
2023-03-15 10:34:23 -04:00
let specifier = self
. url_map
. normalize_url ( & params . text_document . uri , LspUrlKind ::File ) ;
2021-10-28 19:56:01 -04:00
if ! self . is_diagnosable ( & specifier )
2021-06-02 06:29:58 -04:00
| | ! self . config . specifier_enabled ( & specifier )
{
2021-05-18 02:35:46 -04:00
return Ok ( None ) ;
}
2023-11-30 21:54:59 -05:00
let mark = self
. performance
. mark_with_args ( " lsp.document_symbol " , & params ) ;
2022-04-25 11:23:24 -04:00
let asset_or_document = self . get_asset_or_document ( & specifier ) ? ;
2021-11-12 11:42:04 -05:00
let line_index = asset_or_document . line_index ( ) ;
2021-04-19 21:29:27 -04:00
2021-11-16 17:23:25 -05:00
let navigation_tree =
self . get_navigation_tree ( & specifier ) . await . map_err ( | err | {
error! (
2024-03-01 21:25:38 -05:00
" Error getting document symbols for \" {} \" : {:#} " ,
2021-11-16 17:23:25 -05:00
specifier , err
) ;
LspError ::internal_error ( )
2021-04-19 21:29:27 -04:00
} ) ? ;
2021-11-16 17:23:25 -05:00
let response = if let Some ( child_items ) = & navigation_tree . child_items {
2021-04-19 21:29:27 -04:00
let mut document_symbols = Vec ::< DocumentSymbol > ::new ( ) ;
for item in child_items {
2021-10-28 19:56:01 -04:00
item
. collect_document_symbols ( line_index . clone ( ) , & mut document_symbols ) ;
2021-04-19 21:29:27 -04:00
}
Some ( DocumentSymbolResponse ::Nested ( document_symbols ) )
} else {
None
} ;
self . performance . measure ( mark ) ;
Ok ( response )
}
2020-12-21 08:44:26 -05:00
async fn formatting (
& self ,
params : DocumentFormattingParams ,
2020-12-29 23:17:17 -05:00
) -> LspResult < Option < Vec < TextEdit > > > {
2023-10-09 18:43:32 -04:00
let mut specifier = self
2023-03-15 10:34:23 -04:00
. url_map
. normalize_url ( & params . text_document . uri , LspUrlKind ::File ) ;
2023-10-09 18:43:32 -04:00
// skip formatting any files ignored by the config file
2024-03-26 11:52:20 -04:00
if ! self
. config
. tree
. fmt_options_for_specifier ( & specifier )
. files
. matches_specifier ( & specifier )
{
2023-10-09 18:43:32 -04:00
return Ok ( None ) ;
}
2021-11-12 11:42:04 -05:00
let document = match self . documents . get ( & specifier ) {
Some ( doc ) if doc . is_open ( ) = > doc ,
_ = > return Ok ( None ) ,
} ;
2023-10-09 18:43:32 -04:00
// Detect vendored paths. Vendor file URLs will normalize to their remote
// counterparts, but for formatting we want to favour the file URL.
// TODO(nayeemrmn): Implement `Document::file_resource_path()` or similar.
if specifier . scheme ( ) ! = " file "
& & params . text_document . uri . scheme ( ) = = " file "
{
specifier = params . text_document . uri . clone ( ) ;
}
2022-11-28 17:28:54 -05:00
let file_path = specifier_to_file_path ( & specifier ) . map_err ( | err | {
2024-03-01 21:25:38 -05:00
error! ( " {:#} " , err ) ;
2022-11-28 17:28:54 -05:00
LspError ::invalid_request ( )
} ) ? ;
2023-11-30 21:54:59 -05:00
let mark = self . performance . mark_with_args ( " lsp.formatting " , & params ) ;
2021-09-13 14:19:10 -04:00
2023-07-20 09:28:40 -04:00
// spawn a blocking task to allow doing other work while this is occurring
2023-10-08 23:39:52 -04:00
let text_edits = deno_core ::unsync ::spawn_blocking ( {
2024-03-26 11:52:20 -04:00
let fmt_options = self
. config
. tree
. fmt_options_for_specifier ( & specifier )
. options
. clone ( ) ;
2023-07-20 09:28:40 -04:00
let document = document . clone ( ) ;
move | | {
2023-10-08 23:39:52 -04:00
let format_result = match document . maybe_parsed_source ( ) {
2023-07-20 09:28:40 -04:00
Some ( Ok ( parsed_source ) ) = > {
format_parsed_source ( & parsed_source , & fmt_options )
}
2024-03-01 21:25:38 -05:00
Some ( Err ( err ) ) = > Err ( anyhow! ( " {:#} " , err ) ) ,
2023-07-20 09:28:40 -04:00
None = > {
// the file path is only used to determine what formatter should
// be used to format the file, so give the filepath an extension
// that matches what the user selected as the language
let file_path = document
. maybe_language_id ( )
. and_then ( | id | id . as_extension ( ) )
. map ( | ext | file_path . with_extension ( ext ) )
. unwrap_or ( file_path ) ;
// it's not a js/ts file, so attempt to format its contents
format_file ( & file_path , & document . content ( ) , & fmt_options )
}
2023-10-08 23:39:52 -04:00
} ;
match format_result {
Ok ( Some ( new_text ) ) = > Some ( text ::get_edits (
& document . content ( ) ,
& new_text ,
document . line_index ( ) . as_ref ( ) ,
) ) ,
Ok ( None ) = > Some ( Vec ::new ( ) ) ,
Err ( err ) = > {
lsp_warn! ( " Format error: {:#} " , err ) ;
None
}
2023-07-20 09:28:40 -04:00
}
2022-12-19 20:22:17 -05:00
}
2023-07-20 09:28:40 -04:00
} )
. await
. unwrap ( ) ;
2021-09-07 10:39:32 -04:00
2021-01-26 19:32:49 -05:00
self . performance . measure ( mark ) ;
2020-12-21 08:44:26 -05:00
if let Some ( text_edits ) = text_edits {
if text_edits . is_empty ( ) {
Ok ( None )
} else {
Ok ( Some ( text_edits ) )
}
} else {
2023-03-15 10:34:23 -04:00
self . client . show_message ( MessageType ::WARNING , format! ( " Unable to format \" {specifier} \" . Likely due to unrecoverable syntax errors in the file. " ) ) ;
2020-12-21 08:44:26 -05:00
Ok ( None )
}
}
2022-01-18 16:28:47 -05:00
async fn hover ( & self , params : HoverParams ) -> LspResult < Option < Hover > > {
2023-03-15 10:34:23 -04:00
let specifier = self . url_map . normalize_url (
& params . text_document_position_params . text_document . uri ,
LspUrlKind ::File ,
) ;
2021-10-28 19:56:01 -04:00
if ! self . is_diagnosable ( & specifier )
2021-06-02 06:29:58 -04:00
| | ! self . config . specifier_enabled ( & specifier )
{
2021-05-09 21:16:04 -04:00
return Ok ( None ) ;
}
2023-11-30 21:54:59 -05:00
let mark = self . performance . mark_with_args ( " lsp.hover " , & params ) ;
2022-04-25 11:23:24 -04:00
let asset_or_doc = self . get_asset_or_document ( & specifier ) ? ;
2021-11-12 11:42:04 -05:00
let hover = if let Some ( ( _ , dep , range ) ) = asset_or_doc
. get_maybe_dependency ( & params . text_document_position_params . position )
{
let dep_maybe_types_dependency = dep
. get_code ( )
2022-02-24 20:03:12 -05:00
. and_then ( | s | self . documents . get ( s ) )
2022-01-31 17:33:57 -05:00
. map ( | d | d . maybe_types_dependency ( ) ) ;
let value = match ( dep . maybe_code . is_none ( ) , dep . maybe_type . is_none ( ) , & dep_maybe_types_dependency ) {
( false , false , None ) = > format! (
2021-10-28 19:56:01 -04:00
" **Resolved Dependency** \n \n **Code**: {} \n \n **Types**: {} \n " ,
2024-03-04 10:48:23 -05:00
self . resolution_to_hover_text ( & dep . maybe_code ) ,
self . resolution_to_hover_text ( & dep . maybe_type ) ,
2021-10-28 19:56:01 -04:00
) ,
2022-01-31 17:33:57 -05:00
( false , false , Some ( types_dep ) ) if ! types_dep . is_none ( ) = > format! (
2021-11-07 19:50:48 -05:00
" **Resolved Dependency** \n \n **Code**: {} \n **Types**: {} \n **Import Types**: {} \n " ,
2024-03-04 10:48:23 -05:00
self . resolution_to_hover_text ( & dep . maybe_code ) ,
self . resolution_to_hover_text ( & dep . maybe_type ) ,
self . resolution_to_hover_text ( types_dep ) ,
2021-11-07 19:50:48 -05:00
) ,
2022-01-31 17:33:57 -05:00
( false , false , Some ( _ ) ) = > format! (
" **Resolved Dependency** \n \n **Code**: {} \n \n **Types**: {} \n " ,
2024-03-04 10:48:23 -05:00
self . resolution_to_hover_text ( & dep . maybe_code ) ,
self . resolution_to_hover_text ( & dep . maybe_type ) ,
2021-10-28 19:56:01 -04:00
) ,
2022-01-31 17:33:57 -05:00
( false , true , Some ( types_dep ) ) if ! types_dep . is_none ( ) = > format! (
2021-11-07 19:50:48 -05:00
" **Resolved Dependency** \n \n **Code**: {} \n \n **Types**: {} \n " ,
2024-03-04 10:48:23 -05:00
self . resolution_to_hover_text ( & dep . maybe_code ) ,
self . resolution_to_hover_text ( types_dep ) ,
2021-11-07 19:50:48 -05:00
) ,
2022-01-31 17:33:57 -05:00
( false , true , _ ) = > format! (
" **Resolved Dependency** \n \n **Code**: {} \n " ,
2024-03-04 10:48:23 -05:00
self . resolution_to_hover_text ( & dep . maybe_code ) ,
2022-01-31 17:33:57 -05:00
) ,
( true , false , _ ) = > format! (
2021-10-28 19:56:01 -04:00
" **Resolved Dependency** \n \n **Types**: {} \n " ,
2024-03-04 10:48:23 -05:00
self . resolution_to_hover_text ( & dep . maybe_type ) ,
2021-10-28 19:56:01 -04:00
) ,
2022-01-31 17:33:57 -05:00
( true , true , _ ) = > unreachable! ( " {} " , json! ( params ) ) ,
2021-10-28 19:56:01 -04:00
} ;
2022-01-06 19:27:13 -05:00
let value =
if let Some ( docs ) = self . module_registries . get_hover ( & dep ) . await {
2023-01-27 10:43:16 -05:00
format! ( " {value} \n \n --- \n \n {docs} " )
2022-01-06 19:27:13 -05:00
} else {
value
} ;
2021-10-28 19:56:01 -04:00
Some ( Hover {
contents : HoverContents ::Markup ( MarkupContent {
kind : MarkupKind ::Markdown ,
value ,
} ) ,
range : Some ( to_lsp_range ( & range ) ) ,
} )
2020-12-21 08:44:26 -05:00
} else {
2021-11-12 11:42:04 -05:00
let line_index = asset_or_doc . line_index ( ) ;
2023-05-12 19:07:40 -04:00
let position =
line_index . offset_tsc ( params . text_document_position_params . position ) ? ;
let maybe_quick_info = self
2021-06-24 19:06:51 -04:00
. ts_server
2023-05-12 19:07:40 -04:00
. get_quick_info ( self . snapshot ( ) , specifier . clone ( ) , position )
. await ? ;
2022-02-09 18:08:53 -05:00
maybe_quick_info . map ( | qi | qi . to_hover ( line_index , self ) )
2021-06-24 19:06:51 -04:00
} ;
self . performance . measure ( mark ) ;
Ok ( hover )
2020-12-21 08:44:26 -05:00
}
2024-03-04 10:48:23 -05:00
fn resolution_to_hover_text ( & self , resolution : & Resolution ) -> String {
match resolution {
Resolution ::Ok ( resolved ) = > {
let specifier = & resolved . specifier ;
2024-03-27 11:58:18 -04:00
let format = | scheme : & str , rest : & str | -> String {
format! ( " {} ​ {} " , scheme , rest ) . replace ( '@' , " ​@ " )
} ;
2024-03-04 10:48:23 -05:00
match specifier . scheme ( ) {
" data " = > " _(a data url)_ " . to_string ( ) ,
" blob " = > " _(a blob url)_ " . to_string ( ) ,
2024-03-27 11:58:18 -04:00
" file " = > format (
& specifier [ .. url ::Position ::AfterScheme ] ,
& to_percent_decoded_str ( & specifier [ url ::Position ::AfterScheme .. ] ) ,
) ,
2024-03-04 10:48:23 -05:00
_ = > {
2024-03-27 11:58:18 -04:00
let mut result = format (
2024-03-04 10:48:23 -05:00
& specifier [ .. url ::Position ::AfterScheme ] ,
& specifier [ url ::Position ::AfterScheme .. ] ,
2024-03-27 11:58:18 -04:00
) ;
2024-03-04 10:48:23 -05:00
if let Ok ( jsr_req_ref ) =
JsrPackageReqReference ::from_specifier ( specifier )
{
if let Some ( url ) = self
. documents
. get_jsr_resolver ( )
. jsr_to_registry_url ( & jsr_req_ref )
{
result = format! ( " {result} (< {url} >) " ) ;
}
}
result
}
}
}
Resolution ::Err ( _ ) = > " _[errored]_ " . to_string ( ) ,
Resolution ::None = > " _[missing]_ " . to_string ( ) ,
}
}
2021-02-04 13:53:02 -05:00
async fn code_action (
2022-01-19 11:38:40 -05:00
& self ,
2021-02-04 13:53:02 -05:00
params : CodeActionParams ,
) -> LspResult < Option < CodeActionResponse > > {
2023-03-15 10:34:23 -04:00
let specifier = self
. url_map
. normalize_url ( & params . text_document . uri , LspUrlKind ::File ) ;
2021-10-28 19:56:01 -04:00
if ! self . is_diagnosable ( & specifier )
2021-06-02 06:29:58 -04:00
| | ! self . config . specifier_enabled ( & specifier )
{
2021-02-04 13:53:02 -05:00
return Ok ( None ) ;
}
2023-11-30 21:54:59 -05:00
let mark = self . performance . mark_with_args ( " lsp.code_action " , & params ) ;
2021-08-05 21:46:32 -04:00
let mut all_actions = CodeActionResponse ::new ( ) ;
2022-04-25 11:23:24 -04:00
let asset_or_doc = self . get_asset_or_document ( & specifier ) ? ;
2021-11-12 11:42:04 -05:00
let line_index = asset_or_doc . line_index ( ) ;
2021-08-05 21:46:32 -04:00
// QuickFix
2021-02-04 13:53:02 -05:00
let fixable_diagnostics : Vec < & Diagnostic > = params
. context
. diagnostics
. iter ( )
. filter ( | d | match & d . source {
Some ( source ) = > match source . as_str ( ) {
" deno-ts " = > match & d . code {
Some ( NumberOrString ::String ( code ) ) = > {
self . ts_fixable_diagnostics . contains ( code )
}
Some ( NumberOrString ::Number ( code ) ) = > {
self . ts_fixable_diagnostics . contains ( & code . to_string ( ) )
}
_ = > false ,
} ,
2023-08-27 00:04:12 -04:00
" deno-lint " = > d . code . is_some ( ) ,
2023-01-24 15:14:49 -05:00
" deno " = > diagnostics ::DenoDiagnostic ::is_fixable ( d ) ,
2021-02-04 13:53:02 -05:00
_ = > false ,
} ,
None = > false ,
} )
. collect ( ) ;
2021-08-05 21:46:32 -04:00
if ! fixable_diagnostics . is_empty ( ) {
let mut code_actions = CodeActionCollection ::default ( ) ;
let file_diagnostics = self
. diagnostics_server
2022-02-02 18:02:59 -05:00
. get_ts_diagnostics ( & specifier , asset_or_doc . document_lsp_version ( ) ) ;
2023-09-24 18:33:52 -04:00
let mut includes_no_cache = false ;
2021-08-05 21:46:32 -04:00
for diagnostic in & fixable_diagnostics {
match diagnostic . source . as_deref ( ) {
Some ( " deno-ts " ) = > {
let code = match diagnostic . code . as_ref ( ) . unwrap ( ) {
NumberOrString ::String ( code ) = > code . to_string ( ) ,
NumberOrString ::Number ( code ) = > code . to_string ( ) ,
2021-04-07 05:47:31 -04:00
} ;
2021-08-05 21:46:32 -04:00
let codes = vec! [ code ] ;
2023-05-12 19:07:40 -04:00
let actions = self
. ts_server
. get_code_fixes (
self . snapshot ( ) ,
specifier . clone ( ) ,
line_index . offset_tsc ( diagnostic . range . start ) ?
.. line_index . offset_tsc ( diagnostic . range . end ) ? ,
codes ,
2024-03-26 11:52:20 -04:00
( & self
. config
. tree
. fmt_options_for_specifier ( & specifier )
. options )
. into ( ) ,
2023-09-25 22:54:07 -04:00
tsc ::UserPreferences ::from_config_for_specifier (
& self . config ,
& specifier ,
) ,
2023-05-12 19:07:40 -04:00
)
. await ;
2021-08-05 21:46:32 -04:00
for action in actions {
2021-02-11 23:17:48 -05:00
code_actions
2021-08-05 21:46:32 -04:00
. add_ts_fix_action ( & specifier , & action , diagnostic , self )
. map_err ( | err | {
2024-03-01 21:25:38 -05:00
error! ( " Unable to convert fix: {:#} " , err ) ;
2021-08-05 21:46:32 -04:00
LspError ::internal_error ( )
} ) ? ;
if code_actions . is_fix_all_action (
& action ,
diagnostic ,
& file_diagnostics ,
) {
code_actions
. add_ts_fix_all_action ( & action , & specifier , diagnostic ) ;
}
2021-02-11 23:17:48 -05:00
}
}
2023-09-24 18:33:52 -04:00
Some ( " deno " ) = > {
if diagnostic . code
= = Some ( NumberOrString ::String ( " no-cache " . to_string ( ) ) )
2024-02-12 17:12:49 -05:00
| | diagnostic . code
= = Some ( NumberOrString ::String ( " no-cache-jsr " . to_string ( ) ) )
2023-09-24 18:33:52 -04:00
| | diagnostic . code
= = Some ( NumberOrString ::String ( " no-cache-npm " . to_string ( ) ) )
{
includes_no_cache = true ;
}
code_actions
. add_deno_fix_action ( & specifier , diagnostic )
. map_err ( | err | {
2024-03-01 21:25:38 -05:00
error! ( " {:#} " , err ) ;
2023-09-24 18:33:52 -04:00
LspError ::internal_error ( )
} ) ?
}
2021-08-05 21:46:32 -04:00
Some ( " deno-lint " ) = > code_actions
2024-03-21 17:18:59 -04:00
. add_deno_lint_actions (
2021-08-05 21:46:32 -04:00
& specifier ,
diagnostic ,
2021-11-12 11:42:04 -05:00
asset_or_doc . document ( ) . map ( | d | d . text_info ( ) ) ,
2022-02-24 20:03:12 -05:00
asset_or_doc . maybe_parsed_source ( ) . and_then ( | r | r . ok ( ) ) ,
2021-08-05 21:46:32 -04:00
)
. map_err ( | err | {
2024-03-01 21:25:38 -05:00
error! ( " Unable to fix lint error: {:#} " , err ) ;
2021-08-05 21:46:32 -04:00
LspError ::internal_error ( )
} ) ? ,
_ = > ( ) ,
2021-02-11 23:17:48 -05:00
}
2021-02-04 13:53:02 -05:00
}
2023-09-24 18:33:52 -04:00
if includes_no_cache {
let no_cache_diagnostics =
self . diagnostics_state . no_cache_diagnostics ( & specifier ) ;
let uncached_deps = no_cache_diagnostics
. iter ( )
. filter_map ( | d | {
let data = serde_json ::from_value ::< DiagnosticDataSpecifier > (
d . data . clone ( ) . into ( ) ,
)
. ok ( ) ? ;
Some ( data . specifier )
} )
. collect ::< HashSet < _ > > ( ) ;
if uncached_deps . len ( ) > 1 {
code_actions
. add_cache_all_action ( & specifier , no_cache_diagnostics . to_owned ( ) ) ;
}
}
2021-08-05 21:46:32 -04:00
code_actions . set_preferred_fixes ( ) ;
all_actions . extend ( code_actions . get_response ( ) ) ;
2021-02-04 13:53:02 -05:00
}
2021-08-05 21:46:32 -04:00
// Refactor
2023-03-15 17:46:36 -04:00
let only = params
. context
. only
. as_ref ( )
. and_then ( | values | values . first ( ) . map ( | v | v . as_str ( ) . to_owned ( ) ) )
. unwrap_or_default ( ) ;
2023-05-12 19:07:40 -04:00
let refactor_infos = self
2021-08-05 21:46:32 -04:00
. ts_server
2023-05-12 19:07:40 -04:00
. get_applicable_refactors (
self . snapshot ( ) ,
specifier . clone ( ) ,
line_index . offset_tsc ( params . range . start ) ?
.. line_index . offset_tsc ( params . range . end ) ? ,
2023-09-25 22:54:07 -04:00
Some ( tsc ::UserPreferences ::from_config_for_specifier (
& self . config ,
& specifier ,
) ) ,
2023-05-12 19:07:40 -04:00
only ,
)
. await ? ;
2021-08-05 21:46:32 -04:00
let mut refactor_actions = Vec ::< CodeAction > ::new ( ) ;
for refactor_info in refactor_infos . iter ( ) {
refactor_actions
. extend ( refactor_info . to_code_actions ( & specifier , & params . range ) ) ;
}
all_actions . extend (
2023-01-26 17:24:03 -05:00
refactor ::prune_invalid_actions ( refactor_actions , 5 )
2021-08-05 21:46:32 -04:00
. into_iter ( )
. map ( CodeActionOrCommand ::CodeAction ) ,
) ;
2021-08-09 19:56:34 -04:00
let code_action_disabled_support =
self . config . client_capabilities . code_action_disabled_support ;
let actions : Vec < CodeActionOrCommand > = all_actions . into_iter ( ) . filter ( | ca | {
code_action_disabled_support
| | matches! ( ca , CodeActionOrCommand ::CodeAction ( ca ) if ca . disabled . is_none ( ) )
} ) . collect ( ) ;
let response = if actions . is_empty ( ) {
2021-08-05 21:46:32 -04:00
None
2021-08-09 19:56:34 -04:00
} else {
Some ( actions )
2021-08-05 21:46:32 -04:00
} ;
2021-08-09 19:56:34 -04:00
2021-02-04 13:53:02 -05:00
self . performance . measure ( mark ) ;
2021-08-05 21:46:32 -04:00
Ok ( response )
2021-02-04 13:53:02 -05:00
}
2021-02-05 15:10:53 -05:00
async fn code_action_resolve (
2022-01-19 11:38:40 -05:00
& self ,
2021-02-05 15:10:53 -05:00
params : CodeAction ,
) -> LspResult < CodeAction > {
2021-08-05 21:46:32 -04:00
if params . kind . is_none ( ) | | params . data . is_none ( ) {
return Ok ( params ) ;
}
2023-11-30 21:54:59 -05:00
let mark = self
. performance
. mark_with_args ( " lsp.code_action_resolve " , & params ) ;
2021-08-05 21:46:32 -04:00
let kind = params . kind . clone ( ) . unwrap ( ) ;
let data = params . data . clone ( ) . unwrap ( ) ;
let result = if kind . as_str ( ) . starts_with ( CodeActionKind ::QUICKFIX . as_str ( ) )
{
2021-02-24 22:15:55 -05:00
let code_action_data : CodeActionData =
from_value ( data ) . map_err ( | err | {
2024-03-01 21:25:38 -05:00
error! ( " Unable to decode code action data: {:#} " , err ) ;
2021-02-24 22:15:55 -05:00
LspError ::invalid_params ( " The CodeAction's data is invalid. " )
} ) ? ;
2023-05-12 19:07:40 -04:00
let combined_code_actions = self
2021-02-24 22:15:55 -05:00
. ts_server
2023-08-17 10:46:11 -04:00
. get_combined_code_fix (
self . snapshot ( ) ,
& code_action_data ,
2024-03-26 11:52:20 -04:00
( & self
. config
. tree
. fmt_options_for_specifier ( & code_action_data . specifier )
. options )
. into ( ) ,
2023-09-25 22:54:07 -04:00
tsc ::UserPreferences ::from_config_for_specifier (
& self . config ,
& code_action_data . specifier ,
) ,
2023-08-17 10:46:11 -04:00
)
2023-05-12 19:07:40 -04:00
. await ? ;
2021-02-24 22:15:55 -05:00
if combined_code_actions . commands . is_some ( ) {
error! ( " Deno does not support code actions with commands. " ) ;
2021-08-05 21:46:32 -04:00
return Err ( LspError ::invalid_request ( ) ) ;
2021-02-24 22:15:55 -05:00
}
2021-08-05 21:46:32 -04:00
let changes = if code_action_data . fix_id = = " fixMissingImport " {
fix_ts_import_changes (
& code_action_data . specifier ,
& combined_code_actions . changes ,
2024-03-26 11:52:20 -04:00
& self . get_ts_response_import_mapper ( & code_action_data . specifier ) ,
2021-08-05 21:46:32 -04:00
)
. map_err ( | err | {
2024-03-01 21:25:38 -05:00
error! ( " Unable to remap changes: {:#} " , err ) ;
2021-08-05 21:46:32 -04:00
LspError ::internal_error ( )
} ) ?
} else {
2022-04-25 11:23:24 -04:00
combined_code_actions . changes
2021-08-05 21:46:32 -04:00
} ;
2023-01-03 05:41:50 -05:00
let mut code_action = params ;
2022-04-25 11:23:24 -04:00
code_action . edit = ts_changes_to_edit ( & changes , self ) . map_err ( | err | {
2024-03-01 21:25:38 -05:00
error! ( " Unable to convert changes to edits: {:#} " , err ) ;
2022-04-25 11:23:24 -04:00
LspError ::internal_error ( )
} ) ? ;
2021-08-05 21:46:32 -04:00
code_action
} else if kind . as_str ( ) . starts_with ( CodeActionKind ::REFACTOR . as_str ( ) ) {
2023-01-03 05:41:50 -05:00
let mut code_action = params ;
2021-08-05 21:46:32 -04:00
let action_data : refactor ::RefactorCodeActionData = from_value ( data )
. map_err ( | err | {
2024-03-01 21:25:38 -05:00
error! ( " Unable to decode code action data: {:#} " , err ) ;
2021-08-05 21:46:32 -04:00
LspError ::invalid_params ( " The CodeAction's data is invalid. " )
} ) ? ;
2022-04-25 11:23:24 -04:00
let asset_or_doc = self . get_asset_or_document ( & action_data . specifier ) ? ;
2021-11-12 11:42:04 -05:00
let line_index = asset_or_doc . line_index ( ) ;
2023-05-12 19:07:40 -04:00
let refactor_edit_info = self
. ts_server
. get_edits_for_refactor (
self . snapshot ( ) ,
2023-09-21 01:46:39 -04:00
action_data . specifier . clone ( ) ,
2024-03-26 11:52:20 -04:00
( & self
. config
. tree
. fmt_options_for_specifier ( & action_data . specifier )
. options )
. into ( ) ,
2023-05-12 19:07:40 -04:00
line_index . offset_tsc ( action_data . range . start ) ?
.. line_index . offset_tsc ( action_data . range . end ) ? ,
action_data . refactor_name ,
action_data . action_name ,
2023-09-25 22:54:07 -04:00
Some ( tsc ::UserPreferences ::from_config_for_specifier (
& self . config ,
& action_data . specifier ,
) ) ,
2023-05-12 19:07:40 -04:00
)
. await ? ;
2024-03-11 23:48:00 -04:00
code_action . edit = refactor_edit_info . to_workspace_edit ( self ) ? ;
2021-08-05 21:46:32 -04:00
code_action
2021-02-24 22:15:55 -05:00
} else {
// The code action doesn't need to be resolved
2021-08-05 21:46:32 -04:00
params
2021-02-24 22:15:55 -05:00
} ;
2021-08-05 21:46:32 -04:00
2021-02-05 15:10:53 -05:00
self . performance . measure ( mark ) ;
2021-08-05 21:46:32 -04:00
Ok ( result )
2021-02-05 15:10:53 -05:00
}
2024-03-26 11:52:20 -04:00
pub fn get_ts_response_import_mapper (
& self ,
referrer : & ModuleSpecifier ,
) -> TsResponseImportMapper {
2023-07-01 21:07:57 -04:00
TsResponseImportMapper ::new (
& self . documents ,
2024-03-26 11:52:20 -04:00
self . config . tree . import_map_for_specifier ( referrer ) ,
2023-11-04 12:41:51 -04:00
self . npm . node_resolver . as_deref ( ) ,
2023-10-02 17:53:55 -04:00
self . npm . resolver . as_deref ( ) ,
2023-07-01 21:07:57 -04:00
)
}
2021-01-31 22:30:41 -05:00
async fn code_lens (
2022-12-19 20:22:17 -05:00
& self ,
2021-01-31 22:30:41 -05:00
params : CodeLensParams ,
) -> LspResult < Option < Vec < CodeLens > > > {
2023-03-15 10:34:23 -04:00
let specifier = self
. url_map
. normalize_url ( & params . text_document . uri , LspUrlKind ::File ) ;
2021-10-28 19:56:01 -04:00
if ! self . is_diagnosable ( & specifier )
2021-06-02 06:29:58 -04:00
| | ! self . config . specifier_enabled ( & specifier )
2021-05-09 21:16:04 -04:00
{
2021-01-31 22:30:41 -05:00
return Ok ( None ) ;
}
2023-11-30 21:54:59 -05:00
let mark = self . performance . mark_with_args ( " lsp.code_lens " , & params ) ;
2022-04-25 11:23:24 -04:00
let asset_or_doc = self . get_asset_or_document ( & specifier ) ? ;
2023-11-30 11:23:47 -05:00
let settings = self . config . workspace_settings_for_specifier ( & specifier ) ;
let mut code_lenses = Vec ::new ( ) ;
if settings . code_lens . test
& & self . config . specifier_enabled_for_test ( & specifier )
{
if let Some ( Ok ( parsed_source ) ) = asset_or_doc . maybe_parsed_source ( ) {
code_lenses . extend (
code_lens ::collect_test ( & specifier , parsed_source ) . map_err (
| err | {
error! (
2024-03-01 21:25:38 -05:00
" Error getting test code lenses for \" {} \" : {:#} " ,
2023-11-30 11:23:47 -05:00
& specifier , err
) ;
LspError ::internal_error ( )
} ,
) ? ,
) ;
}
}
if settings . code_lens . implementations | | settings . code_lens . references {
let navigation_tree =
self . get_navigation_tree ( & specifier ) . await . map_err ( | err | {
2024-03-01 21:25:38 -05:00
error! ( " Error getting code lenses for \" {} \" : {:#} " , specifier , err ) ;
2023-11-30 11:23:47 -05:00
LspError ::internal_error ( )
} ) ? ;
let line_index = asset_or_doc . line_index ( ) ;
code_lenses . extend (
code_lens ::collect_tsc (
& specifier ,
& settings . code_lens ,
line_index ,
& navigation_tree ,
)
. map_err ( | err | {
error! (
2024-03-01 21:25:38 -05:00
" Error getting ts code lenses for \" {:#} \" : {:#} " ,
2023-11-30 11:23:47 -05:00
& specifier , err
) ;
LspError ::internal_error ( )
} ) ? ,
) ;
}
2021-01-31 22:30:41 -05:00
self . performance . measure ( mark ) ;
2021-06-04 17:31:44 -04:00
2023-11-30 11:23:47 -05:00
if code_lenses . is_empty ( ) {
return Ok ( None ) ;
}
2021-06-04 17:31:44 -04:00
Ok ( Some ( code_lenses ) )
2021-01-31 22:30:41 -05:00
}
async fn code_lens_resolve (
2022-01-19 11:38:40 -05:00
& self ,
2021-06-04 17:31:44 -04:00
code_lens : CodeLens ,
2021-01-31 22:30:41 -05:00
) -> LspResult < CodeLens > {
2023-11-30 21:54:59 -05:00
let mark = self
. performance
. mark_with_args ( " lsp.code_lens_resolve " , & code_lens ) ;
2021-06-04 17:31:44 -04:00
let result = if code_lens . data . is_some ( ) {
code_lens ::resolve_code_lens ( code_lens , self )
. await
. map_err ( | err | {
2024-03-01 21:25:38 -05:00
error! ( " Error resolving code lens: {:#} " , err ) ;
2021-06-04 17:31:44 -04:00
LspError ::internal_error ( )
} )
2021-01-31 22:30:41 -05:00
} else {
Err ( LspError ::invalid_params (
" Code lens is missing the \" data \" property. " ,
) )
2021-06-04 17:31:44 -04:00
} ;
self . performance . measure ( mark ) ;
result
2021-01-31 22:30:41 -05:00
}
2020-12-21 08:44:26 -05:00
async fn document_highlight (
2022-01-19 11:38:40 -05:00
& self ,
2020-12-21 08:44:26 -05:00
params : DocumentHighlightParams ,
2020-12-29 23:17:17 -05:00
) -> LspResult < Option < Vec < DocumentHighlight > > > {
2023-03-15 10:34:23 -04:00
let specifier = self . url_map . normalize_url (
& params . text_document_position_params . text_document . uri ,
LspUrlKind ::File ,
) ;
2021-10-28 19:56:01 -04:00
if ! self . is_diagnosable ( & specifier )
2021-06-02 06:29:58 -04:00
| | ! self . config . specifier_enabled ( & specifier )
{
2021-05-09 21:16:04 -04:00
return Ok ( None ) ;
}
2023-11-30 21:54:59 -05:00
let mark = self
. performance
. mark_with_args ( " lsp.document_highlight " , & params ) ;
2022-04-25 11:23:24 -04:00
let asset_or_doc = self . get_asset_or_document ( & specifier ) ? ;
2021-11-12 11:42:04 -05:00
let line_index = asset_or_doc . line_index ( ) ;
2020-12-21 08:44:26 -05:00
let files_to_search = vec! [ specifier . clone ( ) ] ;
2023-05-12 19:07:40 -04:00
let maybe_document_highlights = self
2021-02-24 22:15:55 -05:00
. ts_server
2023-05-12 19:07:40 -04:00
. get_document_highlights (
self . snapshot ( ) ,
specifier ,
line_index . offset_tsc ( params . text_document_position_params . position ) ? ,
files_to_search ,
)
. await ? ;
2020-12-21 08:44:26 -05:00
if let Some ( document_highlights ) = maybe_document_highlights {
2021-01-26 19:32:49 -05:00
let result = document_highlights
. into_iter ( )
2022-02-24 20:03:12 -05:00
. flat_map ( | dh | dh . to_highlight ( line_index . clone ( ) ) )
2021-01-26 19:32:49 -05:00
. collect ( ) ;
self . performance . measure ( mark ) ;
Ok ( Some ( result ) )
2020-12-21 08:44:26 -05:00
} else {
2021-01-26 19:32:49 -05:00
self . performance . measure ( mark ) ;
2020-12-21 08:44:26 -05:00
Ok ( None )
}
}
async fn references (
2022-01-19 11:38:40 -05:00
& self ,
2020-12-21 08:44:26 -05:00
params : ReferenceParams ,
2020-12-29 23:17:17 -05:00
) -> LspResult < Option < Vec < Location > > > {
2023-03-15 10:34:23 -04:00
let specifier = self . url_map . normalize_url (
& params . text_document_position . text_document . uri ,
LspUrlKind ::File ,
) ;
2021-10-28 19:56:01 -04:00
if ! self . is_diagnosable ( & specifier )
2021-06-02 06:29:58 -04:00
| | ! self . config . specifier_enabled ( & specifier )
{
2021-05-09 21:16:04 -04:00
return Ok ( None ) ;
}
2021-06-02 06:29:58 -04:00
2023-11-30 21:54:59 -05:00
let mark = self . performance . mark_with_args ( " lsp.references " , & params ) ;
2022-04-25 11:23:24 -04:00
let asset_or_doc = self . get_asset_or_document ( & specifier ) ? ;
2021-11-12 11:42:04 -05:00
let line_index = asset_or_doc . line_index ( ) ;
2023-03-30 12:15:21 -04:00
let maybe_referenced_symbols = self
2021-02-24 22:15:55 -05:00
. ts_server
2023-03-30 12:15:21 -04:00
. find_references (
self . snapshot ( ) ,
2023-05-12 19:07:40 -04:00
specifier . clone ( ) ,
2023-03-30 12:15:21 -04:00
line_index . offset_tsc ( params . text_document_position . position ) ? ,
)
. await ? ;
2020-12-21 08:44:26 -05:00
2023-03-30 12:15:21 -04:00
if let Some ( symbols ) = maybe_referenced_symbols {
2020-12-21 08:44:26 -05:00
let mut results = Vec ::new ( ) ;
2023-03-30 12:15:21 -04:00
for reference in symbols . iter ( ) . flat_map ( | s | & s . references ) {
2020-12-21 08:44:26 -05:00
if ! params . context . include_declaration & & reference . is_definition {
continue ;
}
let reference_specifier =
2023-03-30 12:15:21 -04:00
resolve_url ( & reference . entry . document_span . file_name ) . unwrap ( ) ;
2021-11-16 17:23:25 -05:00
let reference_line_index = if reference_specifier = = specifier {
line_index . clone ( )
} else {
let asset_or_doc =
2022-04-25 11:23:24 -04:00
self . get_asset_or_document ( & reference_specifier ) ? ;
2021-11-16 17:23:25 -05:00
asset_or_doc . line_index ( )
} ;
2023-03-30 12:15:21 -04:00
results . push (
reference
. entry
. to_location ( reference_line_index , & self . url_map ) ,
) ;
2020-12-21 08:44:26 -05:00
}
2021-01-26 19:32:49 -05:00
self . performance . measure ( mark ) ;
2020-12-21 08:44:26 -05:00
Ok ( Some ( results ) )
} else {
2021-01-26 19:32:49 -05:00
self . performance . measure ( mark ) ;
2020-12-21 08:44:26 -05:00
Ok ( None )
}
}
async fn goto_definition (
2022-01-19 11:38:40 -05:00
& self ,
2020-12-21 08:44:26 -05:00
params : GotoDefinitionParams ,
2020-12-29 23:17:17 -05:00
) -> LspResult < Option < GotoDefinitionResponse > > {
2023-03-15 10:34:23 -04:00
let specifier = self . url_map . normalize_url (
& params . text_document_position_params . text_document . uri ,
LspUrlKind ::File ,
) ;
2021-10-28 19:56:01 -04:00
if ! self . is_diagnosable ( & specifier )
2021-06-02 06:29:58 -04:00
| | ! self . config . specifier_enabled ( & specifier )
{
2021-05-09 21:16:04 -04:00
return Ok ( None ) ;
}
2021-06-02 06:29:58 -04:00
2023-11-30 21:54:59 -05:00
let mark = self
. performance
. mark_with_args ( " lsp.goto_definition " , & params ) ;
2022-04-25 11:23:24 -04:00
let asset_or_doc = self . get_asset_or_document ( & specifier ) ? ;
2021-11-12 11:42:04 -05:00
let line_index = asset_or_doc . line_index ( ) ;
2023-05-12 19:07:40 -04:00
let maybe_definition = self
2021-02-24 22:15:55 -05:00
. ts_server
2023-05-12 19:07:40 -04:00
. get_definition (
self . snapshot ( ) ,
specifier ,
line_index . offset_tsc ( params . text_document_position_params . position ) ? ,
)
. await ? ;
2020-12-21 08:44:26 -05:00
if let Some ( definition ) = maybe_definition {
2024-03-11 23:48:00 -04:00
let results = definition . to_definition ( line_index , self ) ;
2021-01-26 19:32:49 -05:00
self . performance . measure ( mark ) ;
Ok ( results )
2020-12-21 08:44:26 -05:00
} else {
2021-01-26 19:32:49 -05:00
self . performance . measure ( mark ) ;
2020-12-21 08:44:26 -05:00
Ok ( None )
}
}
2021-11-22 19:09:19 -05:00
async fn goto_type_definition (
2022-01-19 11:38:40 -05:00
& self ,
2021-11-22 19:09:19 -05:00
params : GotoTypeDefinitionParams ,
) -> LspResult < Option < GotoTypeDefinitionResponse > > {
2023-03-15 10:34:23 -04:00
let specifier = self . url_map . normalize_url (
& params . text_document_position_params . text_document . uri ,
LspUrlKind ::File ,
) ;
2021-11-22 19:09:19 -05:00
if ! self . is_diagnosable ( & specifier )
| | ! self . config . specifier_enabled ( & specifier )
{
return Ok ( None ) ;
}
2023-11-30 21:54:59 -05:00
let mark = self
. performance
. mark_with_args ( " lsp.goto_definition " , & params ) ;
2022-04-25 11:23:24 -04:00
let asset_or_doc = self . get_asset_or_document ( & specifier ) ? ;
2021-11-22 19:09:19 -05:00
let line_index = asset_or_doc . line_index ( ) ;
2023-05-12 19:07:40 -04:00
let maybe_definition_info = self
2021-11-22 19:09:19 -05:00
. ts_server
2023-05-12 19:07:40 -04:00
. get_type_definition (
self . snapshot ( ) ,
specifier ,
line_index . offset_tsc ( params . text_document_position_params . position ) ? ,
)
. await ? ;
2021-11-22 19:09:19 -05:00
let response = if let Some ( definition_info ) = maybe_definition_info {
let mut location_links = Vec ::new ( ) ;
for info in definition_info {
2022-04-25 11:23:24 -04:00
if let Some ( link ) = info . document_span . to_link ( line_index . clone ( ) , self )
2021-11-22 19:09:19 -05:00
{
location_links . push ( link ) ;
}
}
Some ( GotoTypeDefinitionResponse ::Link ( location_links ) )
} else {
None
} ;
self . performance . measure ( mark ) ;
Ok ( response )
}
2020-12-21 08:44:26 -05:00
async fn completion (
2022-01-19 11:38:40 -05:00
& self ,
2020-12-21 08:44:26 -05:00
params : CompletionParams ,
2020-12-29 23:17:17 -05:00
) -> LspResult < Option < CompletionResponse > > {
2023-03-15 10:34:23 -04:00
let specifier = self . url_map . normalize_url (
& params . text_document_position . text_document . uri ,
LspUrlKind ::File ,
) ;
2023-10-24 16:27:27 -04:00
let language_settings =
self . config . language_settings_for_specifier ( & specifier ) ;
2021-10-28 19:56:01 -04:00
if ! self . is_diagnosable ( & specifier )
2021-06-02 06:29:58 -04:00
| | ! self . config . specifier_enabled ( & specifier )
2023-09-25 22:54:07 -04:00
| | ! language_settings . map ( | s | s . suggest . enabled ) . unwrap_or ( true )
2021-06-02 06:29:58 -04:00
{
2021-05-09 21:16:04 -04:00
return Ok ( None ) ;
}
2021-06-02 06:29:58 -04:00
2023-11-30 21:54:59 -05:00
let mark = self . performance . mark_with_args ( " lsp.completion " , & params ) ;
2022-04-25 11:23:24 -04:00
let asset_or_doc = self . get_asset_or_document ( & specifier ) ? ;
2021-03-24 20:13:37 -04:00
// Import specifiers are something wholly internal to Deno, so for
// completions, we will use internal logic and if there are completions
// for imports, we will return those and not send a message into tsc, where
// other completions come from.
2023-09-25 22:54:07 -04:00
let mut response = None ;
if language_settings
. map ( | s | s . suggest . include_completions_for_import_statements )
. unwrap_or ( true )
2021-04-08 21:27:27 -04:00
{
2023-09-25 22:54:07 -04:00
response = completions ::get_import_completions (
& specifier ,
& params . text_document_position . position ,
& self . config . snapshot ( ) ,
& self . client ,
& self . module_registries ,
2024-02-28 22:54:16 -05:00
& self . jsr_search_api ,
2023-09-25 22:54:07 -04:00
& self . npm . search_api ,
& self . documents ,
2024-03-26 11:52:20 -04:00
self . config . tree . import_map_for_specifier ( & specifier ) ,
2023-09-25 22:54:07 -04:00
)
. await ;
}
if response . is_none ( ) {
2021-11-12 11:42:04 -05:00
let line_index = asset_or_doc . line_index ( ) ;
2022-07-11 19:35:18 -04:00
let ( trigger_character , trigger_kind ) =
if let Some ( context ) = & params . context {
(
context . trigger_character . clone ( ) ,
Some ( context . trigger_kind . into ( ) ) ,
)
} else {
( None , None )
} ;
2021-03-24 20:13:37 -04:00
let position =
line_index . offset_tsc ( params . text_document_position . position ) ? ;
2023-05-12 19:07:40 -04:00
let maybe_completion_info = self
. ts_server
. get_completions (
self . snapshot ( ) ,
specifier . clone ( ) ,
position ,
tsc ::GetCompletionsAtPositionOptions {
2023-09-25 22:54:07 -04:00
user_preferences : tsc ::UserPreferences ::from_config_for_specifier (
& self . config ,
& specifier ,
) ,
2023-05-12 19:07:40 -04:00
trigger_character ,
trigger_kind ,
2021-03-24 20:13:37 -04:00
} ,
2024-03-26 11:52:20 -04:00
( & self
. config
. tree
. fmt_options_for_specifier ( & specifier )
. options )
. into ( ) ,
2023-05-12 19:07:40 -04:00
)
. await ;
2020-12-21 08:44:26 -05:00
2021-03-24 20:13:37 -04:00
if let Some ( completions ) = maybe_completion_info {
2023-09-25 22:54:07 -04:00
response = Some (
completions . as_completion_response (
line_index ,
& self
. config
. language_settings_for_specifier ( & specifier )
. cloned ( )
. unwrap_or_default ( )
. suggest ,
& specifier ,
position ,
self ,
) ,
2021-03-24 20:13:37 -04:00
) ;
}
} ;
self . performance . measure ( mark ) ;
Ok ( response )
2020-12-21 08:44:26 -05:00
}
2021-03-15 18:01:41 -04:00
async fn completion_resolve (
2022-01-19 11:38:40 -05:00
& self ,
2021-03-15 18:01:41 -04:00
params : CompletionItem ,
) -> LspResult < CompletionItem > {
2023-11-30 21:54:59 -05:00
let mark = self
. performance
. mark_with_args ( " lsp.completion_resolve " , & params ) ;
2021-03-24 20:13:37 -04:00
let completion_item = if let Some ( data ) = & params . data {
let data : completions ::CompletionItemData =
serde_json ::from_value ( data . clone ( ) ) . map_err ( | err | {
2024-03-01 21:25:38 -05:00
error! ( " {:#} " , err ) ;
2021-03-15 18:01:41 -04:00
LspError ::invalid_params (
" Could not decode data field of completion item. " ,
)
} ) ? ;
2022-07-11 19:35:18 -04:00
if let Some ( data ) = & data . tsc {
2023-01-03 05:41:50 -05:00
let specifier = & data . specifier ;
2023-05-12 19:07:40 -04:00
let result = self
. ts_server
2023-09-25 22:54:07 -04:00
. get_completion_details (
self . snapshot ( ) ,
GetCompletionDetailsArgs {
2024-03-26 11:52:20 -04:00
format_code_settings : Some (
( & self
. config
. tree
. fmt_options_for_specifier ( specifier )
. options )
. into ( ) ,
) ,
2023-09-25 22:54:07 -04:00
preferences : Some (
tsc ::UserPreferences ::from_config_for_specifier (
& self . config ,
specifier ,
) ,
) ,
.. data . into ( )
} ,
)
2023-05-12 19:07:40 -04:00
. await ;
2023-01-03 12:13:21 -05:00
match result {
Ok ( maybe_completion_info ) = > {
if let Some ( completion_info ) = maybe_completion_info {
completion_info
. as_completion_item ( & params , data , specifier , self )
. map_err ( | err | {
error! (
2024-03-01 21:25:38 -05:00
" Failed to serialize virtual_text_document response: {:#} " ,
2023-01-03 12:13:21 -05:00
err
) ;
LspError ::internal_error ( )
} ) ?
} else {
2022-07-11 19:35:18 -04:00
error! (
2023-01-03 12:13:21 -05:00
" Received an undefined response from tsc for completion details. "
2022-07-11 19:35:18 -04:00
) ;
2023-01-03 12:13:21 -05:00
params
}
}
Err ( err ) = > {
2024-03-01 21:25:38 -05:00
error! ( " Unable to get completion info from TypeScript: {:#} " , err ) ;
2023-01-03 12:13:21 -05:00
return Ok ( params ) ;
}
2021-03-24 20:13:37 -04:00
}
2021-12-13 14:24:11 -05:00
} else if let Some ( url ) = data . documentation {
CompletionItem {
documentation : self . module_registries . get_documentation ( & url ) . await ,
data : None ,
.. params
}
2021-03-15 18:01:41 -04:00
} else {
2021-03-24 20:13:37 -04:00
params
2021-03-15 18:01:41 -04:00
}
} else {
2021-03-24 20:13:37 -04:00
params
} ;
self . performance . measure ( mark ) ;
Ok ( completion_item )
2021-03-15 18:01:41 -04:00
}
2021-01-12 16:53:27 -05:00
async fn goto_implementation (
2022-01-19 11:38:40 -05:00
& self ,
2021-01-12 16:53:27 -05:00
params : GotoImplementationParams ,
) -> LspResult < Option < GotoImplementationResponse > > {
2023-03-15 10:34:23 -04:00
let specifier = self . url_map . normalize_url (
& params . text_document_position_params . text_document . uri ,
LspUrlKind ::File ,
) ;
2021-10-28 19:56:01 -04:00
if ! self . is_diagnosable ( & specifier )
2021-06-02 06:29:58 -04:00
| | ! self . config . specifier_enabled ( & specifier )
{
2021-05-09 21:16:04 -04:00
return Ok ( None ) ;
}
2021-06-02 06:29:58 -04:00
2023-11-30 21:54:59 -05:00
let mark = self
. performance
. mark_with_args ( " lsp.goto_implementation " , & params ) ;
2022-04-25 11:23:24 -04:00
let asset_or_doc = self . get_asset_or_document ( & specifier ) ? ;
2021-11-12 11:42:04 -05:00
let line_index = asset_or_doc . line_index ( ) ;
2021-01-12 16:53:27 -05:00
2023-05-12 19:07:40 -04:00
let maybe_implementations = self
2021-02-24 22:15:55 -05:00
. ts_server
2023-05-12 19:07:40 -04:00
. get_implementations (
self . snapshot ( ) ,
specifier ,
line_index . offset_tsc ( params . text_document_position_params . position ) ? ,
)
. await ? ;
2021-01-12 16:53:27 -05:00
2021-02-17 22:15:13 -05:00
let result = if let Some ( implementations ) = maybe_implementations {
let mut links = Vec ::new ( ) ;
for implementation in implementations {
2022-04-25 11:23:24 -04:00
if let Some ( link ) = implementation . to_link ( line_index . clone ( ) , self ) {
2021-02-17 22:15:13 -05:00
links . push ( link )
2021-01-12 16:53:27 -05:00
}
}
2021-02-17 22:15:13 -05:00
Some ( GotoDefinitionResponse ::Link ( links ) )
2021-01-12 16:53:27 -05:00
} else {
2021-02-17 22:15:13 -05:00
None
} ;
self . performance . measure ( mark ) ;
Ok ( result )
2021-01-12 16:53:27 -05:00
}
2021-04-02 02:21:07 -04:00
async fn folding_range (
2022-01-19 11:38:40 -05:00
& self ,
2021-04-02 02:21:07 -04:00
params : FoldingRangeParams ,
) -> LspResult < Option < Vec < FoldingRange > > > {
2023-03-15 10:34:23 -04:00
let specifier = self
. url_map
. normalize_url ( & params . text_document . uri , LspUrlKind ::File ) ;
2021-10-28 19:56:01 -04:00
if ! self . is_diagnosable ( & specifier )
2021-06-02 06:29:58 -04:00
| | ! self . config . specifier_enabled ( & specifier )
{
2021-04-02 02:21:07 -04:00
return Ok ( None ) ;
}
2023-11-30 21:54:59 -05:00
let mark = self
. performance
. mark_with_args ( " lsp.folding_range " , & params ) ;
2022-04-25 11:23:24 -04:00
let asset_or_doc = self . get_asset_or_document ( & specifier ) ? ;
2021-04-02 02:21:07 -04:00
2023-05-12 19:07:40 -04:00
let outlining_spans = self
2021-04-02 02:21:07 -04:00
. ts_server
2023-05-12 19:07:40 -04:00
. get_outlining_spans ( self . snapshot ( ) , specifier )
. await ? ;
2021-04-02 02:21:07 -04:00
let response = if ! outlining_spans . is_empty ( ) {
Some (
outlining_spans
. iter ( )
. map ( | span | {
span . to_folding_range (
2021-11-12 11:42:04 -05:00
asset_or_doc . line_index ( ) ,
2022-05-20 16:40:55 -04:00
asset_or_doc . text ( ) . as_bytes ( ) ,
2021-04-02 02:21:07 -04:00
self . config . client_capabilities . line_folding_only ,
)
} )
. collect ::< Vec < FoldingRange > > ( ) ,
)
} else {
None
} ;
self . performance . measure ( mark ) ;
Ok ( response )
}
2021-04-19 01:11:26 -04:00
async fn incoming_calls (
2022-01-19 11:38:40 -05:00
& self ,
2021-04-19 01:11:26 -04:00
params : CallHierarchyIncomingCallsParams ,
) -> LspResult < Option < Vec < CallHierarchyIncomingCall > > > {
2023-03-15 10:34:23 -04:00
let specifier = self
. url_map
. normalize_url ( & params . item . uri , LspUrlKind ::File ) ;
2021-10-28 19:56:01 -04:00
if ! self . is_diagnosable ( & specifier )
2021-06-02 06:29:58 -04:00
| | ! self . config . specifier_enabled ( & specifier )
{
2021-04-19 01:11:26 -04:00
return Ok ( None ) ;
}
2023-11-30 21:54:59 -05:00
let mark = self
. performance
. mark_with_args ( " lsp.incoming_calls " , & params ) ;
2022-04-25 11:23:24 -04:00
let asset_or_doc = self . get_asset_or_document ( & specifier ) ? ;
2021-11-12 11:42:04 -05:00
let line_index = asset_or_doc . line_index ( ) ;
2021-04-19 01:11:26 -04:00
let incoming_calls : Vec < tsc ::CallHierarchyIncomingCall > = self
. ts_server
2023-05-12 19:07:40 -04:00
. provide_call_hierarchy_incoming_calls (
self . snapshot ( ) ,
specifier ,
line_index . offset_tsc ( params . item . selection_range . start ) ? ,
)
. await ? ;
2021-04-19 01:11:26 -04:00
let maybe_root_path_owned = self
2022-03-20 21:33:37 -04:00
. config
2023-09-09 10:04:21 -04:00
. root_uri ( )
2022-11-28 17:28:54 -05:00
. and_then ( | uri | specifier_to_file_path ( uri ) . ok ( ) ) ;
2021-04-19 01:11:26 -04:00
let mut resolved_items = Vec ::< CallHierarchyIncomingCall > ::new ( ) ;
for item in incoming_calls . iter ( ) {
2022-04-25 11:23:24 -04:00
if let Some ( resolved ) = item . try_resolve_call_hierarchy_incoming_call (
self ,
maybe_root_path_owned . as_deref ( ) ,
) {
2021-04-19 01:11:26 -04:00
resolved_items . push ( resolved ) ;
}
}
self . performance . measure ( mark ) ;
Ok ( Some ( resolved_items ) )
}
async fn outgoing_calls (
2022-01-19 11:38:40 -05:00
& self ,
2021-04-19 01:11:26 -04:00
params : CallHierarchyOutgoingCallsParams ,
) -> LspResult < Option < Vec < CallHierarchyOutgoingCall > > > {
2023-03-15 10:34:23 -04:00
let specifier = self
. url_map
. normalize_url ( & params . item . uri , LspUrlKind ::File ) ;
2021-10-28 19:56:01 -04:00
if ! self . is_diagnosable ( & specifier )
2021-06-02 06:29:58 -04:00
| | ! self . config . specifier_enabled ( & specifier )
{
2021-04-19 01:11:26 -04:00
return Ok ( None ) ;
}
2023-11-30 21:54:59 -05:00
let mark = self
. performance
. mark_with_args ( " lsp.outgoing_calls " , & params ) ;
2022-04-25 11:23:24 -04:00
let asset_or_doc = self . get_asset_or_document ( & specifier ) ? ;
2021-11-12 11:42:04 -05:00
let line_index = asset_or_doc . line_index ( ) ;
2021-04-19 01:11:26 -04:00
let outgoing_calls : Vec < tsc ::CallHierarchyOutgoingCall > = self
. ts_server
2023-05-12 19:07:40 -04:00
. provide_call_hierarchy_outgoing_calls (
self . snapshot ( ) ,
specifier ,
line_index . offset_tsc ( params . item . selection_range . start ) ? ,
)
. await ? ;
2021-04-19 01:11:26 -04:00
let maybe_root_path_owned = self
2022-03-20 21:33:37 -04:00
. config
2023-09-09 10:04:21 -04:00
. root_uri ( )
2022-11-28 17:28:54 -05:00
. and_then ( | uri | specifier_to_file_path ( uri ) . ok ( ) ) ;
2021-04-19 01:11:26 -04:00
let mut resolved_items = Vec ::< CallHierarchyOutgoingCall > ::new ( ) ;
for item in outgoing_calls . iter ( ) {
2022-04-25 11:23:24 -04:00
if let Some ( resolved ) = item . try_resolve_call_hierarchy_outgoing_call (
line_index . clone ( ) ,
self ,
maybe_root_path_owned . as_deref ( ) ,
) {
2021-04-19 01:11:26 -04:00
resolved_items . push ( resolved ) ;
}
}
self . performance . measure ( mark ) ;
Ok ( Some ( resolved_items ) )
}
async fn prepare_call_hierarchy (
2022-01-19 11:38:40 -05:00
& self ,
2021-04-19 01:11:26 -04:00
params : CallHierarchyPrepareParams ,
) -> LspResult < Option < Vec < CallHierarchyItem > > > {
2023-03-15 10:34:23 -04:00
let specifier = self . url_map . normalize_url (
& params . text_document_position_params . text_document . uri ,
LspUrlKind ::File ,
) ;
2021-10-28 19:56:01 -04:00
if ! self . is_diagnosable ( & specifier )
2021-06-02 06:29:58 -04:00
| | ! self . config . specifier_enabled ( & specifier )
{
2021-05-09 21:16:04 -04:00
return Ok ( None ) ;
}
2021-06-02 06:29:58 -04:00
2021-05-11 00:54:10 -04:00
let mark = self
. performance
2023-11-30 21:54:59 -05:00
. mark_with_args ( " lsp.prepare_call_hierarchy " , & params ) ;
2022-04-25 11:23:24 -04:00
let asset_or_doc = self . get_asset_or_document ( & specifier ) ? ;
2021-11-12 11:42:04 -05:00
let line_index = asset_or_doc . line_index ( ) ;
2021-04-19 01:11:26 -04:00
2023-05-12 19:07:40 -04:00
let maybe_one_or_many = self
. ts_server
. prepare_call_hierarchy (
self . snapshot ( ) ,
specifier ,
line_index . offset_tsc ( params . text_document_position_params . position ) ? ,
)
. await ? ;
2021-04-19 01:11:26 -04:00
let response = if let Some ( one_or_many ) = maybe_one_or_many {
let maybe_root_path_owned = self
2022-03-20 21:33:37 -04:00
. config
2023-09-09 10:04:21 -04:00
. root_uri ( )
2022-11-28 17:28:54 -05:00
. and_then ( | uri | specifier_to_file_path ( uri ) . ok ( ) ) ;
2021-04-19 01:11:26 -04:00
let mut resolved_items = Vec ::< CallHierarchyItem > ::new ( ) ;
match one_or_many {
tsc ::OneOrMany ::One ( item ) = > {
2022-04-25 11:23:24 -04:00
if let Some ( resolved ) = item . try_resolve_call_hierarchy_item (
self ,
maybe_root_path_owned . as_deref ( ) ,
) {
2021-04-19 01:11:26 -04:00
resolved_items . push ( resolved )
}
}
tsc ::OneOrMany ::Many ( items ) = > {
for item in items . iter ( ) {
2022-04-25 11:23:24 -04:00
if let Some ( resolved ) = item . try_resolve_call_hierarchy_item (
self ,
maybe_root_path_owned . as_deref ( ) ,
) {
2021-04-19 01:11:26 -04:00
resolved_items . push ( resolved ) ;
}
}
}
}
Some ( resolved_items )
} else {
None
} ;
self . performance . measure ( mark ) ;
Ok ( response )
}
2020-12-29 19:58:20 -05:00
async fn rename (
2022-01-19 11:38:40 -05:00
& self ,
2020-12-29 19:58:20 -05:00
params : RenameParams ,
2020-12-29 23:17:17 -05:00
) -> LspResult < Option < WorkspaceEdit > > {
2023-03-15 10:34:23 -04:00
let specifier = self . url_map . normalize_url (
& params . text_document_position . text_document . uri ,
LspUrlKind ::File ,
) ;
2021-10-28 19:56:01 -04:00
if ! self . is_diagnosable ( & specifier )
2021-06-02 06:29:58 -04:00
| | ! self . config . specifier_enabled ( & specifier )
{
2021-05-09 21:16:04 -04:00
return Ok ( None ) ;
}
2020-12-29 19:58:20 -05:00
2023-11-30 21:54:59 -05:00
let mark = self . performance . mark_with_args ( " lsp.rename " , & params ) ;
2022-04-25 11:23:24 -04:00
let asset_or_doc = self . get_asset_or_document ( & specifier ) ? ;
2021-11-12 11:42:04 -05:00
let line_index = asset_or_doc . line_index ( ) ;
2020-12-29 19:58:20 -05:00
2023-05-12 19:07:40 -04:00
let maybe_locations = self
2021-02-24 22:15:55 -05:00
. ts_server
2023-05-12 19:07:40 -04:00
. find_rename_locations (
self . snapshot ( ) ,
specifier ,
line_index . offset_tsc ( params . text_document_position . position ) ? ,
)
. await ? ;
2020-12-29 19:58:20 -05:00
2021-01-22 05:03:16 -05:00
if let Some ( locations ) = maybe_locations {
let rename_locations = tsc ::RenameLocations { locations } ;
let workspace_edits = rename_locations
2021-02-06 07:39:01 -05:00
. into_workspace_edit ( & params . new_name , self )
2021-01-22 05:03:16 -05:00
. map_err ( | err | {
2024-03-01 21:25:38 -05:00
error! ( " Failed to get workspace edits: {:#} " , err ) ;
2021-01-22 05:03:16 -05:00
LspError ::internal_error ( )
} ) ? ;
2021-01-26 19:32:49 -05:00
self . performance . measure ( mark ) ;
2021-01-22 05:03:16 -05:00
Ok ( Some ( workspace_edits ) )
} else {
2021-01-26 19:32:49 -05:00
self . performance . measure ( mark ) ;
2021-01-22 05:03:16 -05:00
Ok ( None )
2020-12-29 19:58:20 -05:00
}
}
2021-03-23 19:33:25 -04:00
async fn selection_range (
2022-12-19 20:22:17 -05:00
& self ,
2021-03-23 19:33:25 -04:00
params : SelectionRangeParams ,
) -> LspResult < Option < Vec < SelectionRange > > > {
2023-03-15 10:34:23 -04:00
let specifier = self
. url_map
. normalize_url ( & params . text_document . uri , LspUrlKind ::File ) ;
2021-10-28 19:56:01 -04:00
if ! self . is_diagnosable ( & specifier )
2021-06-02 06:29:58 -04:00
| | ! self . config . specifier_enabled ( & specifier )
{
2021-03-23 19:33:25 -04:00
return Ok ( None ) ;
}
2023-11-30 21:54:59 -05:00
let mark = self
. performance
. mark_with_args ( " lsp.selection_range " , & params ) ;
2022-04-25 11:23:24 -04:00
let asset_or_doc = self . get_asset_or_document ( & specifier ) ? ;
2021-11-12 11:42:04 -05:00
let line_index = asset_or_doc . line_index ( ) ;
2021-03-23 19:33:25 -04:00
let mut selection_ranges = Vec ::< SelectionRange > ::new ( ) ;
for position in params . positions {
let selection_range : tsc ::SelectionRange = self
. ts_server
2023-05-12 19:07:40 -04:00
. get_smart_selection_range (
self . snapshot ( ) ,
specifier . clone ( ) ,
line_index . offset_tsc ( position ) ? ,
)
. await ? ;
2021-03-23 19:33:25 -04:00
2021-10-28 19:56:01 -04:00
selection_ranges
. push ( selection_range . to_selection_range ( line_index . clone ( ) ) ) ;
2021-03-23 19:33:25 -04:00
}
self . performance . measure ( mark ) ;
Ok ( Some ( selection_ranges ) )
}
2021-04-19 21:26:36 -04:00
async fn semantic_tokens_full (
2022-12-19 20:22:17 -05:00
& self ,
2021-04-19 21:26:36 -04:00
params : SemanticTokensParams ,
) -> LspResult < Option < SemanticTokensResult > > {
2023-03-15 10:34:23 -04:00
let specifier = self
. url_map
. normalize_url ( & params . text_document . uri , LspUrlKind ::File ) ;
2023-09-10 15:09:45 -04:00
if ! self . is_diagnosable ( & specifier ) {
2021-04-19 21:26:36 -04:00
return Ok ( None ) ;
}
2023-11-30 21:54:59 -05:00
let mark = self
. performance
. mark_with_args ( " lsp.semantic_tokens_full " , & params ) ;
2022-04-25 11:23:24 -04:00
let asset_or_doc = self . get_asset_or_document ( & specifier ) ? ;
2021-11-12 11:42:04 -05:00
let line_index = asset_or_doc . line_index ( ) ;
2021-04-19 21:26:36 -04:00
2023-05-12 19:07:40 -04:00
let semantic_classification = self
2021-04-19 21:26:36 -04:00
. ts_server
2023-05-12 19:07:40 -04:00
. get_encoded_semantic_classifications (
self . snapshot ( ) ,
specifier ,
0 .. line_index . text_content_length_utf16 ( ) . into ( ) ,
)
. await ? ;
2021-04-19 21:26:36 -04:00
2021-11-16 17:23:25 -05:00
let semantic_tokens =
2022-03-02 16:06:38 -05:00
semantic_classification . to_semantic_tokens ( & asset_or_doc , line_index ) ? ;
2021-04-19 21:26:36 -04:00
let response = if ! semantic_tokens . data . is_empty ( ) {
Some ( SemanticTokensResult ::Tokens ( semantic_tokens ) )
} else {
None
} ;
self . performance . measure ( mark ) ;
Ok ( response )
}
async fn semantic_tokens_range (
2022-12-19 20:22:17 -05:00
& self ,
2021-04-19 21:26:36 -04:00
params : SemanticTokensRangeParams ,
) -> LspResult < Option < SemanticTokensRangeResult > > {
2023-03-15 10:34:23 -04:00
let specifier = self
. url_map
. normalize_url ( & params . text_document . uri , LspUrlKind ::File ) ;
2023-09-10 15:09:45 -04:00
if ! self . is_diagnosable ( & specifier ) {
2021-04-19 21:26:36 -04:00
return Ok ( None ) ;
}
2021-06-02 06:29:58 -04:00
2021-05-11 00:54:10 -04:00
let mark = self
. performance
2023-11-30 21:54:59 -05:00
. mark_with_args ( " lsp.semantic_tokens_range " , & params ) ;
2022-04-25 11:23:24 -04:00
let asset_or_doc = self . get_asset_or_document ( & specifier ) ? ;
2021-11-12 11:42:04 -05:00
let line_index = asset_or_doc . line_index ( ) ;
2021-04-19 21:26:36 -04:00
2023-05-12 19:07:40 -04:00
let semantic_classification = self
2021-04-19 21:26:36 -04:00
. ts_server
2023-05-12 19:07:40 -04:00
. get_encoded_semantic_classifications (
self . snapshot ( ) ,
specifier ,
line_index . offset_tsc ( params . range . start ) ?
.. line_index . offset_tsc ( params . range . end ) ? ,
)
. await ? ;
2021-04-19 21:26:36 -04:00
2021-11-16 17:23:25 -05:00
let semantic_tokens =
2022-03-02 16:06:38 -05:00
semantic_classification . to_semantic_tokens ( & asset_or_doc , line_index ) ? ;
2021-04-19 21:26:36 -04:00
let response = if ! semantic_tokens . data . is_empty ( ) {
Some ( SemanticTokensRangeResult ::Tokens ( semantic_tokens ) )
} else {
None
} ;
self . performance . measure ( mark ) ;
Ok ( response )
}
2021-02-15 21:34:09 -05:00
async fn signature_help (
2022-12-19 20:22:17 -05:00
& self ,
2021-02-15 21:34:09 -05:00
params : SignatureHelpParams ,
) -> LspResult < Option < SignatureHelp > > {
2023-03-15 10:34:23 -04:00
let specifier = self . url_map . normalize_url (
& params . text_document_position_params . text_document . uri ,
LspUrlKind ::File ,
) ;
2021-10-28 19:56:01 -04:00
if ! self . is_diagnosable ( & specifier )
2021-06-02 06:29:58 -04:00
| | ! self . config . specifier_enabled ( & specifier )
{
2021-05-09 21:16:04 -04:00
return Ok ( None ) ;
}
2021-06-02 06:29:58 -04:00
2023-11-30 21:54:59 -05:00
let mark = self
. performance
. mark_with_args ( " lsp.signature_help " , & params ) ;
2022-04-25 11:23:24 -04:00
let asset_or_doc = self . get_asset_or_document ( & specifier ) ? ;
2021-11-12 11:42:04 -05:00
let line_index = asset_or_doc . line_index ( ) ;
2021-02-15 21:34:09 -05:00
let options = if let Some ( context ) = params . context {
tsc ::SignatureHelpItemsOptions {
trigger_reason : Some ( tsc ::SignatureHelpTriggerReason {
kind : context . trigger_kind . into ( ) ,
trigger_character : context . trigger_character ,
} ) ,
}
} else {
tsc ::SignatureHelpItemsOptions {
trigger_reason : None ,
}
} ;
2021-02-24 22:15:55 -05:00
let maybe_signature_help_items : Option < tsc ::SignatureHelpItems > = self
. ts_server
2023-05-12 19:07:40 -04:00
. get_signature_help_items (
self . snapshot ( ) ,
specifier ,
line_index . offset_tsc ( params . text_document_position_params . position ) ? ,
options ,
)
. await ? ;
2021-02-15 21:34:09 -05:00
if let Some ( signature_help_items ) = maybe_signature_help_items {
2022-02-09 18:08:53 -05:00
let signature_help = signature_help_items . into_signature_help ( self ) ;
2021-02-15 21:34:09 -05:00
self . performance . measure ( mark ) ;
Ok ( Some ( signature_help ) )
} else {
self . performance . measure ( mark ) ;
Ok ( None )
}
}
2021-11-22 19:08:56 -05:00
2023-08-25 20:50:47 -04:00
async fn will_rename_files (
& self ,
params : RenameFilesParams ,
) -> LspResult < Option < WorkspaceEdit > > {
let mut changes = vec! [ ] ;
for rename in params . files {
2023-09-25 22:54:07 -04:00
let old_specifier = self . url_map . normalize_url (
& resolve_url ( & rename . old_uri ) . unwrap ( ) ,
LspUrlKind ::File ,
) ;
let options = self
. config
. language_settings_for_specifier ( & old_specifier )
. map ( | s | s . update_imports_on_file_move . clone ( ) )
. unwrap_or_default ( ) ;
// Note that `Always` and `Prompt` are treated the same in the server, the
// client will worry about that after receiving the edits.
if options . enabled = = UpdateImportsOnFileMoveEnabled ::Never {
continue ;
}
2024-03-26 11:52:20 -04:00
let format_code_settings = ( & self
. config
. tree
. fmt_options_for_specifier ( & old_specifier )
. options )
. into ( ) ;
2023-08-25 20:50:47 -04:00
changes . extend (
self
. ts_server
. get_edits_for_file_rename (
self . snapshot ( ) ,
2023-09-25 22:54:07 -04:00
old_specifier ,
2023-08-25 20:50:47 -04:00
self . url_map . normalize_url (
& resolve_url ( & rename . new_uri ) . unwrap ( ) ,
LspUrlKind ::File ,
) ,
2024-03-26 11:52:20 -04:00
format_code_settings ,
2023-08-25 20:50:47 -04:00
tsc ::UserPreferences {
allow_text_changes_in_new_files : Some ( true ) ,
.. Default ::default ( )
} ,
)
. await ? ,
) ;
}
file_text_changes_to_workspace_edit ( & changes , self )
}
2021-11-22 19:08:56 -05:00
async fn symbol (
2022-12-19 20:22:17 -05:00
& self ,
2021-11-22 19:08:56 -05:00
params : WorkspaceSymbolParams ,
) -> LspResult < Option < Vec < SymbolInformation > > > {
2023-11-30 21:54:59 -05:00
let mark = self . performance . mark_with_args ( " lsp.symbol " , & params ) ;
2021-11-22 19:08:56 -05:00
2023-05-12 19:07:40 -04:00
let navigate_to_items = self
2021-11-22 19:08:56 -05:00
. ts_server
2023-05-12 19:07:40 -04:00
. get_navigate_to_items (
self . snapshot ( ) ,
tsc ::GetNavigateToItemsArgs {
search : params . query ,
// this matches vscode's hard coded result count
max_result_count : Some ( 256 ) ,
file : None ,
} ,
)
. await ? ;
2021-11-22 19:08:56 -05:00
let maybe_symbol_information = if navigate_to_items . is_empty ( ) {
None
} else {
let mut symbol_information = Vec ::new ( ) ;
for item in navigate_to_items {
2022-04-25 11:23:24 -04:00
if let Some ( info ) = item . to_symbol_information ( self ) {
2021-11-22 19:08:56 -05:00
symbol_information . push ( info ) ;
}
}
Some ( symbol_information )
} ;
self . performance . measure ( mark ) ;
Ok ( maybe_symbol_information )
}
2022-02-02 18:02:59 -05:00
fn send_diagnostics_update ( & self ) {
2023-05-26 02:10:18 -04:00
let snapshot = DiagnosticServerUpdateMessage {
snapshot : self . snapshot ( ) ,
config : self . config . snapshot ( ) ,
2023-08-02 16:57:25 -04:00
url_map : self . url_map . clone ( ) ,
2023-05-26 02:10:18 -04:00
} ;
2022-02-02 18:02:59 -05:00
if let Err ( err ) = self . diagnostics_server . update ( snapshot ) {
2024-03-01 21:25:38 -05:00
error! ( " Cannot update diagnostics: {:#} " , err ) ;
2022-02-02 18:02:59 -05:00
}
}
2022-03-29 18:59:27 -04:00
/// Send a message to the testing server to look for any changes in tests and
/// update the client.
fn send_testing_update ( & self ) {
if let Some ( testing_server ) = & self . maybe_testing_server {
if let Err ( err ) = testing_server . update ( self . snapshot ( ) ) {
2024-03-01 21:25:38 -05:00
error! ( " Cannot update testing server: {:#} " , err ) ;
2022-03-29 18:59:27 -04:00
}
}
}
2020-12-21 08:44:26 -05:00
}
2022-04-03 00:17:30 -04:00
#[ tower_lsp::async_trait ]
impl tower_lsp ::LanguageServer for LanguageServer {
2023-09-05 11:36:35 -04:00
async fn execute_command (
& self ,
params : ExecuteCommandParams ,
) -> LspResult < Option < Value > > {
if params . command = = " deno.cache " {
2024-02-28 22:54:16 -05:00
#[ derive(Default, Deserialize) ]
#[ serde(rename_all = " camelCase " ) ]
struct Options {
#[ serde(default) ]
force_global_cache : bool ,
}
#[ derive(Deserialize) ]
struct Arguments ( Vec < Url > , Url , #[ serde(default) ] Options ) ;
let Arguments ( specifiers , referrer , options ) =
serde_json ::from_value ( json! ( params . arguments ) )
. map_err ( | err | LspError ::invalid_params ( err . to_string ( ) ) ) ? ;
self
. cache ( specifiers , referrer , options . force_global_cache )
. await
2023-10-10 00:53:41 -04:00
} else if params . command = = " deno.reloadImportRegistries " {
self . 0. write ( ) . await . reload_import_registries ( ) . await
} else {
Ok ( None )
2023-09-05 11:36:35 -04:00
}
}
2021-01-26 04:55:04 -05:00
async fn initialize (
& self ,
params : InitializeParams ,
) -> LspResult < InitializeResult > {
2022-12-19 20:22:17 -05:00
let mut language_server = self . 0. write ( ) . await ;
2022-02-02 18:02:59 -05:00
language_server . diagnostics_server . start ( ) ;
2021-03-09 21:41:35 -05:00
language_server . initialize ( params ) . await
2021-01-26 04:55:04 -05:00
}
2023-03-15 10:34:23 -04:00
async fn initialized ( & self , _ : InitializedParams ) {
2023-08-25 20:50:47 -04:00
let mut registrations = Vec ::with_capacity ( 2 ) ;
2023-11-17 16:40:12 -05:00
let ( client , http_client ) = {
2023-03-15 10:34:23 -04:00
let mut ls = self . 0. write ( ) . await ;
if ls
. config
. client_capabilities
. workspace_did_change_watched_files
{
// we are going to watch all the JSON files in the workspace, and the
// notification handler will pick up any of the changes of those files we
// are interested in.
2023-08-25 20:50:47 -04:00
let options = DidChangeWatchedFilesRegistrationOptions {
watchers : vec ! [ FileSystemWatcher {
2023-09-26 16:57:14 -04:00
glob_pattern : GlobPattern ::String (
" **/*.{json,jsonc,lock} " . to_string ( ) ,
) ,
2023-09-01 16:13:13 -04:00
kind : None ,
2023-08-25 20:50:47 -04:00
} ] ,
} ;
registrations . push ( Registration {
2023-03-15 10:34:23 -04:00
id : " workspace/didChangeWatchedFiles " . to_string ( ) ,
method : " workspace/didChangeWatchedFiles " . to_string ( ) ,
2023-08-25 20:50:47 -04:00
register_options : Some ( serde_json ::to_value ( options ) . unwrap ( ) ) ,
} ) ;
}
if ls . config . client_capabilities . workspace_will_rename_files {
let options = FileOperationRegistrationOptions {
filters : vec ! [ FileOperationFilter {
scheme : Some ( " file " . to_string ( ) ) ,
pattern : FileOperationPattern {
glob : " **/* " . to_string ( ) ,
matches : None ,
options : None ,
} ,
} ] ,
} ;
registrations . push ( Registration {
id : " workspace/willRenameFiles " . to_string ( ) ,
method : " workspace/willRenameFiles " . to_string ( ) ,
register_options : Some ( serde_json ::to_value ( options ) . unwrap ( ) ) ,
2023-03-15 10:34:23 -04:00
} ) ;
}
if ls . config . client_capabilities . testing_api {
let test_server = testing ::TestServer ::new (
ls . client . clone ( ) ,
ls . performance . clone ( ) ,
2023-09-09 10:04:21 -04:00
ls . config . root_uri ( ) . cloned ( ) ,
2023-03-15 10:34:23 -04:00
) ;
ls . maybe_testing_server = Some ( test_server ) ;
}
2024-01-17 15:22:28 -05:00
2024-03-26 11:52:20 -04:00
let mut config_events = vec! [ ] ;
for ( scope_uri , config_data ) in ls . config . tree . data_by_scope ( ) {
if let Some ( config_file ) = & config_data . config_file {
2024-01-23 01:12:41 -05:00
config_events . push ( lsp_custom ::DenoConfigurationChangeEvent {
2024-03-26 11:52:20 -04:00
scope_uri : scope_uri . clone ( ) ,
2024-01-23 01:12:41 -05:00
file_uri : config_file . specifier . clone ( ) ,
typ : lsp_custom ::DenoConfigurationChangeType ::Added ,
configuration_type : lsp_custom ::DenoConfigurationType ::DenoJson ,
} ) ;
}
2024-03-26 11:52:20 -04:00
if let Some ( package_json ) = & config_data . package_json {
2024-01-23 01:12:41 -05:00
config_events . push ( lsp_custom ::DenoConfigurationChangeEvent {
2024-03-26 11:52:20 -04:00
scope_uri : scope_uri . clone ( ) ,
2024-01-23 01:12:41 -05:00
file_uri : package_json . specifier ( ) ,
typ : lsp_custom ::DenoConfigurationChangeType ::Added ,
configuration_type : lsp_custom ::DenoConfigurationType ::PackageJson ,
} ) ;
}
2024-03-26 11:52:20 -04:00
}
if ! config_events . is_empty ( ) {
ls . client . send_did_change_deno_configuration_notification (
lsp_custom ::DidChangeDenoConfigurationNotificationParams {
changes : config_events ,
} ,
) ;
2024-01-17 15:22:28 -05:00
}
2023-11-17 16:40:12 -05:00
( ls . client . clone ( ) , ls . http_client . clone ( ) )
2023-03-15 10:34:23 -04:00
} ;
2023-08-25 20:50:47 -04:00
for registration in registrations {
2023-03-15 10:34:23 -04:00
if let Err ( err ) = client
. when_outside_lsp_lock ( )
. register_capability ( vec! [ registration ] )
. await
{
2023-03-30 10:43:16 -04:00
lsp_warn! ( " Client errored on capabilities. \n {:#} " , err ) ;
2023-03-15 10:34:23 -04:00
}
}
2023-10-24 16:27:27 -04:00
self . refresh_configuration ( ) . await ;
2023-05-22 21:28:36 -04:00
{
let mut ls = self . 0. write ( ) . await ;
2023-12-08 12:04:56 -05:00
init_log_file ( ls . config . log_file ( ) ) ;
2023-07-26 18:52:31 -04:00
ls . refresh_documents_config ( ) . await ;
2023-05-22 21:28:36 -04:00
ls . diagnostics_server . invalidate_all ( ) ;
ls . send_diagnostics_update ( ) ;
2024-01-02 18:48:34 -05:00
ls . task_queue . start ( self . clone ( ) ) ;
} ;
2023-11-14 17:10:51 -05:00
if upgrade_check_enabled ( ) {
2023-11-17 16:40:12 -05:00
// spawn to avoid lsp send/sync requirement, but also just
// to ensure this initialized method returns quickly
spawn ( async move {
match check_for_upgrades_for_lsp ( http_client ) . await {
Ok ( version_info ) = > {
client . send_did_upgrade_check_notification (
lsp_custom ::DidUpgradeCheckNotificationParams {
upgrade_available : version_info . map ( | info | {
lsp_custom ::UpgradeAvailable {
latest_version : info . latest_version ,
is_canary : info . is_canary ,
}
} ) ,
} ,
) ;
}
Err ( err ) = > lsp_warn! ( " Failed to check for upgrades: {err} " ) ,
2023-11-14 17:10:51 -05:00
}
2023-11-17 16:40:12 -05:00
} ) ;
2023-11-14 17:10:51 -05:00
}
2024-01-02 18:48:34 -05:00
lsp_log! ( " Server ready. " ) ;
2021-01-26 04:55:04 -05:00
}
async fn shutdown ( & self ) -> LspResult < ( ) > {
2023-11-21 23:08:48 -05:00
self . 1. cancel ( ) ;
2024-03-11 23:48:00 -04:00
self . 0. write ( ) . await . shutdown ( )
2021-01-26 04:55:04 -05:00
}
async fn did_open ( & self , params : DidOpenTextDocumentParams ) {
2023-02-06 16:49:49 -05:00
if params . text_document . uri . scheme ( ) = = " deno " {
2022-02-02 18:02:59 -05:00
// we can ignore virtual text documents opening, as they don't need to
// be tracked in memory, as they are static assets that won't change
// already managed by the language service
return ;
}
2023-10-24 16:27:27 -04:00
let mut inner = self . 0. write ( ) . await ;
let specifier = inner
. url_map
. normalize_url ( & params . text_document . uri , LspUrlKind ::File ) ;
2024-03-11 23:48:00 -04:00
let document = inner . did_open ( & specifier , params ) ;
2023-10-24 16:27:27 -04:00
if document . is_diagnosable ( ) {
inner . refresh_npm_specifiers ( ) . await ;
let specifiers = inner . documents . dependents ( & specifier ) ;
inner . diagnostics_server . invalidate ( & specifiers ) ;
inner . send_diagnostics_update ( ) ;
inner . send_testing_update ( ) ;
2022-01-25 10:30:38 -05:00
}
2021-01-26 04:55:04 -05:00
}
async fn did_change ( & self , params : DidChangeTextDocumentParams ) {
2022-12-19 20:22:17 -05:00
self . 0. write ( ) . await . did_change ( params ) . await
2021-01-26 04:55:04 -05:00
}
2023-09-24 12:59:42 -04:00
async fn did_save ( & self , params : DidSaveTextDocumentParams ) {
let uri = & params . text_document . uri ;
2024-01-30 12:17:34 -05:00
let specifier = {
2023-10-12 10:37:56 -04:00
let mut inner = self . 0. write ( ) . await ;
2023-09-25 22:54:07 -04:00
let specifier = inner . url_map . normalize_url ( uri , LspUrlKind ::File ) ;
2023-10-12 10:37:56 -04:00
inner . documents . save ( & specifier ) ;
2023-10-24 16:27:27 -04:00
if ! inner
. config
. workspace_settings_for_specifier ( & specifier )
. cache_on_save
2023-09-25 22:54:07 -04:00
| | ! inner . config . specifier_enabled ( & specifier )
| | ! inner . diagnostics_state . has_no_cache_diagnostics ( & specifier )
2023-09-24 12:59:42 -04:00
{
return ;
}
2023-09-25 22:54:07 -04:00
match specifier_to_file_path ( & specifier ) {
Ok ( path ) if is_importable_ext ( & path ) = > { }
_ = > return ,
}
2024-01-30 12:17:34 -05:00
specifier
} ;
2024-02-28 22:54:16 -05:00
if let Err ( err ) = self . cache ( vec! [ ] , specifier . clone ( ) , false ) . await {
2024-03-01 21:25:38 -05:00
lsp_warn! ( " Failed to cache \" {} \" on save: {:#} " , & specifier , err ) ;
2023-09-24 12:59:42 -04:00
}
2021-02-09 17:46:12 -05:00
}
2021-01-26 04:55:04 -05:00
async fn did_close ( & self , params : DidCloseTextDocumentParams ) {
2022-12-19 20:22:17 -05:00
self . 0. write ( ) . await . did_close ( params ) . await
2021-01-26 04:55:04 -05:00
}
async fn did_change_configuration (
& self ,
params : DidChangeConfigurationParams ,
) {
2023-10-24 16:27:27 -04:00
let mark = {
2023-03-15 10:34:23 -04:00
let inner = self . 0. read ( ) . await ;
2023-10-24 16:27:27 -04:00
inner
. performance
2023-11-30 21:54:59 -05:00
. mark_with_args ( " lsp.did_change_configuration " , & params )
2022-01-25 10:30:38 -05:00
} ;
2023-10-24 16:27:27 -04:00
self . refresh_configuration ( ) . await ;
2022-01-25 10:30:38 -05:00
2022-12-19 20:22:17 -05:00
let mut inner = self . 0. write ( ) . await ;
2023-10-24 16:27:27 -04:00
inner . did_change_configuration ( params ) . await ;
2022-01-25 10:30:38 -05:00
inner . performance . measure ( mark ) ;
2021-01-26 04:55:04 -05:00
}
async fn did_change_watched_files (
& self ,
params : DidChangeWatchedFilesParams ,
) {
2022-12-19 20:22:17 -05:00
self . 0. write ( ) . await . did_change_watched_files ( params ) . await
2021-01-26 04:55:04 -05:00
}
2022-03-20 21:33:37 -04:00
async fn did_change_workspace_folders (
& self ,
params : DidChangeWorkspaceFoldersParams ,
) {
2023-03-15 10:34:23 -04:00
let ( performance , mark ) = {
let mut ls = self . 0. write ( ) . await ;
let mark = ls
. performance
2023-11-30 21:54:59 -05:00
. mark_with_args ( " lsp.did_change_workspace_folders " , & params ) ;
2023-03-15 10:34:23 -04:00
ls . did_change_workspace_folders ( params ) ;
( ls . performance . clone ( ) , mark )
2022-03-20 21:33:37 -04:00
} ;
2023-03-15 10:34:23 -04:00
2023-10-24 16:27:27 -04:00
self . refresh_configuration ( ) . await ;
{
2023-05-22 21:28:36 -04:00
let mut ls = self . 0. write ( ) . await ;
2024-03-21 00:29:52 -04:00
ls . refresh_workspace_files ( ) ;
2024-03-26 11:52:20 -04:00
ls . refresh_config_tree ( ) . await ;
2023-07-26 18:52:31 -04:00
ls . refresh_documents_config ( ) . await ;
2023-05-22 21:28:36 -04:00
ls . diagnostics_server . invalidate_all ( ) ;
ls . send_diagnostics_update ( ) ;
}
2023-03-15 10:34:23 -04:00
performance . measure ( mark ) ;
2022-03-20 21:33:37 -04:00
}
2021-04-19 21:29:27 -04:00
async fn document_symbol (
& self ,
params : DocumentSymbolParams ,
) -> LspResult < Option < DocumentSymbolResponse > > {
2022-12-19 20:22:17 -05:00
self . 0. read ( ) . await . document_symbol ( params ) . await
2021-04-19 21:29:27 -04:00
}
2021-01-26 04:55:04 -05:00
async fn formatting (
& self ,
params : DocumentFormattingParams ,
) -> LspResult < Option < Vec < TextEdit > > > {
2022-12-19 20:22:17 -05:00
self . 0. read ( ) . await . formatting ( params ) . await
2021-01-26 04:55:04 -05:00
}
async fn hover ( & self , params : HoverParams ) -> LspResult < Option < Hover > > {
2022-12-19 20:22:17 -05:00
self . 0. read ( ) . await . hover ( params ) . await
2021-01-26 04:55:04 -05:00
}
2023-09-26 16:57:14 -04:00
async fn inlay_hint (
& self ,
params : InlayHintParams ,
) -> LspResult < Option < Vec < InlayHint > > > {
self . 0. read ( ) . await . inlay_hint ( params ) . await
}
2021-02-04 13:53:02 -05:00
async fn code_action (
& self ,
params : CodeActionParams ,
) -> LspResult < Option < CodeActionResponse > > {
2022-12-19 20:22:17 -05:00
self . 0. read ( ) . await . code_action ( params ) . await
2021-02-04 13:53:02 -05:00
}
2021-02-05 15:10:53 -05:00
async fn code_action_resolve (
& self ,
params : CodeAction ,
) -> LspResult < CodeAction > {
2022-12-19 20:22:17 -05:00
self . 0. read ( ) . await . code_action_resolve ( params ) . await
2021-02-05 15:10:53 -05:00
}
2021-01-31 22:30:41 -05:00
async fn code_lens (
& self ,
params : CodeLensParams ,
) -> LspResult < Option < Vec < CodeLens > > > {
2022-12-19 20:22:17 -05:00
self . 0. read ( ) . await . code_lens ( params ) . await
2021-01-31 22:30:41 -05:00
}
async fn code_lens_resolve ( & self , params : CodeLens ) -> LspResult < CodeLens > {
2022-12-19 20:22:17 -05:00
self . 0. read ( ) . await . code_lens_resolve ( params ) . await
2021-01-31 22:30:41 -05:00
}
2021-01-26 04:55:04 -05:00
async fn document_highlight (
& self ,
params : DocumentHighlightParams ,
) -> LspResult < Option < Vec < DocumentHighlight > > > {
2022-12-19 20:22:17 -05:00
self . 0. read ( ) . await . document_highlight ( params ) . await
2021-01-26 04:55:04 -05:00
}
async fn references (
& self ,
params : ReferenceParams ,
) -> LspResult < Option < Vec < Location > > > {
2022-12-19 20:22:17 -05:00
self . 0. read ( ) . await . references ( params ) . await
2021-01-26 04:55:04 -05:00
}
async fn goto_definition (
& self ,
params : GotoDefinitionParams ,
) -> LspResult < Option < GotoDefinitionResponse > > {
2022-12-19 20:22:17 -05:00
self . 0. read ( ) . await . goto_definition ( params ) . await
2021-01-26 04:55:04 -05:00
}
2021-11-22 19:09:19 -05:00
async fn goto_type_definition (
& self ,
params : GotoTypeDefinitionParams ,
) -> LspResult < Option < GotoTypeDefinitionResponse > > {
2022-12-19 20:22:17 -05:00
self . 0. read ( ) . await . goto_type_definition ( params ) . await
2021-11-22 19:09:19 -05:00
}
2021-01-26 04:55:04 -05:00
async fn completion (
& self ,
params : CompletionParams ,
) -> LspResult < Option < CompletionResponse > > {
2022-12-19 20:22:17 -05:00
self . 0. read ( ) . await . completion ( params ) . await
2021-01-26 04:55:04 -05:00
}
2021-03-15 18:01:41 -04:00
async fn completion_resolve (
& self ,
params : CompletionItem ,
) -> LspResult < CompletionItem > {
2022-12-19 20:22:17 -05:00
self . 0. read ( ) . await . completion_resolve ( params ) . await
2021-03-15 18:01:41 -04:00
}
2021-01-26 04:55:04 -05:00
async fn goto_implementation (
& self ,
params : GotoImplementationParams ,
) -> LspResult < Option < GotoImplementationResponse > > {
2022-12-19 20:22:17 -05:00
self . 0. read ( ) . await . goto_implementation ( params ) . await
2021-01-26 04:55:04 -05:00
}
2021-04-02 02:21:07 -04:00
async fn folding_range (
& self ,
params : FoldingRangeParams ,
) -> LspResult < Option < Vec < FoldingRange > > > {
2022-12-19 20:22:17 -05:00
self . 0. read ( ) . await . folding_range ( params ) . await
2021-04-02 02:21:07 -04:00
}
2021-04-19 01:11:26 -04:00
async fn incoming_calls (
& self ,
params : CallHierarchyIncomingCallsParams ,
) -> LspResult < Option < Vec < CallHierarchyIncomingCall > > > {
2022-12-19 20:22:17 -05:00
self . 0. read ( ) . await . incoming_calls ( params ) . await
2021-04-19 01:11:26 -04:00
}
async fn outgoing_calls (
& self ,
params : CallHierarchyOutgoingCallsParams ,
) -> LspResult < Option < Vec < CallHierarchyOutgoingCall > > > {
2022-12-19 20:22:17 -05:00
self . 0. read ( ) . await . outgoing_calls ( params ) . await
2021-04-19 01:11:26 -04:00
}
async fn prepare_call_hierarchy (
& self ,
params : CallHierarchyPrepareParams ,
) -> LspResult < Option < Vec < CallHierarchyItem > > > {
2022-12-19 20:22:17 -05:00
self . 0. read ( ) . await . prepare_call_hierarchy ( params ) . await
2021-04-19 01:11:26 -04:00
}
2021-01-26 04:55:04 -05:00
async fn rename (
& self ,
params : RenameParams ,
) -> LspResult < Option < WorkspaceEdit > > {
2022-12-19 20:22:17 -05:00
self . 0. read ( ) . await . rename ( params ) . await
2021-01-26 04:55:04 -05:00
}
2021-03-23 19:33:25 -04:00
async fn selection_range (
& self ,
params : SelectionRangeParams ,
) -> LspResult < Option < Vec < SelectionRange > > > {
2022-12-19 20:22:17 -05:00
self . 0. read ( ) . await . selection_range ( params ) . await
2021-03-23 19:33:25 -04:00
}
2021-04-19 21:26:36 -04:00
async fn semantic_tokens_full (
& self ,
params : SemanticTokensParams ,
) -> LspResult < Option < SemanticTokensResult > > {
2022-12-19 20:22:17 -05:00
self . 0. read ( ) . await . semantic_tokens_full ( params ) . await
2021-04-19 21:26:36 -04:00
}
async fn semantic_tokens_range (
& self ,
params : SemanticTokensRangeParams ,
) -> LspResult < Option < SemanticTokensRangeResult > > {
2022-12-19 20:22:17 -05:00
self . 0. read ( ) . await . semantic_tokens_range ( params ) . await
2021-04-19 21:26:36 -04:00
}
2021-02-15 21:34:09 -05:00
async fn signature_help (
& self ,
params : SignatureHelpParams ,
) -> LspResult < Option < SignatureHelp > > {
2022-12-19 20:22:17 -05:00
self . 0. read ( ) . await . signature_help ( params ) . await
2021-02-15 21:34:09 -05:00
}
2021-11-22 19:08:56 -05:00
2023-08-25 20:50:47 -04:00
async fn will_rename_files (
& self ,
params : RenameFilesParams ,
) -> LspResult < Option < WorkspaceEdit > > {
self . 0. read ( ) . await . will_rename_files ( params ) . await
}
2021-11-22 19:08:56 -05:00
async fn symbol (
& self ,
params : WorkspaceSymbolParams ,
) -> LspResult < Option < Vec < SymbolInformation > > > {
2022-12-19 20:22:17 -05:00
self . 0. read ( ) . await . symbol ( params ) . await
2021-11-22 19:08:56 -05:00
}
2021-01-26 04:55:04 -05:00
}
2022-12-19 20:22:17 -05:00
struct PrepareCacheResult {
cli_options : CliOptions ,
2023-01-24 08:23:19 -05:00
roots : Vec < ModuleSpecifier > ,
2022-12-19 20:22:17 -05:00
open_docs : Vec < Document > ,
mark : PerformanceMark ,
}
2021-02-04 13:53:02 -05:00
// These are implementations of custom commands supported by the LSP
2021-01-26 04:55:04 -05:00
impl Inner {
2022-12-19 20:22:17 -05:00
fn prepare_cache (
& self ,
2024-01-30 12:17:34 -05:00
specifiers : Vec < ModuleSpecifier > ,
referrer : ModuleSpecifier ,
2024-02-28 22:54:16 -05:00
force_global_cache : bool ,
2023-02-22 20:16:16 -05:00
) -> Result < Option < PrepareCacheResult > , AnyError > {
2024-01-30 12:17:34 -05:00
let mark = self
. performance
. mark_with_args ( " lsp.cache " , ( & specifiers , & referrer ) ) ;
2024-03-26 11:52:20 -04:00
let config_data = self . config . tree . data_for_specifier ( & referrer ) ;
2024-01-30 12:17:34 -05:00
let roots = if ! specifiers . is_empty ( ) {
specifiers
2021-06-21 17:18:32 -04:00
} else {
2024-03-26 11:52:20 -04:00
vec! [ referrer . clone ( ) ]
2021-10-10 17:26:22 -04:00
} ;
2023-05-22 21:28:36 -04:00
let workspace_settings = self . config . workspace_settings ( ) ;
2022-07-01 11:50:16 -04:00
let mut cli_options = CliOptions ::new (
Flags {
2023-08-01 20:49:09 -04:00
cache_path : self . maybe_global_cache_path . clone ( ) ,
2023-05-22 21:28:36 -04:00
ca_stores : workspace_settings . certificate_stores . clone ( ) ,
ca_data : workspace_settings . tls_certificate . clone ( ) . map ( CaData ::File ) ,
unsafely_ignore_certificate_errors : workspace_settings
. unsafely_ignore_certificate_errors
. clone ( ) ,
2023-07-10 17:45:09 -04:00
node_modules_dir : Some (
2024-03-26 11:52:20 -04:00
config_data
. as_ref ( )
. and_then ( | d | d . node_modules_dir . as_ref ( ) )
. is_some ( ) ,
2023-07-10 17:45:09 -04:00
) ,
2023-05-22 21:28:36 -04:00
// bit of a hack to force the lsp to cache the @types/node package
type_check_mode : crate ::args ::TypeCheckMode ::Local ,
2022-07-01 11:50:16 -04:00
.. Default ::default ( )
} ,
2024-01-18 15:57:30 -05:00
self . initial_cwd . clone ( ) ,
2024-03-26 11:52:20 -04:00
config_data
. as_ref ( )
. and_then ( | d | d . config_file . as_deref ( ) . cloned ( ) ) ,
config_data . as_ref ( ) . and_then ( | d | d . lockfile . clone ( ) ) ,
config_data
. as_ref ( )
. and_then ( | d | d . package_json . as_deref ( ) . cloned ( ) ) ,
2024-02-28 22:54:16 -05:00
force_global_cache ,
2023-02-22 20:16:16 -05:00
) ? ;
2024-03-01 21:13:04 -05:00
// don't use the specifier in self.maybe_import_map because it's not
// necessarily an import map specifier (could be a deno.json)
2024-03-26 11:52:20 -04:00
if let Some ( import_map ) = self . resolve_import_map_specifier ( & referrer ) ? {
2024-03-01 21:13:04 -05:00
cli_options . set_import_map_specifier ( Some ( import_map ) ) ;
}
2022-07-01 11:50:16 -04:00
2023-03-29 16:25:48 -04:00
let open_docs = self . documents . documents ( DocumentsFilter ::OpenDiagnosable ) ;
2022-12-19 20:22:17 -05:00
Ok ( Some ( PrepareCacheResult {
cli_options ,
open_docs ,
roots ,
mark ,
} ) )
}
2021-10-10 17:26:22 -04:00
2022-12-19 20:22:17 -05:00
async fn post_cache ( & self , mark : PerformanceMark ) {
2022-06-27 13:43:43 -04:00
// Now that we have dependencies loaded, we need to re-analyze all the files.
// For that we're invalidating all the existing diagnostics and restarting
// the language server for TypeScript (as it might hold to some stale
// documents).
self . diagnostics_server . invalidate_all ( ) ;
2023-05-12 19:07:40 -04:00
self . ts_server . restart ( self . snapshot ( ) ) . await ;
2023-01-28 10:18:32 -05:00
self . send_diagnostics_update ( ) ;
self . send_testing_update ( ) ;
self . performance . measure ( mark ) ;
}
2021-02-12 05:08:36 -05:00
fn get_performance ( & self ) -> Value {
2021-01-26 19:32:49 -05:00
let averages = self . performance . averages ( ) ;
2021-02-12 05:08:36 -05:00
json! ( { " averages " : averages } )
2021-01-26 19:32:49 -05:00
}
2023-10-12 11:07:27 -04:00
fn task_definitions ( & self ) -> LspResult < Vec < TaskDefinition > > {
let mut result = vec! [ ] ;
2024-03-26 11:52:20 -04:00
for config_file in self . config . tree . config_files ( ) {
2023-10-12 11:07:27 -04:00
if let Some ( tasks ) = json! ( & config_file . json . tasks ) . as_object ( ) {
for ( name , value ) in tasks {
let Some ( command ) = value . as_str ( ) else {
continue ;
} ;
result . push ( TaskDefinition {
name : name . clone ( ) ,
command : command . to_string ( ) ,
source_uri : config_file . specifier . clone ( ) ,
} ) ;
}
} ;
}
2024-03-26 11:52:20 -04:00
for package_json in self . config . tree . package_jsons ( ) {
2023-10-12 11:07:27 -04:00
if let Some ( scripts ) = & package_json . scripts {
for ( name , command ) in scripts {
result . push ( TaskDefinition {
name : name . clone ( ) ,
command : command . clone ( ) ,
source_uri : package_json . specifier ( ) ,
} ) ;
}
}
}
result . sort_by_key ( | d | d . name . clone ( ) ) ;
Ok ( result )
2022-03-28 20:27:43 -04:00
}
2022-10-15 22:39:43 -04:00
async fn inlay_hint (
& self ,
params : InlayHintParams ,
) -> LspResult < Option < Vec < InlayHint > > > {
2023-03-15 10:34:23 -04:00
let specifier = self
. url_map
. normalize_url ( & params . text_document . uri , LspUrlKind ::File ) ;
2022-10-15 22:39:43 -04:00
if ! self . is_diagnosable ( & specifier )
| | ! self . config . specifier_enabled ( & specifier )
2023-10-24 16:27:27 -04:00
| | ! self . config . enabled_inlay_hints_for_specifier ( & specifier )
2022-10-15 22:39:43 -04:00
{
return Ok ( None ) ;
}
2023-11-30 21:54:59 -05:00
let mark = self . performance . mark_with_args ( " lsp.inlay_hint " , & params ) ;
2022-10-15 22:39:43 -04:00
let asset_or_doc = self . get_asset_or_document ( & specifier ) ? ;
let line_index = asset_or_doc . line_index ( ) ;
2023-05-12 19:07:40 -04:00
let text_span =
tsc ::TextSpan ::from_range ( & params . range , line_index . clone ( ) ) . map_err (
| err | {
2024-03-01 21:25:38 -05:00
error! ( " Failed to convert range to text_span: {:#} " , err ) ;
2023-05-12 19:07:40 -04:00
LspError ::internal_error ( )
} ,
) ? ;
let maybe_inlay_hints = self
2022-10-15 22:39:43 -04:00
. ts_server
2023-05-12 19:07:40 -04:00
. provide_inlay_hints (
self . snapshot ( ) ,
2023-09-21 01:46:39 -04:00
specifier . clone ( ) ,
2023-05-12 19:07:40 -04:00
text_span ,
2023-09-25 22:54:07 -04:00
tsc ::UserPreferences ::from_config_for_specifier (
& self . config ,
& specifier ,
) ,
2023-05-12 19:07:40 -04:00
)
. await ? ;
2022-10-15 22:39:43 -04:00
let maybe_inlay_hints = maybe_inlay_hints . map ( | hints | {
hints
. iter ( )
. map ( | hint | hint . to_lsp ( line_index . clone ( ) ) )
. collect ( )
} ) ;
self . performance . measure ( mark ) ;
Ok ( maybe_inlay_hints )
}
2021-04-08 21:27:27 -04:00
async fn reload_import_registries ( & mut self ) -> LspResult < Option < Value > > {
2022-11-28 17:28:54 -05:00
remove_dir_all_if_exists ( & self . module_registries_location )
2021-04-08 21:27:27 -04:00
. await
. map_err ( | err | {
2024-03-01 21:25:38 -05:00
error! ( " Unable to remove registries cache: {:#} " , err ) ;
2021-04-08 21:27:27 -04:00
LspError ::internal_error ( )
} ) ? ;
self . update_registries ( ) . await . map_err ( | err | {
2024-03-01 21:25:38 -05:00
error! ( " Unable to update registries: {:#} " , err ) ;
2021-04-08 21:27:27 -04:00
LspError ::internal_error ( )
} ) ? ;
Ok ( Some ( json! ( true ) ) )
}
2022-04-25 11:23:24 -04:00
fn virtual_text_document (
2022-12-19 20:22:17 -05:00
& self ,
2021-06-01 07:53:08 -04:00
params : lsp_custom ::VirtualTextDocumentParams ,
2020-12-29 23:17:17 -05:00
) -> LspResult < Option < String > > {
2021-05-11 00:54:10 -04:00
let mark = self
. performance
2023-11-30 21:54:59 -05:00
. mark_with_args ( " lsp.virtual_text_document " , & params ) ;
2023-03-15 10:34:23 -04:00
let specifier = self
. url_map
. normalize_url ( & params . text_document . uri , LspUrlKind ::File ) ;
2023-09-26 20:48:34 -04:00
let contents = if specifier . scheme ( ) = = " deno "
& & specifier . path ( ) = = " /status.md "
{
2021-01-26 19:32:49 -05:00
let mut contents = String ::new ( ) ;
2021-11-12 11:42:04 -05:00
let mut documents_specifiers = self
. documents
2023-03-29 16:25:48 -04:00
. documents ( DocumentsFilter ::All )
2021-11-12 11:42:04 -05:00
. into_iter ( )
. map ( | d | d . specifier ( ) . clone ( ) )
. collect ::< Vec < _ > > ( ) ;
2021-04-19 17:10:43 -04:00
documents_specifiers . sort ( ) ;
let measures = self . performance . to_vec ( ) ;
2023-05-11 17:17:14 -04:00
let workspace_settings = self . config . workspace_settings ( ) ;
2021-01-26 19:32:49 -05:00
2022-07-01 09:28:06 -04:00
write! (
contents ,
2020-12-21 08:44:26 -05:00
r #" # Deno Language Server Status
2021-01-04 16:52:20 -05:00
2021-07-20 21:50:43 -04:00
## Workspace Settings
` ` ` json
{ }
` ` `
## Workspace Details
2021-04-19 17:10:43 -04:00
- < details > < summary > Documents in memory : { } < / summary >
- { }
< / details >
- < details > < summary > Performance measures : { } < / summary >
- { }
< / details >
2021-01-26 19:32:49 -05:00
" #,
2021-07-20 21:50:43 -04:00
serde_json ::to_string_pretty ( & workspace_settings ) . unwrap ( ) ,
2021-10-28 19:56:01 -04:00
documents_specifiers . len ( ) ,
2021-04-19 17:10:43 -04:00
documents_specifiers
. into_iter ( )
. map ( | s | s . to_string ( ) )
. collect ::< Vec < String > > ( )
. join ( " \n - " ) ,
measures . len ( ) ,
measures
. iter ( )
. map ( | m | m . to_string ( ) )
. collect ::< Vec < String > > ( )
. join ( " \n - " )
2022-07-01 09:28:06 -04:00
)
. unwrap ( ) ;
2023-12-12 02:18:10 -05:00
2021-04-19 17:10:43 -04:00
contents
2023-12-12 02:18:10 -05:00
. push_str ( " \n ## Performance (last 3 000 entries) \n \n |Name|Count|Duration| \n |---|---|---| \n " ) ;
2023-12-11 11:33:56 -05:00
let mut averages = self . performance . averages_as_f64 ( ) ;
averages . sort_by ( | a , b | a . 0. cmp ( & b . 0 ) ) ;
for ( name , count , average_duration ) in averages {
2023-12-12 02:18:10 -05:00
writeln! ( contents , " |{}|{}|{}ms| " , name , count , average_duration )
2023-12-11 11:33:56 -05:00
. unwrap ( ) ;
2021-01-26 19:32:49 -05:00
}
2023-12-12 02:18:10 -05:00
contents . push_str (
" \n ## Performance (total) \n \n |Name|Count|Duration| \n |---|---|---| \n " ,
) ;
let mut measurements_by_type = self . performance . measurements_by_type ( ) ;
measurements_by_type . sort_by ( | a , b | a . 0. cmp ( & b . 0 ) ) ;
for ( name , total_count , total_duration ) in measurements_by_type {
writeln! (
contents ,
" |{}|{}|{:.3}ms| " ,
name , total_count , total_duration
)
. unwrap ( ) ;
}
2021-01-26 19:32:49 -05:00
Some ( contents )
2020-12-21 08:44:26 -05:00
} else {
2022-04-25 11:23:24 -04:00
let asset_or_doc = self . get_maybe_asset_or_document ( & specifier ) ;
2021-11-12 11:42:04 -05:00
if let Some ( asset_or_doc ) = asset_or_doc {
Some ( asset_or_doc . text ( ) . to_string ( ) )
} else {
error! ( " The source was not found: {} " , specifier ) ;
None
2020-12-21 08:44:26 -05:00
}
} ;
2021-01-26 19:32:49 -05:00
self . performance . measure ( mark ) ;
2020-12-21 08:44:26 -05:00
Ok ( contents )
}
}
2024-03-21 00:29:52 -04:00
#[ cfg(test) ]
mod tests {
use super ::* ;
use pretty_assertions ::assert_eq ;
use test_util ::TempDir ;
#[ test ]
fn test_walk_workspace ( ) {
let temp_dir = TempDir ::new ( ) ;
temp_dir . create_dir_all ( " root1/node_modules/ " ) ;
temp_dir . write ( " root1/node_modules/mod.ts " , " " ) ; // no, node_modules
temp_dir . create_dir_all ( " root1/sub_dir " ) ;
temp_dir . create_dir_all ( " root1/target " ) ;
temp_dir . create_dir_all ( " root1/node_modules " ) ;
temp_dir . create_dir_all ( " root1/.git " ) ;
temp_dir . create_dir_all ( " root1/file.ts " ) ; // no, directory
temp_dir . write ( " root1/mod0.ts " , " " ) ; // yes
temp_dir . write ( " root1/mod1.js " , " " ) ; // yes
temp_dir . write ( " root1/mod2.tsx " , " " ) ; // yes
temp_dir . write ( " root1/mod3.d.ts " , " " ) ; // yes
temp_dir . write ( " root1/mod4.jsx " , " " ) ; // yes
temp_dir . write ( " root1/mod5.mjs " , " " ) ; // yes
temp_dir . write ( " root1/mod6.mts " , " " ) ; // yes
temp_dir . write ( " root1/mod7.d.mts " , " " ) ; // yes
temp_dir . write ( " root1/mod8.json " , " " ) ; // yes
temp_dir . write ( " root1/mod9.jsonc " , " " ) ; // yes
temp_dir . write ( " root1/other.txt " , " " ) ; // no, text file
temp_dir . write ( " root1/other.wasm " , " " ) ; // no, don't load wasm
temp_dir . write ( " root1/Cargo.toml " , " " ) ; // no
temp_dir . write ( " root1/sub_dir/mod.ts " , " " ) ; // yes
temp_dir . write ( " root1/sub_dir/data.min.ts " , " " ) ; // no, minified file
temp_dir . write ( " root1/.git/main.ts " , " " ) ; // no, .git folder
temp_dir . write ( " root1/node_modules/main.ts " , " " ) ; // no, because it's in a node_modules folder
temp_dir . write ( " root1/target/main.ts " , " " ) ; // no, because there is a Cargo.toml in the root directory
temp_dir . create_dir_all ( " root2/folder " ) ;
temp_dir . create_dir_all ( " root2/sub_folder " ) ;
temp_dir . write ( " root2/file1.ts " , " " ) ; // yes, enabled
temp_dir . write ( " root2/file2.ts " , " " ) ; // no, not enabled
temp_dir . write ( " root2/folder/main.ts " , " " ) ; // yes, enabled
temp_dir . write ( " root2/folder/other.ts " , " " ) ; // no, disabled
temp_dir . write ( " root2/sub_folder/a.js " , " " ) ; // no, not enabled
temp_dir . write ( " root2/sub_folder/b.ts " , " " ) ; // no, not enabled
temp_dir . write ( " root2/sub_folder/c.js " , " " ) ; // no, not enabled
temp_dir . create_dir_all ( " root3/ " ) ;
temp_dir . write ( " root3/mod.ts " , " " ) ; // no, not enabled
let mut config = Config ::new_with_roots ( vec! [
temp_dir . uri ( ) . join ( " root1/ " ) . unwrap ( ) ,
temp_dir . uri ( ) . join ( " root2/ " ) . unwrap ( ) ,
temp_dir . uri ( ) . join ( " root3/ " ) . unwrap ( ) ,
] ) ;
config . set_workspace_settings (
Default ::default ( ) ,
vec! [
(
temp_dir . uri ( ) . join ( " root1/ " ) . unwrap ( ) ,
WorkspaceSettings {
enable : Some ( true ) ,
.. Default ::default ( )
} ,
) ,
(
temp_dir . uri ( ) . join ( " root2/ " ) . unwrap ( ) ,
WorkspaceSettings {
enable : Some ( true ) ,
enable_paths : Some ( vec! [
" file1.ts " . to_string ( ) ,
" folder " . to_string ( ) ,
] ) ,
disable_paths : vec ! [ " folder/other.ts " . to_string ( ) ] ,
.. Default ::default ( )
} ,
) ,
(
temp_dir . uri ( ) . join ( " root3/ " ) . unwrap ( ) ,
WorkspaceSettings {
enable : Some ( false ) ,
.. Default ::default ( )
} ,
) ,
] ,
) ;
let ( workspace_files , hit_limit ) = Inner ::walk_workspace ( & config ) ;
assert! ( ! hit_limit ) ;
assert_eq! (
json! ( workspace_files ) ,
json! ( [
temp_dir . uri ( ) . join ( " root1/mod0.ts " ) . unwrap ( ) ,
temp_dir . uri ( ) . join ( " root1/mod1.js " ) . unwrap ( ) ,
temp_dir . uri ( ) . join ( " root1/mod2.tsx " ) . unwrap ( ) ,
temp_dir . uri ( ) . join ( " root1/mod3.d.ts " ) . unwrap ( ) ,
temp_dir . uri ( ) . join ( " root1/mod4.jsx " ) . unwrap ( ) ,
temp_dir . uri ( ) . join ( " root1/mod5.mjs " ) . unwrap ( ) ,
temp_dir . uri ( ) . join ( " root1/mod6.mts " ) . unwrap ( ) ,
temp_dir . uri ( ) . join ( " root1/mod7.d.mts " ) . unwrap ( ) ,
temp_dir . uri ( ) . join ( " root1/mod8.json " ) . unwrap ( ) ,
temp_dir . uri ( ) . join ( " root1/mod9.jsonc " ) . unwrap ( ) ,
temp_dir . uri ( ) . join ( " root1/sub_dir/mod.ts " ) . unwrap ( ) ,
temp_dir . uri ( ) . join ( " root2/file1.ts " ) . unwrap ( ) ,
temp_dir . uri ( ) . join ( " root2/folder/main.ts " ) . unwrap ( ) ,
] )
) ;
}
}