client.rs

  1use std::ops::ControlFlow;
  2use std::path::PathBuf;
  3use std::sync::Arc;
  4
  5use async_lsp::lsp_types::notification::{Progress, PublishDiagnostics, ShowMessage};
  6use async_lsp::lsp_types::{
  7    ClientCapabilities, DiagnosticClientCapabilities, InitializeParams, InitializedParams,
  8    TextDocumentClientCapabilities, Url, WindowClientCapabilities, WorkspaceFolder,
  9};
 10use async_lsp::router::Router;
 11use async_lsp::{LanguageServer, MainLoop, ServerSocket as LSPServerSocket};
 12use async_process::{Child, Command as ProcessCommand, Stdio};
 13use futures::channel::oneshot;
 14use tower::ServiceBuilder;
 15
 16use crate::config::Config;
 17
 18pub struct LSPClientState {
 19    pub config: Arc<Config>,
 20    pub indexed_tx: Option<oneshot::Sender<()>>,
 21}
 22
 23mod control_flow_state {
 24    pub struct Stop;
 25}
 26
 27pub struct LSPClient {
 28    child: Child,
 29    pub mainloop: MainLoop<Router<LSPClientState>>,
 30    pub server: LSPServerSocket,
 31}
 32
 33impl LSPClient {
 34    pub async fn setup(config: Arc<Config>) -> anyhow::Result<Self> {
 35        let child = ProcessCommand::new(&config.lsp_server_command.command)
 36            .args(&config.lsp_server_command.args)
 37            .current_dir(&config.project_root)
 38            .stdin(Stdio::piped())
 39            .stdout(Stdio::piped())
 40            .stderr(Stdio::inherit())
 41            .kill_on_drop(true)
 42            .spawn()
 43            .expect(
 44                format!(
 45                    "Failed to start lsp: {} {:?}",
 46                    &config.lsp_server_command.command, &config.lsp_server_command.args
 47                )
 48                .as_ref(),
 49            );
 50
 51        let config_clone = config.clone();
 52        let (mainloop, mut server) = async_lsp::MainLoop::new_client(move |_server| {
 53            let mut router = Router::new(LSPClientState {
 54                config: config_clone,
 55                indexed_tx: None,
 56            });
 57
 58            router
 59                .notification::<Progress>(|_this, _params| ControlFlow::Continue(()))
 60                .notification::<PublishDiagnostics>(|_this, _params| ControlFlow::Continue(()))
 61                .notification::<ShowMessage>(|_this, _params| ControlFlow::Continue(()))
 62                .event(|_, _: control_flow_state::Stop| ControlFlow::Break(Ok(())));
 63
 64            ServiceBuilder::new().service(router)
 65        });
 66
 67        let project_root_canonicalized = tokio::fs::canonicalize(&config.project_root)
 68            .await
 69            .expect("Failed to canonicalize project root");
 70
 71        let uri = Url::from_file_path(&project_root_canonicalized)
 72            .expect("Failed to create URL from project_root path");
 73
 74        let _init_ret = server
 75            .initialize(InitializeParams {
 76                workspace_folders: Some(vec![WorkspaceFolder {
 77                    uri: uri,
 78                    name: "root".into(),
 79                }]),
 80                capabilities: ClientCapabilities {
 81                    window: Some(WindowClientCapabilities {
 82                        work_done_progress: Some(true),
 83                        ..WindowClientCapabilities::default()
 84                    }),
 85                    text_document: Some(TextDocumentClientCapabilities {
 86                        diagnostic: Some(DiagnosticClientCapabilities {
 87                            ..DiagnosticClientCapabilities::default()
 88                        }),
 89                        ..TextDocumentClientCapabilities::default()
 90                    }),
 91                    ..ClientCapabilities::default()
 92                },
 93                ..InitializeParams::default()
 94            })
 95            .await
 96            .unwrap();
 97
 98        server
 99            .initialized(InitializedParams {})
100            .expect("Bad response to Initialized message");
101
102        Ok(Self {
103            child,
104            mainloop,
105            server,
106        })
107    }
108
109    pub async fn run_main_loop(mut self) -> anyhow::Result<()> {
110        let stdin = self.child.stdin.take().unwrap();
111        let stdout = self.child.stdout.take().unwrap();
112        self.mainloop.run_buffered(stdout, stdin).await?;
113        Ok(())
114    }
115}