use crate::{
editor::Actions,
lsp::{
LspManager,
client::Status,
rpc::{ErrorCode, Message, Request, Response, ResponseError},
},
};
use lsp_types::request as req;
use std::{borrow::Cow, fmt};
use tracing::error;
mod completion;
mod format;
mod goto;
mod hover;
mod init;
mod references;
mod rename;
pub(crate) use init::OpenDocument;
pub(crate) trait LspRequest:
req::Request + fmt::Debug + Send + Sync + Sized + 'static
{
type Data: Send + Sync + fmt::Debug + 'static;
type Pending: Send + Sync + fmt::Debug + 'static;
fn data(lsp_id: usize, data: Self::Data, pending: Self::Pending) -> RequestData<Self>
where
Self: Sized,
{
RequestData {
lsp_id,
data: Some(data),
pending: Some(pending),
}
}
fn build_params(data: Self::Data) -> Self::Params;
fn send(lsp_id: usize, data: Self::Data, p: Self::Pending, man: &mut LspManager) {
let client = match man.clients.get_mut(&lsp_id) {
Some(client) => match client.status {
Status::Running => client,
Status::Initializing => {
man.send_status("LSP server still initializing");
return;
}
},
None => {
man.send_status("no attached LSP client for buffer");
return;
}
};
let params = match serde_json::to_value(Self::build_params(data)) {
Ok(params) => params,
Err(e) => {
error!(error=%e, "unable to serialize LSP request");
man.report_error(format!("unable to send {} LSP request: {e}", Self::METHOD));
return;
}
};
let id = client.next_id();
let res = client.write(Message::Request(Request {
id: id.clone(),
method: Cow::Borrowed(Self::METHOD),
params,
}));
if let Err(e) = res {
man.report_error(format!("unable to send {} LSP request: {e}", Self::METHOD));
return;
}
man.pending.insert(
(client.id, id),
Box::new(PendingRequestData::<Self> {
lsp_id,
pending: Some(p),
}),
);
}
fn handle(
lsp_id: usize,
res: Response,
pending: Self::Pending,
man: &mut LspManager,
) -> Option<Actions> {
match res {
Response::Result { result, .. } => match serde_json::from_value(result) {
Ok(res) => Self::handle_res(lsp_id, res, pending, man),
Err(error) => Self::handle_err(
lsp_id,
ResponseError {
code: ErrorCode::Unknown,
message: error.to_string(),
data: None,
},
man,
),
},
Response::Error { error, .. } => Self::handle_err(lsp_id, error, man),
}
}
fn handle_res(
lsp_id: usize,
res: Self::Result,
pending: Self::Pending,
man: &mut LspManager,
) -> Option<Actions>;
#[allow(unused_variables)]
fn handle_err(lsp_id: usize, err: ResponseError, man: &mut LspManager) -> Option<Actions> {
error!("LSP - dropping malformed response: {err:?}");
None
}
}
#[derive(Debug)]
pub(crate) struct RequestData<T: LspRequest> {
lsp_id: usize,
data: Option<T::Data>,
pending: Option<T::Pending>,
}
pub(crate) trait PreparedLspRequest: Send + Sync + fmt::Debug + 'static {
fn send(&mut self, man: &mut LspManager);
}
impl<T> PreparedLspRequest for RequestData<T>
where
T: LspRequest,
{
fn send(&mut self, man: &mut LspManager) {
T::send(
self.lsp_id,
self.data.take().unwrap(),
self.pending.take().unwrap(),
man,
)
}
}
#[derive(Debug)]
pub(crate) struct PendingRequestData<T: LspRequest> {
lsp_id: usize,
pending: Option<T::Pending>,
}
pub(crate) trait PendingLspRequest: Send + Sync + fmt::Debug + 'static {
fn handle(&mut self, res: Response, man: &mut LspManager) -> Option<Actions>;
}
impl<T> PendingLspRequest for PendingRequestData<T>
where
T: LspRequest,
{
fn handle(&mut self, res: Response, man: &mut LspManager) -> Option<Actions> {
T::handle(self.lsp_id, res, self.pending.take().unwrap(), man)
}
}