sync_ls/
server.rs

1//! A synchronous language server implementation.
2
3#[cfg(feature = "dap")]
4mod dap_srv;
5
6#[cfg(feature = "lsp")]
7mod lsp_srv;
8
9use core::fmt;
10use std::any::Any;
11use std::collections::HashMap;
12use std::path::{Path, PathBuf};
13use std::pin::Pin;
14#[cfg(feature = "web")]
15use std::sync::atomic::AtomicU32;
16use std::sync::{Arc, Weak};
17
18use futures::future::MaybeDone;
19use parking_lot::Mutex;
20use serde::Serialize;
21use serde_json::{Value as JsonValue, from_value};
22use tinymist_std::time::Instant;
23
24use crate::msg::*;
25use crate::req_queue;
26use crate::*;
27
28type ImmutPath = Arc<Path>;
29
30/// A future that may be done in place or not.
31pub type ResponseFuture<T> = MaybeDone<Pin<Box<dyn std::future::Future<Output = T> + Send>>>;
32/// A future that may be rejected before actual started.
33pub type LspResponseFuture<T> = LspResult<ResponseFuture<T>>;
34/// A future that could be rejected by common error in `LspResponseFuture`.
35pub type SchedulableResponse<T> = LspResponseFuture<LspResult<T>>;
36/// The common response future type for language servers.
37pub type AnySchedulableResponse = SchedulableResponse<JsonValue>;
38/// The result of a scheduling response
39pub type ScheduleResult = AnySchedulableResponse;
40/// The result of a scheduled response which could be finally caught by
41/// `schedule_tail`.
42/// - Returns Ok(Some()) -> Already responded
43/// - Returns Ok(None) -> Need to respond none
44/// - Returns Err(..) -> Need to respond error
45pub type ScheduledResult = LspResult<Option<()>>;
46
47/// The untyped connect tx for language servers.
48pub type ConnectionTx = TConnectionTx<Message>;
49/// The untyped connect rx for language servers.
50pub type ConnectionRx = TConnectionRx<Message>;
51
52/// The sender of the language server.
53#[derive(Debug, Clone)]
54pub struct TConnectionTx<M> {
55    /// The sender of the events.
56    pub event: crossbeam_channel::Sender<Event>,
57    /// The sender of the LSP messages.
58    pub lsp: crossbeam_channel::Sender<Message>,
59    pub(crate) marker: std::marker::PhantomData<M>,
60}
61
62/// The sender of the language server.
63#[derive(Debug, Clone)]
64pub struct TConnectionRx<M> {
65    /// The receiver of the events.
66    pub event: crossbeam_channel::Receiver<Event>,
67    /// The receiver of the LSP messages.
68    pub lsp: crossbeam_channel::Receiver<Message>,
69    pub(crate) marker: std::marker::PhantomData<M>,
70}
71
72impl<M: TryFrom<Message, Error = anyhow::Error>> TConnectionRx<M> {
73    /// Receives a message or an event.
74    pub fn recv(&self) -> anyhow::Result<EventOrMessage<M>> {
75        crossbeam_channel::select_biased! {
76            recv(self.lsp) -> msg => Ok(EventOrMessage::Msg(msg?.try_into()?)),
77            recv(self.event) -> event => Ok(event.map(EventOrMessage::Evt)?),
78        }
79    }
80}
81
82/// This is a helper enum to handle both events and messages.
83pub enum EventOrMessage<M> {
84    /// An event received.
85    Evt(Event),
86    /// A message received.
87    Msg(M),
88}
89
90/// Connection is just a pair of channels of LSP messages.
91pub struct Connection<M> {
92    /// The senders of the connection.
93    pub sender: TConnectionTx<M>,
94    /// The receivers of the connection.
95    pub receiver: TConnectionRx<M>,
96}
97
98impl<M: TryFrom<Message, Error = anyhow::Error>> From<Connection<Message>> for Connection<M> {
99    fn from(conn: Connection<Message>) -> Self {
100        Self {
101            sender: TConnectionTx {
102                event: conn.sender.event,
103                lsp: conn.sender.lsp,
104                marker: std::marker::PhantomData,
105            },
106            receiver: TConnectionRx {
107                event: conn.receiver.event,
108                lsp: conn.receiver.lsp,
109                marker: std::marker::PhantomData,
110            },
111        }
112    }
113}
114
115impl<M: TryFrom<Message, Error = anyhow::Error>> From<TConnectionTx<M>> for ConnectionTx {
116    fn from(conn: TConnectionTx<M>) -> Self {
117        Self {
118            event: conn.event,
119            lsp: conn.lsp,
120            marker: std::marker::PhantomData,
121        }
122    }
123}
124
125type AnyCaster<S> = Arc<dyn Fn(&mut dyn Any) -> &mut S + Send + Sync>;
126
127/// A Lsp client with typed service `S`.
128pub struct TypedLspClient<S> {
129    client: LspClient,
130    caster: AnyCaster<S>,
131}
132
133impl<S> TypedLspClient<S> {
134    /// Converts the client to an untyped client.
135    pub fn to_untyped(self) -> LspClient {
136        self.client
137    }
138}
139
140impl<S: 'static> TypedLspClient<S> {
141    /// Returns the untyped lsp client.
142    pub fn untyped(&self) -> &LspClient {
143        &self.client
144    }
145
146    /// Casts the service to another type.
147    pub fn cast<T: 'static>(&self, f: fn(&mut S) -> &mut T) -> TypedLspClient<T> {
148        let caster = self.caster.clone();
149        TypedLspClient {
150            client: self.client.clone(),
151            caster: Arc::new(move |s| f(caster(s))),
152        }
153    }
154
155    /// Sends a event to the client itself.
156    pub fn send_event<T: std::any::Any + Send + 'static>(&self, event: T) {
157        self.sender.send_event(event);
158    }
159}
160
161impl<S> Clone for TypedLspClient<S> {
162    fn clone(&self) -> Self {
163        Self {
164            client: self.client.clone(),
165            caster: self.caster.clone(),
166        }
167    }
168}
169
170impl<S> std::ops::Deref for TypedLspClient<S> {
171    type Target = LspClient;
172
173    fn deref(&self) -> &Self::Target {
174        &self.client
175    }
176}
177
178// send_request: Function,
179// send_notification: Function,
180/// The root of the language server host.
181/// Will close connection when dropped.
182#[derive(Debug, Clone)]
183pub struct LspClientRoot {
184    weak: LspClient,
185    _strong: Arc<ConnectionTx>,
186}
187
188impl LspClientRoot {
189    /// Creates a new language server host.
190    pub fn new<M: TryFrom<Message, Error = anyhow::Error> + GetMessageKind>(
191        handle: tokio::runtime::Handle,
192        sender: TConnectionTx<M>,
193    ) -> Self {
194        let _strong = Arc::new(sender.into());
195        let weak = LspClient {
196            handle,
197            msg_kind: M::MESSAGE_KIND,
198            sender: TransportHost::System(SystemTransportSender {
199                sender: Arc::downgrade(&_strong),
200            }),
201            req_queue: Arc::new(Mutex::new(ReqQueue::default())),
202
203            hook: Arc::new(()),
204        };
205        Self { weak, _strong }
206    }
207
208    /// Creates a new language server host from js.
209    #[cfg(feature = "web")]
210    pub fn new_js(handle: tokio::runtime::Handle, transport: JsTransportSender) -> Self {
211        let dummy = dummy_transport::<LspMessage>();
212
213        let _strong = Arc::new(dummy.sender.into());
214        let weak = LspClient {
215            handle,
216            msg_kind: LspMessage::MESSAGE_KIND,
217            sender: TransportHost::Js(transport),
218            req_queue: Arc::new(Mutex::new(ReqQueue::default())),
219
220            hook: Arc::new(()),
221        };
222        Self { weak, _strong }
223    }
224
225    /// Sets the hook for the language server host.
226    pub fn with_hook(mut self, hook: Arc<dyn LsHook>) -> Self {
227        self.weak.hook = hook;
228        self
229    }
230
231    /// Returns the weak reference to the language server host.
232    pub fn weak(&self) -> LspClient {
233        self.weak.clone()
234    }
235}
236
237type ReqHandler = Box<dyn for<'a> FnOnce(&'a mut dyn Any, LspOrDapResponse) + Send + Sync>;
238type ReqQueue = req_queue::ReqQueue<(String, Instant), ReqHandler>;
239
240#[derive(Debug, Clone)]
241enum TransportHost {
242    System(SystemTransportSender),
243    #[cfg(feature = "web")]
244    Js(JsTransportSender),
245}
246
247#[derive(Debug, Clone)]
248struct SystemTransportSender {
249    pub(crate) sender: Weak<ConnectionTx>,
250}
251
252/// Creates a new js transport host.
253#[cfg(feature = "web")]
254#[derive(Debug, Clone)]
255pub struct JsTransportSender {
256    event_id: Arc<AtomicU32>,
257    events: Arc<Mutex<HashMap<u32, Event>>>,
258    pub(crate) sender_event: js_sys::Function,
259    pub(crate) sender_request: js_sys::Function,
260    pub(crate) sender_notification: js_sys::Function,
261}
262
263#[cfg(feature = "web")]
264impl JsTransportSender {
265    /// Creates a new JS transport host.
266    pub fn new(
267        sender_event: js_sys::Function,
268        sender_request: js_sys::Function,
269        sender_notification: js_sys::Function,
270    ) -> Self {
271        Self {
272            event_id: Arc::new(AtomicU32::new(0)),
273            events: Arc::new(Mutex::new(HashMap::new())),
274            sender_event,
275            sender_request,
276            sender_notification,
277        }
278    }
279}
280
281#[cfg(feature = "web")]
282/// SAFETY:
283/// This is only safe if the `JsTransportHost` is used in a single thread.
284unsafe impl Send for TransportHost {}
285
286#[cfg(feature = "web")]
287/// SAFETY:
288/// This is only safe if the `JsTransportHost` is used in a single thread.
289unsafe impl Sync for TransportHost {}
290
291impl TransportHost {
292    /// Sends a event to the server itself.
293    pub fn send_event<T: std::any::Any + Send + 'static>(&self, event: T) {
294        match self {
295            TransportHost::System(host) => {
296                let Some(sender) = host.sender.upgrade() else {
297                    log::warn!("failed to send request: connection closed");
298                    return;
299                };
300
301                if let Err(res) = sender.event.send(Box::new(event)) {
302                    log::warn!("failed to send event: {res:?}");
303                }
304            }
305            #[cfg(feature = "web")]
306            TransportHost::Js(host) => {
307                let event_id = {
308                    let event_id = host
309                        .event_id
310                        .fetch_add(1, std::sync::atomic::Ordering::SeqCst);
311                    let mut lg = host.events.lock();
312                    lg.insert(event_id, Box::new(event));
313                    js_sys::Number::from(event_id)
314                };
315                if let Err(err) = host
316                    .sender_event
317                    .call1(&wasm_bindgen::JsValue::UNDEFINED, &event_id.into())
318                {
319                    log::error!("failed to send event: {err:?}");
320                }
321            }
322        }
323    }
324
325    pub fn send_message(&self, response: Message) {
326        match self {
327            TransportHost::System(host) => {
328                let Some(sender) = host.sender.upgrade() else {
329                    log::warn!("failed to send response: connection closed");
330                    return;
331                };
332                if let Err(res) = sender.lsp.send(response) {
333                    log::warn!("failed to send response: {res:?}");
334                }
335            }
336            #[cfg(feature = "web")]
337            TransportHost::Js(host) => match response {
338                #[cfg(feature = "lsp")]
339                Message::Lsp(lsp::Message::Request(req)) => {
340                    let msg = to_js_value(&req).expect("failed to serialize request to js value");
341                    if let Err(err) = host
342                        .sender_request
343                        .call1(&wasm_bindgen::JsValue::UNDEFINED, &msg)
344                    {
345                        log::error!("failed to send request: {err:?}");
346                    }
347                }
348                #[cfg(feature = "lsp")]
349                Message::Lsp(lsp::Message::Notification(req)) => {
350                    let msg = to_js_value(&req).expect("failed to serialize request to js value");
351                    if let Err(err) = host
352                        .sender_notification
353                        .call1(&wasm_bindgen::JsValue::UNDEFINED, &msg)
354                    {
355                        log::error!("failed to send request: {err:?}");
356                    }
357                }
358                #[cfg(feature = "lsp")]
359                Message::Lsp(lsp::Message::Response(req)) => {
360                    panic!("unexpected response to js world: {req:?}");
361                }
362                #[cfg(feature = "dap")]
363                Message::Dap(dap::Message::Request(req)) => {
364                    let msg = to_js_value(&req).expect("failed to serialize request to js value");
365                    if let Err(err) = host
366                        .sender_request
367                        .call1(&wasm_bindgen::JsValue::UNDEFINED, &msg)
368                    {
369                        log::error!("failed to send request: {err:?}");
370                    }
371                }
372                #[cfg(feature = "dap")]
373                Message::Dap(dap::Message::Event(req)) => {
374                    let msg = to_js_value(&req).expect("failed to serialize request to js value");
375                    if let Err(err) = host
376                        .sender_notification
377                        .call1(&wasm_bindgen::JsValue::UNDEFINED, &msg)
378                    {
379                        log::error!("failed to send request: {err:?}");
380                    }
381                }
382                #[cfg(feature = "dap")]
383                Message::Dap(dap::Message::Response(req)) => {
384                    panic!("unexpected response to js world: {req:?}");
385                }
386            },
387        }
388    }
389}
390
391// todo: poor performance, struct -> serde_json -> serde_wasm_bindgen ->
392// serialize -> deserialize??
393#[cfg(feature = "web")]
394fn to_js_value<T: serde::Serialize>(
395    value: &T,
396) -> Result<wasm_bindgen::JsValue, serde_wasm_bindgen::Error> {
397    value.serialize(&serde_wasm_bindgen::Serializer::new().serialize_maps_as_objects(true))
398}
399
400/// The host for the language server, or known as the LSP client.
401#[derive(Debug, Clone)]
402pub struct LspClient {
403    /// The tokio handle.
404    pub handle: tokio::runtime::Handle,
405
406    pub(crate) msg_kind: MessageKind,
407    sender: TransportHost,
408    pub(crate) req_queue: Arc<Mutex<ReqQueue>>,
409
410    pub(crate) hook: Arc<dyn LsHook>,
411}
412
413impl LspClient {
414    /// Returns the untyped lsp client.
415    pub fn untyped(&self) -> &Self {
416        self
417    }
418
419    /// converts the client to a typed client.
420    pub fn to_typed<S: Any>(&self) -> TypedLspClient<S> {
421        TypedLspClient {
422            client: self.clone(),
423            caster: Arc::new(|s| s.downcast_mut().expect("invalid cast")),
424        }
425    }
426
427    /// Checks if there are pending requests.
428    pub fn has_pending_requests(&self) -> bool {
429        self.req_queue.lock().incoming.has_pending()
430    }
431
432    /// Prints states of the request queue and panics.
433    pub fn begin_panic(&self) {
434        self.req_queue.lock().begin_panic();
435    }
436
437    /// Sends a event to the server itself.
438    pub fn send_event<T: std::any::Any + Send + 'static>(&self, event: T) {
439        self.sender.send_event(event);
440    }
441
442    /// Completes an server2client request in the request queue.
443    #[cfg(feature = "lsp")]
444    pub fn complete_lsp_request<S: Any>(&self, service: &mut S, response: lsp::Response) {
445        let mut req_queue = self.req_queue.lock();
446        let Some(handler) = req_queue.outgoing.complete(response.id.clone()) else {
447            log::warn!("received response for unknown request");
448            return;
449        };
450        drop(req_queue);
451        handler(service, response.into())
452    }
453
454    /// Completes an server2client request in the request queue.
455    #[cfg(feature = "dap")]
456    pub fn complete_dap_request<S: Any>(&self, service: &mut S, response: dap::Response) {
457        let mut req_queue = self.req_queue.lock();
458        let Some(handler) = req_queue
459            .outgoing
460            // todo: casting i64 to i32
461            .complete((response.request_seq as i32).into())
462        else {
463            log::warn!("received response for unknown request");
464            return;
465        };
466        drop(req_queue);
467        handler(service, response.into())
468    }
469
470    /// Registers an client2server request in the request queue.
471    pub fn register_request(&self, method: &str, id: &RequestId, received_at: Instant) {
472        let mut req_queue = self.req_queue.lock();
473        self.hook.start_request(id, method);
474        req_queue
475            .incoming
476            .register(id.clone(), (method.to_owned(), received_at));
477    }
478
479    fn respond_result(&self, id: RequestId, result: LspResult<JsonValue>) {
480        let req_id = id.clone();
481        let msg: Message = match (self.msg_kind, result) {
482            #[cfg(feature = "lsp")]
483            (MessageKind::Lsp, res) => lsp::Response::new(id, res).into(),
484            #[cfg(feature = "dap")]
485            (MessageKind::Dap, Ok(resp)) => dap::Response::success(RequestId::dap(id), resp).into(),
486            #[cfg(feature = "dap")]
487            (MessageKind::Dap, Err(e)) => {
488                dap::Response::error(RequestId::dap(id), Some(e.message), None).into()
489            }
490        };
491
492        self.respond(req_id, msg);
493    }
494
495    /// Completes an client2server request in the request queue.
496    pub fn respond(&self, id: RequestId, response: Message) {
497        let mut req_queue = self.req_queue.lock();
498        let Some((method, received_at)) = req_queue.incoming.complete(&id) else {
499            return;
500        };
501
502        self.hook.stop_request(&id, &method, received_at);
503
504        self.sender.send_message(response);
505    }
506}
507
508impl LspClient {
509    /// Finally sends the response if it is not sent before.
510    /// From the definition, the response is already sent if it is `Some(())`.
511    pub async fn schedule_tail(self, req_id: RequestId, resp: ScheduleResult) {
512        match resp {
513            Ok(MaybeDone::Done(result)) => {
514                self.respond_result(req_id, result);
515            }
516            Ok(MaybeDone::Future(result)) => {
517                self.respond_result(req_id, result.await);
518            }
519            Ok(MaybeDone::Gone) => {
520                log::warn!("response for request({req_id:?}) already taken");
521                self.respond_result(req_id, Err(internal_error("response already taken")));
522            }
523            Err(err) => {
524                self.respond_result(req_id, Err(err));
525            }
526        }
527    }
528}
529
530/// A trait that defines the hook for the language server.
531pub trait LsHook: fmt::Debug + Send + Sync {
532    /// Starts a request.
533    fn start_request(&self, req_id: &RequestId, method: &str);
534    /// Stops a request.
535    fn stop_request(&self, req_id: &RequestId, method: &str, received_at: Instant);
536    /// Starts a notification.
537    fn start_notification(&self, method: &str);
538    /// Stops a notification.
539    fn stop_notification(&self, method: &str, received_at: Instant, result: LspResult<()>);
540}
541
542impl LsHook for () {
543    fn start_request(&self, req_id: &RequestId, method: &str) {
544        log::info!("handling {method} - ({req_id})");
545    }
546
547    fn stop_request(&self, req_id: &RequestId, method: &str, received_at: Instant) {
548        let duration = received_at.elapsed();
549        log::info!("handled  {method} - ({req_id}) in {duration:0.2?}");
550    }
551
552    fn start_notification(&self, method: &str) {
553        log::info!("notifying {method}");
554    }
555
556    fn stop_notification(&self, method: &str, received_at: Instant, result: LspResult<()>) {
557        let request_duration = received_at.elapsed();
558        if let Err(err) = result {
559            log::error!("notify {method} failed in {request_duration:0.2?}: {err:?}");
560        } else {
561            log::info!("notify {method} succeeded in {request_duration:0.2?}");
562        }
563    }
564}
565
566type AsyncHandler<S, T, R> = fn(srv: &mut S, args: T) -> SchedulableResponse<R>;
567type RawHandler<S, T> = fn(srv: &mut S, args: T) -> ScheduleResult;
568type BoxPureHandler<S, T> = Box<dyn Fn(&mut S, T) -> LspResult<()>>;
569type BoxHandler<S, T> = Box<dyn Fn(&mut S, T) -> SchedulableResponse<JsonValue>>;
570type ExecuteCmdMap<S> = HashMap<&'static str, BoxHandler<S, Vec<JsonValue>>>;
571type RegularCmdMap<S> = HashMap<&'static str, BoxHandler<S, JsonValue>>;
572type NotifyCmdMap<S> = HashMap<&'static str, BoxPureHandler<S, JsonValue>>;
573type ResourceMap<S> = HashMap<ImmutPath, BoxHandler<S, Vec<JsonValue>>>;
574type MayInitBoxHandler<A, S, T> =
575    Box<dyn for<'a> Fn(ServiceState<'a, A, S>, &LspClient, T) -> anyhow::Result<()>>;
576type EventMap<A, S> = HashMap<core::any::TypeId, MayInitBoxHandler<A, S, Event>>;
577
578/// A trait that initializes the language server.
579pub trait Initializer {
580    /// The type of the initialization request.
581    type I: for<'de> serde::Deserialize<'de>;
582    /// The type of the service.
583    type S;
584
585    /// Handles the initialization request.
586    /// If the behind protocol is the standard LSP, the request is
587    /// `InitializeParams`.
588    fn initialize(self, req: Self::I) -> (Self::S, AnySchedulableResponse);
589}
590
591/// The language server builder serving LSP.
592#[cfg(feature = "lsp")]
593pub type LspBuilder<Args> = LsBuilder<LspMessage, Args>;
594/// The language server builder serving DAP.
595#[cfg(feature = "dap")]
596pub type DapBuilder<Args> = LsBuilder<DapMessage, Args>;
597
598/// The builder pattern for the language server.
599pub struct LsBuilder<M, Args: Initializer> {
600    /// The extra initialization arguments.
601    pub args: Args,
602    /// The client surface for the implementing language server.
603    pub client: LspClient,
604    /// The event handlers.
605    pub events: EventMap<Args, Args::S>,
606    /// The command handlers.
607    pub command_handlers: ExecuteCmdMap<Args::S>,
608    /// The notification handlers.
609    pub notif_handlers: NotifyCmdMap<Args::S>,
610    /// The LSP request handlers.
611    pub req_handlers: RegularCmdMap<Args::S>,
612    /// The resource handlers.
613    pub resource_handlers: ResourceMap<Args::S>,
614    _marker: std::marker::PhantomData<M>,
615}
616
617impl<M, Args: Initializer> LsBuilder<M, Args>
618where
619    Args::S: 'static,
620{
621    /// Creates a new language server builder.
622    pub fn new(args: Args, client: LspClient) -> Self {
623        Self {
624            args,
625            client,
626            events: EventMap::new(),
627            command_handlers: ExecuteCmdMap::new(),
628            notif_handlers: NotifyCmdMap::new(),
629            req_handlers: RegularCmdMap::new(),
630            resource_handlers: ResourceMap::new(),
631            _marker: std::marker::PhantomData,
632        }
633    }
634
635    /// Registers an event handler.
636    pub fn with_event<T: std::any::Any>(
637        mut self,
638        ins: &T,
639        handler: impl for<'a> Fn(ServiceState<'a, Args, Args::S>, T) -> anyhow::Result<()> + 'static,
640    ) -> Self {
641        self.events.insert(
642            ins.type_id(),
643            Box::new(move |s, _client, req| handler(s, *req.downcast().unwrap())),
644        );
645        self
646    }
647
648    /// Registers an async resource handler.
649    pub fn with_resource(
650        mut self,
651        path: &'static str,
652        handler: fn(&mut Args::S, Vec<JsonValue>) -> AnySchedulableResponse,
653    ) -> Self {
654        self.resource_handlers
655            .insert(Path::new(path).into(), Box::new(handler));
656        self
657    }
658
659    /// Builds the language server driver.
660    pub fn build(self) -> LsDriver<M, Args> {
661        LsDriver {
662            state: State::Uninitialized(Some(Box::new(self.args))),
663            events: self.events,
664            client: self.client,
665            commands: self.command_handlers,
666            notifications: self.notif_handlers,
667            requests: self.req_handlers,
668            resources: self.resource_handlers,
669            _marker: std::marker::PhantomData,
670        }
671    }
672}
673
674/// An enum to represent the state of the language server.
675pub enum ServiceState<'a, A, S> {
676    /// The service is uninitialized.
677    Uninitialized(Option<&'a mut A>),
678    /// The service is initializing.
679    Ready(&'a mut S),
680}
681
682impl<A, S> ServiceState<'_, A, S> {
683    /// Converts the state to an option holding the ready service.
684    pub fn ready(&mut self) -> Option<&mut S> {
685        match self {
686            ServiceState::Ready(s) => Some(s),
687            _ => None,
688        }
689    }
690}
691
692#[derive(Debug, Clone, PartialEq, Eq)]
693enum State<Args, S> {
694    Uninitialized(Option<Box<Args>>),
695    Initializing(S),
696    Ready(S),
697    ShuttingDown,
698}
699
700impl<Args, S> State<Args, S> {
701    fn opt(&self) -> Option<&S> {
702        match &self {
703            State::Ready(s) => Some(s),
704            _ => None,
705        }
706    }
707
708    fn opt_mut(&mut self) -> Option<&mut S> {
709        match self {
710            State::Ready(s) => Some(s),
711            _ => None,
712        }
713    }
714}
715
716/// The language server driver.
717pub struct LsDriver<M, Args: Initializer> {
718    /// State to synchronize with the client.
719    state: State<Args, Args::S>,
720    /// The language server client.
721    pub client: LspClient,
722
723    // Handle maps
724    /// Events for dispatching.
725    pub events: EventMap<Args, Args::S>,
726    /// Extra commands provided with `textDocument/executeCommand`.
727    pub commands: ExecuteCmdMap<Args::S>,
728    /// Notifications for dispatching.
729    pub notifications: NotifyCmdMap<Args::S>,
730    /// Requests for dispatching.
731    pub requests: RegularCmdMap<Args::S>,
732    /// Resources for dispatching.
733    pub resources: ResourceMap<Args::S>,
734    _marker: std::marker::PhantomData<M>,
735}
736
737impl<M, Args: Initializer> LsDriver<M, Args> {
738    /// Gets the state of the language server.
739    pub fn state(&self) -> Option<&Args::S> {
740        self.state.opt()
741    }
742
743    /// Gets the mutable state of the language server.
744    pub fn state_mut(&mut self) -> Option<&mut Args::S> {
745        self.state.opt_mut()
746    }
747
748    /// Makes the language server ready.
749    pub fn ready(&mut self, params: Args::I) -> AnySchedulableResponse {
750        let args = match &mut self.state {
751            State::Uninitialized(args) => args,
752            _ => return just_result(Err(invalid_request("server is already initialized"))),
753        };
754
755        let args = args.take().expect("already initialized");
756        let (s, res) = args.initialize(params);
757        self.state = State::Ready(s);
758
759        res
760    }
761
762    /// Get static resources with help of tinymist service, for example, a
763    /// static help pages for some typst function.
764    pub fn get_resources(&mut self, args: Vec<JsonValue>) -> ScheduleResult {
765        let s = self.state.opt_mut().ok_or_else(not_initialized)?;
766
767        let path =
768            from_value::<PathBuf>(args[0].clone()).map_err(|e| invalid_params(e.to_string()))?;
769
770        let Some(handler) = self.resources.get(path.as_path()) else {
771            log::error!("asked for unknown resource: {path:?}");
772            return Err(method_not_found());
773        };
774
775        // Note our redirection will keep the first path argument in the args vec.
776        handler(s, args)
777    }
778}
779
780/// A helper function to create a `LspResponseFuture`
781pub fn just_ok<T, E>(res: T) -> Result<ResponseFuture<Result<T, E>>, E> {
782    Ok(futures::future::MaybeDone::Done(Ok(res)))
783}
784
785/// A helper function to create a `LspResponseFuture`
786pub fn just_result<T, E>(res: Result<T, E>) -> Result<ResponseFuture<Result<T, E>>, E> {
787    Ok(futures::future::MaybeDone::Done(res))
788}
789
790/// A helper function to create a `LspResponseFuture`
791pub fn just_future<T, E>(
792    fut: impl std::future::Future<Output = Result<T, E>> + Send + 'static,
793) -> Result<ResponseFuture<Result<T, E>>, E> {
794    Ok(futures::future::MaybeDone::Future(Box::pin(fut)))
795}
796
797/// Creates an invalid params error.
798pub fn invalid_params(msg: impl fmt::Display) -> ResponseError {
799    resp_err(ErrorCode::InvalidParams, msg)
800}
801
802/// Creates an internal error.
803pub fn internal_error(msg: impl fmt::Display) -> ResponseError {
804    resp_err(ErrorCode::InternalError, msg)
805}
806
807/// Creates a not initialized error.
808pub fn not_initialized() -> ResponseError {
809    resp_err(ErrorCode::ServerNotInitialized, "not initialized yet")
810}
811
812/// Creates a method not found error.
813pub fn method_not_found() -> ResponseError {
814    resp_err(ErrorCode::MethodNotFound, "method not found")
815}
816
817/// Creates an invalid request error.
818pub fn invalid_request(msg: impl fmt::Display) -> ResponseError {
819    resp_err(ErrorCode::InvalidRequest, msg)
820}
821
822fn from_json<T: serde::de::DeserializeOwned>(json: JsonValue) -> LspResult<T> {
823    serde_json::from_value(json).map_err(invalid_request)
824}
825
826/// Erases the response type to a generic `JsonValue`.
827pub fn erased_response<T: Serialize + 'static>(resp: SchedulableResponse<T>) -> ScheduleResult {
828    /// Responds a typed result to the client.
829    fn map_respond_result<T: Serialize>(result: LspResult<T>) -> LspResult<JsonValue> {
830        result.and_then(|t| serde_json::to_value(t).map_err(internal_error))
831    }
832
833    let resp = resp?;
834
835    use futures::future::MaybeDone::*;
836    Ok(match resp {
837        Done(result) => MaybeDone::Done(map_respond_result(result)),
838        Future(fut) => MaybeDone::Future(Box::pin(async move { map_respond_result(fut.await) })),
839        Gone => {
840            log::warn!("response already taken");
841            MaybeDone::Done(Err(internal_error("response already taken")))
842        }
843    })
844}
845
846fn resp_err(code: ErrorCode, msg: impl fmt::Display) -> ResponseError {
847    ResponseError {
848        code: code as i32,
849        message: msg.to_string(),
850        data: None,
851    }
852}