summaryrefslogtreecommitdiff
path: root/cli/lsp/language_server.rs
diff options
context:
space:
mode:
authorBen Noordhuis <info@bnoordhuis.nl>2021-01-26 10:55:04 +0100
committerGitHub <noreply@github.com>2021-01-26 10:55:04 +0100
commit2828690fc7bb510c3248dda7b1cda8793e789ca6 (patch)
tree96ca85ab8ae9a2d60679729cc161539c3900a386 /cli/lsp/language_server.rs
parent2823c02e434577393cf0575d4ad9116da1076b17 (diff)
fix(lsp): fix deadlocks, use one big mutex (#9271)
The LSP code had numerous places where competing threads could take out out locks in different orders, making it very prone to deadlocks. This commit sidesteps the entire issue by switching to a single lock. The above is a little white lie: the Sources struct still uses a mutex internally to avoid having to boil the ocean (because being honest about what it does involves changing all its methods to `&mut self` but that ripples out extensively...) I'll save that one for another day.
Diffstat (limited to 'cli/lsp/language_server.rs')
-rw-r--r--cli/lsp/language_server.rs439
1 files changed, 268 insertions, 171 deletions
diff --git a/cli/lsp/language_server.rs b/cli/lsp/language_server.rs
index 2ccbb6284..21a229b47 100644
--- a/cli/lsp/language_server.rs
+++ b/cli/lsp/language_server.rs
@@ -18,7 +18,6 @@ use std::collections::HashMap;
use std::env;
use std::path::PathBuf;
use std::sync::Arc;
-use std::sync::Mutex;
use tokio::fs;
use crate::deno_dir;
@@ -42,35 +41,44 @@ use super::tsc::TsServer;
use super::utils;
#[derive(Debug, Clone)]
-pub struct LanguageServer {
- assets: Arc<Mutex<HashMap<ModuleSpecifier, Option<AssetDocument>>>>,
- client: Client,
- ts_server: TsServer,
- config: Arc<Mutex<Config>>,
- documents: Arc<Mutex<DocumentCache>>,
- sources: Arc<Mutex<Sources>>,
- diagnostics: Arc<Mutex<DiagnosticCollection>>,
- maybe_config_uri: Arc<Mutex<Option<Url>>>,
- maybe_import_map: Arc<Mutex<Option<ImportMap>>>,
- maybe_import_map_uri: Arc<Mutex<Option<Url>>>,
-}
+pub struct LanguageServer(Arc<tokio::sync::Mutex<Inner>>);
#[derive(Debug, Clone, Default)]
pub struct StateSnapshot {
- pub assets: Arc<Mutex<HashMap<ModuleSpecifier, Option<AssetDocument>>>>,
+ pub assets: HashMap<ModuleSpecifier, Option<AssetDocument>>,
pub documents: DocumentCache,
- pub sources: Arc<Mutex<Sources>>,
+ pub sources: Sources,
+}
+
+#[derive(Debug)]
+struct Inner {
+ assets: HashMap<ModuleSpecifier, Option<AssetDocument>>,
+ client: Client,
+ ts_server: TsServer,
+ config: Config,
+ documents: DocumentCache,
+ sources: Sources,
+ diagnostics: DiagnosticCollection,
+ maybe_config_uri: Option<Url>,
+ maybe_import_map: Option<ImportMap>,
+ maybe_import_map_uri: Option<Url>,
}
impl LanguageServer {
pub fn new(client: Client) -> Self {
+ Self(Arc::new(tokio::sync::Mutex::new(Inner::new(client))))
+ }
+}
+
+impl Inner {
+ fn new(client: Client) -> Self {
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");
let location = dir.root.join("deps");
- let sources = Arc::new(Mutex::new(Sources::new(&location)));
+ let sources = Sources::new(&location);
- LanguageServer {
+ Self {
assets: Default::default(),
client,
ts_server: TsServer::new(),
@@ -85,20 +93,18 @@ impl LanguageServer {
}
fn enabled(&self) -> bool {
- let config = self.config.lock().unwrap();
- config.settings.enable
+ self.config.settings.enable
}
/// Searches assets, open documents and external sources for a line_index,
/// which might be performed asynchronously, hydrating in memory caches for
/// subsequent requests.
- pub async fn get_line_index(
+ async fn get_line_index(
&self,
specifier: ModuleSpecifier,
) -> Result<LineIndex, AnyError> {
if specifier.as_url().scheme() == "asset" {
- let maybe_asset =
- { self.assets.lock().unwrap().get(&specifier).cloned() };
+ let maybe_asset = self.assets.get(&specifier).cloned();
if let Some(maybe_asset) = maybe_asset {
if let Some(asset) = maybe_asset {
Ok(asset.line_index)
@@ -106,22 +112,19 @@ impl LanguageServer {
Err(anyhow!("asset is missing: {}", specifier))
}
} else {
- let state_snapshot = self.snapshot();
+ let mut state_snapshot = self.snapshot();
if let Some(asset) =
- tsc::get_asset(&specifier, &self.ts_server, &state_snapshot).await?
+ tsc::get_asset(&specifier, &self.ts_server, &mut state_snapshot)
+ .await?
{
Ok(asset.line_index)
} else {
Err(anyhow!("asset is missing: {}", specifier))
}
}
- } else if let Some(line_index) =
- self.documents.lock().unwrap().line_index(&specifier)
- {
+ } else if let Some(line_index) = self.documents.line_index(&specifier) {
Ok(line_index)
- } else if let Some(line_index) =
- self.sources.lock().unwrap().get_line_index(&specifier)
- {
+ } else if let Some(line_index) = self.sources.get_line_index(&specifier) {
Ok(line_index)
} else {
Err(anyhow!("Unable to find line index for: {}", specifier))
@@ -130,124 +133,129 @@ impl LanguageServer {
/// Only searches already cached assets and documents for a line index. If
/// the line index cannot be found, `None` is returned.
- pub fn get_line_index_sync(
+ fn get_line_index_sync(
&self,
specifier: &ModuleSpecifier,
) -> Option<LineIndex> {
if specifier.as_url().scheme() == "asset" {
- if let Some(Some(asset)) = self.assets.lock().unwrap().get(specifier) {
+ if let Some(Some(asset)) = self.assets.get(specifier) {
Some(asset.line_index.clone())
} else {
None
}
} else {
- let documents = self.documents.lock().unwrap();
+ let documents = &self.documents;
if documents.contains(specifier) {
documents.line_index(specifier)
} else {
- self.sources.lock().unwrap().get_line_index(specifier)
+ self.sources.get_line_index(specifier)
}
}
}
- async fn prepare_diagnostics(&self) -> Result<(), AnyError> {
+ async fn prepare_diagnostics(&mut self) -> Result<(), AnyError> {
let (enabled, lint_enabled) = {
- let config = self.config.lock().unwrap();
+ let config = &self.config;
(config.settings.enable, config.settings.lint)
};
let lint = async {
- let mut disturbed = false;
+ let mut diagnostics = None;
if lint_enabled {
- let diagnostic_collection = self.diagnostics.lock().unwrap().clone();
- let diagnostics = diagnostics::generate_lint_diagnostics(
- self.snapshot(),
- diagnostic_collection,
- )
- .await;
- disturbed = !diagnostics.is_empty();
- {
- let mut diagnostics_collection = self.diagnostics.lock().unwrap();
- for (specifier, version, diagnostics) in diagnostics {
- diagnostics_collection.set(
- specifier,
- DiagnosticSource::Lint,
- version,
- diagnostics,
- );
- }
- }
+ diagnostics = Some(
+ diagnostics::generate_lint_diagnostics(
+ self.snapshot(),
+ self.diagnostics.clone(),
+ )
+ .await,
+ );
};
- Ok::<bool, AnyError>(disturbed)
+ Ok::<_, AnyError>(diagnostics)
};
let ts = async {
- let mut disturbed = false;
+ let mut diagnostics = None;
if enabled {
- let diagnostics_collection = self.diagnostics.lock().unwrap().clone();
- let diagnostics = diagnostics::generate_ts_diagnostics(
- self.snapshot(),
- diagnostics_collection,
- &self.ts_server,
- )
- .await?;
- disturbed = !diagnostics.is_empty();
- {
- let mut diagnostics_collection = self.diagnostics.lock().unwrap();
- for (specifier, version, diagnostics) in diagnostics {
- diagnostics_collection.set(
- specifier,
- DiagnosticSource::TypeScript,
- version,
- diagnostics,
- );
- }
- }
+ diagnostics = Some(
+ diagnostics::generate_ts_diagnostics(
+ self.snapshot(),
+ self.diagnostics.clone(),
+ &self.ts_server,
+ )
+ .await?,
+ );
};
- Ok::<bool, AnyError>(disturbed)
+ Ok::<_, AnyError>(diagnostics)
};
let deps = async {
- let mut disturbed = false;
+ let mut diagnostics = None;
if enabled {
- let diagnostics_collection = self.diagnostics.lock().unwrap().clone();
- let diagnostics = diagnostics::generate_dependency_diagnostics(
- self.snapshot(),
- diagnostics_collection,
- )
- .await?;
- disturbed = !diagnostics.is_empty();
- {
- let mut diagnostics_collection = self.diagnostics.lock().unwrap();
- for (specifier, version, diagnostics) in diagnostics {
- diagnostics_collection.set(
- specifier,
- DiagnosticSource::Deno,
- version,
- diagnostics,
- );
- }
- }
+ diagnostics = Some(
+ diagnostics::generate_dependency_diagnostics(
+ self.snapshot(),
+ self.diagnostics.clone(),
+ )
+ .await?,
+ );
};
- Ok::<bool, AnyError>(disturbed)
+ Ok::<_, AnyError>(diagnostics)
};
let (lint_res, ts_res, deps_res) = tokio::join!(lint, ts, deps);
- if lint_res? || ts_res? || deps_res? {
+ let mut disturbed = false;
+
+ if let Some(diagnostics) = lint_res? {
+ for (specifier, version, diagnostics) in diagnostics {
+ self.diagnostics.set(
+ specifier,
+ DiagnosticSource::Lint,
+ version,
+ diagnostics,
+ );
+ disturbed = true;
+ }
+ }
+
+ if let Some(diagnostics) = ts_res? {
+ for (specifier, version, diagnostics) in diagnostics {
+ self.diagnostics.set(
+ specifier,
+ DiagnosticSource::TypeScript,
+ version,
+ diagnostics,
+ );
+ disturbed = true;
+ }
+ }
+
+ if let Some(diagnostics) = deps_res? {
+ for (specifier, version, diagnostics) in diagnostics {
+ self.diagnostics.set(
+ specifier,
+ DiagnosticSource::Deno,
+ version,
+ diagnostics,
+ );
+ disturbed = true;
+ }
+ }
+
+ if disturbed {
self.publish_diagnostics().await?;
}
Ok(())
}
- async fn publish_diagnostics(&self) -> Result<(), AnyError> {
+ async fn publish_diagnostics(&mut self) -> Result<(), AnyError> {
let (maybe_changes, diagnostics_collection) = {
- let mut diagnostics_collection = self.diagnostics.lock().unwrap();
+ let diagnostics_collection = &mut self.diagnostics;
let maybe_changes = diagnostics_collection.take_changes();
(maybe_changes, diagnostics_collection.clone())
};
if let Some(diagnostic_changes) = maybe_changes {
- let settings = self.config.lock().unwrap().settings.clone();
+ let settings = self.config.settings.clone();
for specifier in diagnostic_changes {
// TODO(@kitsonk) not totally happy with the way we collect and store
// different types of diagnostics and offer them up to the client, we
@@ -275,7 +283,7 @@ impl LanguageServer {
);
}
let uri = specifier.as_url().clone();
- let version = self.documents.lock().unwrap().version(&specifier);
+ let version = self.documents.version(&specifier);
self
.client
.publish_diagnostics(uri, diagnostics, version)
@@ -286,17 +294,17 @@ impl LanguageServer {
Ok(())
}
- pub fn snapshot(&self) -> StateSnapshot {
+ fn snapshot(&self) -> StateSnapshot {
StateSnapshot {
assets: self.assets.clone(),
- documents: self.documents.lock().unwrap().clone(),
+ documents: self.documents.clone(),
sources: self.sources.clone(),
}
}
- pub async fn update_import_map(&self) -> Result<(), AnyError> {
+ async fn update_import_map(&mut self) -> Result<(), AnyError> {
let (maybe_import_map, maybe_root_uri) = {
- let config = self.config.lock().unwrap();
+ let config = &self.config;
(config.settings.import_map.clone(), config.root_uri.clone())
};
if let Some(import_map_str) = &maybe_import_map {
@@ -331,15 +339,15 @@ impl LanguageServer {
})?;
let import_map =
ImportMap::from_json(&import_map_url.to_string(), &import_map_json)?;
- *self.maybe_import_map_uri.lock().unwrap() = Some(import_map_url);
- *self.maybe_import_map.lock().unwrap() = Some(import_map);
+ self.maybe_import_map_uri = Some(import_map_url);
+ self.maybe_import_map = Some(import_map);
} else {
- *self.maybe_import_map.lock().unwrap() = None;
+ self.maybe_import_map = None;
}
Ok(())
}
- async fn update_tsconfig(&self) -> Result<(), AnyError> {
+ async fn update_tsconfig(&mut self) -> Result<(), AnyError> {
let mut tsconfig = TsConfig::new(json!({
"allowJs": true,
"experimentalDecorators": true,
@@ -351,7 +359,7 @@ impl LanguageServer {
"target": "esnext",
}));
let (maybe_config, maybe_root_uri) = {
- let config = self.config.lock().unwrap();
+ let config = &self.config;
if config.settings.unstable {
let unstable_libs = json!({
"lib": ["deno.ns", "deno.window", "deno.unstable"]
@@ -394,7 +402,7 @@ impl LanguageServer {
let (value, maybe_ignored_options) =
parse_config(&config_text, &config_path)?;
tsconfig.merge(&value);
- *self.maybe_config_uri.lock().unwrap() = Some(config_url);
+ self.maybe_config_uri = Some(config_url);
if let Some(ignored_options) = maybe_ignored_options {
// TODO(@kitsonk) turn these into diagnostics that can be sent to the
// client
@@ -409,10 +417,10 @@ impl LanguageServer {
}
}
-#[lspower::async_trait]
-impl lspower::LanguageServer for LanguageServer {
+// lspower::LanguageServer methods. This file's LanguageServer delegates to us.
+impl Inner {
async fn initialize(
- &self,
+ &mut self,
params: InitializeParams,
) -> LspResult<InitializeResult> {
info!("Starting Deno language server...");
@@ -441,7 +449,7 @@ impl lspower::LanguageServer for LanguageServer {
}
{
- let mut config = self.config.lock().unwrap();
+ let config = &mut self.config;
config.root_uri = params.root_uri;
if let Some(value) = params.initialization_options {
config.update(value)?;
@@ -459,7 +467,7 @@ impl lspower::LanguageServer for LanguageServer {
})
}
- async fn initialized(&self, _: InitializedParams) {
+ async fn initialized(&mut self, _: InitializedParams) {
// Check to see if we need to setup the import map
if let Err(err) = self.update_import_map().await {
self
@@ -470,8 +478,6 @@ impl lspower::LanguageServer for LanguageServer {
if self
.config
- .lock()
- .unwrap()
.client_capabilities
.workspace_did_change_watched_files
{
@@ -506,7 +512,7 @@ impl lspower::LanguageServer for LanguageServer {
Ok(())
}
- async fn did_open(&self, params: DidOpenTextDocumentParams) {
+ async fn did_open(&mut self, params: DidOpenTextDocumentParams) {
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
@@ -514,16 +520,14 @@ impl lspower::LanguageServer for LanguageServer {
return;
}
let specifier = utils::normalize_url(params.text_document.uri);
- self.documents.lock().unwrap().open(
+ self.documents.open(
specifier.clone(),
params.text_document.version,
params.text_document.text,
);
if let Err(err) = self
.documents
- .lock()
- .unwrap()
- .analyze_dependencies(&specifier, &self.maybe_import_map.lock().unwrap())
+ .analyze_dependencies(&specifier, &self.maybe_import_map)
{
error!("{}", err);
}
@@ -534,9 +538,9 @@ impl lspower::LanguageServer for LanguageServer {
}
}
- async fn did_change(&self, params: DidChangeTextDocumentParams) {
+ async fn did_change(&mut self, params: DidChangeTextDocumentParams) {
let specifier = utils::normalize_url(params.text_document.uri);
- if let Err(err) = self.documents.lock().unwrap().change(
+ if let Err(err) = self.documents.change(
&specifier,
params.text_document.version,
params.content_changes,
@@ -545,9 +549,7 @@ impl lspower::LanguageServer for LanguageServer {
}
if let Err(err) = self
.documents
- .lock()
- .unwrap()
- .analyze_dependencies(&specifier, &self.maybe_import_map.lock().unwrap())
+ .analyze_dependencies(&specifier, &self.maybe_import_map)
{
error!("{}", err);
}
@@ -558,7 +560,7 @@ impl lspower::LanguageServer for LanguageServer {
}
}
- async fn did_close(&self, params: DidCloseTextDocumentParams) {
+ async fn did_close(&mut self, params: DidCloseTextDocumentParams) {
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
@@ -566,7 +568,7 @@ impl lspower::LanguageServer for LanguageServer {
return;
}
let specifier = utils::normalize_url(params.text_document.uri);
- self.documents.lock().unwrap().close(&specifier);
+ self.documents.close(&specifier);
// TODO(@kitsonk): how to better lazily do this?
if let Err(err) = self.prepare_diagnostics().await {
@@ -579,16 +581,10 @@ impl lspower::LanguageServer for LanguageServer {
}
async fn did_change_configuration(
- &self,
+ &mut self,
params: DidChangeConfigurationParams,
) {
- let config = if self
- .config
- .lock()
- .unwrap()
- .client_capabilities
- .workspace_configuration
- {
+ let config = if self.config.client_capabilities.workspace_configuration {
self
.client
.configuration(vec![ConfigurationItem {
@@ -611,7 +607,7 @@ impl lspower::LanguageServer for LanguageServer {
};
if let Some(config) = config {
- if let Err(err) = self.config.lock().unwrap().update(config) {
+ if let Err(err) = self.config.update(config) {
error!("failed to update settings: {}", err);
}
if let Err(err) = self.update_import_map().await {
@@ -632,14 +628,12 @@ impl lspower::LanguageServer for LanguageServer {
}
async fn did_change_watched_files(
- &self,
+ &mut self,
params: DidChangeWatchedFilesParams,
) {
// if the current import map has changed, we need to reload it
- let maybe_import_map_uri =
- self.maybe_import_map_uri.lock().unwrap().clone();
- if let Some(import_map_uri) = maybe_import_map_uri {
- if params.changes.iter().any(|fe| import_map_uri == fe.uri) {
+ if let Some(import_map_uri) = &self.maybe_import_map_uri {
+ if params.changes.iter().any(|fe| *import_map_uri == fe.uri) {
if let Err(err) = self.update_import_map().await {
self
.client
@@ -649,9 +643,8 @@ impl lspower::LanguageServer for LanguageServer {
}
}
// if the current tsconfig has changed, we need to reload it
- let maybe_config_uri = self.maybe_config_uri.lock().unwrap().clone();
- if let Some(config_uri) = maybe_config_uri {
- if params.changes.iter().any(|fe| config_uri == fe.uri) {
+ if let Some(config_uri) = &self.maybe_config_uri {
+ if params.changes.iter().any(|fe| *config_uri == fe.uri) {
if let Err(err) = self.update_tsconfig().await {
self
.client
@@ -669,8 +662,6 @@ impl lspower::LanguageServer for LanguageServer {
let specifier = utils::normalize_url(params.text_document.uri.clone());
let file_text = self
.documents
- .lock()
- .unwrap()
.content(&specifier)
.map_err(|_| {
LspError::invalid_params(
@@ -793,7 +784,7 @@ impl lspower::LanguageServer for LanguageServer {
}
async fn references(
- &self,
+ &mut self,
params: ReferenceParams,
) -> LspResult<Option<Vec<Location>>> {
if !self.enabled() {
@@ -842,7 +833,7 @@ impl lspower::LanguageServer for LanguageServer {
}
async fn goto_definition(
- &self,
+ &mut self,
params: GotoDefinitionParams,
) -> LspResult<Option<GotoDefinitionResponse>> {
if !self.enabled() {
@@ -1038,7 +1029,7 @@ impl lspower::LanguageServer for LanguageServer {
.into_workspace_edit(
&params.new_name,
|s| self.get_line_index(s),
- |s| self.documents.lock().unwrap().version(&s),
+ |s| self.documents.version(&s),
)
.await
.map_err(|err| {
@@ -1052,7 +1043,7 @@ impl lspower::LanguageServer for LanguageServer {
}
async fn request_else(
- &self,
+ &mut self,
method: &str,
params: Option<Value>,
) -> LspResult<Option<Value>> {
@@ -1089,30 +1080,139 @@ impl lspower::LanguageServer for LanguageServer {
}
}
+#[lspower::async_trait]
+impl lspower::LanguageServer for LanguageServer {
+ async fn initialize(
+ &self,
+ params: InitializeParams,
+ ) -> LspResult<InitializeResult> {
+ self.0.lock().await.initialize(params).await
+ }
+
+ 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) {
+ self.0.lock().await.did_open(params).await
+ }
+
+ async fn did_change(&self, params: DidChangeTextDocumentParams) {
+ self.0.lock().await.did_change(params).await
+ }
+
+ async fn did_close(&self, params: DidCloseTextDocumentParams) {
+ self.0.lock().await.did_close(params).await
+ }
+
+ async fn did_save(&self, params: DidSaveTextDocumentParams) {
+ self.0.lock().await.did_save(params).await
+ }
+
+ async fn did_change_configuration(
+ &self,
+ params: DidChangeConfigurationParams,
+ ) {
+ self.0.lock().await.did_change_configuration(params).await
+ }
+
+ async fn did_change_watched_files(
+ &self,
+ params: DidChangeWatchedFilesParams,
+ ) {
+ self.0.lock().await.did_change_watched_files(params).await
+ }
+
+ 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
+ }
+
+ 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
+ }
+
+ async fn completion(
+ &self,
+ params: CompletionParams,
+ ) -> LspResult<Option<CompletionResponse>> {
+ self.0.lock().await.completion(params).await
+ }
+
+ async fn goto_implementation(
+ &self,
+ params: GotoImplementationParams,
+ ) -> LspResult<Option<GotoImplementationResponse>> {
+ self.0.lock().await.goto_implementation(params).await
+ }
+
+ async fn rename(
+ &self,
+ params: RenameParams,
+ ) -> LspResult<Option<WorkspaceEdit>> {
+ self.0.lock().await.rename(params).await
+ }
+
+ async fn request_else(
+ &self,
+ method: &str,
+ params: Option<Value>,
+ ) -> LspResult<Option<Value>> {
+ self.0.lock().await.request_else(method, params).await
+ }
+}
+
#[derive(Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
-pub struct CacheParams {
- pub text_document: TextDocumentIdentifier,
+struct CacheParams {
+ text_document: TextDocumentIdentifier,
}
#[derive(Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase")]
-pub struct VirtualTextDocumentParams {
- pub text_document: TextDocumentIdentifier,
+struct VirtualTextDocumentParams {
+ text_document: TextDocumentIdentifier,
}
-impl LanguageServer {
- async fn cache(&self, params: CacheParams) -> LspResult<bool> {
+impl Inner {
+ async fn cache(&mut self, params: CacheParams) -> LspResult<bool> {
let specifier = utils::normalize_url(params.text_document.uri);
- let maybe_import_map = self.maybe_import_map.lock().unwrap().clone();
+ let maybe_import_map = self.maybe_import_map.clone();
sources::cache(specifier.clone(), maybe_import_map)
.await
.map_err(|err| {
error!("{}", err);
LspError::internal_error()
})?;
- if self.documents.lock().unwrap().contains(&specifier) {
- self.diagnostics.lock().unwrap().invalidate(&specifier);
+ if self.documents.contains(&specifier) {
+ self.diagnostics.invalidate(&specifier);
}
self.prepare_diagnostics().await.map_err(|err| {
error!("{}", err);
@@ -1128,20 +1228,18 @@ impl LanguageServer {
let specifier = utils::normalize_url(params.text_document.uri);
let url = specifier.as_url();
let contents = if url.as_str() == "deno:/status.md" {
- let documents = self.documents.lock().unwrap();
Some(format!(
r#"# Deno Language Server Status
- Documents in memory: {}
"#,
- documents.len()
+ self.documents.len()
))
} else {
match url.scheme() {
"asset" => {
- let maybe_asset =
- { self.assets.lock().unwrap().get(&specifier).cloned() };
+ let maybe_asset = self.assets.get(&specifier).cloned();
if let Some(maybe_asset) = maybe_asset {
if let Some(asset) = maybe_asset {
Some(asset.text)
@@ -1149,9 +1247,9 @@ impl LanguageServer {
None
}
} else {
- let state_snapshot = self.snapshot();
+ let mut state_snapshot = self.snapshot();
if let Some(asset) =
- tsc::get_asset(&specifier, &self.ts_server, &state_snapshot)
+ tsc::get_asset(&specifier, &self.ts_server, &mut state_snapshot)
.await
.map_err(|_| LspError::internal_error())?
{
@@ -1163,8 +1261,7 @@ impl LanguageServer {
}
}
_ => {
- let mut sources = self.sources.lock().unwrap();
- if let Some(text) = sources.get_text(&specifier) {
+ if let Some(text) = self.sources.get_text(&specifier) {
Some(text)
} else {
error!("The cached sources was not found: {}", specifier);