2022-01-07 22:09:52 -05:00
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
2020-12-21 08:44:26 -05:00
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 ;
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 ;
use deno_core ::ModuleSpecifier ;
2021-09-10 21:38:24 -04:00
use import_map ::ImportMap ;
2021-03-26 12:34:25 -04:00
use log ::error ;
use log ::warn ;
2021-02-04 13:53:02 -05:00
use serde_json ::from_value ;
2020-12-21 08:44:26 -05:00
use std ::env ;
use std ::path ::PathBuf ;
use std ::sync ::Arc ;
use tokio ::fs ;
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 ;
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 ;
2021-05-09 21:16:04 -04:00
use super ::config ::SETTINGS_SECTION ;
2020-12-21 08:44:26 -05:00
use super ::diagnostics ;
2022-01-17 17:09:43 -05:00
use super ::diagnostics ::DiagnosticsServer ;
2021-10-28 19:56:01 -04:00
use super ::documents ::to_hover_text ;
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 ;
2021-06-02 06:29:58 -04:00
use super ::documents ::LanguageId ;
2022-01-19 16:05:19 -05:00
use super ::logging ::lsp_log ;
2021-06-01 07:53:08 -04:00
use super ::lsp_custom ;
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 ;
2021-08-05 21:46:32 -04:00
use super ::refactor ;
2022-01-23 19:27:52 -05:00
use super ::registries ::ModuleRegistry ;
use super ::registries ::ModuleRegistryOptions ;
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 ;
2020-12-21 08:44:26 -05:00
use super ::tsc ::TsServer ;
2021-02-17 23:37:05 -05:00
use super ::urls ;
2021-05-18 02:35:46 -04:00
use crate ::config_file ::ConfigFile ;
2021-10-11 18:02:33 -04:00
use crate ::config_file ::FmtConfig ;
use crate ::config_file ::LintConfig ;
2021-05-18 02:35:46 -04:00
use crate ::config_file ::TsConfig ;
use crate ::deno_dir ;
2021-09-13 00:19:23 -04:00
use crate ::file_fetcher ::get_source_from_data_url ;
2021-06-25 21:44:27 -04:00
use crate ::fs_util ;
2022-01-13 18:17:56 -05:00
use crate ::proc_state ::import_map_from_text ;
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 ;
2020-12-21 08:44:26 -05:00
2021-04-08 21:27:27 -04:00
pub const REGISTRIES_PATH : & str = " registries " ;
2021-10-28 19:56:01 -04:00
const CACHE_PATH : & str = " deps " ;
2021-04-08 21:27:27 -04:00
2020-12-21 08:44:26 -05:00
#[ derive(Debug, Clone) ]
2021-01-26 04:55:04 -05:00
pub struct LanguageServer ( Arc < tokio ::sync ::Mutex < Inner > > ) ;
2020-12-21 08:44:26 -05:00
2022-01-19 17:10:14 -05:00
/// Snapshot of the state used by TSC.
2021-11-18 13:50:24 -05:00
#[ derive(Debug, Default) ]
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 ,
2021-10-28 19:56:01 -04:00
pub documents : Documents ,
2022-01-19 17:10:14 -05:00
pub root_uri : Option < Url > ,
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 ,
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 ,
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.
maybe_cache_path : Option < PathBuf > ,
2021-10-10 17:26:22 -04:00
/// A lazily created "server" for handling cache requests.
2022-02-01 21:04:26 -05:00
maybe_cache_server : Option < cache ::CacheServer > ,
2021-06-21 17:18:32 -04:00
/// An optional configuration file which has been specified in the client
/// options.
maybe_config_file : Option < ConfigFile > ,
2021-10-11 18:02:33 -04:00
/// An optional configuration for formatter which has been taken from specified config file.
maybe_fmt_config : Option < FmtConfig > ,
2021-02-04 13:53:02 -05:00
/// An optional import map which is used to resolve modules.
2022-03-23 09:54:22 -04:00
pub maybe_import_map : Option < Arc < ImportMap > > ,
2021-02-04 13:53:02 -05:00
/// The URL for the import map which is used to determine relative imports.
2021-01-26 04:55:04 -05:00
maybe_import_map_uri : Option < Url > ,
2022-03-29 18:59:27 -04:00
/// An optional configuration for linter which has been taken from specified config file.
pub maybe_lint_config : Option < LintConfig > ,
/// A lazily create "server" for handling test run requests.
maybe_testing_server : Option < testing ::TestServer > ,
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.
2022-03-23 09:54:22 -04:00
pub url_map : urls ::LspUrlMap ,
2020-12-21 08:44:26 -05:00
}
impl LanguageServer {
pub fn new ( client : Client ) -> Self {
2021-01-26 04:55:04 -05:00
Self ( Arc ::new ( tokio ::sync ::Mutex ::new ( Inner ::new ( client ) ) ) )
}
2022-04-03 00:17:30 -04:00
pub async fn cache_request (
& self ,
params : Option < Value > ,
) -> LspResult < Option < Value > > {
match params . map ( serde_json ::from_value ) {
Some ( Ok ( params ) ) = > self . 0. lock ( ) . await . cache ( params ) . await ,
Some ( Err ( err ) ) = > Err ( LspError ::invalid_params ( err . to_string ( ) ) ) ,
None = > Err ( LspError ::invalid_params ( " Missing parameters " ) ) ,
}
}
pub async fn performance_request ( & self ) -> LspResult < Option < Value > > {
Ok ( Some ( self . 0. lock ( ) . await . get_performance ( ) ) )
}
pub async fn reload_import_registries_request (
& self ,
) -> LspResult < Option < Value > > {
self . 0. lock ( ) . await . reload_import_registries ( ) . await
}
pub async fn task_request ( & self ) -> LspResult < Option < Value > > {
self . 0. lock ( ) . await . get_tasks ( )
}
pub async fn test_run_request (
& self ,
params : Option < Value > ,
) -> LspResult < Option < Value > > {
let inner = self . 0. lock ( ) . await ;
if let Some ( testing_server ) = & inner . maybe_testing_server {
match params . map ( serde_json ::from_value ) {
Some ( Ok ( params ) ) = > testing_server
. run_request ( params , inner . config . get_workspace_settings ( ) ) ,
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 > > {
if let Some ( testing_server ) = & self . 0. lock ( ) . await . maybe_testing_server {
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 (
self . 0. lock ( ) . await . virtual_text_document ( params ) . await ? ,
)
. map_err ( | err | {
error! (
" Failed to serialize virtual_text_document response: {} " ,
err
) ;
LspError ::internal_error ( )
} ) ? ,
) ) ,
Some ( Err ( err ) ) = > Err ( LspError ::invalid_params ( err . to_string ( ) ) ) ,
None = > Err ( LspError ::invalid_params ( " Missing parameters " ) ) ,
}
}
2021-01-26 04:55:04 -05:00
}
impl Inner {
fn new ( client : Client ) -> Self {
2020-12-21 08:44:26 -05:00
let maybe_custom_root = env ::var ( " DENO_DIR " ) . map ( String ::into ) . ok ( ) ;
let dir = deno_dir ::DenoDir ::new ( maybe_custom_root )
. expect ( " could not access DENO_DIR " ) ;
2021-04-08 21:27:27 -04:00
let module_registries_location = dir . root . join ( REGISTRIES_PATH ) ;
2022-01-23 19:27:52 -05:00
let module_registries = ModuleRegistry ::new (
& module_registries_location ,
ModuleRegistryOptions ::default ( ) ,
)
. expect ( " could not create module registries " ) ;
2021-10-28 19:56:01 -04:00
let location = dir . root . join ( CACHE_PATH ) ;
let documents = Documents ::new ( & location ) ;
2022-02-01 21:04:26 -05:00
let cache_metadata = cache ::CacheMetadata ::new ( & location ) ;
2022-01-17 17:09:43 -05:00
let performance = Arc ::new ( Performance ::default ( ) ) ;
let ts_server = Arc ::new ( TsServer ::new ( performance . clone ( ) ) ) ;
2022-01-25 10:30:38 -05:00
let config = Config ::new ( ) ;
2022-01-17 17:09:43 -05:00
let diagnostics_server = DiagnosticsServer ::new (
client . clone ( ) ,
performance . clone ( ) ,
ts_server . clone ( ) ,
) ;
2022-01-18 16:28:47 -05:00
let assets = Assets ::new ( ts_server . clone ( ) ) ;
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 ,
2022-01-17 17:09:43 -05:00
diagnostics_server ,
2021-10-28 19:56:01 -04:00
documents ,
2021-07-27 17:25:09 -04:00
maybe_cache_path : None ,
2021-10-10 17:26:22 -04:00
maybe_cache_server : None ,
2021-07-27 17:25:09 -04:00
maybe_config_file : None ,
maybe_import_map : None ,
maybe_import_map_uri : None ,
2022-03-29 18:59:27 -04:00
maybe_lint_config : None ,
maybe_fmt_config : None ,
maybe_testing_server : None ,
2021-04-08 21:27:27 -04:00
module_registries ,
module_registries_location ,
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 ( ) ,
2020-12-21 08:44:26 -05:00
}
}
2021-11-12 11:42:04 -05:00
/// Searches assets and open documents which might be performed asynchronously,
/// hydrating in memory caches for subsequent requests.
2022-03-23 09:54:22 -04:00
pub async 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 > {
self
. get_maybe_asset_or_document ( specifier )
. await ?
. map_or_else (
| | {
Err ( LspError ::invalid_params ( format! (
" Unable to find asset or document for: {} " ,
specifier
) ) )
} ,
Ok ,
)
2021-01-22 05:03:16 -05:00
}
2021-11-12 11:42:04 -05:00
/// Searches assets and open documents which might be performed asynchronously,
/// hydrating in memory caches for subsequent requests.
2022-03-23 09:54:22 -04:00
pub async fn get_maybe_asset_or_document (
2022-01-18 16:28:47 -05:00
& self ,
2021-01-22 05:03:16 -05:00
specifier : & ModuleSpecifier ,
2021-11-12 11:42:04 -05:00
) -> LspResult < Option < AssetOrDocument > > {
2021-05-11 00:54:10 -04:00
let mark = self . performance . mark (
2021-11-12 11:42:04 -05:00
" get_maybe_asset_or_document " ,
2021-05-11 00:54:10 -04:00
Some ( json! ( { " specifier " : specifier } ) ) ,
) ;
2021-11-12 11:42:04 -05:00
let result = if specifier . scheme ( ) = = " asset " {
2022-01-18 16:28:47 -05:00
self
. assets
. get ( specifier , | | self . snapshot ( ) )
. await ?
. map ( AssetOrDocument ::Asset )
2021-01-22 05:03:16 -05:00
} else {
2021-11-12 11:42:04 -05:00
self . documents . get ( specifier ) . map ( AssetOrDocument ::Document )
2021-01-26 19:32:49 -05:00
} ;
self . performance . measure ( mark ) ;
2021-11-12 11:42:04 -05:00
Ok ( result )
2020-12-21 08:44:26 -05:00
}
2021-11-12 11:42:04 -05:00
/// Only searches already cached assets and documents. If
/// the asset or document cannot be found an error is returned.
2022-03-23 09:54:22 -04:00
pub fn get_cached_asset_or_document (
2021-06-07 07:38:07 -04:00
& self ,
specifier : & ModuleSpecifier ,
2021-11-12 11:42:04 -05:00
) -> LspResult < AssetOrDocument > {
self
. get_maybe_cached_asset_or_document ( specifier )
. map_or_else (
| | {
Err ( LspError ::invalid_params ( format! (
" An unexpected specifier ({}) was provided. " ,
specifier
) ) )
} ,
Ok ,
)
}
/// Only searches already cached assets and documents. If
/// the asset or document cannot be found, `None` is returned.
2022-03-23 09:54:22 -04:00
pub fn get_maybe_cached_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 " {
self
. assets
2022-01-18 16:28:47 -05:00
. get_cached ( specifier )
2021-11-12 11:42:04 -05:00
. flatten ( )
2022-01-19 17:10:14 -05:00
. 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 (
2021-01-31 22:30:41 -05:00
& mut self ,
specifier : & ModuleSpecifier ,
2021-10-28 19:56:01 -04:00
) -> Result < Arc < tsc ::NavigationTree > , AnyError > {
2021-05-11 00:54:10 -04:00
let mark = self . performance . mark (
" get_navigation_tree " ,
Some ( json! ( { " specifier " : specifier } ) ) ,
) ;
2021-11-12 11:42:04 -05:00
let asset_or_doc = self . get_cached_asset_or_document ( specifier ) ? ;
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
. request (
2022-01-19 17:10:14 -05:00
self . snapshot ( ) ,
2021-11-12 11:42:04 -05:00
tsc ::RequestMethod ::GetNavigationTree ( specifier . clone ( ) ) ,
)
. 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-09-13 14:19:10 -04:00
/// Returns a tuple with parsed `ConfigFile` and `Url` pointing to that file.
/// If there's no config file specified in settings returns `None`.
2022-01-17 14:45:05 -05:00
fn get_config_file ( & self ) -> Result < Option < ConfigFile > , AnyError > {
2021-09-13 14:19:10 -04:00
let workspace_settings = self . config . get_workspace_settings ( ) ;
let maybe_config = workspace_settings . config ;
if let Some ( config_str ) = & maybe_config {
2021-06-24 08:41:04 -04:00
if ! config_str . is_empty ( ) {
2022-03-20 21:33:37 -04:00
lsp_log! ( " Setting Deno configuration from: \" {} \" " , config_str ) ;
2021-06-24 08:41:04 -04:00
let config_url = if let Ok ( url ) = Url ::from_file_path ( config_str ) {
Ok ( url )
2022-03-20 21:33:37 -04:00
} else if let Some ( root_uri ) = & self . config . root_uri {
2021-11-24 15:14:19 -05:00
root_uri . join ( config_str ) . map_err ( | _ | {
2021-06-24 08:41:04 -04:00
anyhow! ( " Bad file path for configuration file: \" {} \" " , config_str )
} )
} else {
Err ( anyhow! (
" The path to the configuration file ( \" {} \" ) is not resolvable. " ,
config_str
) )
} ? ;
2021-12-15 13:23:43 -05:00
lsp_log! ( " Resolved configuration file: \" {} \" " , config_url ) ;
2021-06-24 08:41:04 -04:00
2021-11-24 15:14:19 -05:00
let config_file = ConfigFile ::from_specifier ( & config_url ) ? ;
2022-01-17 14:45:05 -05:00
return Ok ( Some ( config_file ) ) ;
2021-06-24 08:41:04 -04:00
}
}
2021-09-13 14:19:10 -04:00
2022-01-17 20:10:17 -05:00
// Auto-discover config
// It is possible that root_uri is not set, for example when having a single
// file open and not a workspace. In those situations we can't
// automatically discover the configuration
2022-03-20 21:33:37 -04:00
if let Some ( root_uri ) = & self . config . root_uri {
2022-02-05 17:41:15 -05:00
let root_path = fs_util ::specifier_to_file_path ( root_uri ) ? ;
2022-01-17 20:10:17 -05:00
let mut checked = std ::collections ::HashSet ::new ( ) ;
let maybe_config =
crate ::config_file ::discover_from ( & root_path , & mut checked ) ? ;
Ok ( maybe_config . map ( | c | {
lsp_log! ( " Auto-resolved configuration file: \" {} \" " , c . specifier ) ;
c
} ) )
} else {
Ok ( None )
}
2021-09-13 14:19:10 -04:00
}
2021-10-28 19:56:01 -04:00
fn is_diagnosable ( & self , specifier : & ModuleSpecifier ) -> bool {
if specifier . scheme ( ) = = " asset " {
matches! (
MediaType ::from ( specifier ) ,
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
}
}
2021-09-13 14:19:10 -04:00
fn merge_user_tsconfig (
2022-01-18 16:28:47 -05:00
& self ,
2021-09-13 14:19:10 -04:00
tsconfig : & mut TsConfig ,
) -> Result < ( ) , AnyError > {
2021-10-11 18:02:33 -04:00
if let Some ( config_file ) = self . maybe_config_file . as_ref ( ) {
2021-09-13 14:19:10 -04:00
let ( value , maybe_ignored_options ) = config_file . to_compiler_options ( ) ? ;
tsconfig . merge ( & value ) ;
if let Some ( ignored_options ) = maybe_ignored_options {
// TODO(@kitsonk) turn these into diagnostics that can be sent to the
// client
warn! ( " {} " , ignored_options ) ;
}
}
2021-06-24 08:41:04 -04:00
Ok ( ( ) )
}
2022-03-23 09:54:22 -04:00
pub fn snapshot ( & self ) -> Arc < StateSnapshot > {
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 ( ) ,
2021-01-26 04:55:04 -05:00
documents : self . documents . clone ( ) ,
2022-03-20 21:33:37 -04:00
root_uri : self . config . root_uri . clone ( ) ,
2022-01-19 17:10:14 -05:00
} )
2020-12-21 08:44:26 -05:00
}
2021-07-27 17:25:09 -04:00
pub fn update_cache ( & mut self ) -> Result < ( ) , AnyError > {
let mark = self . performance . mark ( " update_cache " , None ::< ( ) > ) ;
self . performance . measure ( mark ) ;
2021-10-10 17:26:22 -04:00
self . maybe_cache_server = None ;
2022-01-19 17:10:14 -05:00
let maybe_cache = self . config . get_workspace_settings ( ) . cache ;
2021-07-27 17:25:09 -04:00
let maybe_cache_path = if let Some ( cache_str ) = & maybe_cache {
2021-12-15 13:23:43 -05:00
lsp_log! ( " Setting 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 )
2022-03-20 21:33:37 -04:00
} else if let Some ( root_uri ) = & self . config . root_uri {
2021-11-24 15:14:19 -05:00
let root_path = fs_util ::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
) )
} ? ;
2021-11-24 15:14:19 -05:00
let cache_path = fs_util ::specifier_to_file_path ( & cache_url ) ? ;
2021-12-15 13:23:43 -05:00
lsp_log! (
2021-07-27 17:25:09 -04:00
" Resolved cache path: \" {} \" " ,
cache_path . to_string_lossy ( )
) ;
Some ( cache_path )
} else {
None
} ;
if self . maybe_cache_path ! = maybe_cache_path {
let maybe_custom_root = maybe_cache_path
. clone ( )
. or_else ( | | env ::var ( " DENO_DIR " ) . map ( String ::into ) . ok ( ) ) ;
2022-01-23 19:27:52 -05:00
let dir = deno_dir ::DenoDir ::new ( maybe_custom_root ) ? ;
2021-07-27 17:25:09 -04:00
let module_registries_location = dir . root . join ( REGISTRIES_PATH ) ;
2022-01-23 19:27:52 -05:00
let workspace_settings = self . config . get_workspace_settings ( ) ;
let maybe_root_path = self
2022-03-20 21:33:37 -04:00
. config
2022-01-23 19:27:52 -05:00
. root_uri
. as_ref ( )
. and_then ( | uri | fs_util ::specifier_to_file_path ( uri ) . ok ( ) ) ;
self . module_registries = ModuleRegistry ::new (
& module_registries_location ,
ModuleRegistryOptions {
maybe_root_path ,
maybe_ca_stores : workspace_settings . certificate_stores . clone ( ) ,
maybe_ca_file : workspace_settings . tls_certificate . clone ( ) ,
unsafely_ignore_certificate_errors : workspace_settings
. unsafely_ignore_certificate_errors ,
} ,
) ? ;
2021-07-27 17:25:09 -04:00
self . module_registries_location = module_registries_location ;
2022-02-01 21:04:26 -05:00
let location = dir . root . join ( CACHE_PATH ) ;
self . documents . set_location ( & location ) ;
self . cache_metadata . set_location ( & location ) ;
2021-07-27 17:25:09 -04:00
self . maybe_cache_path = maybe_cache_path ;
}
Ok ( ( ) )
}
2021-01-26 19:32:49 -05:00
pub async fn update_import_map ( & mut self ) -> Result < ( ) , AnyError > {
2021-05-11 00:54:10 -04:00
let mark = self . performance . mark ( " update_import_map " , None ::< ( ) > ) ;
2021-10-10 17:26:22 -04:00
self . maybe_cache_server = None ;
2022-02-22 18:51:14 -05:00
let maybe_import_map_url = if let Some ( import_map_str ) =
self . config . get_workspace_settings ( ) . import_map
{
lsp_log! (
" Setting import map from workspace settings: \" {} \" " ,
import_map_str
) ;
if let Some ( config_file ) = & self . maybe_config_file {
if let Some ( import_map_path ) = config_file . to_import_map_path ( ) {
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 ::from_file_path ( & import_map_str ) {
Some ( url )
2021-09-13 00:19:23 -04:00
} else if import_map_str . starts_with ( " data: " ) {
2022-02-22 18:51:14 -05:00
Some ( Url ::parse ( & import_map_str ) . map_err ( | _ | {
anyhow! ( " Bad data url for import map: {} " , import_map_str )
} ) ? )
2022-03-20 21:33:37 -04:00
} else if let Some ( root_uri ) = & self . config . root_uri {
2021-11-24 15:14:19 -05:00
let root_path = fs_util ::specifier_to_file_path ( root_uri ) ? ;
2022-02-22 18:51:14 -05:00
let import_map_path = root_path . join ( & import_map_str ) ;
Some ( Url ::from_file_path ( import_map_path ) . map_err ( | _ | {
anyhow! ( " Bad file path for import map: {} " , import_map_str )
} ) ? )
2020-12-21 08:44:26 -05:00
} else {
2022-02-22 18:51:14 -05:00
return Err ( anyhow! (
2020-12-22 05:21:18 -05:00
" The path to the import map ( \" {} \" ) is not resolvable. " ,
import_map_str
2022-02-22 18:51:14 -05:00
) ) ;
}
} else if let Some ( config_file ) = & self . maybe_config_file {
if let Some ( import_map_path ) = config_file . to_import_map_path ( ) {
lsp_log! (
" Setting import map from configuration file: \" {} \" " ,
import_map_path
) ;
let specifier =
if let Ok ( config_file_path ) = config_file . specifier . to_file_path ( ) {
let import_map_file_path = config_file_path
. parent ( )
. ok_or_else ( | | {
anyhow! ( " Bad config file specifier: {} " , config_file . specifier )
} ) ?
. join ( & import_map_path ) ;
ModuleSpecifier ::from_file_path ( import_map_file_path ) . unwrap ( )
} else {
deno_core ::resolve_import (
& import_map_path ,
config_file . specifier . as_str ( ) ,
) ?
} ;
Some ( specifier )
} else {
None
}
} else {
None
} ;
if let Some ( import_map_url ) = maybe_import_map_url {
2021-09-13 00:19:23 -04:00
let import_map_json = if import_map_url . scheme ( ) = = " data " {
get_source_from_data_url ( & import_map_url ) ? . 0
} else {
2021-11-24 15:14:19 -05:00
let import_map_path = fs_util ::specifier_to_file_path ( & import_map_url ) ? ;
2021-12-15 13:23:43 -05:00
lsp_log! (
2021-09-13 00:19:23 -04:00
" Resolved import map: \" {} \" " ,
import_map_path . to_string_lossy ( )
) ;
2020-12-22 05:21:18 -05:00
fs ::read_to_string ( import_map_path ) . await . map_err ( | err | {
anyhow! (
" Failed to load the import map at: {}. [{}] " ,
import_map_url ,
err
)
2021-09-13 00:19:23 -04:00
} ) ?
} ;
2022-01-13 18:17:56 -05:00
let import_map = import_map_from_text ( & import_map_url , & import_map_json ) ? ;
2021-01-26 04:55:04 -05:00
self . maybe_import_map_uri = Some ( import_map_url ) ;
2022-01-13 18:17:56 -05:00
self . maybe_import_map = Some ( Arc ::new ( import_map ) ) ;
2020-12-21 08:44:26 -05:00
} else {
2022-02-22 18:51:14 -05:00
self . maybe_import_map_uri = None ;
2021-01-26 04:55:04 -05:00
self . maybe_import_map = None ;
2020-12-22 05:21:18 -05:00
}
2021-01-26 19:32:49 -05:00
self . performance . measure ( mark ) ;
2020-12-22 05:21:18 -05:00
Ok ( ( ) )
}
2021-12-15 13:23:43 -05:00
pub fn update_debug_flag ( & self ) {
2021-05-20 05:56:48 -04:00
let internal_debug = self . config . get_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 > {
2021-05-11 00:54:10 -04:00
let mark = self . performance . mark ( " update_registries " , None ::< ( ) > ) ;
2022-01-23 19:27:52 -05:00
let workspace_settings = self . config . get_workspace_settings ( ) ;
let maybe_root_path = self
2022-03-20 21:33:37 -04:00
. config
2022-01-23 19:27:52 -05:00
. root_uri
. as_ref ( )
. and_then ( | uri | fs_util ::specifier_to_file_path ( uri ) . ok ( ) ) ;
self . module_registries = ModuleRegistry ::new (
& self . module_registries_location ,
ModuleRegistryOptions {
maybe_root_path ,
maybe_ca_stores : workspace_settings . certificate_stores . clone ( ) ,
maybe_ca_file : workspace_settings . tls_certificate . clone ( ) ,
unsafely_ignore_certificate_errors : workspace_settings
. unsafely_ignore_certificate_errors
. clone ( ) ,
} ,
) ? ;
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 {
self . module_registries . disable ( registry ) . await ? ;
}
}
self . performance . measure ( mark ) ;
Ok ( ( ) )
}
2021-10-11 18:02:33 -04:00
fn update_config_file ( & mut self ) -> Result < ( ) , AnyError > {
self . maybe_config_file = None ;
self . maybe_fmt_config = None ;
self . maybe_lint_config = None ;
2022-01-17 14:45:05 -05:00
if let Some ( config_file ) = self . get_config_file ( ) ? {
2021-10-11 18:02:33 -04:00
let lint_config = config_file
. to_lint_config ( )
. map_err ( | err | {
anyhow! ( " Unable to update lint configuration: {:?} " , err )
} ) ?
. unwrap_or_default ( ) ;
let fmt_config = config_file
. to_fmt_config ( )
. map_err ( | err | {
anyhow! ( " Unable to update formatter configuration: {:?} " , err )
} ) ?
. unwrap_or_default ( ) ;
self . maybe_config_file = Some ( config_file ) ;
self . maybe_lint_config = Some ( lint_config ) ;
self . maybe_fmt_config = Some ( fmt_config ) ;
}
Ok ( ( ) )
}
2021-01-26 04:55:04 -05:00
async fn update_tsconfig ( & mut self ) -> Result < ( ) , AnyError > {
2021-05-11 00:54:10 -04:00
let mark = self . performance . mark ( " update_tsconfig " , None ::< ( ) > ) ;
2020-12-22 05:21:18 -05:00
let mut tsconfig = TsConfig ::new ( json! ( {
" allowJs " : true ,
2021-02-05 06:01:48 -05:00
" esModuleInterop " : true ,
2020-12-22 05:21:18 -05:00
" experimentalDecorators " : true ,
" isolatedModules " : true ,
2021-02-05 06:01:48 -05:00
" jsx " : " react " ,
2020-12-22 05:21:18 -05:00
" lib " : [ " deno.ns " , " deno.window " ] ,
" module " : " esnext " ,
" noEmit " : true ,
2021-12-15 13:22:36 -05:00
" resolveJsonModule " : true ,
2020-12-22 05:21:18 -05:00
" strict " : true ,
" target " : " esnext " ,
2021-04-10 17:56:40 -04:00
" useDefineForClassFields " : true ,
2021-11-04 06:30:37 -04:00
// TODO(@kitsonk) remove for Deno 1.15
" useUnknownInCatchVariables " : false ,
2020-12-22 05:21:18 -05:00
} ) ) ;
2021-09-13 14:19:10 -04:00
let config = & self . config ;
let workspace_settings = config . get_workspace_settings ( ) ;
if workspace_settings . unstable {
let unstable_libs = json! ( {
" lib " : [ " deno.ns " , " deno.window " , " deno.unstable " ]
} ) ;
tsconfig . merge ( & unstable_libs ) ;
}
if let Err ( err ) = self . merge_user_tsconfig ( & mut tsconfig ) {
2021-11-24 20:10:12 -05:00
self . client . show_message ( MessageType ::WARNING , err ) . await ;
2020-12-22 05:21:18 -05:00
}
2021-02-24 22:15:55 -05:00
let _ok : bool = self
2020-12-22 05:21:18 -05:00
. ts_server
2022-01-19 17:10:14 -05:00
. request ( self . snapshot ( ) , tsc ::RequestMethod ::Configure ( tsconfig ) )
2020-12-22 05:21:18 -05:00
. await ? ;
2021-01-26 19:32:49 -05:00
self . performance . measure ( mark ) ;
2020-12-22 05:21:18 -05:00
Ok ( ( ) )
2020-12-21 08:44:26 -05:00
}
}
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... " ) ;
2021-05-11 00:54:10 -04:00
let mark = self . performance . mark ( " initialize " , Some ( & 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 )
}
2020-12-21 08:44:26 -05:00
let capabilities = capabilities ::server_capabilities ( & params . capabilities ) ;
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 ( ) ,
) ;
}
{
2021-11-24 15:14:19 -05:00
// sometimes this root uri may not have a trailing slash, so force it to
2022-03-20 21:33:37 -04:00
self . config . root_uri = params
2021-11-24 15:14:19 -05:00
. root_uri
. map ( | s | self . url_map . normalize_url ( & s ) )
. map ( fs_util ::ensure_directory_specifier ) ;
2020-12-21 08:44:26 -05:00
if let Some ( value ) = params . initialization_options {
2022-01-19 17:10:14 -05:00
self . config . set_workspace_settings ( value ) . map_err ( | err | {
2021-05-20 05:56:48 -04:00
error! ( " Cannot set workspace settings: {} " , err ) ;
LspError ::internal_error ( )
} ) ? ;
2020-12-21 08:44:26 -05:00
}
2022-03-20 21:33:37 -04:00
self . config . workspace_folders = params . workspace_folders . map ( | folders | {
folders
. into_iter ( )
. map ( | folder | ( self . url_map . normalize_url ( & folder . uri ) , folder ) )
. collect ( )
} ) ;
2022-01-19 17:10:14 -05:00
self . config . update_capabilities ( & params . capabilities ) ;
2020-12-21 08:44:26 -05:00
}
2021-05-11 00:54:10 -04:00
self . update_debug_flag ( ) ;
2021-07-27 17:25:09 -04:00
// Check to see if we need to change the cache path
if let Err ( err ) = self . update_cache ( ) {
2021-11-24 20:10:12 -05:00
self . client . show_message ( MessageType ::WARNING , err ) . await ;
2021-07-27 17:25:09 -04:00
}
2021-10-11 18:02:33 -04:00
if let Err ( err ) = self . update_config_file ( ) {
2021-11-24 20:10:12 -05:00
self . client . show_message ( MessageType ::WARNING , err ) . await ;
2021-10-11 18:02:33 -04:00
}
2020-12-22 05:21:18 -05:00
if let Err ( err ) = self . update_tsconfig ( ) . await {
2021-11-24 20:10:12 -05:00
self . client . show_message ( MessageType ::WARNING , err ) . await ;
2020-12-22 05:21:18 -05:00
}
2020-12-21 08:44:26 -05:00
2021-02-04 13:53:02 -05:00
if capabilities . code_action_provider . is_some ( ) {
2021-02-24 22:15:55 -05:00
let fixable_diagnostics : Vec < String > = self
2021-02-04 13:53:02 -05:00
. ts_server
2022-01-19 17:10:14 -05:00
. request ( self . snapshot ( ) , tsc ::RequestMethod ::GetSupportedCodeFixes )
2021-02-04 13:53:02 -05:00
. await
. map_err ( | err | {
error! ( " Unable to get fixable diagnostics: {} " , err ) ;
LspError ::internal_error ( )
} ) ? ;
self . ts_fixable_diagnostics = fixable_diagnostics ;
}
2020-12-21 08:44:26 -05:00
// Check to see if we need to setup the import map
if let Err ( err ) = self . update_import_map ( ) . await {
2021-11-24 20:10:12 -05:00
self . client . show_message ( MessageType ::WARNING , err ) . await ;
2020-12-21 08:44:26 -05:00
}
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 {
2021-11-24 20:10:12 -05:00
self . client . show_message ( MessageType ::WARNING , err ) . await ;
2021-04-08 21:27:27 -04:00
}
2021-11-08 20:26:39 -05:00
self . documents . update_config (
self . maybe_import_map . clone ( ) ,
self . maybe_config_file . as_ref ( ) ,
) ;
2020-12-21 08:44:26 -05:00
2021-07-27 17:25:09 -04:00
self . performance . measure ( mark ) ;
Ok ( InitializeResult {
capabilities ,
server_info : Some ( server_info ) ,
} )
}
async fn initialized ( & mut self , _ : InitializedParams ) {
2021-01-04 16:52:20 -05:00
if self
. config
. client_capabilities
. workspace_did_change_watched_files
2020-12-21 08:44:26 -05:00
{
2021-01-04 16:52:20 -05:00
// 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.
let watch_registration_options =
DidChangeWatchedFilesRegistrationOptions {
watchers : vec ! [ FileSystemWatcher {
2022-03-28 05:40:39 -04:00
glob_pattern : " **/*.json{c} " . to_string ( ) ,
2021-01-04 16:52:20 -05:00
kind : Some ( WatchKind ::Change ) ,
} ] ,
} ;
let registration = Registration {
id : " workspace/didChangeWatchedFiles " . to_string ( ) ,
method : " workspace/didChangeWatchedFiles " . to_string ( ) ,
register_options : Some (
serde_json ::to_value ( watch_registration_options ) . unwrap ( ) ,
) ,
} ;
if let Err ( err ) =
self . client . register_capability ( vec! [ registration ] ) . await
{
warn! ( " Client errored on capabilities. \n {} " , err ) ;
}
2020-12-21 08:44:26 -05:00
}
2022-03-20 21:33:37 -04:00
self . config . update_enabled_paths ( self . client . clone ( ) ) . await ;
2020-12-21 08:44:26 -05:00
2022-03-29 18:59:27 -04:00
if self . config . client_capabilities . testing_api {
let test_server = testing ::TestServer ::new (
self . client . clone ( ) ,
self . performance . clone ( ) ,
self . config . root_uri . clone ( ) ,
) ;
self . maybe_testing_server = Some ( test_server ) ;
}
2021-12-15 13:23:43 -05:00
lsp_log! ( " Server ready. " ) ;
2020-12-21 08:44:26 -05:00
}
2020-12-29 23:17:17 -05:00
async fn shutdown ( & self ) -> LspResult < ( ) > {
2020-12-21 08:44:26 -05:00
Ok ( ( ) )
}
2022-01-25 10:30:38 -05:00
async fn did_open (
& mut self ,
specifier : & ModuleSpecifier ,
params : DidOpenTextDocumentParams ,
2022-02-02 18:02:59 -05:00
) -> Document {
2021-05-11 00:54:10 -04:00
let mark = self . performance . mark ( " did_open " , Some ( & params ) ) ;
2021-08-18 23:19:12 -04:00
let language_id =
params
. text_document
. language_id
. parse ( )
. unwrap_or_else ( | err | {
error! ( " {} " , err ) ;
LanguageId ::Unknown
} ) ;
if language_id = = LanguageId ::Unknown {
warn! (
" Unsupported language id \" {} \" received for document \" {} \" . " ,
params . text_document . language_id , params . text_document . uri
) ;
}
2021-10-28 19:56:01 -04:00
let content = Arc ::new ( params . text_document . text ) ;
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 ( ) ,
content ,
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 ) {
2021-05-11 00:54:10 -04:00
let mark = self . performance . mark ( " did_change " , Some ( & params ) ) ;
2021-02-17 23:37:05 -05:00
let specifier = self . url_map . normalize_url ( & params . text_document . uri ) ;
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 ( ) {
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
}
}
2021-02-09 17:46:12 -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
}
2021-01-26 04:55:04 -05:00
async fn did_close ( & mut self , params : DidCloseTextDocumentParams ) {
2021-05-11 00:54:10 -04:00
let mark = self . performance . mark ( " did_close " , Some ( & params ) ) ;
2020-12-21 08:44:26 -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 ;
}
2021-02-17 23:37:05 -05:00
let specifier = self . url_map . normalize_url ( & params . text_document . uri ) ;
2021-01-22 05:03:16 -05:00
2021-10-28 19:56:01 -04:00
if let Err ( err ) = self . documents . close ( & specifier ) {
error! ( " {} " , err ) ;
}
if self . is_diagnosable ( & specifier ) {
2021-07-26 17:40:12 -04:00
let mut specifiers = self . documents . dependents ( & specifier ) ;
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
}
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 ,
2022-01-25 10:30:38 -05:00
client_workspace_config : Option < Value > ,
2021-01-04 16:52:20 -05:00
params : DidChangeConfigurationParams ,
2020-12-21 08:44:26 -05:00
) {
2021-06-01 05:24:36 -04:00
let maybe_config =
if self . config . client_capabilities . workspace_configuration {
2022-01-25 10:30:38 -05:00
client_workspace_config
2021-06-01 05:24:36 -04:00
} else {
params
. settings
. as_object ( )
2022-02-24 20:03:12 -05:00
. and_then ( | settings | settings . get ( SETTINGS_SECTION ) )
2021-06-01 05:24:36 -04:00
. cloned ( )
} ;
if let Some ( value ) = maybe_config {
if let Err ( err ) = self . config . set_workspace_settings ( value ) {
2021-05-09 21:16:04 -04:00
error! ( " failed to update settings: {} " , err ) ;
2021-02-08 05:45:46 -05:00
}
2020-12-21 08:44:26 -05:00
}
2021-05-09 21:16:04 -04:00
2021-05-11 00:54:10 -04:00
self . update_debug_flag ( ) ;
2021-07-27 17:25:09 -04:00
if let Err ( err ) = self . update_cache ( ) {
2021-11-24 20:10:12 -05:00
self . client . show_message ( MessageType ::WARNING , err ) . await ;
2021-07-27 17:25:09 -04:00
}
2021-05-09 21:16:04 -04:00
if let Err ( err ) = self . update_registries ( ) . await {
2021-11-24 20:10:12 -05:00
self . client . show_message ( MessageType ::WARNING , err ) . await ;
2021-05-09 21:16:04 -04:00
}
2021-10-11 18:02:33 -04:00
if let Err ( err ) = self . update_config_file ( ) {
2021-11-24 20:10:12 -05:00
self . client . show_message ( MessageType ::WARNING , err ) . await ;
2021-10-11 18:02:33 -04:00
}
2022-02-22 18:51:14 -05:00
if let Err ( err ) = self . update_import_map ( ) . await {
self . client . show_message ( MessageType ::WARNING , err ) . await ;
}
2021-05-09 21:16:04 -04:00
if let Err ( err ) = self . update_tsconfig ( ) . await {
2021-11-24 20:10:12 -05:00
self . client . show_message ( MessageType ::WARNING , err ) . await ;
2021-05-09 21:16:04 -04:00
}
2022-02-02 18:02:59 -05:00
2021-11-08 20:26:39 -05:00
self . documents . update_config (
self . maybe_import_map . clone ( ) ,
self . maybe_config_file . as_ref ( ) ,
) ;
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
. mark ( " did_change_watched_files " , Some ( & params ) ) ;
2021-07-25 01:33:42 -04:00
let mut touched = false ;
2021-11-23 12:32:40 -05:00
let changes : Vec < Url > = params
. changes
. iter ( )
. map ( | f | self . url_map . normalize_url ( & f . uri ) )
. collect ( ) ;
2020-12-30 22:33:44 -05:00
// if the current tsconfig has changed, we need to reload it
2022-01-17 14:45:05 -05:00
if let Some ( config_file ) = & self . maybe_config_file {
if changes . iter ( ) . any ( | uri | config_file . specifier = = * uri ) {
2021-10-11 18:02:33 -04:00
if let Err ( err ) = self . update_config_file ( ) {
2021-11-24 20:10:12 -05:00
self . client . show_message ( MessageType ::WARNING , err ) . await ;
2021-10-11 18:02:33 -04:00
}
2020-12-30 22:33:44 -05:00
if let Err ( err ) = self . update_tsconfig ( ) . await {
2021-11-24 20:10:12 -05:00
self . client . show_message ( MessageType ::WARNING , err ) . await ;
2020-12-30 22:33:44 -05:00
}
2021-07-25 01:33:42 -04:00
touched = true ;
}
}
2022-02-22 18:51:14 -05:00
// if the current import map, or config file has changed, we need to reload
// reload the import map
if let Some ( import_map_uri ) = & self . maybe_import_map_uri {
if changes . iter ( ) . any ( | uri | import_map_uri = = uri ) | | touched {
if let Err ( err ) = self . update_import_map ( ) . await {
self . client . show_message ( MessageType ::WARNING , err ) . await ;
}
touched = true ;
}
}
2021-07-25 01:33:42 -04:00
if touched {
2021-11-08 20:26:39 -05:00
self . documents . update_config (
self . maybe_import_map . clone ( ) ,
self . maybe_config_file . as_ref ( ) ,
) ;
2022-02-02 18:02:59 -05:00
self . diagnostics_server . invalidate_all ( ) ;
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
}
2022-03-20 21:33:37 -04:00
async fn did_change_workspace_folders (
& mut self ,
params : DidChangeWorkspaceFoldersParams ,
) {
let mark = self
. performance
. mark ( " did_change_workspace_folders " , Some ( & params ) ) ;
let mut workspace_folders = params
. event
. added
. into_iter ( )
. map ( | folder | ( self . url_map . normalize_url ( & folder . uri ) , folder ) )
. collect ::< Vec < ( ModuleSpecifier , WorkspaceFolder ) > > ( ) ;
if let Some ( current_folders ) = & self . config . workspace_folders {
for ( specifier , folder ) in current_folders {
if ! params . event . removed . is_empty ( )
& & params . event . removed . iter ( ) . any ( | f | f . uri = = folder . uri )
{
continue ;
}
workspace_folders . push ( ( specifier . clone ( ) , folder . clone ( ) ) ) ;
}
}
self . config . workspace_folders = Some ( workspace_folders ) ;
self . performance . measure ( mark ) ;
}
2021-04-19 21:29:27 -04:00
async fn document_symbol (
2021-05-09 21:16:04 -04:00
& mut self ,
2021-04-19 21:29:27 -04:00
params : DocumentSymbolParams ,
) -> LspResult < Option < DocumentSymbolResponse > > {
2021-05-09 21:16:04 -04:00
let specifier = self . url_map . normalize_url ( & params . text_document . uri ) ;
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 ) ;
}
2021-05-11 00:54:10 -04:00
let mark = self . performance . mark ( " document_symbol " , Some ( & params ) ) ;
2021-11-12 11:42:04 -05:00
let asset_or_document = self . get_cached_asset_or_document ( & specifier ) ? ;
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! (
" Error getting document symbols for \" {} \" : {} " ,
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 > > > {
2021-02-17 23:37:05 -05:00
let specifier = self . url_map . normalize_url ( & params . text_document . uri ) ;
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 ) ,
} ;
2021-06-02 06:29:58 -04:00
let mark = self . performance . mark ( " formatting " , Some ( & params ) ) ;
2020-12-21 08:44:26 -05:00
let file_path =
2021-11-24 15:14:19 -05:00
fs_util ::specifier_to_file_path ( & specifier ) . map_err ( | err | {
2021-11-23 10:38:11 -05:00
error! ( " {} " , err ) ;
LspError ::invalid_request ( )
} ) ? ;
2020-12-21 08:44:26 -05:00
2021-10-11 18:02:33 -04:00
let fmt_options = if let Some ( fmt_config ) = self . maybe_fmt_config . as_ref ( ) {
2021-11-24 15:14:19 -05:00
// skip formatting any files ignored by the config file
if ! fmt_config . files . matches_specifier ( & specifier ) {
return Ok ( None ) ;
}
2021-10-11 18:02:33 -04:00
fmt_config . options . clone ( )
2021-09-13 14:19:10 -04:00
} else {
Default ::default ( )
} ;
2020-12-21 08:44:26 -05:00
let text_edits = tokio ::task ::spawn_blocking ( move | | {
2021-11-12 11:42:04 -05:00
let format_result = match document . maybe_parsed_source ( ) {
2021-10-28 19:56:01 -04:00
Some ( Ok ( parsed_source ) ) = > {
format_parsed_source ( & parsed_source , fmt_options )
2021-09-13 14:19:10 -04:00
}
2022-01-04 17:02:56 -05:00
Some ( Err ( err ) ) = > Err ( anyhow! ( " {} " , err ) ) ,
2021-09-07 10:39:32 -04:00
None = > {
// it's not a js/ts file, so attempt to format its contents
2021-11-12 11:42:04 -05:00
format_file ( & file_path , document . content ( ) . as_str ( ) , fmt_options )
2021-09-07 10:39:32 -04:00
}
} ;
match format_result {
2022-03-29 17:28:55 -04:00
Ok ( Some ( new_text ) ) = > Some ( text ::get_edits (
document . content ( ) . as_str ( ) ,
& new_text ,
document . line_index ( ) . as_ref ( ) ,
) ) ,
Ok ( None ) = > Some ( Vec ::new ( ) ) ,
2020-12-21 08:44:26 -05:00
Err ( err ) = > {
2021-09-07 10:39:32 -04:00
// TODO(lucacasonato): handle error properly
2020-12-21 08:44:26 -05:00
warn! ( " Format error: {} " , err ) ;
None
}
}
} )
. await
. unwrap ( ) ;
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 {
2021-11-24 20:10:12 -05:00
self . client . show_message ( MessageType ::WARNING , format! ( " Unable to format \" {} \" . Likely due to unrecoverable syntax errors in the file. " , specifier ) ) . await ;
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 > > {
2021-02-17 23:37:05 -05:00
let specifier = self
. url_map
. normalize_url ( & params . text_document_position_params . text_document . uri ) ;
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-24 19:06:51 -04:00
let mark = self . performance . mark ( " hover " , Some ( & params ) ) ;
2021-11-12 11:42:04 -05:00
let asset_or_doc = self . get_cached_asset_or_document ( & specifier ) ? ;
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 " ,
2022-01-31 17:33:57 -05:00
to_hover_text ( & dep . maybe_code ) ,
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 " ,
2022-01-31 17:33:57 -05:00
to_hover_text ( & dep . maybe_code ) ,
to_hover_text ( & dep . maybe_type ) ,
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 " ,
to_hover_text ( & dep . maybe_code ) ,
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 " ,
2022-01-31 17:33:57 -05:00
to_hover_text ( & dep . maybe_code ) ,
2021-11-07 19:50:48 -05:00
to_hover_text ( types_dep )
) ,
2022-01-31 17:33:57 -05:00
( false , true , _ ) = > format! (
" **Resolved Dependency** \n \n **Code**: {} \n " ,
to_hover_text ( & dep . maybe_code )
) ,
( true , false , _ ) = > format! (
2021-10-28 19:56:01 -04:00
" **Resolved Dependency** \n \n **Types**: {} \n " ,
2022-01-31 17:33:57 -05:00
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 {
format! ( " {} \n \n --- \n \n {} " , value , docs )
} 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 ( ) ;
2021-06-24 19:06:51 -04:00
let req = tsc ::RequestMethod ::GetQuickInfo ( (
specifier ,
line_index . offset_tsc ( params . text_document_position_params . position ) ? ,
) ) ;
let maybe_quick_info : Option < tsc ::QuickInfo > = self
. ts_server
2022-01-19 17:10:14 -05:00
. request ( self . snapshot ( ) , req )
2021-06-24 19:06:51 -04:00
. await
. map_err ( | err | {
error! ( " Unable to get quick info: {} " , err ) ;
LspError ::internal_error ( )
} ) ? ;
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
}
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 > > {
2021-05-09 21:16:04 -04:00
let specifier = self . url_map . normalize_url ( & params . text_document . uri ) ;
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 ) ;
}
2021-05-11 00:54:10 -04:00
let mark = self . performance . mark ( " code_action " , Some ( & params ) ) ;
2021-08-05 21:46:32 -04:00
let mut all_actions = CodeActionResponse ::new ( ) ;
2021-11-12 11:42:04 -05:00
let asset_or_doc = self . get_cached_asset_or_document ( & specifier ) ? ;
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 ,
} ,
2021-06-21 02:43:35 -04:00
" deno-lint " = > matches! ( & d . code , Some ( _ ) ) ,
2022-02-04 02:14:57 -05:00
" deno " = > diagnostics ::DenoDiagnostic ::is_fixable ( & d . code ) ,
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 ( ) ) ;
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 ] ;
let req = tsc ::RequestMethod ::GetCodeFixes ( (
specifier . clone ( ) ,
line_index . offset_tsc ( diagnostic . range . start ) ? ,
line_index . offset_tsc ( diagnostic . range . end ) ? ,
codes ,
) ) ;
let actions : Vec < tsc ::CodeFixAction > =
2022-01-19 17:10:14 -05:00
match self . ts_server . request ( self . snapshot ( ) , req ) . await {
2021-08-05 21:46:32 -04:00
Ok ( items ) = > items ,
Err ( err ) = > {
// sometimes tsc reports errors when retrieving code actions
// because they don't reflect the current state of the document
// so we will log them to the output, but we won't send an error
// message back to the client.
error! ( " Error getting actions from TypeScript: {} " , err ) ;
Vec ::new ( )
}
} ;
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 )
. await
. map_err ( | err | {
error! ( " Unable to convert fix: {} " , err ) ;
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
}
}
2021-08-05 21:46:32 -04:00
Some ( " deno " ) = > code_actions
2021-12-15 22:53:17 -05:00
. add_deno_fix_action ( & specifier , diagnostic )
2021-02-11 23:17:48 -05:00
. map_err ( | err | {
error! ( " {} " , err ) ;
LspError ::internal_error ( )
2021-08-05 21:46:32 -04:00
} ) ? ,
Some ( " deno-lint " ) = > code_actions
. add_deno_lint_ignore_action (
& 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 | {
error! ( " Unable to fix lint error: {} " , err ) ;
LspError ::internal_error ( )
} ) ? ,
_ = > ( ) ,
2021-02-11 23:17:48 -05:00
}
2021-02-04 13:53:02 -05:00
}
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
let start = line_index . offset_tsc ( params . range . start ) ? ;
let length = line_index . offset_tsc ( params . range . end ) ? - start ;
let only =
params
. context
. only
. as_ref ( )
. map_or ( String ::default ( ) , | values | {
values
. first ( )
. map_or ( String ::default ( ) , | v | v . as_str ( ) . to_owned ( ) )
} ) ;
let req = tsc ::RequestMethod ::GetApplicableRefactors ( (
specifier . clone ( ) ,
tsc ::TextSpan { start , length } ,
only ,
) ) ;
let refactor_infos : Vec < tsc ::ApplicableRefactorInfo > = self
. ts_server
2022-01-19 17:10:14 -05:00
. request ( self . snapshot ( ) , req )
2021-08-05 21:46:32 -04:00
. await
. map_err ( | err | {
error! ( " Failed to request to tsserver {} " , err ) ;
LspError ::invalid_request ( )
} ) ? ;
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 (
refactor ::prune_invalid_actions ( & refactor_actions , 5 )
. 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 ) ;
}
2021-05-11 00:54:10 -04:00
let mark = self . performance . mark ( " code_action_resolve " , Some ( & 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 ( ) )
{
2022-01-19 17:10:14 -05:00
let snapshot = self . snapshot ( ) ;
2021-02-24 22:15:55 -05:00
let code_action_data : CodeActionData =
from_value ( data ) . map_err ( | err | {
error! ( " Unable to decode code action data: {} " , err ) ;
LspError ::invalid_params ( " The CodeAction's data is invalid. " )
} ) ? ;
let req = tsc ::RequestMethod ::GetCombinedCodeFix ( (
2021-05-29 07:21:11 -04:00
code_action_data . specifier . clone ( ) ,
2021-02-24 22:15:55 -05:00
json! ( code_action_data . fix_id . clone ( ) ) ,
) ) ;
let combined_code_actions : tsc ::CombinedCodeActions = self
. ts_server
2022-01-19 17:10:14 -05:00
. request ( snapshot . clone ( ) , req )
2021-02-24 22:15:55 -05:00
. await
. map_err ( | err | {
error! ( " Unable to get combined fix from TypeScript: {} " , err ) ;
LspError ::internal_error ( )
} ) ? ;
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 ,
2022-01-19 17:10:14 -05:00
& self . documents ,
2021-08-05 21:46:32 -04:00
)
. map_err ( | err | {
error! ( " Unable to remap changes: {} " , err ) ;
LspError ::internal_error ( )
} ) ?
} else {
combined_code_actions . changes . clone ( )
} ;
let mut code_action = params . clone ( ) ;
code_action . edit =
ts_changes_to_edit ( & changes , self ) . await . map_err ( | err | {
error! ( " Unable to convert changes to edits: {} " , err ) ;
LspError ::internal_error ( )
} ) ? ;
code_action
} else if kind . as_str ( ) . starts_with ( CodeActionKind ::REFACTOR . as_str ( ) ) {
2022-01-19 17:10:14 -05:00
let snapshot = self . snapshot ( ) ;
2021-08-05 21:46:32 -04:00
let mut code_action = params . clone ( ) ;
let action_data : refactor ::RefactorCodeActionData = from_value ( data )
. map_err ( | err | {
error! ( " Unable to decode code action data: {} " , err ) ;
LspError ::invalid_params ( " The CodeAction's data is invalid. " )
} ) ? ;
2021-11-12 11:42:04 -05:00
let asset_or_doc =
self . get_cached_asset_or_document ( & action_data . specifier ) ? ;
let line_index = asset_or_doc . line_index ( ) ;
2021-08-05 21:46:32 -04:00
let start = line_index . offset_tsc ( action_data . range . start ) ? ;
let length = line_index . offset_tsc ( action_data . range . end ) ? - start ;
let req = tsc ::RequestMethod ::GetEditsForRefactor ( (
action_data . specifier . clone ( ) ,
tsc ::TextSpan { start , length } ,
action_data . refactor_name . clone ( ) ,
action_data . action_name . clone ( ) ,
) ) ;
2022-01-19 17:10:14 -05:00
let refactor_edit_info : tsc ::RefactorEditInfo =
self . ts_server . request ( snapshot , req ) . await . map_err ( | err | {
2021-08-05 21:46:32 -04:00
error! ( " Failed to request to tsserver {} " , err ) ;
LspError ::invalid_request ( )
} ) ? ;
code_action . edit = refactor_edit_info
. to_workspace_edit ( self )
. await
. map_err ( | err | {
error! ( " Unable to convert changes to edits: {} " , err ) ;
LspError ::internal_error ( )
} ) ? ;
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
}
2021-01-31 22:30:41 -05:00
async fn code_lens (
& mut self ,
params : CodeLensParams ,
) -> LspResult < Option < Vec < CodeLens > > > {
2021-05-09 21:16:04 -04:00
let specifier = self . url_map . normalize_url ( & params . text_document . uri ) ;
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-06-07 07:38:07 -04:00
| | ! ( self . config . get_workspace_settings ( ) . enabled_code_lens ( )
| | self . config . specifier_code_lens_test ( & specifier ) )
2021-05-09 21:16:04 -04:00
{
2021-01-31 22:30:41 -05:00
return Ok ( None ) ;
}
2021-05-11 00:54:10 -04:00
let mark = self . performance . mark ( " code_lens " , Some ( & params ) ) ;
2021-11-12 11:42:04 -05:00
let asset_or_doc = self . get_cached_asset_or_document ( & specifier ) ? ;
2021-09-07 10:39:32 -04:00
let navigation_tree =
self . get_navigation_tree ( & specifier ) . await . map_err ( | err | {
2021-06-04 17:31:44 -04:00
error! ( " Error getting code lenses for \" {} \" : {} " , specifier , err ) ;
LspError ::internal_error ( )
2021-01-31 22:30:41 -05:00
} ) ? ;
2022-02-24 20:03:12 -05:00
let parsed_source = asset_or_doc . maybe_parsed_source ( ) . and_then ( | r | r . ok ( ) ) ;
2021-11-12 11:42:04 -05:00
let line_index = asset_or_doc . line_index ( ) ;
2021-09-07 10:39:32 -04:00
let code_lenses = code_lens ::collect (
& specifier ,
2021-10-28 19:56:01 -04:00
parsed_source ,
2021-09-07 10:39:32 -04:00
& self . config ,
2021-10-28 19:56:01 -04:00
line_index ,
2021-09-07 10:39:32 -04:00
& navigation_tree ,
)
. await
. map_err ( | err | {
error! ( " Error getting code lenses for \" {} \" : {} " , 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
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 > {
2021-06-04 17:31:44 -04:00
let mark = self . performance . mark ( " code_lens_resolve " , Some ( & code_lens ) ) ;
let result = if code_lens . data . is_some ( ) {
code_lens ::resolve_code_lens ( code_lens , self )
. await
. map_err ( | err | {
error! ( " Error resolving code lens: {} " , err ) ;
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 > > > {
2021-02-17 23:37:05 -05:00
let specifier = self
. url_map
. normalize_url ( & params . text_document_position_params . text_document . uri ) ;
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-05-11 00:54:10 -04:00
let mark = self . performance . mark ( " document_highlight " , Some ( & params ) ) ;
2021-11-12 11:42:04 -05:00
let asset_or_doc = self . get_cached_asset_or_document ( & specifier ) ? ;
let line_index = asset_or_doc . line_index ( ) ;
2020-12-21 08:44:26 -05:00
let files_to_search = vec! [ specifier . clone ( ) ] ;
let req = tsc ::RequestMethod ::GetDocumentHighlights ( (
specifier ,
2021-01-22 05:03:16 -05:00
line_index . offset_tsc ( params . text_document_position_params . position ) ? ,
2020-12-21 08:44:26 -05:00
files_to_search ,
) ) ;
2021-02-24 22:15:55 -05:00
let maybe_document_highlights : Option < Vec < tsc ::DocumentHighlights > > = self
. ts_server
2022-01-19 17:10:14 -05:00
. request ( self . snapshot ( ) , req )
2021-02-24 22:15:55 -05:00
. await
. map_err ( | err | {
error! ( " Unable to get document highlights from TypeScript: {} " , err ) ;
LspError ::internal_error ( )
} ) ? ;
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 > > > {
2021-02-17 23:37:05 -05:00
let specifier = self
. url_map
. normalize_url ( & params . text_document_position . text_document . uri ) ;
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 . mark ( " references " , Some ( & params ) ) ;
2021-11-12 11:42:04 -05:00
let asset_or_doc = self . get_cached_asset_or_document ( & specifier ) ? ;
let line_index = asset_or_doc . line_index ( ) ;
2020-12-21 08:44:26 -05:00
let req = tsc ::RequestMethod ::GetReferences ( (
2021-11-16 17:23:25 -05:00
specifier . clone ( ) ,
2021-01-22 05:03:16 -05:00
line_index . offset_tsc ( params . text_document_position . position ) ? ,
2020-12-21 08:44:26 -05:00
) ) ;
2021-02-24 22:15:55 -05:00
let maybe_references : Option < Vec < tsc ::ReferenceEntry > > = self
. ts_server
2022-01-19 17:10:14 -05:00
. request ( self . snapshot ( ) , req )
2021-02-24 22:15:55 -05:00
. await
. map_err ( | err | {
error! ( " Unable to get references from TypeScript: {} " , err ) ;
LspError ::internal_error ( )
} ) ? ;
2020-12-21 08:44:26 -05:00
if let Some ( references ) = maybe_references {
let mut results = Vec ::new ( ) ;
for reference in references {
if ! params . context . include_declaration & & reference . is_definition {
continue ;
}
let reference_specifier =
2021-02-17 13:47:18 -05:00
resolve_url ( & reference . 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 =
self . get_asset_or_document ( & reference_specifier ) . await ? ;
asset_or_doc . line_index ( )
} ;
2022-01-19 17:10:14 -05:00
results
. push ( reference . 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 > > {
2021-02-17 23:37:05 -05:00
let specifier = self
. url_map
. normalize_url ( & params . text_document_position_params . text_document . uri ) ;
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 . mark ( " goto_definition " , Some ( & params ) ) ;
2021-11-12 11:42:04 -05:00
let asset_or_doc = self . get_cached_asset_or_document ( & specifier ) ? ;
let line_index = asset_or_doc . line_index ( ) ;
2020-12-21 08:44:26 -05:00
let req = tsc ::RequestMethod ::GetDefinition ( (
specifier ,
2021-01-22 05:03:16 -05:00
line_index . offset_tsc ( params . text_document_position_params . position ) ? ,
2020-12-21 08:44:26 -05:00
) ) ;
2021-02-24 22:15:55 -05:00
let maybe_definition : Option < tsc ::DefinitionInfoAndBoundSpan > = self
. ts_server
2022-01-19 17:10:14 -05:00
. request ( self . snapshot ( ) , req )
2021-02-24 22:15:55 -05:00
. await
. map_err ( | err | {
error! ( " Unable to get definition from TypeScript: {} " , err ) ;
LspError ::internal_error ( )
} ) ? ;
2020-12-21 08:44:26 -05:00
if let Some ( definition ) = maybe_definition {
2021-10-28 19:56:01 -04:00
let results = definition . to_definition ( line_index , self ) . await ;
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 > > {
let specifier = self
. url_map
. normalize_url ( & params . text_document_position_params . text_document . uri ) ;
if ! self . is_diagnosable ( & specifier )
| | ! self . config . specifier_enabled ( & specifier )
{
return Ok ( None ) ;
}
let mark = self . performance . mark ( " goto_definition " , Some ( & params ) ) ;
let asset_or_doc = self . get_cached_asset_or_document ( & specifier ) ? ;
let line_index = asset_or_doc . line_index ( ) ;
let req = tsc ::RequestMethod ::GetTypeDefinition {
specifier ,
position : line_index
. offset_tsc ( params . text_document_position_params . position ) ? ,
} ;
let maybe_definition_info : Option < Vec < tsc ::DefinitionInfo > > = self
. ts_server
2022-01-19 17:10:14 -05:00
. request ( self . snapshot ( ) , req )
2021-11-22 19:09:19 -05:00
. await
. map_err ( | err | {
error! ( " Unable to get type definition from TypeScript: {} " , err ) ;
LspError ::internal_error ( )
} ) ? ;
let response = if let Some ( definition_info ) = maybe_definition_info {
let mut location_links = Vec ::new ( ) ;
for info in definition_info {
if let Some ( link ) =
info . document_span . to_link ( line_index . clone ( ) , self ) . await
{
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 > > {
2021-02-17 23:37:05 -05:00
let specifier = self
. url_map
. normalize_url ( & params . text_document_position . text_document . uri ) ;
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 . mark ( " completion " , Some ( & params ) ) ;
2021-11-12 11:42:04 -05:00
let asset_or_doc = self . get_cached_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.
let response = if let Some ( response ) = completions ::get_import_completions (
& specifier ,
& params . text_document_position . position ,
2022-01-19 17:10:14 -05:00
& self . config . snapshot ( ) ,
2021-06-01 07:53:08 -04:00
self . client . clone ( ) ,
2022-01-19 17:10:14 -05:00
& self . module_registries ,
& self . documents ,
2022-02-09 15:13:50 -05:00
self . maybe_import_map . clone ( ) ,
2021-04-08 21:27:27 -04:00
)
. await
{
2021-03-24 20:13:37 -04:00
Some ( response )
} else {
2021-11-12 11:42:04 -05:00
let line_index = asset_or_doc . line_index ( ) ;
2021-03-24 20:13:37 -04:00
let trigger_character = if let Some ( context ) = & params . context {
context . trigger_character . clone ( )
2021-01-22 05:03:16 -05:00
} else {
2021-03-24 20:13:37 -04:00
None
2021-01-22 05:03:16 -05:00
} ;
2021-03-24 20:13:37 -04:00
let position =
line_index . offset_tsc ( params . text_document_position . position ) ? ;
let req = tsc ::RequestMethod ::GetCompletions ( (
specifier . clone ( ) ,
position ,
tsc ::GetCompletionsAtPositionOptions {
user_preferences : tsc ::UserPreferences {
2021-09-15 22:07:52 -04:00
allow_text_changes_in_new_files : Some ( specifier . scheme ( ) = = " file " ) ,
include_automatic_optional_chain_completions : Some ( true ) ,
provide_refactor_not_applicable_reason : Some ( true ) ,
2021-03-24 20:13:37 -04:00
include_completions_with_insert_text : Some ( true ) ,
2021-09-15 22:07:52 -04:00
allow_incomplete_completions : Some ( true ) ,
2021-03-24 20:13:37 -04:00
.. Default ::default ( )
} ,
trigger_character ,
2021-03-15 18:01:41 -04:00
} ,
2021-03-24 20:13:37 -04:00
) ) ;
2022-01-19 17:10:14 -05:00
let snapshot = self . snapshot ( ) ;
let maybe_completion_info : Option < tsc ::CompletionInfo > =
self . ts_server . request ( snapshot , req ) . await . map_err ( | err | {
2021-03-24 20:13:37 -04:00
error! ( " Unable to get completion info from TypeScript: {} " , err ) ;
LspError ::internal_error ( )
} ) ? ;
2020-12-21 08:44:26 -05:00
2021-03-24 20:13:37 -04:00
if let Some ( completions ) = maybe_completion_info {
let results = completions . as_completion_response (
2021-10-28 19:56:01 -04:00
line_index ,
2021-05-20 05:56:48 -04:00
& self . config . get_workspace_settings ( ) . suggest ,
2021-03-24 20:13:37 -04:00
& specifier ,
position ,
) ;
Some ( results )
} else {
None
}
} ;
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 > {
2021-05-11 00:54:10 -04:00
let mark = self . performance . mark ( " completion_resolve " , Some ( & 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 | {
2021-03-15 18:01:41 -04:00
error! ( " {} " , err ) ;
LspError ::invalid_params (
" Could not decode data field of completion item. " ,
)
} ) ? ;
2021-03-24 20:13:37 -04:00
if let Some ( data ) = data . tsc {
let req = tsc ::RequestMethod ::GetCompletionDetails ( data . into ( ) ) ;
2022-01-19 17:10:14 -05:00
let maybe_completion_info : Option < tsc ::CompletionEntryDetails > =
self . ts_server . request ( self . snapshot ( ) , req ) . await . map_err (
| err | {
error! ( " Unable to get completion info from TypeScript: {} " , err ) ;
LspError ::internal_error ( )
} ,
) ? ;
2021-03-24 20:13:37 -04:00
if let Some ( completion_info ) = maybe_completion_info {
2022-02-09 18:08:53 -05:00
completion_info . as_completion_item ( & params , self )
2021-03-24 20:13:37 -04:00
} else {
error! (
" Received an undefined response from tsc for completion details. "
) ;
params
}
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 > > {
2021-02-17 23:37:05 -05:00
let specifier = self
. url_map
. normalize_url ( & params . text_document_position_params . text_document . uri ) ;
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 . mark ( " goto_implementation " , Some ( & params ) ) ;
2021-11-12 11:42:04 -05:00
let asset_or_doc = self . get_cached_asset_or_document ( & specifier ) ? ;
let line_index = asset_or_doc . line_index ( ) ;
2021-01-12 16:53:27 -05:00
let req = tsc ::RequestMethod ::GetImplementation ( (
specifier ,
2021-01-22 05:03:16 -05:00
line_index . offset_tsc ( params . text_document_position_params . position ) ? ,
2021-01-12 16:53:27 -05:00
) ) ;
2021-02-24 22:15:55 -05:00
let maybe_implementations : Option < Vec < tsc ::ImplementationLocation > > = self
. ts_server
2022-01-19 17:10:14 -05:00
. request ( self . snapshot ( ) , req )
2021-02-24 22:15:55 -05:00
. await
2021-01-12 16:53:27 -05:00
. map_err ( | err | {
2021-02-24 22:15:55 -05:00
error! ( " Failed to request to tsserver {} " , err ) ;
LspError ::invalid_request ( )
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 {
2021-10-28 19:56:01 -04:00
if let Some ( link ) =
implementation . to_link ( line_index . clone ( ) , self ) . await
{
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 > > > {
2021-05-09 21:16:04 -04:00
let specifier = self . url_map . normalize_url ( & params . text_document . uri ) ;
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 ) ;
}
2021-06-02 06:29:58 -04:00
let mark = self . performance . mark ( " folding_range " , Some ( & params ) ) ;
2021-11-12 11:42:04 -05:00
let asset_or_doc = self . get_cached_asset_or_document ( & specifier ) ? ;
2021-04-02 02:21:07 -04:00
let req = tsc ::RequestMethod ::GetOutliningSpans ( specifier . clone ( ) ) ;
let outlining_spans : Vec < tsc ::OutliningSpan > = self
. ts_server
2022-01-19 17:10:14 -05:00
. request ( self . snapshot ( ) , req )
2021-04-02 02:21:07 -04:00
. await
. map_err ( | err | {
error! ( " Failed to request to tsserver {} " , err ) ;
LspError ::invalid_request ( )
} ) ? ;
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 ( ) ,
asset_or_doc . text ( ) . as_str ( ) . 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 > > > {
2021-05-09 21:16:04 -04:00
let specifier = self . url_map . normalize_url ( & params . item . uri ) ;
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 ) ;
}
2021-06-02 06:29:58 -04:00
let mark = self . performance . mark ( " incoming_calls " , Some ( & params ) ) ;
2021-11-12 11:42:04 -05:00
let asset_or_doc = self . get_cached_asset_or_document ( & specifier ) ? ;
let line_index = asset_or_doc . line_index ( ) ;
2021-04-19 01:11:26 -04:00
let req = tsc ::RequestMethod ::ProvideCallHierarchyIncomingCalls ( (
specifier . clone ( ) ,
line_index . offset_tsc ( params . item . selection_range . start ) ? ,
) ) ;
let incoming_calls : Vec < tsc ::CallHierarchyIncomingCall > = self
. ts_server
2022-01-19 17:10:14 -05:00
. request ( self . snapshot ( ) , req )
2021-04-19 01:11:26 -04:00
. await
. map_err ( | err | {
error! ( " Failed to request to tsserver {} " , err ) ;
LspError ::invalid_request ( )
} ) ? ;
let maybe_root_path_owned = self
2022-03-20 21:33:37 -04:00
. config
2021-04-19 01:11:26 -04:00
. root_uri
. as_ref ( )
2021-11-24 15:14:19 -05:00
. and_then ( | uri | fs_util ::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 ( ) {
if let Some ( resolved ) = item
. try_resolve_call_hierarchy_incoming_call (
self ,
maybe_root_path_owned . as_deref ( ) ,
)
. await
{
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 > > > {
2021-05-09 21:16:04 -04:00
let specifier = self . url_map . normalize_url ( & params . item . uri ) ;
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 ) ;
}
2021-06-02 06:29:58 -04:00
let mark = self . performance . mark ( " outgoing_calls " , Some ( & params ) ) ;
2021-11-12 11:42:04 -05:00
let asset_or_doc = self . get_cached_asset_or_document ( & specifier ) ? ;
let line_index = asset_or_doc . line_index ( ) ;
2021-04-19 01:11:26 -04:00
let req = tsc ::RequestMethod ::ProvideCallHierarchyOutgoingCalls ( (
specifier . clone ( ) ,
line_index . offset_tsc ( params . item . selection_range . start ) ? ,
) ) ;
let outgoing_calls : Vec < tsc ::CallHierarchyOutgoingCall > = self
. ts_server
2022-01-19 17:10:14 -05:00
. request ( self . snapshot ( ) , req )
2021-04-19 01:11:26 -04:00
. await
. map_err ( | err | {
error! ( " Failed to request to tsserver {} " , err ) ;
LspError ::invalid_request ( )
} ) ? ;
let maybe_root_path_owned = self
2022-03-20 21:33:37 -04:00
. config
2021-04-19 01:11:26 -04:00
. root_uri
. as_ref ( )
2021-11-24 15:14:19 -05:00
. and_then ( | uri | fs_util ::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 ( ) {
if let Some ( resolved ) = item
. try_resolve_call_hierarchy_outgoing_call (
2021-10-28 19:56:01 -04:00
line_index . clone ( ) ,
2021-04-19 01:11:26 -04:00
self ,
maybe_root_path_owned . as_deref ( ) ,
)
. await
{
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 > > > {
let specifier = self
. url_map
. normalize_url ( & params . text_document_position_params . text_document . uri ) ;
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
. mark ( " prepare_call_hierarchy " , Some ( & params ) ) ;
2021-11-12 11:42:04 -05:00
let asset_or_doc = self . get_cached_asset_or_document ( & specifier ) ? ;
let line_index = asset_or_doc . line_index ( ) ;
2021-04-19 01:11:26 -04:00
let req = tsc ::RequestMethod ::PrepareCallHierarchy ( (
specifier . clone ( ) ,
line_index . offset_tsc ( params . text_document_position_params . position ) ? ,
) ) ;
let maybe_one_or_many : Option < tsc ::OneOrMany < tsc ::CallHierarchyItem > > =
self
. ts_server
2022-01-19 17:10:14 -05:00
. request ( self . snapshot ( ) , req )
2021-04-19 01:11:26 -04:00
. await
. map_err ( | err | {
error! ( " Failed to request to tsserver {} " , err ) ;
LspError ::invalid_request ( )
} ) ? ;
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
2021-04-19 01:11:26 -04:00
. root_uri
. as_ref ( )
2021-11-24 15:14:19 -05:00
. and_then ( | uri | fs_util ::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 ) = > {
if let Some ( resolved ) = item
. try_resolve_call_hierarchy_item (
self ,
maybe_root_path_owned . as_deref ( ) ,
)
. await
{
resolved_items . push ( resolved )
}
}
tsc ::OneOrMany ::Many ( items ) = > {
for item in items . iter ( ) {
if let Some ( resolved ) = item
. try_resolve_call_hierarchy_item (
self ,
maybe_root_path_owned . as_deref ( ) ,
)
. await
{
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 > > {
2021-02-17 23:37:05 -05:00
let specifier = self
. url_map
. normalize_url ( & params . text_document_position . text_document . uri ) ;
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
2021-06-02 06:29:58 -04:00
let mark = self . performance . mark ( " rename " , Some ( & params ) ) ;
2021-11-12 11:42:04 -05:00
let asset_or_doc = self . get_cached_asset_or_document ( & specifier ) ? ;
let line_index = asset_or_doc . line_index ( ) ;
2020-12-29 19:58:20 -05:00
2021-06-19 11:23:50 -04:00
let req = tsc ::RequestMethod ::FindRenameLocations {
2020-12-29 19:58:20 -05:00
specifier ,
2021-06-19 11:23:50 -04:00
position : line_index
. offset_tsc ( params . text_document_position . position ) ? ,
find_in_strings : false ,
find_in_comments : false ,
provide_prefix_and_suffix_text_for_rename : false ,
} ;
2020-12-29 19:58:20 -05:00
2021-02-24 22:15:55 -05:00
let maybe_locations : Option < Vec < tsc ::RenameLocation > > = self
. ts_server
2022-01-19 17:10:14 -05:00
. request ( self . snapshot ( ) , req )
2021-02-24 22:15:55 -05:00
. await
. map_err ( | err | {
error! ( " Failed to request to tsserver {} " , err ) ;
LspError ::invalid_request ( )
} ) ? ;
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
. await
. map_err ( | err | {
2021-02-09 04:48:53 -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 (
2021-05-09 21:16:04 -04:00
& mut self ,
2021-03-23 19:33:25 -04:00
params : SelectionRangeParams ,
) -> LspResult < Option < Vec < SelectionRange > > > {
2021-05-09 21:16:04 -04:00
let specifier = self . url_map . normalize_url ( & params . text_document . uri ) ;
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 ) ;
}
2021-06-02 06:29:58 -04:00
let mark = self . performance . mark ( " selection_range " , Some ( & params ) ) ;
2021-11-12 11:42:04 -05:00
let asset_or_doc = self . get_cached_asset_or_document ( & specifier ) ? ;
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 req = tsc ::RequestMethod ::GetSmartSelectionRange ( (
specifier . clone ( ) ,
line_index . offset_tsc ( position ) ? ,
) ) ;
let selection_range : tsc ::SelectionRange = self
. ts_server
2022-01-19 17:10:14 -05:00
. request ( self . snapshot ( ) , req )
2021-03-23 19:33:25 -04:00
. await
. map_err ( | err | {
error! ( " Failed to request to tsserver {} " , err ) ;
LspError ::invalid_request ( )
} ) ? ;
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 (
2021-05-09 21:16:04 -04:00
& mut self ,
2021-04-19 21:26:36 -04:00
params : SemanticTokensParams ,
) -> LspResult < Option < SemanticTokensResult > > {
2021-05-09 21:16:04 -04:00
let specifier = self . url_map . normalize_url ( & params . text_document . uri ) ;
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 21:26:36 -04:00
return Ok ( None ) ;
}
2021-06-02 06:29:58 -04:00
let mark = self . performance . mark ( " semantic_tokens_full " , Some ( & params ) ) ;
2021-11-12 11:42:04 -05:00
let asset_or_doc = self . get_cached_asset_or_document ( & specifier ) ? ;
let line_index = asset_or_doc . line_index ( ) ;
2021-04-19 21:26:36 -04:00
let req = tsc ::RequestMethod ::GetEncodedSemanticClassifications ( (
specifier . clone ( ) ,
tsc ::TextSpan {
start : 0 ,
length : line_index . text_content_length_utf16 ( ) . into ( ) ,
} ,
) ) ;
let semantic_classification : tsc ::Classifications = self
. ts_server
2022-01-19 17:10:14 -05:00
. request ( self . snapshot ( ) , req )
2021-04-19 21:26:36 -04:00
. await
. map_err ( | err | {
error! ( " Failed to request to tsserver {} " , err ) ;
LspError ::invalid_request ( )
} ) ? ;
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 (
2021-05-09 21:16:04 -04:00
& mut self ,
2021-04-19 21:26:36 -04:00
params : SemanticTokensRangeParams ,
) -> LspResult < Option < SemanticTokensRangeResult > > {
2021-05-09 21:16:04 -04:00
let specifier = self . url_map . normalize_url ( & params . text_document . uri ) ;
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 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
. mark ( " semantic_tokens_range " , Some ( & params ) ) ;
2021-11-12 11:42:04 -05:00
let asset_or_doc = self . get_cached_asset_or_document ( & specifier ) ? ;
let line_index = asset_or_doc . line_index ( ) ;
2021-04-19 21:26:36 -04:00
let start = line_index . offset_tsc ( params . range . start ) ? ;
let length = line_index . offset_tsc ( params . range . end ) ? - start ;
let req = tsc ::RequestMethod ::GetEncodedSemanticClassifications ( (
specifier . clone ( ) ,
tsc ::TextSpan { start , length } ,
) ) ;
let semantic_classification : tsc ::Classifications = self
. ts_server
2022-01-19 17:10:14 -05:00
. request ( self . snapshot ( ) , req )
2021-04-19 21:26:36 -04:00
. await
. map_err ( | err | {
error! ( " Failed to request to tsserver {} " , err ) ;
LspError ::invalid_request ( )
} ) ? ;
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 (
2021-05-09 21:16:04 -04:00
& mut self ,
2021-02-15 21:34:09 -05:00
params : SignatureHelpParams ,
) -> LspResult < Option < SignatureHelp > > {
2021-02-17 23:37:05 -05:00
let specifier = self
. url_map
. normalize_url ( & params . text_document_position_params . text_document . uri ) ;
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 . mark ( " signature_help " , Some ( & params ) ) ;
2021-11-12 11:42:04 -05:00
let asset_or_doc = self . get_cached_asset_or_document ( & specifier ) ? ;
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 ,
}
} ;
let req = tsc ::RequestMethod ::GetSignatureHelpItems ( (
specifier ,
line_index . offset_tsc ( params . text_document_position_params . position ) ? ,
options ,
) ) ;
2021-02-24 22:15:55 -05:00
let maybe_signature_help_items : Option < tsc ::SignatureHelpItems > = self
. ts_server
2022-01-19 17:10:14 -05:00
. request ( self . snapshot ( ) , req )
2021-02-24 22:15:55 -05:00
. await
. map_err ( | err | {
error! ( " Failed to request to tsserver: {} " , err ) ;
LspError ::invalid_request ( )
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
async fn symbol (
& mut self ,
params : WorkspaceSymbolParams ,
) -> LspResult < Option < Vec < SymbolInformation > > > {
let mark = self . performance . mark ( " symbol " , Some ( & params ) ) ;
let req = tsc ::RequestMethod ::GetNavigateToItems {
search : params . query ,
// this matches vscode's hard coded result count
max_result_count : Some ( 256 ) ,
file : None ,
} ;
let navigate_to_items : Vec < tsc ::NavigateToItem > = self
. ts_server
2022-01-19 17:10:14 -05:00
. request ( self . snapshot ( ) , req )
2021-11-22 19:08:56 -05:00
. await
. map_err ( | err | {
error! ( " Failed request to tsserver: {} " , err ) ;
LspError ::invalid_request ( )
} ) ? ;
let maybe_symbol_information = if navigate_to_items . is_empty ( ) {
None
} else {
let mut symbol_information = Vec ::new ( ) ;
for item in navigate_to_items {
if let Some ( info ) = item . to_symbol_information ( self ) . await {
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 ) {
let snapshot = (
self . snapshot ( ) ,
self . config . snapshot ( ) ,
self . maybe_lint_config . clone ( ) ,
) ;
if let Err ( err ) = self . diagnostics_server . update ( snapshot ) {
error! ( " Cannot update diagnostics: {} " , err ) ;
}
}
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 ( ) ) {
error! ( " Cannot update testing server: {} " , err ) ;
}
}
}
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 {
2021-01-26 04:55:04 -05:00
async fn initialize (
& self ,
params : InitializeParams ,
) -> LspResult < InitializeResult > {
2021-03-09 21:41:35 -05:00
let mut language_server = self . 0. lock ( ) . 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
}
async fn initialized ( & self , params : InitializedParams ) {
self . 0. lock ( ) . await . initialized ( params ) . await
}
async fn shutdown ( & self ) -> LspResult < ( ) > {
self . 0. lock ( ) . await . shutdown ( ) . await
}
async fn did_open ( & self , params : DidOpenTextDocumentParams ) {
2022-02-02 18:02:59 -05:00
if params . text_document . uri . scheme ( ) = = " deno " {
// 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 ;
}
2022-01-25 10:30:38 -05:00
let ( client , uri , specifier , had_specifier_settings ) = {
let mut inner = self . 0. lock ( ) . await ;
let client = inner . client . clone ( ) ;
let uri = params . text_document . uri . clone ( ) ;
let specifier = inner . url_map . normalize_url ( & uri ) ;
2022-02-02 18:02:59 -05:00
let document = inner . did_open ( & specifier , params ) . await ;
2022-01-25 10:30:38 -05:00
let has_specifier_settings =
inner . config . has_specifier_settings ( & specifier ) ;
2022-02-02 18:02:59 -05:00
if document . is_diagnosable ( ) {
let specifiers = inner . documents . dependents ( & specifier ) ;
inner . diagnostics_server . invalidate ( & specifiers ) ;
2022-03-20 21:33:37 -04:00
// don't send diagnostics yet if we don't have the specifier settings
2022-02-02 18:02:59 -05:00
if has_specifier_settings {
inner . send_diagnostics_update ( ) ;
2022-03-29 18:59:27 -04:00
inner . send_testing_update ( ) ;
2022-02-02 18:02:59 -05:00
}
}
2022-01-25 10:30:38 -05:00
( client , uri , specifier , has_specifier_settings )
} ;
// retrieve the specifier settings outside the lock if
// they haven't been asked for yet on its own time
if ! had_specifier_settings {
let language_server = self . clone ( ) ;
tokio ::spawn ( async move {
let response = client . specifier_configuration ( & uri ) . await ;
2022-02-02 18:02:59 -05:00
let mut inner = language_server . 0. lock ( ) . await ;
2022-01-25 10:30:38 -05:00
match response {
Ok ( specifier_settings ) = > {
2022-02-02 18:02:59 -05:00
// now update the config and send a diagnostics update
2022-01-25 10:30:38 -05:00
inner . config . set_specifier_settings (
2022-02-02 18:02:59 -05:00
specifier . clone ( ) ,
2022-01-25 10:30:38 -05:00
uri ,
specifier_settings ,
) ;
}
Err ( err ) = > {
error! ( " {} " , err ) ;
}
}
2022-02-02 18:02:59 -05:00
if inner
. documents
. get ( & specifier )
. map ( | d | d . is_diagnosable ( ) )
. unwrap_or ( false )
{
inner . send_diagnostics_update ( ) ;
2022-03-29 18:59:27 -04:00
inner . send_testing_update ( ) ;
2022-02-02 18:02:59 -05:00
}
2022-01-25 10:30:38 -05:00
} ) ;
}
2021-01-26 04:55:04 -05:00
}
async fn did_change ( & self , params : DidChangeTextDocumentParams ) {
self . 0. lock ( ) . await . did_change ( params ) . await
}
2021-02-09 17:46:12 -05:00
async fn did_save ( & self , _params : DidSaveTextDocumentParams ) {
// We don't need to do anything on save at the moment, but if this isn't
// implemented, lspower complains about it not being implemented.
}
2021-01-26 04:55:04 -05:00
async fn did_close ( & self , params : DidCloseTextDocumentParams ) {
self . 0. lock ( ) . await . did_close ( params ) . await
}
async fn did_change_configuration (
& self ,
params : DidChangeConfigurationParams ,
) {
2022-01-25 10:30:38 -05:00
let ( has_workspace_capability , client , specifiers , mark ) = {
let inner = self . 0. lock ( ) . await ;
let mark = inner
. performance
. mark ( " did_change_configuration " , Some ( & params ) ) ;
let specifiers =
if inner . config . client_capabilities . workspace_configuration {
Some ( inner . config . get_specifiers_with_client_uris ( ) )
} else {
None
} ;
(
inner . config . client_capabilities . workspace_configuration ,
inner . client . clone ( ) ,
specifiers ,
mark ,
)
} ;
2022-03-20 21:33:37 -04:00
// start retrieving all the specifiers' settings outside the lock on its own
// time
2022-01-25 10:30:38 -05:00
if let Some ( specifiers ) = specifiers {
let language_server = self . clone ( ) ;
let client = client . clone ( ) ;
tokio ::spawn ( async move {
if let Ok ( configs ) = client
. specifier_configurations (
2022-02-23 16:01:20 -05:00
specifiers . iter ( ) . map ( | s | s . client_uri . clone ( ) ) . collect ( ) ,
2022-01-25 10:30:38 -05:00
)
. await
{
let mut inner = language_server . 0. lock ( ) . await ;
for ( i , value ) in configs . into_iter ( ) . enumerate ( ) {
match value {
Ok ( specifier_settings ) = > {
let entry = specifiers [ i ] . clone ( ) ;
inner . config . set_specifier_settings (
entry . specifier ,
entry . client_uri ,
specifier_settings ,
) ;
}
Err ( err ) = > {
error! ( " {} " , err ) ;
}
}
}
}
2022-03-20 21:33:37 -04:00
let mut ls = language_server . 0. lock ( ) . await ;
if ls . config . update_enabled_paths ( client ) . await {
ls . diagnostics_server . invalidate_all ( ) ;
// this will be called in the inner did_change_configuration, but the
// problem then becomes, if there was a change, the snapshot used
// will be an out of date one, so we will call it again here if the
// workspace folders have been touched
ls . send_diagnostics_update ( ) ;
}
2022-01-25 10:30:38 -05:00
} ) ;
}
// Get the configuration from the client outside of the lock
// in order to prevent potential deadlocking scenarios where
// the server holds a lock and calls into the client, which
// calls into the server which deadlocks acquiring the lock.
// There is a gap here between when the configuration is
// received and acquiring the lock, but most likely there
// won't be any racing here.
let client_workspace_config = if has_workspace_capability {
let config_response = client . workspace_configuration ( ) . await ;
match config_response {
Ok ( value ) = > Some ( value ) ,
Err ( err ) = > {
error! ( " {} " , err ) ;
None
}
}
} else {
None
} ;
// now update the inner state
let mut inner = self . 0. lock ( ) . await ;
inner
. did_change_configuration ( client_workspace_config , params )
. await ;
inner . performance . measure ( mark ) ;
2021-01-26 04:55:04 -05:00
}
async fn did_change_watched_files (
& self ,
params : DidChangeWatchedFilesParams ,
) {
self . 0. lock ( ) . await . did_change_watched_files ( params ) . await
}
2022-03-20 21:33:37 -04:00
async fn did_change_workspace_folders (
& self ,
params : DidChangeWorkspaceFoldersParams ,
) {
let client = {
let mut inner = self . 0. lock ( ) . await ;
inner . did_change_workspace_folders ( params ) . await ;
inner . client . clone ( )
} ;
let language_server = self . clone ( ) ;
tokio ::spawn ( async move {
let mut ls = language_server . 0. lock ( ) . await ;
if ls . config . update_enabled_paths ( client ) . await {
ls . diagnostics_server . invalidate_all ( ) ;
ls . send_diagnostics_update ( ) ;
}
} ) ;
}
2021-04-19 21:29:27 -04:00
async fn document_symbol (
& self ,
params : DocumentSymbolParams ,
) -> LspResult < Option < DocumentSymbolResponse > > {
self . 0. lock ( ) . await . document_symbol ( params ) . await
}
2021-01-26 04:55:04 -05:00
async fn formatting (
& self ,
params : DocumentFormattingParams ,
) -> LspResult < Option < Vec < TextEdit > > > {
self . 0. lock ( ) . await . formatting ( params ) . await
}
async fn hover ( & self , params : HoverParams ) -> LspResult < Option < Hover > > {
self . 0. lock ( ) . await . hover ( params ) . await
}
2021-02-04 13:53:02 -05:00
async fn code_action (
& self ,
params : CodeActionParams ,
) -> LspResult < Option < CodeActionResponse > > {
self . 0. lock ( ) . await . code_action ( params ) . await
}
2021-02-05 15:10:53 -05:00
async fn code_action_resolve (
& self ,
params : CodeAction ,
) -> LspResult < CodeAction > {
self . 0. lock ( ) . await . code_action_resolve ( params ) . await
}
2021-01-31 22:30:41 -05:00
async fn code_lens (
& self ,
params : CodeLensParams ,
) -> LspResult < Option < Vec < CodeLens > > > {
self . 0. lock ( ) . await . code_lens ( params ) . await
}
async fn code_lens_resolve ( & self , params : CodeLens ) -> LspResult < CodeLens > {
self . 0. lock ( ) . await . code_lens_resolve ( params ) . await
}
2021-01-26 04:55:04 -05:00
async fn document_highlight (
& self ,
params : DocumentHighlightParams ,
) -> LspResult < Option < Vec < DocumentHighlight > > > {
self . 0. lock ( ) . await . document_highlight ( params ) . await
}
async fn references (
& self ,
params : ReferenceParams ,
) -> LspResult < Option < Vec < Location > > > {
self . 0. lock ( ) . await . references ( params ) . await
}
async fn goto_definition (
& self ,
params : GotoDefinitionParams ,
) -> LspResult < Option < GotoDefinitionResponse > > {
self . 0. lock ( ) . await . goto_definition ( params ) . await
}
2021-11-22 19:09:19 -05:00
async fn goto_type_definition (
& self ,
params : GotoTypeDefinitionParams ,
) -> LspResult < Option < GotoTypeDefinitionResponse > > {
self . 0. lock ( ) . await . goto_type_definition ( params ) . await
}
2021-01-26 04:55:04 -05:00
async fn completion (
& self ,
params : CompletionParams ,
) -> LspResult < Option < CompletionResponse > > {
self . 0. lock ( ) . await . completion ( params ) . await
}
2021-03-15 18:01:41 -04:00
async fn completion_resolve (
& self ,
params : CompletionItem ,
) -> LspResult < CompletionItem > {
self . 0. lock ( ) . await . completion_resolve ( params ) . await
}
2021-01-26 04:55:04 -05:00
async fn goto_implementation (
& self ,
params : GotoImplementationParams ,
) -> LspResult < Option < GotoImplementationResponse > > {
self . 0. lock ( ) . await . goto_implementation ( params ) . await
}
2021-04-02 02:21:07 -04:00
async fn folding_range (
& self ,
params : FoldingRangeParams ,
) -> LspResult < Option < Vec < FoldingRange > > > {
self . 0. lock ( ) . await . folding_range ( params ) . await
}
2021-04-19 01:11:26 -04:00
async fn incoming_calls (
& self ,
params : CallHierarchyIncomingCallsParams ,
) -> LspResult < Option < Vec < CallHierarchyIncomingCall > > > {
self . 0. lock ( ) . await . incoming_calls ( params ) . await
}
async fn outgoing_calls (
& self ,
params : CallHierarchyOutgoingCallsParams ,
) -> LspResult < Option < Vec < CallHierarchyOutgoingCall > > > {
self . 0. lock ( ) . await . outgoing_calls ( params ) . await
}
async fn prepare_call_hierarchy (
& self ,
params : CallHierarchyPrepareParams ,
) -> LspResult < Option < Vec < CallHierarchyItem > > > {
self . 0. lock ( ) . await . prepare_call_hierarchy ( params ) . await
}
2021-01-26 04:55:04 -05:00
async fn rename (
& self ,
params : RenameParams ,
) -> LspResult < Option < WorkspaceEdit > > {
self . 0. lock ( ) . await . rename ( params ) . await
}
2021-03-23 19:33:25 -04:00
async fn selection_range (
& self ,
params : SelectionRangeParams ,
) -> LspResult < Option < Vec < SelectionRange > > > {
self . 0. lock ( ) . await . selection_range ( params ) . await
}
2021-04-19 21:26:36 -04:00
async fn semantic_tokens_full (
& self ,
params : SemanticTokensParams ,
) -> LspResult < Option < SemanticTokensResult > > {
self . 0. lock ( ) . await . semantic_tokens_full ( params ) . await
}
async fn semantic_tokens_range (
& self ,
params : SemanticTokensRangeParams ,
) -> LspResult < Option < SemanticTokensRangeResult > > {
self . 0. lock ( ) . await . semantic_tokens_range ( params ) . await
}
2021-02-15 21:34:09 -05:00
async fn signature_help (
& self ,
params : SignatureHelpParams ,
) -> LspResult < Option < SignatureHelp > > {
self . 0. lock ( ) . await . signature_help ( params ) . await
}
2021-11-22 19:08:56 -05:00
async fn symbol (
& self ,
params : WorkspaceSymbolParams ,
) -> LspResult < Option < Vec < SymbolInformation > > > {
self . 0. lock ( ) . await . symbol ( params ) . await
}
2021-01-26 04:55:04 -05:00
}
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 {
2021-02-11 23:17:48 -05:00
/// Similar to `deno cache` on the command line, where modules will be cached
/// in the Deno cache, including any of their dependencies.
2021-06-01 07:53:08 -04:00
async fn cache (
& mut self ,
params : lsp_custom ::CacheParams ,
) -> LspResult < Option < Value > > {
2021-02-17 23:37:05 -05:00
let referrer = self . url_map . normalize_url ( & params . referrer . uri ) ;
2021-10-28 19:56:01 -04:00
if ! self . is_diagnosable ( & referrer ) {
2021-06-02 06:29:58 -04:00
return Ok ( None ) ;
}
let mark = self . performance . mark ( " cache " , Some ( & params ) ) ;
2021-10-10 17:26:22 -04:00
let roots = if ! params . uris . is_empty ( ) {
params
. uris
. iter ( )
2022-01-31 17:33:57 -05:00
. map ( | t | {
(
self . url_map . normalize_url ( & t . uri ) ,
deno_graph ::ModuleKind ::Esm ,
)
} )
2021-10-10 17:26:22 -04:00
. collect ( )
2021-06-21 17:18:32 -04:00
} else {
2022-01-31 17:33:57 -05:00
vec! [ ( referrer . clone ( ) , deno_graph ::ModuleKind ::Esm ) ]
2021-10-10 17:26:22 -04:00
} ;
if self . maybe_cache_server . is_none ( ) {
self . maybe_cache_server = Some (
2022-02-01 21:04:26 -05:00
cache ::CacheServer ::new (
2021-10-10 17:26:22 -04:00
self . maybe_cache_path . clone ( ) ,
self . maybe_import_map . clone ( ) ,
2021-11-08 20:26:39 -05:00
self . maybe_config_file . clone ( ) ,
2022-01-23 19:27:52 -05:00
None ,
None ,
None ,
2021-10-10 17:26:22 -04:00
)
. await ,
) ;
2020-12-29 23:17:17 -05:00
}
2021-10-10 17:26:22 -04:00
let cache_server = self . maybe_cache_server . as_ref ( ) . unwrap ( ) ;
if let Err ( err ) = cache_server . cache ( roots ) . await {
2021-11-24 20:10:12 -05:00
self . client . show_message ( MessageType ::WARNING , err ) . await ;
2021-10-10 17:26:22 -04:00
}
2021-02-11 23:17:48 -05:00
// now that we have dependencies loaded, we need to re-analyze them and
// invalidate some diagnostics
2022-02-02 18:02:59 -05:00
self . diagnostics_server . invalidate ( & [ referrer ] ) ;
self . send_diagnostics_update ( ) ;
2022-03-29 18:59:27 -04:00
self . send_testing_update ( ) ;
2021-02-11 23:17:48 -05:00
2021-01-26 19:32:49 -05:00
self . performance . measure ( mark ) ;
2021-04-08 21:27:27 -04:00
Ok ( Some ( json! ( true ) ) )
2020-12-29 23:17:17 -05:00
}
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
}
2022-03-28 20:27:43 -04:00
fn get_tasks ( & self ) -> LspResult < Option < Value > > {
Ok (
self
. maybe_config_file
. as_ref ( )
. and_then ( | cf | cf . to_lsp_tasks ( ) ) ,
)
}
2021-04-08 21:27:27 -04:00
async fn reload_import_registries ( & mut self ) -> LspResult < Option < Value > > {
2021-06-25 21:44:27 -04:00
fs_util ::remove_dir_all_if_exists ( & self . module_registries_location )
2021-04-08 21:27:27 -04:00
. await
. map_err ( | err | {
error! ( " Unable to remove registries cache: {} " , err ) ;
LspError ::internal_error ( )
} ) ? ;
self . update_registries ( ) . await . map_err ( | err | {
error! ( " Unable to update registries: {} " , err ) ;
LspError ::internal_error ( )
} ) ? ;
Ok ( Some ( json! ( true ) ) )
}
2020-12-21 08:44:26 -05:00
async fn virtual_text_document (
2021-02-06 07:39:01 -05:00
& mut 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
. mark ( " virtual_text_document " , Some ( & params ) ) ;
2021-02-17 23:37:05 -05:00
let specifier = self . url_map . normalize_url ( & params . text_document . uri ) ;
2021-02-17 13:47:18 -05:00
let contents = if specifier . as_str ( ) = = " deno:/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
. documents ( false , false )
. 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 ( ) ;
2021-07-20 21:50:43 -04:00
let workspace_settings = self . config . get_workspace_settings ( ) ;
2021-01-26 19:32:49 -05:00
contents . push_str ( & format! (
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 - " )
2021-01-26 19:32:49 -05:00
) ) ;
2021-04-19 17:10:43 -04:00
contents
. push_str ( " \n ## Performance \n \n |Name|Duration|Count| \n |---|---|---| \n " ) ;
let mut averages = self . performance . averages ( ) ;
averages . sort ( ) ;
for average in averages {
2021-01-26 19:32:49 -05:00
contents . push_str ( & format! (
2021-04-19 17:10:43 -04:00
" |{}|{}ms|{}| \n " ,
2021-01-26 19:32:49 -05:00
average . name , average . average_duration , average . count
) ) ;
}
Some ( contents )
2020-12-21 08:44:26 -05:00
} else {
2021-11-12 11:42:04 -05:00
let asset_or_doc = self
. get_maybe_asset_or_document ( & specifier )
. await
. map_err ( | _ | LspError ::internal_error ( ) ) ? ;
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 )
}
}