[ty] Add documentation for server traits (#19137)

This PR adds some basic documentation for the traits in the server
implementation.
This commit is contained in:
Dhruv Manilawala 2025-07-07 19:56:09 +05:30 committed by GitHub
parent 8cf1b876ee
commit 56258bb3b7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 123 additions and 38 deletions

View file

@ -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<lsp_types::Url> {

View file

@ -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: &<YourParameterType>)` 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: &<<Self as RequestHandler>::RequestType as Request>::Params,
) -> std::borrow::Cow<lsp_types::Url>;
@ -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: &<YourParameterType>)` 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: &<<Self as NotificationHandler>::NotificationType as LSPNotification>::Params,
) -> std::borrow::Cow<lsp_types::Url>;

View file

@ -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<lsp_types::Url> {
fn document_url(params: &DocumentDiagnosticParams) -> Cow<Url> {
Cow::Borrowed(&params.text_document.uri)
}

View file

@ -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 = <<Self as RequestHandler>::RequestType as Request>::METHOD;
const METHOD: &'static str = <<Self as RequestHandler>::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: &<<Self as RequestHandler>::RequestType as Request>::Params,
) -> std::borrow::Cow<lsp_types::Url>;
) -> Cow<Url>;
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<SessionSnapshot>,
@ -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 =
<<Self as NotificationHandler>::NotificationType as LSPNotification>::METHOD;
type NotificationType: Notification;
const METHOD: &'static str = <<Self as NotificationHandler>::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: <<Self as NotificationHandler>::NotificationType as LSPNotification>::Params,
params: <<Self as NotificationHandler>::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: &<YourParameterType>)` in the trait
/// implementation.
/// Returns the URL of the document that this notification handler operates on.
fn document_url(
params: &<<Self as NotificationHandler>::NotificationType as LSPNotification>::Params,
) -> std::borrow::Cow<lsp_types::Url>;
params: &<<Self as NotificationHandler>::NotificationType as Notification>::Params,
) -> Cow<Url>;
fn run_with_snapshot(
snapshot: DocumentSnapshot,
client: &Client,
params: <<Self as NotificationHandler>::NotificationType as LSPNotification>::Params,
params: <<Self as NotificationHandler>::NotificationType as Notification>::Params,
) -> super::Result<()>;
}