Skip to main content

Crate lsp_server_tokio

Crate lsp_server_tokio 

Source
Expand description

§lsp-server-tokio

An async-first Rust crate for building LSP (Language Server Protocol) servers using Tokio.

This crate provides transport-agnostic async LSP server infrastructure that handles protocol concerns so developers can focus on language-specific logic.

§Quick Start

use futures::StreamExt;
use lsp_server_tokio::{Connection, IncomingMessage, Response};

let mut conn = Connection::stdio();
let capabilities = serde_json::json!({
    "documentFormattingProvider": true
});

let _client_params = conn.initialize(capabilities).await?;
let sender = conn.client_sender();

while let Some(result) = conn.receiver_mut().next().await {
    let msg = result?;

    match conn.route(msg) {
        IncomingMessage::Request(req, _) if req.method == "shutdown" => {
            conn.handle_shutdown(req.id)?;
        }
        IncomingMessage::Request(req, _) => {
            sender.respond(Response::ok(req.id, serde_json::Value::Null))?;
        }
        IncomingMessage::Notification(notif) if notif.method == "exit" => {
            break;
        }
        IncomingMessage::CancelHandled => {}
        IncomingMessage::Notification(_) => {}
        IncomingMessage::ResponseRouted | IncomingMessage::ResponseUnknown(_) => {}
        _ => {}
    }
}

§Testing

Use duplex_transport() when you want connected in-memory transports for unit and integration tests without stdio:

use futures::{SinkExt, StreamExt};
use lsp_server_tokio::{duplex_transport, Message, Request, Response};

let (mut client, mut server) = duplex_transport(4096);

client
    .send(Message::Request(Request::new(1, "textDocument/hover", None)))
    .await
    .unwrap();

if let Some(Ok(Message::Request(req))) = server.next().await {
    server
        .send(Message::Response(Response::ok(
            req.id,
            serde_json::json!({"contents": "Hello"}),
        )))
        .await
        .unwrap();
}

§Core Types

  • RequestId - Identifies requests/responses (supports both integer and string IDs)
  • ErrorCode - LSP specification error codes
  • ResponseError - Error responses with code, message, and optional data
  • Message - Discriminated union of Request, Response, and Notification
  • Request - JSON-RPC request with id and method
  • Response - JSON-RPC response with result or error
  • Notification - JSON-RPC notification (no id, no response)

§Transport Layer

  • Transport - Type alias for Framed<T, LspCodec> providing Stream + Sink
  • transport() - Factory function wrapping any AsyncRead + AsyncWrite
  • duplex_transport() - Creates connected in-memory transports for testing
  • LspCodec - Encoder/Decoder for Content-Length message framing

§Request Routing

The IncomingMessage enum classifies messages received from Connection::route():

Structs§

CancellationToken
A token which can be used to signal a cancellation request to one or more tasks.
ClientSender
A cloneable, non-blocking handle for server→client communication.
Connection
A bidirectional LSP connection with split sender/receiver and request tracking.
IncomingRequests
Tracks requests received from clients (incoming to the server).
LspCodec
LSP wire protocol codec implementing Content-Length framing.
MessageStream
The receiver half of an LSP connection.
Notification
A JSON-RPC 2.0 notification message.
OutgoingRequests
Tracks requests sent to clients (outgoing from the server).
Request
A JSON-RPC 2.0 request message.
RequestQueue
Combined request queue tracking both incoming and outgoing requests.
Response
A JSON-RPC 2.0 response message.
ResponseError
An error response in JSON-RPC format.
SendError
Error returned when the connection is closed and messages can no longer be queued.
StdioTransport
A combined stdin/stdout stream for LSP server communication.

Enums§

ErrorCode
LSP and JSON-RPC 2.0 error codes.
ExitCode
Exit code for the LSP server process.
IncomingMessage
Represents a classified incoming message after routing.
LifecycleState
Represents the lifecycle state of an LSP connection.
Message
A JSON-RPC 2.0 message that can be a Request, Response, or Notification.
ProtocolError
Errors that occur during LSP protocol lifecycle management.
RequestId
A request identifier that can be either an integer or a string.
ResponseBody
The payload of a JSON-RPC 2.0 response — either a success result or an error.

Constants§

CANCEL_REQUEST_METHOD
The method name for cancel request notifications per LSP specification.

Functions§

cancelled_response
Creates a RequestCancelled error response for a cancelled request.
duplex_transport
Creates a pair of connected in-memory transports for testing.
method_not_found_response
Creates a MethodNotFound error response for an unhandled request.
parse_cancel_params
Parses the request ID from $/cancelRequest notification params.
transport
Creates an LSP transport from an async I/O stream.

Type Aliases§

StdioConnection
A Connection backed by StdioTransport.
Transport
A bidirectional LSP transport over any async I/O stream.