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            },
414        }
415    }
416}
417
418// todo: poor performance, struct -> serde_json -> serde_wasm_bindgen ->
419// serialize -> deserialize??
420#[cfg(feature = "web")]
421fn to_js_value<T: serde::Serialize>(
422    value: &T,
423) -> Result<wasm_bindgen::JsValue, serde_wasm_bindgen::Error> {
424    value.serialize(&serde_wasm_bindgen::Serializer::new().serialize_maps_as_objects(true))
425}
426
427/// The host for the language server, or known as the LSP client.
428#[derive(Debug, Clone)]
429pub struct LspClient {
430    /// The tokio handle.
431    pub handle: tokio::runtime::Handle,
432
433    pub(crate) msg_kind: MessageKind,
434    /// The TransportHost between LspClient and LspServer
435    pub sender: TransportHost,
436    pub(crate) req_queue: Arc<Mutex<ReqQueue>>,
437
438    pub(crate) hook: Arc<dyn LsHook>,
439}
440
441impl LspClient {
442    /// Returns the untyped lsp client.
443    pub fn untyped(&self) -> &Self {
444        self
445    }
446
447    /// converts the client to a typed client.
448    pub fn to_typed<S: Any>(&self) -> TypedLspClient<S> {
449        TypedLspClient {
450            client: self.clone(),
451            caster: Arc::new(|s| s.downcast_mut().expect("invalid cast")),
452        }
453    }
454
455    /// Checks if there are pending requests.
456    pub fn has_pending_requests(&self) -> bool {
457        self.req_queue.lock().incoming.has_pending()
458    }
459
460    /// Prints states of the request queue and panics.
461    pub fn begin_panic(&self) {
462        self.req_queue.lock().begin_panic();
463    }
464
465    /// Sends a event to the server itself.
466    pub fn send_event<T: std::any::Any + Send + 'static>(&self, event: T) {
467        self.sender.send_event(event);
468    }
469
470    /// Completes an server2client request in the request queue.
471    #[cfg(feature = "lsp")]
472    pub fn complete_lsp_request<S: Any>(&self, service: &mut S, response: lsp::Response) {
473        let mut req_queue = self.req_queue.lock();
474        let Some(handler) = req_queue.outgoing.complete(response.id.clone()) else {
475            log::warn!("received response for unknown request");
476            return;
477        };
478        drop(req_queue);
479        handler(service, response.into())
480    }
481
482    /// Completes an server2client request in the request queue.
483    #[cfg(feature = "dap")]
484    pub fn complete_dap_request<S: Any>(&self, service: &mut S, response: dap::Response) {
485        let mut req_queue = self.req_queue.lock();
486        let Some(handler) = req_queue
487            .outgoing
488            // todo: casting i64 to i32
489            .complete((response.request_seq as i32).into())
490        else {
491            log::warn!("received response for unknown request");
492            return;
493        };
494        drop(req_queue);
495        handler(service, response.into())
496    }
497
498    /// Registers an client2server request in the request queue.
499    pub fn register_request(&self, method: &str, id: &RequestId, received_at: Time) {
500        let mut req_queue = self.req_queue.lock();
501        self.hook.start_request(id, method);
502        req_queue
503            .incoming
504            .register(id.clone(), (method.to_owned(), received_at));
505    }
506
507    fn respond_result(&self, id: RequestId, result: LspResult<JsonValue>) {
508        let req_id = id.clone();
509        let msg: Message = match (self.msg_kind, result) {
510            #[cfg(feature = "lsp")]
511            (MessageKind::Lsp, res) => lsp::Response::new(id, res).into(),
512            #[cfg(feature = "dap")]
513            (MessageKind::Dap, Ok(resp)) => dap::Response::success(RequestId::dap(id), resp).into(),
514            #[cfg(feature = "dap")]
515            (MessageKind::Dap, Err(e)) => {
516                dap::Response::error(RequestId::dap(id), Some(e.message), None).into()
517            }
518        };
519
520        self.respond(req_id, msg);
521    }
522
523    /// Completes an client2server request in the request queue.
524    pub fn respond(&self, id: RequestId, response: Message) {
525        let mut req_queue = self.req_queue.lock();
526        let Some((method, received_at)) = req_queue.incoming.complete(&id) else {
527            return;
528        };
529
530        self.hook.stop_request(&id, &method, received_at);
531
532        let delay = tinymist_std::time::now().duration_since(received_at);
533        match delay {
534            Ok(delay) => {
535                if delay.as_secs() > 10 {
536                    let worst_outgoing =
537                        req_queue.incoming.pending().max_by_key(|(_, data)| data.1);
538                    let worst_case = if let Some((id, (method, since))) = worst_outgoing {
539                        let duration = tinymist_std::time::now().duration_since(*since);
540                        format!(", worst case: req({method:?}, {id:?}) - {duration:?}")
541                    } else {
542                        String::new()
543                    };
544                    log::warn!(
545                        "request {id:?} is completed after {delay:?}, pending incoming requests: {:?}, pending outgoing requests: {:?}{worst_case}",
546                        req_queue.incoming,
547                        req_queue.outgoing
548                    );
549                }
550            }
551            Err(err) => {
552                log::error!("failed to get delay for request {id:?}: {err:?}");
553            }
554        }
555
556        self.sender.send_message(response);
557    }
558}
559
560impl LspClient {
561    /// Finally sends the response if it is not sent before.
562    /// From the definition, the response is already sent if it is `Some(())`.
563    pub async fn schedule_tail(self, req_id: RequestId, resp: ScheduleResult) {
564        match resp {
565            Ok(MaybeDone::Done(result)) => {
566                self.respond_result(req_id, result);
567            }
568            Ok(MaybeDone::Future(result)) => {
569                self.respond_result(req_id, result.await);
570            }
571            Ok(MaybeDone::Gone) => {
572                log::warn!("response for request({req_id:?}) already taken");
573                self.respond_result(req_id, Err(internal_error("response already taken")));
574            }
575            Err(err) => {
576                self.respond_result(req_id, Err(err));
577            }
578        }
579    }
580}
581
582/// A trait that defines the hook for the language server.
583pub trait LsHook: fmt::Debug + Send + Sync {
584    /// Starts a request.
585    fn start_request(&self, req_id: &RequestId, method: &str);
586    /// Stops a request.
587    fn stop_request(&self, req_id: &RequestId, method: &str, received_at: Time);
588    /// Starts a notification.
589    fn start_notification(&self, track_id: i32, method: &str);
590    /// Stops a notification.
591    fn stop_notification(
592        &self,
593        track_id: i32,
594        method: &str,
595        received_at: Time,
596        result: LspResult<()>,
597    );
598}
599
600impl LsHook for () {
601    fn start_request(&self, req_id: &RequestId, method: &str) {
602        log::info!("handling {method} - ({req_id})");
603    }
604
605    fn stop_request(&self, req_id: &RequestId, method: &str, received_at: Time) {
606        let duration = received_at.elapsed();
607        log::info!("handled  {method} - ({req_id}) in {duration:0.2?}");
608    }
609
610    fn start_notification(&self, track_id: i32, method: &str) {
611        log::info!("notifying ({track_id}) - {method}");
612    }
613
614    fn stop_notification(
615        &self,
616        track_id: i32,
617        method: &str,
618        received_at: Time,
619        result: LspResult<()>,
620    ) {
621        let request_duration = received_at.elapsed();
622        if let Err(err) = result {
623            log::error!(
624                "notify ({track_id}) - {method} failed in {request_duration:0.2?}: {err:?}"
625            );
626        } else {
627            log::info!("notify ({track_id}) - {method} succeeded in {request_duration:0.2?}");
628        }
629    }
630}
631
632type AsyncHandler<S, T, R> = fn(srv: &mut S, args: T) -> SchedulableResponse<R>;
633type RawHandler<S, T> = fn(srv: &mut S, args: T) -> ScheduleResult;
634type BoxPureHandler<S, T> = Box<dyn Fn(&mut S, T) -> LspResult<()>>;
635type BoxHandler<S, T> = Box<dyn Fn(&mut S, T) -> SchedulableResponse<JsonValue>>;
636type ExecuteCmdMap<S> = HashMap<&'static str, BoxHandler<S, Vec<JsonValue>>>;
637type RegularCmdMap<S> = HashMap<&'static str, BoxHandler<S, JsonValue>>;
638type NotifyCmdMap<S> = HashMap<&'static str, BoxPureHandler<S, JsonValue>>;
639type ResourceMap<S> = HashMap<ImmutPath, BoxHandler<S, Vec<JsonValue>>>;
640type MayInitBoxHandler<A, S, T> =
641    Box<dyn for<'a> Fn(ServiceState<'a, A, S>, &LspClient, T) -> anyhow::Result<()>>;
642type EventMap<A, S> = HashMap<core::any::TypeId, MayInitBoxHandler<A, S, Event>>;
643
644/// A trait that initializes the language server.
645pub trait Initializer {
646    /// The type of the initialization request.
647    type I: for<'de> serde::Deserialize<'de>;
648    /// The type of the service.
649    type S;
650
651    /// Handles the initialization request.
652    /// If the behind protocol is the standard LSP, the request is
653    /// `InitializeParams`.
654    fn initialize(self, req: Self::I) -> (Self::S, AnySchedulableResponse);
655}
656
657/// The language server builder serving LSP.
658#[cfg(feature = "lsp")]
659pub type LspBuilder<Args> = LsBuilder<LspMessage, Args>;
660/// The language server builder serving DAP.
661#[cfg(feature = "dap")]
662pub type DapBuilder<Args> = LsBuilder<DapMessage, Args>;
663
664/// The builder pattern for the language server.
665pub struct LsBuilder<M, Args: Initializer> {
666    /// The extra initialization arguments.
667    pub args: Args,
668    /// The client surface for the implementing language server.
669    pub client: LspClient,
670    /// The event handlers.
671    pub events: EventMap<Args, Args::S>,
672    /// The command handlers.
673    pub command_handlers: ExecuteCmdMap<Args::S>,
674    /// The notification handlers.
675    pub notif_handlers: NotifyCmdMap<Args::S>,
676    /// The LSP request handlers.
677    pub req_handlers: RegularCmdMap<Args::S>,
678    /// The resource handlers.
679    pub resource_handlers: ResourceMap<Args::S>,
680    _marker: std::marker::PhantomData<M>,
681}
682
683impl<M, Args: Initializer> LsBuilder<M, Args>
684where
685    Args::S: 'static,
686{
687    /// Creates a new language server builder.
688    pub fn new(args: Args, client: LspClient) -> Self {
689        Self {
690            args,
691            client,
692            events: EventMap::new(),
693            command_handlers: ExecuteCmdMap::new(),
694            notif_handlers: NotifyCmdMap::new(),
695            req_handlers: RegularCmdMap::new(),
696            resource_handlers: ResourceMap::new(),
697            _marker: std::marker::PhantomData,
698        }
699    }
700
701    /// Registers an event handler.
702    pub fn with_event<T: std::any::Any>(
703        mut self,
704        ins: &T,
705        handler: impl for<'a> Fn(ServiceState<'a, Args, Args::S>, T) -> anyhow::Result<()> + 'static,
706    ) -> Self {
707        self.events.insert(
708            ins.type_id(),
709            Box::new(move |s, _client, req| handler(s, *req.downcast().unwrap())),
710        );
711        self
712    }
713
714    /// Registers an async resource handler.
715    pub fn with_resource(
716        mut self,
717        path: &'static str,
718        handler: fn(&mut Args::S, Vec<JsonValue>) -> AnySchedulableResponse,
719    ) -> Self {
720        self.resource_handlers
721            .insert(Path::new(path).into(), Box::new(handler));
722        self
723    }
724
725    /// Builds the language server driver.
726    pub fn build(self) -> LsDriver<M, Args> {
727        LsDriver {
728            state: State::Uninitialized(Some(Box::new(self.args))),
729            next_not_id: AtomicI32::new(1),
730            events: self.events,
731            client: self.client,
732            commands: self.command_handlers,
733            notifications: self.notif_handlers,
734            requests: self.req_handlers,
735            resources: self.resource_handlers,
736            _marker: std::marker::PhantomData,
737        }
738    }
739}
740
741/// An enum to represent the state of the language server.
742pub enum ServiceState<'a, A, S> {
743    /// The service is uninitialized.
744    Uninitialized(Option<&'a mut A>),
745    /// The service is initializing.
746    Ready(&'a mut S),
747}
748
749impl<A, S> ServiceState<'_, A, S> {
750    /// Converts the state to an option holding the ready service.
751    pub fn ready(&mut self) -> Option<&mut S> {
752        match self {
753            ServiceState::Ready(s) => Some(s),
754            _ => None,
755        }
756    }
757}
758
759#[derive(Debug, Clone, PartialEq, Eq)]
760enum State<Args, S> {
761    Uninitialized(Option<Box<Args>>),
762    Initializing(S),
763    Ready(S),
764    ShuttingDown,
765}
766
767impl<Args, S> State<Args, S> {
768    fn opt(&self) -> Option<&S> {
769        match &self {
770            State::Ready(s) => Some(s),
771            _ => None,
772        }
773    }
774
775    fn opt_mut(&mut self) -> Option<&mut S> {
776        match self {
777            State::Ready(s) => Some(s),
778            _ => None,
779        }
780    }
781}
782
783/// The language server driver.
784pub struct LsDriver<M, Args: Initializer> {
785    /// State to synchronize with the client.
786    state: State<Args, Args::S>,
787    /// The language server client.
788    pub client: LspClient,
789    /// The next notification ID.
790    pub next_not_id: AtomicI32,
791
792    // Handle maps
793    /// Events for dispatching.
794    pub events: EventMap<Args, Args::S>,
795    /// Extra commands provided with `textDocument/executeCommand`.
796    pub commands: ExecuteCmdMap<Args::S>,
797    /// Notifications for dispatching.
798    pub notifications: NotifyCmdMap<Args::S>,
799    /// Requests for dispatching.
800    pub requests: RegularCmdMap<Args::S>,
801    /// Resources for dispatching.
802    pub resources: ResourceMap<Args::S>,
803    _marker: std::marker::PhantomData<M>,
804}
805
806impl<M, Args: Initializer> LsDriver<M, Args> {
807    /// Gets the state of the language server.
808    pub fn state(&self) -> Option<&Args::S> {
809        self.state.opt()
810    }
811
812    /// Gets the mutable state of the language server.
813    pub fn state_mut(&mut self) -> Option<&mut Args::S> {
814        self.state.opt_mut()
815    }
816
817    /// Makes the language server ready.
818    pub fn ready(&mut self, params: Args::I) -> AnySchedulableResponse {
819        let args = match &mut self.state {
820            State::Uninitialized(args) => args,
821            _ => return just_result(Err(invalid_request("server is already initialized"))),
822        };
823
824        let args = args.take().expect("already initialized");
825        let (s, res) = args.initialize(params);
826        self.state = State::Ready(s);
827
828        res
829    }
830
831    /// Get static resources with help of tinymist service, for example, a
832    /// static help pages for some typst function.
833    pub fn get_resources(&mut self, args: Vec<JsonValue>) -> ScheduleResult {
834        let s = self.state.opt_mut().ok_or_else(not_initialized)?;
835
836        let path =
837            from_value::<PathBuf>(args[0].clone()).map_err(|e| invalid_params(e.to_string()))?;
838
839        let Some(handler) = self.resources.get(path.as_path()) else {
840            log::error!("asked for unknown resource: {path:?}");
841            return Err(method_not_found());
842        };
843
844        // Note our redirection will keep the first path argument in the args vec.
845        handler(s, args)
846    }
847}
848
849/// A helper function to create a `LspResponseFuture`
850pub fn just_ok<T, E>(res: T) -> Result<ResponseFuture<Result<T, E>>, E> {
851    Ok(futures::future::MaybeDone::Done(Ok(res)))
852}
853
854/// A helper function to create a `LspResponseFuture`
855pub fn just_result<T, E>(res: Result<T, E>) -> Result<ResponseFuture<Result<T, E>>, E> {
856    Ok(futures::future::MaybeDone::Done(res))
857}
858
859/// A helper function to create a `LspResponseFuture`
860pub fn just_future<T, E>(
861    fut: impl std::future::Future<Output = Result<T, E>> + Send + 'static,
862) -> Result<ResponseFuture<Result<T, E>>, E> {
863    Ok(futures::future::MaybeDone::Future(Box::pin(fut)))
864}
865
866/// Creates an invalid params error.
867pub fn invalid_params(msg: impl fmt::Display) -> ResponseError {
868    resp_err(ErrorCode::InvalidParams, msg)
869}
870
871/// Creates an internal error.
872pub fn internal_error(msg: impl fmt::Display) -> ResponseError {
873    resp_err(ErrorCode::InternalError, msg)
874}
875
876/// Creates a not initialized error.
877pub fn not_initialized() -> ResponseError {
878    resp_err(ErrorCode::ServerNotInitialized, "not initialized yet")
879}
880
881/// Creates a method not found error.
882pub fn method_not_found() -> ResponseError {
883    resp_err(ErrorCode::MethodNotFound, "method not found")
884}
885
886/// Creates an invalid request error.
887pub fn invalid_request(msg: impl fmt::Display) -> ResponseError {
888    resp_err(ErrorCode::InvalidRequest, msg)
889}
890
891fn from_json<T: serde::de::DeserializeOwned>(json: JsonValue) -> LspResult<T> {
892    serde_json::from_value(json).map_err(invalid_request)
893}
894
895/// Erases the response type to a generic `JsonValue`.
896pub fn erased_response<T: Serialize + 'static>(resp: SchedulableResponse<T>) -> ScheduleResult {
897    /// Responds a typed result to the client.
898    fn map_respond_result<T: Serialize>(result: LspResult<T>) -> LspResult<JsonValue> {
899        result.and_then(|t| serde_json::to_value(t).map_err(internal_error))
900    }
901
902    let resp = resp?;
903
904    use futures::future::MaybeDone::*;
905    Ok(match resp {
906        Done(result) => MaybeDone::Done(map_respond_result(result)),
907        Future(fut) => MaybeDone::Future(Box::pin(async move { map_respond_result(fut.await) })),
908        Gone => {
909            log::warn!("response already taken");
910            MaybeDone::Done(Err(internal_error("response already taken")))
911        }
912    })
913}
914
915fn resp_err(code: ErrorCode, msg: impl fmt::Display) -> ResponseError {
916    ResponseError {
917        code: code as i32,
918        message: msg.to_string(),
919        data: None,
920    }
921}