diff options
Diffstat (limited to 'support/texlab/crates/texlab/src/server.rs')
-rw-r--r-- | support/texlab/crates/texlab/src/server.rs | 342 |
1 files changed, 138 insertions, 204 deletions
diff --git a/support/texlab/crates/texlab/src/server.rs b/support/texlab/crates/texlab/src/server.rs index f06984d596..0fb186f688 100644 --- a/support/texlab/crates/texlab/src/server.rs +++ b/support/texlab/crates/texlab/src/server.rs @@ -14,7 +14,6 @@ use anyhow::Result; use base_db::{Config, Owner, Workspace}; use commands::{BuildCommand, CleanCommand, CleanTarget, ForwardSearch}; use crossbeam_channel::{Receiver, Sender}; -use diagnostics::{DiagnosticManager, DiagnosticSource}; use distro::{Distro, Language}; use line_index::LineCol; use lsp_server::{Connection, ErrorCode, Message, RequestId}; @@ -22,22 +21,17 @@ use lsp_types::{notification::*, request::*, *}; use notify::event::ModifyKind; use notify_debouncer_full::{DebouncedEvent, Debouncer, FileIdMap}; use parking_lot::{Mutex, RwLock}; -use rowan::ast::AstNode; -use rustc_hash::{FxHashMap, FxHashSet}; +use rustc_hash::FxHashSet; use serde::{de::DeserializeOwned, Serialize}; -use syntax::bibtex; use threadpool::ThreadPool; use crate::{ client::LspClient, features::{ - completion::{self, ResolveInfo}, - definition, folding, formatting, highlight, hover, inlay_hint, link, reference, rename, - symbols, - }, - util::{ - self, capabilities::ClientCapabilitiesExt, line_index_ext::LineIndexExt, normalize_uri, + completion, definition, folding, formatting, highlight, hover, inlay_hint, link, reference, + rename, symbols, }, + util::{from_proto, line_index_ext::LineIndexExt, normalize_uri, to_proto, ClientFlags}, }; use self::{ @@ -55,7 +49,7 @@ enum InternalMessage { SetOptions(Options), FileEvent(Vec<DebouncedEvent>), Diagnostics, - ChktexResult(Url, Vec<lsp_types::Diagnostic>), + ChktexFinished(Url, Vec<diagnostics::Diagnostic>), ForwardSearch(Url, Option<Position>), } @@ -65,70 +59,68 @@ pub struct Server { internal_rx: Receiver<InternalMessage>, workspace: Arc<RwLock<Workspace>>, client: LspClient, - client_capabilities: Arc<ClientCapabilities>, - client_info: Option<Arc<ClientInfo>>, - diagnostic_manager: DiagnosticManager, - chktex_diagnostics: FxHashMap<Url, Vec<Diagnostic>>, + client_flags: Arc<ClientFlags>, + diagnostic_manager: diagnostics::Manager, watcher: FileWatcher, pool: ThreadPool, pending_builds: Arc<Mutex<FxHashSet<u32>>>, } impl Server { - pub fn new(connection: Connection) -> Self { + pub fn exec(connection: Connection) -> Result<()> { let client = LspClient::new(connection.sender.clone()); let (internal_tx, internal_rx) = crossbeam_channel::unbounded(); let watcher = FileWatcher::new(internal_tx.clone()).expect("init file watcher"); - Self { + let mut workspace = Workspace::default(); + + let (id, params) = connection.initialize_start()?; + let params: InitializeParams = serde_json::from_value(params)?; + + let workspace_folders = params + .workspace_folders + .unwrap_or_default() + .into_iter() + .filter(|folder| folder.uri.scheme() == "file") + .flat_map(|folder| folder.uri.to_file_path()) + .collect(); + + workspace.set_folders(workspace_folders); + + let result = InitializeResult { + capabilities: Self::capabilities(), + server_info: Some(ServerInfo { + name: "TexLab".to_owned(), + version: Some(env!("CARGO_PKG_VERSION").to_owned()), + }), + }; + + connection.initialize_finish(id, serde_json::to_value(result)?)?; + + let server = Self { connection: Arc::new(connection), internal_tx, internal_rx, - workspace: Default::default(), + workspace: Arc::new(RwLock::new(workspace)), client, - client_capabilities: Default::default(), - client_info: Default::default(), - chktex_diagnostics: Default::default(), - diagnostic_manager: DiagnosticManager::default(), + client_flags: Arc::new(from_proto::client_flags( + params.capabilities, + params.client_info, + )), + diagnostic_manager: diagnostics::Manager::default(), watcher, pool: threadpool::Builder::new().build(), pending_builds: Default::default(), - } - } + }; - fn run_query<R, Q>(&self, id: RequestId, query: Q) - where - R: Serialize, - Q: FnOnce(&Workspace) -> R + Send + 'static, - { - let client = self.client.clone(); - let workspace = Arc::clone(&self.workspace); - self.pool.execute(move || { - let response = lsp_server::Response::new_ok(id, query(&workspace.read())); - client.send_response(response).unwrap(); - }); - } + let options = serde_json::from_value(params.initialization_options.unwrap_or_default()) + .unwrap_or_default(); - fn run_fallible<R, Q>(&self, id: RequestId, query: Q) - where - R: Serialize, - Q: FnOnce() -> Result<R> + Send + 'static, - { - let client = self.client.clone(); - self.pool.execute(move || match query() { - Ok(result) => { - let response = lsp_server::Response::new_ok(id, result); - client.send_response(response).unwrap(); - } - Err(why) => { - client - .send_error(id, ErrorCode::InternalError, why.to_string()) - .unwrap(); - } - }); + server.run(options)?; + Ok(()) } - fn capabilities(&self) -> ServerCapabilities { + fn capabilities() -> ServerCapabilities { ServerCapabilities { text_document_sync: Some(TextDocumentSyncCapability::Options( TextDocumentSyncOptions { @@ -185,57 +177,40 @@ impl Server { } } - fn initialize(&mut self) -> Result<()> { - let (id, params) = self.connection.initialize_start()?; - let params: InitializeParams = serde_json::from_value(params)?; - - self.client_capabilities = Arc::new(params.capabilities); - self.client_info = params.client_info.map(Arc::new); - - let workspace_folders = params - .workspace_folders - .unwrap_or_default() - .into_iter() - .filter(|folder| folder.uri.scheme() == "file") - .flat_map(|folder| folder.uri.to_file_path()) - .collect(); - - self.workspace.write().set_folders(workspace_folders); - - let result = InitializeResult { - capabilities: self.capabilities(), - server_info: Some(ServerInfo { - name: "TexLab".to_owned(), - version: Some(env!("CARGO_PKG_VERSION").to_owned()), - }), - }; - self.connection - .initialize_finish(id, serde_json::to_value(result)?)?; - - let StartupOptions { skip_distro } = - serde_json::from_value(params.initialization_options.unwrap_or_default()) - .unwrap_or_default(); - - if !skip_distro { - let sender = self.internal_tx.clone(); - self.pool.execute(move || { - let distro = Distro::detect().unwrap_or_else(|why| { - log::warn!("Unable to load distro files: {}", why); - Distro::default() - }); - - log::info!("Detected distribution: {:?}", distro.kind); - sender.send(InternalMessage::SetDistro(distro)).unwrap(); - }); - } + fn run_query<R, Q>(&self, id: RequestId, query: Q) + where + R: Serialize, + Q: FnOnce(&Workspace) -> R + Send + 'static, + { + let client = self.client.clone(); + let workspace = Arc::clone(&self.workspace); + self.pool.execute(move || { + let response = lsp_server::Response::new_ok(id, query(&workspace.read())); + client.send_response(response).unwrap(); + }); + } - self.register_configuration(); - self.pull_options(); - Ok(()) + fn run_fallible<R, Q>(&self, id: RequestId, query: Q) + where + R: Serialize, + Q: FnOnce() -> Result<R> + Send + 'static, + { + let client = self.client.clone(); + self.pool.execute(move || match query() { + Ok(result) => { + let response = lsp_server::Response::new_ok(id, result); + client.send_response(response).unwrap(); + } + Err(why) => { + client + .send_error(id, ErrorCode::InternalError, why.to_string()) + .unwrap(); + } + }); } fn register_configuration(&mut self) { - if self.client_capabilities.has_push_configuration_support() { + if self.client_flags.configuration_push { let registration = Registration { id: "pull-config".to_string(), method: DidChangeConfiguration::METHOD.to_string(), @@ -269,7 +244,7 @@ impl Server { .iter() .filter_map(|path| workspace.lookup_path(path)) { - self.diagnostic_manager.update(&workspace, document); + self.diagnostic_manager.update_syntax(&workspace, document); } drop(workspace); @@ -279,23 +254,16 @@ impl Server { fn publish_diagnostics(&mut self) -> Result<()> { let workspace = self.workspace.read(); - let mut all_diagnostics = - util::diagnostics::collect(&workspace, &mut self.diagnostic_manager); - - for (uri, diagnostics) in &self.chktex_diagnostics { - let Some(document) = workspace.lookup(uri) else { - continue; - }; - let Some(existing) = all_diagnostics.get_mut(document) else { + for (uri, diagnostics) in self.diagnostic_manager.get(&workspace) { + let Some(document) = workspace.lookup(&uri) else { continue; }; - existing.extend(diagnostics.iter().cloned()); - } - util::diagnostics::filter(&mut all_diagnostics, &workspace); + let diagnostics = diagnostics + .into_iter() + .filter_map(|diagnostic| to_proto::diagnostic(&workspace, document, &diagnostic)) + .collect(); - for (document, diagnostics) in all_diagnostics { - let uri = document.uri.clone(); let version = None; let params = PublishDiagnosticsParams { uri, @@ -320,7 +288,7 @@ impl Server { } fn pull_options(&mut self) { - if !self.client_capabilities.has_pull_configuration_support() { + if !self.client_flags.configuration_pull { return; } @@ -364,7 +332,7 @@ impl Server { } fn did_change_configuration(&mut self, params: DidChangeConfigurationParams) -> Result<()> { - if self.client_capabilities.has_pull_configuration_support() { + if self.client_flags.configuration_pull { self.pull_options(); } else { let options = self.client.parse_options(params.settings)?; @@ -392,7 +360,7 @@ impl Server { let workspace = self.workspace.read(); self.diagnostic_manager - .update(&workspace, workspace.lookup(&uri).unwrap()); + .update_syntax(&workspace, workspace.lookup(&uri).unwrap()); if workspace.config().diagnostics.chktex.on_open { drop(workspace); @@ -435,7 +403,7 @@ impl Server { } self.diagnostic_manager - .update(&workspace, workspace.lookup(&uri).unwrap()); + .update_syntax(&workspace, workspace.lookup(&uri).unwrap()); drop(workspace); self.update_workspace(); @@ -478,45 +446,38 @@ impl Server { Ok(()) } - fn run_chktex(&mut self, uri: &Url) { + fn run_chktex(&mut self, uri: &Url) -> Option<()> { let workspace = self.workspace.read(); - let Some(document) = workspace.lookup(uri) else { - return; - }; - let Some(command) = util::chktex::Command::new(&workspace, document) else { - return; - }; + + let document = workspace.lookup(uri)?; + let command = diagnostics::chktex::Command::new(&workspace, document)?; let sender = self.internal_tx.clone(); let uri = document.uri.clone(); self.pool.execute(move || { let diagnostics = command.run().unwrap_or_default(); sender - .send(InternalMessage::ChktexResult(uri, diagnostics)) + .send(InternalMessage::ChktexFinished(uri, diagnostics)) .unwrap(); }); + + Some(()) } - fn document_link(&self, id: RequestId, params: DocumentLinkParams) -> Result<()> { - let mut uri = params.text_document.uri; - normalize_uri(&mut uri); + fn document_link(&self, id: RequestId, mut params: DocumentLinkParams) -> Result<()> { + normalize_uri(&mut params.text_document.uri); self.run_query(id, move |workspace| { - link::find_all(workspace, &uri).unwrap_or_default() + link::find_all(workspace, params).unwrap_or_default() }); Ok(()) } - fn document_symbols(&self, id: RequestId, params: DocumentSymbolParams) -> Result<()> { - let mut uri = params.text_document.uri; - normalize_uri(&mut uri); + fn document_symbols(&self, id: RequestId, mut params: DocumentSymbolParams) -> Result<()> { + normalize_uri(&mut params.text_document.uri); - let capabilities = Arc::clone(&self.client_capabilities); + let client_flags = Arc::clone(&self.client_flags); self.run_query(id, move |workspace| { - let Some(document) = workspace.lookup(&uri) else { - return DocumentSymbolResponse::Flat(vec![]); - }; - - symbols::document_symbols(workspace, document, &capabilities) + symbols::document_symbols(workspace, params, &client_flags) }); Ok(()) @@ -533,11 +494,10 @@ impl Server { fn completion(&self, id: RequestId, mut params: CompletionParams) -> Result<()> { normalize_uri(&mut params.text_document_position.text_document.uri); let position = params.text_document_position.position; - let client_capabilities = Arc::clone(&self.client_capabilities); - let client_info = self.client_info.clone(); + let client_flags = Arc::clone(&self.client_flags); self.update_cursor(¶ms.text_document_position.text_document.uri, position); self.run_query(id, move |db| { - completion::complete(db, ¶ms, &client_capabilities, client_info.as_deref()) + completion::complete(db, params, &client_flags) }); Ok(()) @@ -555,54 +515,20 @@ impl Server { fn completion_resolve(&self, id: RequestId, mut item: CompletionItem) -> Result<()> { self.run_query(id, move |workspace| { - match item - .data - .clone() - .map(|data| serde_json::from_value(data).unwrap()) - { - Some(ResolveInfo::Package | ResolveInfo::DocumentClass) => { - item.documentation = completion_data::DATABASE - .meta(&item.label) - .and_then(|meta| meta.description.as_deref()) - .map(|value| { - Documentation::MarkupContent(MarkupContent { - kind: MarkupKind::PlainText, - value: value.into(), - }) - }); - } - Some(ResolveInfo::Citation { uri, key }) => { - if let Some(data) = workspace - .lookup(&uri) - .and_then(|document| document.data.as_bib()) - { - item.documentation = bibtex::Root::cast(data.root_node()) - .and_then(|root| root.find_entry(&key)) - .and_then(|entry| citeproc::render(&entry)) - .map(|value| { - Documentation::MarkupContent(MarkupContent { - kind: MarkupKind::Markdown, - value, - }) - }); - } - } - None => {} - }; - + completion::resolve(workspace, &mut item); item }); Ok(()) } - fn folding_range(&self, id: RequestId, params: FoldingRangeParams) -> Result<()> { - let mut uri = params.text_document.uri; - normalize_uri(&mut uri); - let client_capabilities = Arc::clone(&self.client_capabilities); + fn folding_range(&self, id: RequestId, mut params: FoldingRangeParams) -> Result<()> { + normalize_uri(&mut params.text_document.uri); + let client_flags = Arc::clone(&self.client_flags); self.run_query(id, move |db| { - folding::find_all(db, &uri, &client_capabilities).unwrap_or_default() + folding::find_all(db, params, &client_flags).unwrap_or_default() }); + Ok(()) } @@ -623,33 +549,28 @@ impl Server { Ok(()) } - fn goto_definition(&self, id: RequestId, params: GotoDefinitionParams) -> Result<()> { - let mut uri = params.text_document_position_params.text_document.uri; - normalize_uri(&mut uri); - let position = params.text_document_position_params.position; - self.run_query(id, move |db| { - definition::goto_definition(db, &uri, position) - }); - + fn goto_definition(&self, id: RequestId, mut params: GotoDefinitionParams) -> Result<()> { + normalize_uri(&mut params.text_document_position_params.text_document.uri); + self.run_query(id, move |db| definition::goto_definition(db, params)); Ok(()) } fn prepare_rename(&self, id: RequestId, mut params: TextDocumentPositionParams) -> Result<()> { normalize_uri(&mut params.text_document.uri); - self.run_query(id, move |db| rename::prepare_rename_all(db, ¶ms)); + self.run_query(id, move |db| rename::prepare_rename_all(db, params)); Ok(()) } fn rename(&self, id: RequestId, mut params: RenameParams) -> Result<()> { normalize_uri(&mut params.text_document_position.text_document.uri); - self.run_query(id, move |db| rename::rename_all(db, ¶ms)); + self.run_query(id, move |db| rename::rename_all(db, params)); Ok(()) } fn document_highlight(&self, id: RequestId, mut params: DocumentHighlightParams) -> Result<()> { normalize_uri(&mut params.text_document_position_params.text_document.uri); self.run_query(id, move |db| { - highlight::find_all(db, ¶ms).unwrap_or_default() + highlight::find_all(db, params).unwrap_or_default() }); Ok(()) @@ -716,11 +637,10 @@ impl Server { Ok(()) } - fn inlay_hints(&self, id: RequestId, params: InlayHintParams) -> Result<()> { - let mut uri = params.text_document.uri; - normalize_uri(&mut uri); + fn inlay_hints(&self, id: RequestId, mut params: InlayHintParams) -> Result<()> { + normalize_uri(&mut params.text_document.uri); self.run_query(id, move |db| { - inlay_hint::find_all(db, &uri, params.range).unwrap_or_default() + inlay_hint::find_all(db, params).unwrap_or_default() }); Ok(()) } @@ -757,7 +677,7 @@ impl Server { let command = BuildCommand::new(&workspace, &uri); let internal = self.internal_tx.clone(); - let progress = self.client_capabilities.has_work_done_progress_support(); + let progress = self.client_flags.progress; let pending_builds = Arc::clone(&self.pending_builds); self.pool.execute(move || { @@ -896,7 +816,7 @@ impl Server { changed |= workspace.load(&path, language, Owner::Server).is_ok(); if let Some(document) = workspace.lookup_path(&path) { - self.diagnostic_manager.update(&workspace, document); + self.diagnostic_manager.update_syntax(&workspace, document); } } } @@ -1111,8 +1031,8 @@ impl Server { InternalMessage::Diagnostics => { self.publish_diagnostics()?; } - InternalMessage::ChktexResult(uri, diagnostics) => { - self.chktex_diagnostics.insert(uri, diagnostics); + InternalMessage::ChktexFinished(uri, diagnostics) => { + self.diagnostic_manager.update_chktex(uri, diagnostics); self.publish_diagnostics()?; } InternalMessage::ForwardSearch(uri, position) => { @@ -1124,8 +1044,22 @@ impl Server { } } - pub fn run(mut self) -> Result<()> { - self.initialize()?; + pub fn run(mut self, options: StartupOptions) -> Result<()> { + if !options.skip_distro { + let sender = self.internal_tx.clone(); + self.pool.execute(move || { + let distro = Distro::detect().unwrap_or_else(|why| { + log::warn!("Unable to load distro files: {}", why); + Distro::default() + }); + + log::info!("Detected distribution: {:?}", distro.kind); + sender.send(InternalMessage::SetDistro(distro)).unwrap(); + }); + } + + self.register_configuration(); + self.pull_options(); self.process_messages()?; self.pool.join(); Ok(()) |