mirror of
https://github.com/denoland/deno.git
synced 2025-09-25 11:49:11 +00:00
perf(lsp): lazily start the ts server (#28392)
This commit is contained in:
parent
e579440170
commit
0ef3f6ba88
4 changed files with 86 additions and 60 deletions
|
@ -2022,7 +2022,6 @@ let c: number = "a";
|
||||||
.await;
|
.await;
|
||||||
let snapshot = Arc::new(snapshot);
|
let snapshot = Arc::new(snapshot);
|
||||||
let ts_server = TsServer::new(Default::default());
|
let ts_server = TsServer::new(Default::default());
|
||||||
ts_server.start(None).unwrap();
|
|
||||||
|
|
||||||
// test enabled
|
// test enabled
|
||||||
{
|
{
|
||||||
|
|
|
@ -213,9 +213,7 @@ pub struct Inner {
|
||||||
registered_semantic_tokens_capabilities: bool,
|
registered_semantic_tokens_capabilities: bool,
|
||||||
pub resolver: Arc<LspResolver>,
|
pub resolver: Arc<LspResolver>,
|
||||||
task_queue: LanguageServerTaskQueue,
|
task_queue: LanguageServerTaskQueue,
|
||||||
/// A memoized version of fixable diagnostic codes retrieved from TypeScript.
|
ts_fixable_diagnostics: tokio::sync::OnceCell<Vec<String>>,
|
||||||
ts_fixable_diagnostics: Vec<String>,
|
|
||||||
/// An abstraction that handles interactions with TypeScript.
|
|
||||||
pub ts_server: Arc<TsServer>,
|
pub ts_server: Arc<TsServer>,
|
||||||
/// A map of specifiers and URLs used to translate over the LSP.
|
/// A map of specifiers and URLs used to translate over the LSP.
|
||||||
pub url_map: urls::LspUrlMap,
|
pub url_map: urls::LspUrlMap,
|
||||||
|
@ -621,6 +619,19 @@ impl Inner {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn ts_fixable_diagnostics(&self) -> &Vec<String> {
|
||||||
|
self
|
||||||
|
.ts_fixable_diagnostics
|
||||||
|
.get_or_init(|| async {
|
||||||
|
self
|
||||||
|
.ts_server
|
||||||
|
.get_supported_code_fixes(self.snapshot())
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
pub fn update_tracing(&mut self) {
|
pub fn update_tracing(&mut self) {
|
||||||
let tracing =
|
let tracing =
|
||||||
self
|
self
|
||||||
|
@ -777,7 +788,7 @@ impl Inner {
|
||||||
|
|
||||||
// lspower::LanguageServer methods. This file's LanguageServer delegates to us.
|
// lspower::LanguageServer methods. This file's LanguageServer delegates to us.
|
||||||
impl Inner {
|
impl Inner {
|
||||||
async fn initialize(
|
fn initialize(
|
||||||
&mut self,
|
&mut self,
|
||||||
params: InitializeParams,
|
params: InitializeParams,
|
||||||
) -> LspResult<InitializeResult> {
|
) -> LspResult<InitializeResult> {
|
||||||
|
@ -862,26 +873,13 @@ impl Inner {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.diagnostics_server.start();
|
self.diagnostics_server.start();
|
||||||
if let Err(e) = self
|
self
|
||||||
.ts_server
|
.ts_server
|
||||||
.start(self.config.internal_inspect().to_address())
|
.set_inspector_server_addr(self.config.internal_inspect().to_address());
|
||||||
{
|
|
||||||
lsp_warn!("{}", e);
|
|
||||||
self.client.show_message(MessageType::ERROR, e);
|
|
||||||
return Err(tower_lsp::jsonrpc::Error::internal_error());
|
|
||||||
};
|
|
||||||
|
|
||||||
self.update_tracing();
|
self.update_tracing();
|
||||||
self.update_debug_flag();
|
self.update_debug_flag();
|
||||||
|
|
||||||
if capabilities.code_action_provider.is_some() {
|
|
||||||
let fixable_diagnostics = self
|
|
||||||
.ts_server
|
|
||||||
.get_supported_code_fixes(self.snapshot())
|
|
||||||
.await?;
|
|
||||||
self.ts_fixable_diagnostics = fixable_diagnostics;
|
|
||||||
}
|
|
||||||
|
|
||||||
if capabilities.semantic_tokens_provider.is_some() {
|
if capabilities.semantic_tokens_provider.is_some() {
|
||||||
self.registered_semantic_tokens_capabilities = true;
|
self.registered_semantic_tokens_capabilities = true;
|
||||||
}
|
}
|
||||||
|
@ -1746,6 +1744,7 @@ impl Inner {
|
||||||
let line_index = asset_or_doc.line_index();
|
let line_index = asset_or_doc.line_index();
|
||||||
|
|
||||||
// QuickFix
|
// QuickFix
|
||||||
|
let ts_fixable_diagnosics = self.ts_fixable_diagnostics().await;
|
||||||
let fixable_diagnostics: Vec<&Diagnostic> = params
|
let fixable_diagnostics: Vec<&Diagnostic> = params
|
||||||
.context
|
.context
|
||||||
.diagnostics
|
.diagnostics
|
||||||
|
@ -1754,10 +1753,10 @@ impl Inner {
|
||||||
Some(source) => match source.as_str() {
|
Some(source) => match source.as_str() {
|
||||||
"deno-ts" => match &d.code {
|
"deno-ts" => match &d.code {
|
||||||
Some(NumberOrString::String(code)) => {
|
Some(NumberOrString::String(code)) => {
|
||||||
self.ts_fixable_diagnostics.contains(code)
|
ts_fixable_diagnosics.contains(code)
|
||||||
}
|
}
|
||||||
Some(NumberOrString::Number(code)) => {
|
Some(NumberOrString::Number(code)) => {
|
||||||
self.ts_fixable_diagnostics.contains(&code.to_string())
|
ts_fixable_diagnosics.contains(&code.to_string())
|
||||||
}
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
|
@ -3399,6 +3398,9 @@ impl Inner {
|
||||||
params: RenameFilesParams,
|
params: RenameFilesParams,
|
||||||
token: &CancellationToken,
|
token: &CancellationToken,
|
||||||
) -> LspResult<Option<WorkspaceEdit>> {
|
) -> LspResult<Option<WorkspaceEdit>> {
|
||||||
|
if !self.ts_server.is_started() {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
let mut changes = vec![];
|
let mut changes = vec![];
|
||||||
for rename in params.files {
|
for rename in params.files {
|
||||||
let old_specifier = self.url_map.uri_to_specifier(
|
let old_specifier = self.url_map.uri_to_specifier(
|
||||||
|
@ -3461,6 +3463,10 @@ impl Inner {
|
||||||
params: WorkspaceSymbolParams,
|
params: WorkspaceSymbolParams,
|
||||||
token: &CancellationToken,
|
token: &CancellationToken,
|
||||||
) -> LspResult<Option<Vec<SymbolInformation>>> {
|
) -> LspResult<Option<Vec<SymbolInformation>>> {
|
||||||
|
if !self.ts_server.is_started() {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
let mark = self.performance.mark_with_args("lsp.symbol", ¶ms);
|
let mark = self.performance.mark_with_args("lsp.symbol", ¶ms);
|
||||||
|
|
||||||
let navigate_to_items = self
|
let navigate_to_items = self
|
||||||
|
@ -3588,7 +3594,7 @@ impl tower_lsp::LanguageServer for LanguageServer {
|
||||||
&self,
|
&self,
|
||||||
params: InitializeParams,
|
params: InitializeParams,
|
||||||
) -> LspResult<InitializeResult> {
|
) -> LspResult<InitializeResult> {
|
||||||
self.inner.write().await.initialize(params).await
|
self.inner.write().await.initialize(params)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn initialized(&self, _: InitializedParams) {
|
async fn initialized(&self, _: InitializedParams) {
|
||||||
|
|
|
@ -19,7 +19,6 @@ use std::thread;
|
||||||
use dashmap::DashMap;
|
use dashmap::DashMap;
|
||||||
use deno_ast::MediaType;
|
use deno_ast::MediaType;
|
||||||
use deno_core::anyhow::anyhow;
|
use deno_core::anyhow::anyhow;
|
||||||
use deno_core::anyhow::Context as _;
|
|
||||||
use deno_core::convert::Smi;
|
use deno_core::convert::Smi;
|
||||||
use deno_core::convert::ToV8;
|
use deno_core::convert::ToV8;
|
||||||
use deno_core::error::AnyError;
|
use deno_core::error::AnyError;
|
||||||
|
@ -245,9 +244,11 @@ pub struct TsServer {
|
||||||
sender: mpsc::UnboundedSender<Request>,
|
sender: mpsc::UnboundedSender<Request>,
|
||||||
receiver: Mutex<Option<mpsc::UnboundedReceiver<Request>>>,
|
receiver: Mutex<Option<mpsc::UnboundedReceiver<Request>>>,
|
||||||
pub specifier_map: Arc<TscSpecifierMap>,
|
pub specifier_map: Arc<TscSpecifierMap>,
|
||||||
|
inspector_server_addr: Mutex<Option<String>>,
|
||||||
inspector_server: Mutex<Option<Arc<InspectorServer>>>,
|
inspector_server: Mutex<Option<Arc<InspectorServer>>>,
|
||||||
pending_change: Mutex<Option<PendingChange>>,
|
pending_change: Mutex<Option<PendingChange>>,
|
||||||
enable_tracing: Arc<AtomicBool>,
|
enable_tracing: Arc<AtomicBool>,
|
||||||
|
start_once: std::sync::Once,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Debug for TsServer {
|
impl std::fmt::Debug for TsServer {
|
||||||
|
@ -257,7 +258,9 @@ impl std::fmt::Debug for TsServer {
|
||||||
.field("sender", &self.sender)
|
.field("sender", &self.sender)
|
||||||
.field("receiver", &self.receiver)
|
.field("receiver", &self.receiver)
|
||||||
.field("specifier_map", &self.specifier_map)
|
.field("specifier_map", &self.specifier_map)
|
||||||
|
.field("inspector_server_addr", &self.inspector_server_addr.lock())
|
||||||
.field("inspector_server", &self.inspector_server.lock().is_some())
|
.field("inspector_server", &self.inspector_server.lock().is_some())
|
||||||
|
.field("start_once", &self.start_once)
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -404,9 +407,11 @@ impl TsServer {
|
||||||
sender: tx,
|
sender: tx,
|
||||||
receiver: Mutex::new(Some(request_rx)),
|
receiver: Mutex::new(Some(request_rx)),
|
||||||
specifier_map: Arc::new(TscSpecifierMap::new()),
|
specifier_map: Arc::new(TscSpecifierMap::new()),
|
||||||
|
inspector_server_addr: Mutex::new(None),
|
||||||
inspector_server: Mutex::new(None),
|
inspector_server: Mutex::new(None),
|
||||||
pending_change: Mutex::new(None),
|
pending_change: Mutex::new(None),
|
||||||
enable_tracing: Default::default(),
|
enable_tracing: Default::default(),
|
||||||
|
start_once: std::sync::Once::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -416,20 +421,28 @@ impl TsServer {
|
||||||
.store(enabled, std::sync::atomic::Ordering::Relaxed);
|
.store(enabled, std::sync::atomic::Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start(
|
/// This should be called before `self.ensure_started()`.
|
||||||
&self,
|
pub fn set_inspector_server_addr(&self, addr: Option<String>) {
|
||||||
inspector_server_addr: Option<String>,
|
*self.inspector_server_addr.lock() = addr;
|
||||||
) -> Result<(), AnyError> {
|
|
||||||
let maybe_inspector_server = match inspector_server_addr {
|
|
||||||
Some(addr) => {
|
|
||||||
let addr: SocketAddr = addr.parse().with_context(|| {
|
|
||||||
format!("Invalid inspector server address \"{}\"", &addr)
|
|
||||||
})?;
|
|
||||||
let server = InspectorServer::new(addr, "deno-lsp-tsc")?;
|
|
||||||
Some(Arc::new(server))
|
|
||||||
}
|
}
|
||||||
None => None,
|
|
||||||
};
|
pub fn ensure_started(&self) {
|
||||||
|
self.start_once.call_once(|| {
|
||||||
|
let maybe_inspector_server = self
|
||||||
|
.inspector_server_addr
|
||||||
|
.lock()
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|addr| {
|
||||||
|
addr
|
||||||
|
.parse::<SocketAddr>()
|
||||||
|
.inspect_err(|err| {
|
||||||
|
lsp_warn!("Invalid inspector server address: {:#}", err);
|
||||||
|
})
|
||||||
|
.ok()
|
||||||
|
})
|
||||||
|
.map(|addr| {
|
||||||
|
Arc::new(InspectorServer::new(addr, "deno-lsp-tsc").unwrap())
|
||||||
|
});
|
||||||
self
|
self
|
||||||
.inspector_server
|
.inspector_server
|
||||||
.lock()
|
.lock()
|
||||||
|
@ -449,7 +462,12 @@ impl TsServer {
|
||||||
enable_tracing,
|
enable_tracing,
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
Ok(())
|
lsp_log!("TS server started.");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_started(&self) -> bool {
|
||||||
|
self.start_once.is_completed()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn project_changed<'a>(
|
pub fn project_changed<'a>(
|
||||||
|
@ -549,6 +567,9 @@ impl TsServer {
|
||||||
|
|
||||||
#[cfg_attr(feature = "lsp-tracing", tracing::instrument(skip_all))]
|
#[cfg_attr(feature = "lsp-tracing", tracing::instrument(skip_all))]
|
||||||
pub async fn cleanup_semantic_cache(&self, snapshot: Arc<StateSnapshot>) {
|
pub async fn cleanup_semantic_cache(&self, snapshot: Arc<StateSnapshot>) {
|
||||||
|
if !self.is_started() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
for scope in snapshot
|
for scope in snapshot
|
||||||
.config
|
.config
|
||||||
.tree
|
.tree
|
||||||
|
@ -1365,6 +1386,7 @@ impl TsServer {
|
||||||
R: de::DeserializeOwned,
|
R: de::DeserializeOwned,
|
||||||
{
|
{
|
||||||
use super::trace::SpanExt;
|
use super::trace::SpanExt;
|
||||||
|
self.ensure_started();
|
||||||
let context = super::trace::Span::current().context();
|
let context = super::trace::Span::current().context();
|
||||||
let mark = self
|
let mark = self
|
||||||
.performance
|
.performance
|
||||||
|
@ -5772,7 +5794,6 @@ mod tests {
|
||||||
});
|
});
|
||||||
let performance = Arc::new(Performance::default());
|
let performance = Arc::new(Performance::default());
|
||||||
let ts_server = TsServer::new(performance);
|
let ts_server = TsServer::new(performance);
|
||||||
ts_server.start(None).unwrap();
|
|
||||||
ts_server.project_changed(
|
ts_server.project_changed(
|
||||||
snapshot.clone(),
|
snapshot.clone(),
|
||||||
[],
|
[],
|
||||||
|
|
|
@ -11488,13 +11488,11 @@ fn lsp_performance() {
|
||||||
"lsp.update_diagnostics_ts",
|
"lsp.update_diagnostics_ts",
|
||||||
"lsp.update_global_cache",
|
"lsp.update_global_cache",
|
||||||
"tsc.host.$getDiagnostics",
|
"tsc.host.$getDiagnostics",
|
||||||
"tsc.host.$getSupportedCodeFixes",
|
|
||||||
"tsc.host.getQuickInfoAtPosition",
|
"tsc.host.getQuickInfoAtPosition",
|
||||||
"tsc.op.op_is_node_file",
|
"tsc.op.op_is_node_file",
|
||||||
"tsc.op.op_load",
|
"tsc.op.op_load",
|
||||||
"tsc.op.op_script_names",
|
"tsc.op.op_script_names",
|
||||||
"tsc.request.$getDiagnostics",
|
"tsc.request.$getDiagnostics",
|
||||||
"tsc.request.$getSupportedCodeFixes",
|
|
||||||
"tsc.request.getQuickInfoAtPosition",
|
"tsc.request.getQuickInfoAtPosition",
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
@ -15135,6 +15133,7 @@ fn lsp_deno_json_scopes_file_rename_import_edits() {
|
||||||
);
|
);
|
||||||
let mut client = context.new_lsp_command().build();
|
let mut client = context.new_lsp_command().build();
|
||||||
client.initialize_default();
|
client.initialize_default();
|
||||||
|
client.did_open_file(&file1);
|
||||||
let res = client.write_request(
|
let res = client.write_request(
|
||||||
"workspace/willRenameFiles",
|
"workspace/willRenameFiles",
|
||||||
json!({
|
json!({
|
||||||
|
@ -15395,6 +15394,7 @@ fn lsp_deno_json_scopes_search_symbol() {
|
||||||
);
|
);
|
||||||
let mut client = context.new_lsp_command().build();
|
let mut client = context.new_lsp_command().build();
|
||||||
client.initialize_default();
|
client.initialize_default();
|
||||||
|
client.did_open_file(&file1);
|
||||||
let res =
|
let res =
|
||||||
client.write_request("workspace/symbol", json!({ "query": "someSymbol" }));
|
client.write_request("workspace/symbol", json!({ "query": "someSymbol" }));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue