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