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