on master help sign in
lsp: Gracefully fail if binary doesn't exist.
5aed1f3Blaž Hrastnik
helix-lsp/src/client.rs+16−6
@@ -34,15 +34,25 @@ pub struct Client {
34}
34}
35
35
36impl Client {
36impl Client {
37− pub fn start(ex: &Executor, cmd: &str, args: &[String]) -> (Self, Receiver<Call>) {
37+ pub fn start(ex: &Executor, cmd: &str, args: &[String]) -> Result<(Self, Receiver<Call>)> {
38+ // smol makes sure the process is reaped on drop, but using kill_on_drop(true) maybe?
38− let mut process = Command::new(cmd)
39+ let process = Command::new(cmd)
39 .args(args)
40 .args(args)
40 .stdin(Stdio::piped())
41 .stdin(Stdio::piped())
41 .stdout(Stdio::piped())
42 .stdout(Stdio::piped())
42 .stderr(Stdio::piped())
43 .stderr(Stdio::piped())
43− .spawn()
44+ .spawn();
44− .expect("Failed to start language server");
45+
45− // smol makes sure the process is reaped on drop, but using kill_on_drop(true) maybe?
46+ // use std::io::ErrorKind;
47+ let mut process = match process {
48+ Ok(process) => process,
49+ Err(err) => match err.kind() {
50+ // ErrorKind::NotFound | ErrorKind::PermissionDenied => {
51+ // return Err(Error::Other(err.into()))
52+ // }
53+ _kind => return Err(Error::Other(err.into())),
54+ },
55+ };
46
56
47 // TODO: do we need bufreader/writer here? or do we use async wrappers on unblock?
57 // TODO: do we need bufreader/writer here? or do we use async wrappers on unblock?
48 let writer = BufWriter::new(process.stdin.take().expect("Failed to open stdin"));
58 let writer = BufWriter::new(process.stdin.take().expect("Failed to open stdin"));
@@ -65,7 +75,7 @@ impl Client {
65 // TODO: async client.initialize()
75 // TODO: async client.initialize()
66 // maybe use an arc<atomic> flag
76 // maybe use an arc<atomic> flag
67
77
68− (client, incoming)
78+ Ok((client, incoming))
69 }
79 }
70
80
71 fn next_request_id(&self) -> jsonrpc::Id {
81 fn next_request_id(&self) -> jsonrpc::Id {
helix-lsp/src/lib.rs+6−4
@@ -104,7 +104,7 @@ use crate::select_all::SelectAll;
104use smol::channel::Receiver;
104use smol::channel::Receiver;
105
105
106pub struct Registry {
106pub struct Registry {
107− inner: HashMap<LanguageId, Arc<Client>>,
107+ inner: HashMap<LanguageId, Option<Arc<Client>>>,
108
108
109 pub incoming: SelectAll<Receiver<Call>>,
109 pub incoming: SelectAll<Receiver<Call>>,
110}
110}
@@ -140,17 +140,19 @@ impl Registry {
140 // TODO: lookup defaults for id (name, args)
140 // TODO: lookup defaults for id (name, args)
141
141
142 // initialize a new client
142 // initialize a new client
143+ let (mut client, incoming) =
143− let (mut client, incoming) = Client::start(&ex, &config.command, &config.args);
144+ Client::start(&ex, &config.command, &config.args).ok()?;
145+
144 // TODO: run this async without blocking
146 // TODO: run this async without blocking
145 smol::block_on(client.initialize()).unwrap();
147 smol::block_on(client.initialize()).unwrap();
146
148
147 s_incoming.push(incoming);
149 s_incoming.push(incoming);
148
150
149− Arc::new(client)
151+ Some(Arc::new(client))
150 })
152 })
151 .clone();
153 .clone();
152
154
153− return Some(language_server);
155+ return language_server;
154 }
156 }
155
157
156 None
158 None