diff --git a/crates/ty_server/src/server/api/requests/diagnostic.rs b/crates/ty_server/src/server/api/requests/diagnostic.rs index 8cead7f135..b455c3b0a4 100644 --- a/crates/ty_server/src/server/api/requests/diagnostic.rs +++ b/crates/ty_server/src/server/api/requests/diagnostic.rs @@ -3,7 +3,7 @@ use std::borrow::Cow; use lsp_types::request::DocumentDiagnosticRequest; use lsp_types::{ DocumentDiagnosticParams, DocumentDiagnosticReport, DocumentDiagnosticReportResult, - FullDocumentDiagnosticReport, RelatedFullDocumentDiagnosticReport, + FullDocumentDiagnosticReport, RelatedFullDocumentDiagnosticReport, Url, }; use crate::server::Result; @@ -22,7 +22,7 @@ impl RequestHandler for DocumentDiagnosticRequestHandler { } impl BackgroundDocumentRequestHandler for DocumentDiagnosticRequestHandler { - fn document_url(params: &DocumentDiagnosticParams) -> Cow { + fn document_url(params: &DocumentDiagnosticParams) -> Cow { Cow::Borrowed(¶ms.text_document.uri) } diff --git a/crates/ty_server/src/server/api/traits.rs b/crates/ty_server/src/server/api/traits.rs index f96f5172c7..de9ce50ca1 100644 --- a/crates/ty_server/src/server/api/traits.rs +++ b/crates/ty_server/src/server/api/traits.rs @@ -1,22 +1,59 @@ -//! A stateful LSP implementation that calls into the ty API. +//! Traits for handling requests and notifications from the LSP client. +//! +//! This module defines the trait abstractions used by the language server to handle incoming +//! requests and notifications from clients. It provides a type-safe way to implement LSP handlers +//! with different execution models (synchronous or asynchronous) and automatic retry capabilities. +//! +//! All request and notification handlers must implement the base traits [`RequestHandler`] and +//! [`NotificationHandler`], respectively, which associate them with specific LSP request or +//! notification types. These base traits are then extended by more specific traits that define +//! the execution model of the handler. +//! +//! The [`SyncRequestHandler`] and [`SyncNotificationHandler`] traits are for handlers that +//! executes synchronously on the main loop, providing mutable access to the [`Session`] that +//! contains the current state of the server. This is useful for handlers that need to modify +//! the server state such as when the content of a file changes. +//! +//! The [`BackgroundDocumentRequestHandler`] and [`BackgroundDocumentNotificationHandler`] traits +//! are for handlers that operate on a single document and can be executed on a background thread. +//! These handlers will have access to a snapshot of the document at the time of the request or +//! notification, allowing them to perform operations without blocking the main loop. There is also +//! the [`BackgroundRequestHandler`] trait for handlers that operate on the entire workspace +//! instead of a single document and can also be executed on a background thread like fetching the +//! workspace diagnostics. +//! +//! The [`RetriableRequestHandler`] trait is a marker trait for handlers that can be retried if the +//! Salsa database is modified during execution. +//! +//! The [`SyncNotificationHandler`] is the most common trait that would be used because most +//! notifications are specific to a single document and require updating the server state. +//! Similarly, the [`BackgroundDocumentRequestHandler`] is the most common request handler that +//! would be used as most requests are document-specific and can be executed in the background. +//! +//! See the `./requests` and `./notifications` directories for concrete implementations of these +//! traits in action. + +use std::borrow::Cow; use crate::session::client::Client; use crate::session::{DocumentSnapshot, Session, WorkspaceSnapshot}; -use lsp_types::notification::Notification as LSPNotification; +use lsp_types::Url; +use lsp_types::notification::Notification; use lsp_types::request::Request; use ty_project::ProjectDatabase; /// A supertrait for any server request handler. pub(super) trait RequestHandler { type RequestType: Request; - const METHOD: &'static str = <::RequestType as Request>::METHOD; + const METHOD: &'static str = <::RequestType>::METHOD; } /// A request handler that needs mutable access to the session. -/// This will block the main message receiver loop, meaning that no -/// incoming requests or notifications will be handled while `run` is -/// executing. Try to avoid doing any I/O or long-running computations. +/// +/// This will block the main message receiver loop, meaning that no incoming requests or +/// notifications will be handled while `run` is executing. Try to avoid doing any I/O or +/// long-running computations. pub(super) trait SyncRequestHandler: RequestHandler { fn run( session: &mut Session, @@ -29,7 +66,13 @@ pub(super) trait RetriableRequestHandler: RequestHandler { /// Whether this request can be cancelled if the Salsa database is modified. const RETRY_ON_CANCELLATION: bool = false; - /// The error to return if the request was cancelled due to a modification to the Salsa database. + /// The error to return if the request was cancelled due to a modification to the Salsa + /// database. + /// + /// By default, this returns a [`ContentModified`] error to indicate that the content of a + /// document has changed since the request was made. + /// + /// [`ContentModified`]: lsp_server::ErrorCode::ContentModified fn salsa_cancellation_error() -> lsp_server::ResponseError { lsp_server::ResponseError { code: lsp_server::ErrorCode::ContentModified as i32, @@ -43,9 +86,10 @@ pub(super) trait RetriableRequestHandler: RequestHandler { /// /// This handler is specific to requests that operate on a single document. pub(super) trait BackgroundDocumentRequestHandler: RetriableRequestHandler { + /// Returns the URL of the document that this request handler operates on. fn document_url( params: &<::RequestType as Request>::Params, - ) -> std::borrow::Cow; + ) -> Cow; fn run_with_snapshot( db: &ProjectDatabase, @@ -56,6 +100,10 @@ pub(super) trait BackgroundDocumentRequestHandler: RetriableRequestHandler { } /// A request handler that can be run on a background thread. +/// +/// Unlike [`BackgroundDocumentRequestHandler`], this handler operates on the entire workspace +/// without being tied to a specific document. It is useful for operations that require access to +/// the entire workspace state, such as fetching workspace diagnostics. pub(super) trait BackgroundRequestHandler: RetriableRequestHandler { fn run( snapshot: WorkspaceSnapshot, @@ -66,35 +114,33 @@ pub(super) trait BackgroundRequestHandler: RetriableRequestHandler { /// A supertrait for any server notification handler. pub(super) trait NotificationHandler { - type NotificationType: LSPNotification; - const METHOD: &'static str = - <::NotificationType as LSPNotification>::METHOD; + type NotificationType: Notification; + const METHOD: &'static str = <::NotificationType>::METHOD; } /// A notification handler that needs mutable access to the session. -/// This will block the main message receiver loop, meaning that no -/// incoming requests or notifications will be handled while `run` is -/// executing. Try to avoid doing any I/O or long-running computations. +/// +/// This will block the main message receiver loop, meaning that no incoming requests or +/// notifications will be handled while `run` is executing. Try to avoid doing any I/O or +/// long-running computations. pub(super) trait SyncNotificationHandler: NotificationHandler { fn run( session: &mut Session, client: &Client, - params: <::NotificationType as LSPNotification>::Params, + params: <::NotificationType as Notification>::Params, ) -> super::Result<()>; } /// A notification handler that can be run on a background thread. pub(super) trait BackgroundDocumentNotificationHandler: NotificationHandler { - /// `document_url` can be implemented automatically with - /// `define_document_url!(params: &)` in the trait - /// implementation. + /// Returns the URL of the document that this notification handler operates on. fn document_url( - params: &<::NotificationType as LSPNotification>::Params, - ) -> std::borrow::Cow; + params: &<::NotificationType as Notification>::Params, + ) -> Cow; fn run_with_snapshot( snapshot: DocumentSnapshot, client: &Client, - params: <::NotificationType as LSPNotification>::Params, + params: <::NotificationType as Notification>::Params, ) -> super::Result<()>; }