use std::fmt::Display;
use thiserror::Error;
use crate::transport::TransportError;
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, Error)]
pub enum Error {
#[error(transparent)]
Lsp(#[from] LspError),
#[error(transparent)]
Transport(#[from] TransportError),
#[cfg(not(target_arch = "wasm32"))]
#[error("no Tokio runtime is running; start one before serving the connection")]
RuntimeRequired,
}
#[derive(Debug, Error)]
pub enum ClientError {
#[error("failed to serialize client parameters: {0}")]
Serialize(#[source] serde_json::Error),
#[error("client connection is closed")]
ConnectionClosed,
#[error("client outbound queue is closed")]
OutboundClosed,
#[error("client outbound queue capacity is exhausted")]
OutboundOverloaded,
#[error("client request was cancelled")]
Cancelled,
#[error("client request timed out")]
Timeout,
#[error("outbound request ID space exhausted")]
IdExhausted,
#[error("remote error (code {code}): {message}", code = .0.code, message = .0.message)]
Remote(crate::raw::JsonRpcError),
#[error("failed to deserialize client response: {0}")]
Deserialize(#[source] serde_json::Error),
#[error("invalid helper parameters: {0}")]
InvalidHelperParams(String),
#[error(transparent)]
Progress(#[from] ProgressError),
}
#[derive(Debug, Error, PartialEq, Eq)]
pub enum ProgressError {
#[error("progress handle has already ended")]
AlreadyEnded,
#[error("progress was cancelled")]
Cancelled,
#[error("progress token is not active on this connection")]
UnknownToken,
#[error("progress percentage {0} is outside the range 0..=100")]
InvalidPercentage(u32),
}
#[derive(Debug, Error, PartialEq, Eq)]
#[non_exhaustive]
pub enum BuildError {
#[error("duplicate handler registered for method `{0}`")]
DuplicateMethod(String),
#[error("method `{0}` is reserved by the framework and cannot be overridden")]
ReservedMethod(String),
#[error("duplicate handler registered for command `{0}`")]
DuplicateCommand(String),
#[error("a command name cannot be empty")]
EmptyCommandName,
#[error(
"commands conflict with an explicit `workspace/executeCommand` handler; \
register either commands or the raw method, not both"
)]
ExecuteCommandConflict,
#[error("conflicting contributions for capability field `{field}`")]
ConflictingCapability {
field: &'static str,
},
#[error("`configure_initialize` may only be supplied once")]
DuplicateConfigureInitialize,
#[error("lifecycle hook `{0}` may only be supplied once")]
DuplicateLifecycleHook(&'static str),
#[error("concurrency limit must be greater than zero")]
InvalidConcurrencyLimit,
#[error("outbound warning threshold must be greater than zero")]
InvalidOutboundWarningThreshold,
#[error("resource policy `{field}` must be greater than zero when enabled")]
InvalidResourcePolicy {
field: crate::ResourcePolicyField,
},
}
#[derive(Debug, Error)]
pub enum LspError {
#[error("internal error: {0}")]
Internal(String),
#[error("invalid params: {0}")]
InvalidParams(String),
#[error("method not found: {0}")]
MethodNotFound(String),
#[error("request cancelled")]
RequestCancelled,
#[error("content modified")]
ContentModified,
#[error("server not initialized")]
ServerNotInitialized,
#[error("invalid request: {0}")]
InvalidRequest(String),
#[error("{message}")]
ServerError {
code: i32,
message: String,
data: Option<serde_json::Value>,
},
}
impl LspError {
pub fn internal(e: impl Display) -> Self {
Self::Internal(e.to_string())
}
pub fn invalid_params(e: impl Display) -> Self {
Self::InvalidParams(e.to_string())
}
pub fn invalid_request(e: impl Display) -> Self {
Self::InvalidRequest(e.to_string())
}
pub fn code(&self) -> i32 {
match self {
Self::Internal(_) => -32603,
Self::InvalidParams(_) => -32602,
Self::MethodNotFound(_) => -32601,
Self::RequestCancelled => -32800,
Self::ContentModified => -32801,
Self::ServerNotInitialized => -32002,
Self::InvalidRequest(_) => -32600,
Self::ServerError { code, .. } => *code,
}
}
pub fn message(&self) -> String {
match self {
Self::Internal(m)
| Self::InvalidParams(m)
| Self::MethodNotFound(m)
| Self::InvalidRequest(m) => m.clone(),
Self::RequestCancelled => "request cancelled".to_string(),
Self::ContentModified => "content modified".to_string(),
Self::ServerNotInitialized => "server not initialized".to_string(),
Self::ServerError { message, .. } => message.clone(),
}
}
pub fn data(&self) -> Option<&serde_json::Value> {
match self {
Self::ServerError { data, .. } => data.as_ref(),
_ => None,
}
}
}