use lsp_types::PublishDiagnosticsParams;
use lsp_types::notification::PublishDiagnostics;
use tokio_util::sync::CancellationToken;
use tracing::{Span, warn};
use crate::client::Client;
use crate::documents::DocumentsView;
use crate::raw::RequestId;
use crate::workspace::Workspace;
#[derive(Debug, Clone)]
pub struct Context {
pub(crate) request_id: Option<RequestId>,
pub(crate) span: Span,
pub(crate) client: Client,
pub(crate) workspace: Workspace,
pub(crate) cancellation: Option<CancellationToken>,
}
impl Context {
pub(crate) fn for_request(
id: RequestId,
span: Span,
client: Client,
workspace: Workspace,
) -> Self {
Self {
request_id: Some(id),
span,
client,
workspace,
cancellation: None,
}
}
pub(crate) fn for_notification(span: Span, client: Client, workspace: Workspace) -> Self {
Self {
request_id: None,
span,
client,
workspace,
cancellation: None,
}
}
pub(crate) fn with_cancellation(mut self, cancellation: CancellationToken) -> Self {
self.cancellation = Some(cancellation);
self
}
pub(crate) fn cancellation(&self) -> Option<&CancellationToken> {
self.cancellation.as_ref()
}
pub fn request_id(&self) -> Option<&RequestId> {
self.request_id.as_ref()
}
pub fn span(&self) -> &Span {
&self.span
}
pub fn documents(&self) -> DocumentsView {
self.workspace.documents()
}
pub fn client(&self) -> Client {
self.client.clone()
}
pub fn workspace(&self) -> &Workspace {
&self.workspace
}
pub fn publish_diagnostics(&self, params: PublishDiagnosticsParams) {
if let Err(error) = self.client.notify::<PublishDiagnostics>(params) {
warn!(%error, "publish_diagnostics: notification failed");
}
}
}
#[cfg(test)]
mod tests {
use std::str::FromStr;
use lsp_types::{InitializeParams, TextDocumentItem, Uri};
use tokio::sync::mpsc;
use super::*;
use crate::client::OutboundRegistry;
use crate::documents::Documents;
fn context() -> (Context, Documents) {
let (out_tx, _out_rx) = mpsc::unbounded_channel();
let documents = Documents::new();
let workspace = Workspace::from_params(&InitializeParams::default(), documents.clone());
let client = Client::new(out_tx, OutboundRegistry::default());
(
Context::for_notification(Span::none(), client, workspace),
documents,
)
}
#[test]
fn cloning_shares_connection_state_instead_of_copying_it() {
let (ctx, documents) = context();
let clone = ctx.clone();
let uri = Uri::from_str("file:///shared.rs").unwrap();
documents.open(TextDocumentItem {
uri: uri.clone(),
language_id: "rust".to_string(),
version: 1,
text: "fn main() {}".to_string(),
});
let doc = clone
.documents()
.get(&uri)
.expect("a cloned context reads the same connection documents");
assert_eq!(doc.text(), "fn main() {}");
assert_eq!(
clone.workspace().roots(),
ctx.workspace().roots(),
"a cloned context shares the one workspace"
);
}
}