sync_ls/
server.rs

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