laburnum 1.17.1

An LSP framework for building language servers and compilers, powered by an incremental query tree with content-addressed storage, task-based dataflow, and parallel queries.
Documentation
// Copyright Two Neutron Stars Incorporated and contributors
// SPDX-License-Identifier: BlueOak-1.0.0

use {
  crate::{
    connect::lsp::LSP_CLIENT_TRACER,
    protocol::lsp,
  },
  serde::{
    Serialize,
    de::DeserializeOwned,
  },
};

pub trait Notification {
  type Params: DeserializeOwned + Serialize + Send + Sync + 'static;
  const METHOD: &'static str;
}

macro_rules! lsp_notification_def {
    (@parse_all [] [$($output:tt)*]) => {
        $($output)*
    };

    (@parse_all [
        $(#[$meta:meta])*
        $name:ident($method:literal, $params:ty);
        $($rest:tt)*
    ] [$($output:tt)*]) => {
        $crate::connect::lsp::notification::lsp_notification_def!(
            @parse_all
            [$($rest)*]
            [$($output)*
                $(#[$meta])*
                #[derive(Debug)]
                pub enum $name {}

                impl Notification for $name {
                    type Params = $params;
                    const METHOD: &'static str = $method;
                }
            ]
        );
    };

    (@parse_all [
        $(#[$meta:meta])*
        $name:ident($method:literal);
        $($rest:tt)*
    ] [$($output:tt)*]) => {
        $crate::connect::lsp::notification::lsp_notification_def!(
            @parse_all
            [$($rest)*]
            [$($output)*
                $(#[$meta])*
                #[derive(Debug)]
                pub enum $name {}

                impl Notification for $name {
                    type Params = ();
                    const METHOD: &'static str = $method;
                }
            ]
        );
    };

    (@parse_methods [] [$($output:tt)*]) => {
        impl $crate::connect::lsp::LspClient {
            $($output)*
        }
    };

    (@parse_methods [
        $(#[$meta:meta])*
        $name:ident($method:literal, $params:ty);
        $($rest:tt)*
    ] [$($output:tt)*]) => {
        $crate::connect::lsp::notification::lsp_notification_def!(
            @parse_methods
            [$($rest)*]
            [$($output)*
                paste::paste! {
                    $(#[$meta])*
                    pub async fn [<$name:snake>](
                        &self,
                        params: $params,
                    ) -> Result<(), $crate::connect::lsp::errors::LspClientError> {
                      use opentelemetry::trace::FutureExt as _;
                      otel::span!(
                        @LSP_CLIENT_TRACER,
                        concat!("laburnum.lsp_client.notification.",stringify!([<$name:snake>])),
                        in |cx| {
                          async move {
                            let result = self.send_notification::<$name>(params).with_context(cx.clone()).await;
                            if let Some(duration) = self.wait_after_notification() {
                                smol::Timer::after(duration).with_context(cx).await;
                            }
                            result
                          }.await
                        }
                      )
                    }
                }
            ]
        );
    };

    (@parse_methods [
        $(#[$meta:meta])*
        $name:ident($method:literal);
        $($rest:tt)*
    ] [$($output:tt)*]) => {
        $crate::connect::lsp::notification::lsp_notification_def!(
            @parse_methods
            [$($rest)*]
            [$($output)*
                paste::paste! {
                    $(#[$meta])*
                    pub async fn [<$name:snake>](&self) -> Result<(), $crate::connect::lsp::errors::LspClientError> {
                      use opentelemetry::trace::FutureExt as _;

                      otel::span!(
                        @LSP_CLIENT_TRACER,
                        concat!("laburnum.lsp_client.notification.",stringify!([<$name:snake>])),
                        in |cx| {
                          async move {
                            let result = self.send_notification::<$name>(()).with_context(cx.clone()).await;
                            if let Some(duration) = self.wait_after_notification() {
                              smol::Timer::after(duration).with_context(cx).await;
                            }
                            result
                          }.await
                        }
                      )
                    }
                }
            ]
        );
    };

    ($($input:tt)*) => {
        $crate::connect::lsp::notification::lsp_notification_def!(@parse_all [$($input)*] []);
        $crate::connect::lsp::notification::lsp_notification_def!(@parse_methods [$($input)*] []);
    };
}

pub(crate) use lsp_notification_def;

lsp_notification_def! {
    /// The base protocol now offers support for request cancellation. To cancel a request,
    /// a notification message with the following properties is sent:
    ///
    /// A request that got canceled still needs to return from the server and send a response back.
    /// It can not be left open / hanging. This is in line with the JSON RPC protocol that requires
    /// that every request sends a response back. In addition it allows for returning partial results on cancel.
    Cancel("$/cancelRequest", lsp::CancelParams);

    /// A notification that should be used by the client to modify the trace
    /// setting of the server.
    SetTrace("$/setTrace", lsp::SetTraceParams);

    /// A notification to log the trace of the server's execution.
    /// The amount and content of these notifications depends on the current trace configuration.
    ///
    /// `LogTrace` should be used for systematic trace reporting. For single debugging messages,
    /// the server should send `LogMessage` notifications.
    LogTrace("$/logTrace", lsp::LogTraceParams);

    /// The initialized notification is sent from the client to the server after the client received
    /// the result of the initialize request but before the client is sending any other request or
    /// notification to the server. The server can use the initialized notification for example to
    /// dynamically register capabilities.
    Initialized("initialized");

    /// The show message notification is sent from a server to a client to ask the client to display a particular message
    /// in the user interface.
    ShowMessage("window/showMessage", lsp::ShowMessageParams);

    /// The log message notification is sent from the server to the client to ask the client to log a particular message.
    LogMessage("window/logMessage", lsp::LogMessageParams);

    /// The telemetry notification is sent from the server to the client to ask the client to log a telemetry event.
    ///
    /// The protocol doesn't specify the payload since no interpretation of the data happens in the protocol. Most clients even don't handle
    /// the event directly but forward them to the extensions owning the corresponding server issuing the event.
    TelemetryEvent("telemetry/event", lsp::OneOf<lsp::LSPObject, lsp::LSPArray>);

    /// A notification sent from the client to the server to signal the change of configuration settings.
    DidChangeConfiguration("workspace/didChangeConfiguration", lsp::DidChangeConfigurationParams);

    /// The document open notification is sent from the client to the server to signal newly opened text documents.
    ///
    /// The document's truth is now managed by the client and the server must not try to read the document's truth
    /// using the document's uri.
    DidOpenTextDocument("textDocument/didOpen", lsp::DidOpenTextDocumentParams);

    /// The document change notification is sent from the client to the server to signal changes to a text document.
    ///
    /// In 2.0 the shape of the params has changed to include proper version numbers and language ids.
    DidChangeTextDocument("textDocument/didChange", lsp::DidChangeTextDocumentParams);

    /// The document will save notification is sent from the client to the server before the document
    /// is actually saved.
    WillSaveTextDocument("textDocument/willSave", lsp::WillSaveTextDocumentParams);

    /// The document close notification is sent from the client to the server when the document got closed in the client.
    ///
    /// The document's truth now exists where the document's uri points to (e.g. if the document's uri is a file uri
    /// the truth now exists on disk).
    DidCloseTextDocument("textDocument/didClose", lsp::DidCloseTextDocumentParams);

    /// The document save notification is sent from the client to the server when the document was saved in the client.
    DidSaveTextDocument("textDocument/didSave", lsp::DidSaveTextDocumentParams);

    DidOpenNotebookDocument("notebookDocument/didOpen", lsp::DidOpenNotebookDocumentParams);

    DidChangeNotebookDocument("notebookDocument/didChange", lsp::DidChangeNotebookDocumentParams);

    DidSaveNotebookDocument("notebookDocument/didSave", lsp::DidSaveNotebookDocumentParams);

    DidCloseNotebookDocument("notebookDocument/didClose", lsp::DidCloseNotebookDocumentParams);

    /// The watched files notification is sent from the client to the server when the client detects changes to files and folders
    /// watched by the language client (note although the name suggest that only file events are sent it is about file system events which include folders as well).
    /// It is recommended that servers register for these file system events using the registration mechanism.
    /// In former implementations clients pushed file events without the server actively asking for it.
    DidChangeWatchedFiles("workspace/didChangeWatchedFiles", lsp::DidChangeWatchedFilesParams);

    /// The workspace/didChangeWorkspaceFolders notification is sent from the client to the server to inform the server
    /// about workspace folder configuration changes
    DidChangeWorkspaceFolders("workspace/didChangeWorkspaceFolders", lsp::DidChangeWorkspaceFoldersParams);

    /// Diagnostics notification are sent from the server to the client to signal results of validation runs.
    PublishDiagnostics("textDocument/publishDiagnostics", lsp::PublishDiagnosticsParams);

    /// The progress notification is sent from the server to the client to ask
    /// the client to indicate progress.
    Progress("$/progress", lsp::ProgressParams);

    /// The `window/workDoneProgress/cancel` notification is sent from the client
    /// to the server to cancel a progress initiated on the server side using the `window/workDoneProgress/create`.
    WorkDoneProgressCancel("window/workDoneProgress/cancel", lsp::WorkDoneProgressCancelParams);

    /// The did create files notification is sent from the client to the server when files were created from within the client.
    DidCreateFiles("workspace/didCreateFiles", lsp::CreateFilesParams);

    /// The did rename files notification is sent from the client to the server when files were renamed from within the client.
    DidRenameFiles("workspace/didRenameFiles", lsp::RenameFilesParams);

    /// The did delete files notification is sent from the client to the server when files were deleted from within the client.
    DidDeleteFiles("workspace/didDeleteFiles", lsp::DeleteFilesParams);

    /// A notification to ask the server to exit its process.
    /// The server should exit with success code 0 if the shutdown request has been received before;
    /// otherwise with error code 1.
    Exit("exit");
}