client.rs

 1use std::ops::ControlFlow;
 2use std::path::PathBuf;
 3
 4use async_lsp::lsp_types::notification::{Progress, PublishDiagnostics, ShowMessage};
 5use async_lsp::lsp_types::{
 6    ClientCapabilities, DiagnosticClientCapabilities, InitializeParams, InitializedParams,
 7    TextDocumentClientCapabilities, Url, WindowClientCapabilities, WorkspaceFolder,
 8};
 9use async_lsp::router::Router;
10use async_lsp::{LanguageServer, ServerSocket as LSPServerSocket};
11use async_process::{Command as ProcessCommand, Stdio};
12use futures::channel::oneshot;
13use tower::ServiceBuilder;
14
15pub struct LSPClientState {
16    pub indexed_tx: Option<oneshot::Sender<()>>,
17}
18
19mod control_flow_state {
20    pub struct Stop;
21}
22
23pub async fn setup_lsp_client(
24    lsp_command: &str,
25    lsp_args: &[String],
26    project_root: &PathBuf,
27) -> Result<(tokio::task::JoinHandle<()>, LSPServerSocket), Box<dyn std::error::Error>> {
28    let mut child = ProcessCommand::new(lsp_command)
29        .args(lsp_args)
30        .current_dir(project_root)
31        .stdin(Stdio::piped())
32        .stdout(Stdio::piped())
33        .stderr(Stdio::inherit())
34        .kill_on_drop(true)
35        .spawn()
36        .expect(format!("Failed to start lsp: {} {:?}", lsp_command, lsp_args).as_ref());
37
38    let stdin = child.stdin.take().unwrap();
39    let stdout = child.stdout.take().unwrap();
40
41    let (mainloop, mut server) = async_lsp::MainLoop::new_client(|_server| {
42        let mut router = Router::new(LSPClientState { indexed_tx: None });
43
44        router
45            .notification::<Progress>(|_this, _params| ControlFlow::Continue(()))
46            .notification::<PublishDiagnostics>(|_this, _params| ControlFlow::Continue(()))
47            .notification::<ShowMessage>(|_this, _params| ControlFlow::Continue(()))
48            .event(|_, _: control_flow_state::Stop| ControlFlow::Break(Ok(())));
49
50        ServiceBuilder::new().service(router)
51    });
52
53    let mainloop_fut = tokio::spawn(async move {
54        mainloop.run_buffered(stdout, stdin).await.unwrap();
55    });
56
57    let project_root_canonicalized = tokio::fs::canonicalize(project_root)
58        .await
59        .expect("Failed to canonicalize project root");
60    let uri = Url::from_file_path(&project_root_canonicalized).unwrap();
61    let _init_ret = server
62        .initialize(InitializeParams {
63            workspace_folders: Some(vec![WorkspaceFolder {
64                uri: uri,
65                name: "root".into(),
66            }]),
67            capabilities: ClientCapabilities {
68                window: Some(WindowClientCapabilities {
69                    work_done_progress: Some(true),
70                    ..WindowClientCapabilities::default()
71                }),
72                text_document: Some(TextDocumentClientCapabilities {
73                    diagnostic: Some(DiagnosticClientCapabilities {
74                        ..DiagnosticClientCapabilities::default()
75                    }),
76                    ..TextDocumentClientCapabilities::default()
77                }),
78                ..ClientCapabilities::default()
79            },
80            ..InitializeParams::default()
81        })
82        .await
83        .unwrap();
84    server.initialized(InitializedParams {}).unwrap();
85
86    Ok((mainloop_fut, server))
87}