summaryrefslogtreecommitdiff
path: root/support/texlab/crates/texlab/src/server.rs
diff options
context:
space:
mode:
Diffstat (limited to 'support/texlab/crates/texlab/src/server.rs')
-rw-r--r--support/texlab/crates/texlab/src/server.rs342
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(&params.text_document_position.text_document.uri, position);
self.run_query(id, move |db| {
- completion::complete(db, &params, &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, &params));
+ 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, &params));
+ 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, &params).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(())