diff --git a/crates/ruff_server/src/server/api.rs b/crates/ruff_server/src/server/api.rs index 42c73528cf..65967f04ec 100644 --- a/crates/ruff_server/src/server/api.rs +++ b/crates/ruff_server/src/server/api.rs @@ -26,8 +26,11 @@ use self::traits::{NotificationHandler, RequestHandler}; use super::{Result, schedule::BackgroundSchedule}; -/// Defines the `document_url` method for implementers of [`traits::Notification`] and [`traits::Request`], -/// given the parameter type used by the implementer. +/// Defines the `document_url` method for implementers of [`Notification`] and [`Request`], given +/// the request or notification parameter type. +/// +/// This would only work if the parameter type has a `text_document` field with a `uri` field +/// that is of type [`lsp_types::Url`]. macro_rules! define_document_url { ($params:ident: &$p:ty) => { fn document_url($params: &$p) -> std::borrow::Cow { diff --git a/crates/ruff_server/src/server/api/traits.rs b/crates/ruff_server/src/server/api/traits.rs index 8d70c5ff67..0003ea4f27 100644 --- a/crates/ruff_server/src/server/api/traits.rs +++ b/crates/ruff_server/src/server/api/traits.rs @@ -1,4 +1,31 @@ -//! A stateful LSP implementation that calls into the Ruff 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. +//! +//! 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 crate::session::{Client, DocumentSnapshot, Session}; @@ -12,9 +39,10 @@ pub(super) trait RequestHandler { } /// 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, @@ -24,10 +52,14 @@ pub(super) trait SyncRequestHandler: RequestHandler { } /// A request handler that can be run on a background thread. +/// +/// This handler is specific to requests that operate on a single document. pub(super) trait BackgroundDocumentRequestHandler: RequestHandler { - /// `document_url` can be implemented automatically with - /// `define_document_url!(params: &)` in the trait - /// implementation. + /// Returns the URL of the document that this request handler operates on. + /// + /// This method can be implemented automatically using the [`define_document_url`] macro. + /// + /// [`define_document_url`]: super::define_document_url fn document_url( params: &<::RequestType as Request>::Params, ) -> std::borrow::Cow; @@ -47,9 +79,10 @@ pub(super) trait NotificationHandler { } /// 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, @@ -60,9 +93,11 @@ pub(super) trait SyncNotificationHandler: NotificationHandler { /// 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. + /// + /// This method can be implemented automatically using the [`define_document_url`] macro. + /// + /// [`define_document_url`]: super::define_document_url fn document_url( params: &<::NotificationType as LSPNotification>::Params, ) -> std::borrow::Cow; 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 2953872ce3..68b45364da 100644 --- a/crates/ty_server/src/server/api/traits.rs +++ b/crates/ty_server/src/server/api/traits.rs @@ -1,24 +1,61 @@ -//! 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 session, which +//! includes all the workspaces, 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 std::panic::AssertUnwindSafe; use crate::session::client::Client; use crate::session::{DocumentSnapshot, Session, SessionSnapshot}; -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, @@ -31,7 +68,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, @@ -45,9 +88,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, @@ -58,6 +102,11 @@ pub(super) trait BackgroundDocumentRequestHandler: RetriableRequestHandler { } /// A request handler that can be run on a background thread. +/// +/// Unlike [`BackgroundDocumentRequestHandler`], this handler operates on the entire session, +/// which includes all the workspaces, without being tied to a specific document. It is useful for +/// operations that require access to the entire session state, such as fetching workspace +/// diagnostics. pub(super) trait BackgroundRequestHandler: RetriableRequestHandler { fn run( snapshot: AssertUnwindSafe, @@ -68,35 +117,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<()>; }