restart lsp if crashed

This commit is contained in:
Dongdong Zhou 2022-03-03 12:41:02 +00:00
parent 963456830c
commit d84062aaa4
1 changed files with 1025 additions and 998 deletions

View File

@ -2,7 +2,7 @@
collections::HashMap, collections::HashMap,
io::BufRead, io::BufRead,
io::{BufReader, BufWriter, Write}, io::{BufReader, BufWriter, Write},
process::{self, Child, Command, Stdio}, process::{self, Child, ChildStdout, Command, Stdio},
sync::{mpsc::channel, Arc}, sync::{mpsc::channel, Arc},
thread, thread,
time::Duration, time::Duration,
@ -52,8 +52,10 @@ pub struct LspState {
pub is_initialized: bool, pub is_initialized: bool,
} }
#[derive(Clone)]
pub struct LspClient { pub struct LspClient {
language_id: String, language_id: String,
exec_path: String,
options: Option<Value>, options: Option<Value>,
state: Arc<Mutex<LspState>>, state: Arc<Mutex<LspState>>,
dispatcher: Dispatcher, dispatcher: Dispatcher,
@ -339,20 +341,13 @@ pub fn new(
options: Option<Value>, options: Option<Value>,
dispatcher: Dispatcher, dispatcher: Dispatcher,
) -> Arc<LspClient> { ) -> Arc<LspClient> {
let mut process = Command::new(exec_path); let mut process = Self::process(exec_path);
#[cfg(target_os = "windows")]
let mut process = process.creation_flags(0x08000000);
let mut process = process
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn()
.expect("Error Occurred");
let writer = Box::new(BufWriter::new(process.stdin.take().unwrap())); let writer = Box::new(BufWriter::new(process.stdin.take().unwrap()));
let stdout = process.stdout.take().unwrap(); let stdout = process.stdout.take().unwrap();
let lsp_client = Arc::new(LspClient { let lsp_client = Arc::new(LspClient {
dispatcher, dispatcher,
exec_path: exec_path.to_string(),
language_id, language_id,
options, options,
state: Arc::new(Mutex::new(LspState { state: Arc::new(Mutex::new(LspState {
@ -366,7 +361,14 @@ pub fn new(
})), })),
}); });
let local_lsp_client = lsp_client.clone(); lsp_client.handle_stdout(stdout);
lsp_client.initialize();
lsp_client
}
fn handle_stdout(&self, stdout: ChildStdout) {
let local_lsp_client = self.clone();
thread::spawn(move || { thread::spawn(move || {
let mut reader = Box::new(BufReader::new(stdout)); let mut reader = Box::new(BufReader::new(stdout));
loop { loop {
@ -375,15 +377,42 @@ pub fn new(
local_lsp_client.handle_message(message_str.as_ref()); local_lsp_client.handle_message(message_str.as_ref());
} }
Err(err) => { Err(err) => {
local_lsp_client.stop();
local_lsp_client.reload();
return; return;
} }
}; };
} }
}); });
}
lsp_client.initialize(); fn process(exec_path: &str) -> Child {
let mut process = Command::new(exec_path);
#[cfg(target_os = "windows")]
let mut process = process.creation_flags(0x08000000);
process
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn()
.expect("Error Occurred")
}
lsp_client fn reload(&self) {
let mut process = Self::process(&self.exec_path);
let writer = Box::new(BufWriter::new(process.stdin.take().unwrap()));
let stdout = process.stdout.take().unwrap();
let mut state = self.state.lock();
state.next_id = 0;
state.pending.clear();
state.opened_documents.clear();
state.server_capabilities = None;
state.is_initialized = false;
state.writer = writer;
state.process = process;
self.handle_stdout(stdout);
self.initialize();
} }
fn stop(&self) { fn stop(&self) {
@ -469,13 +498,11 @@ pub fn handle_response(&self, id: u64, result: Result<Value>) {
callback.call(self, result); callback.call(self, result);
} }
pub fn write(&self, msg: &str) { pub fn write(&self, msg: &str) -> Result<()> {
let mut state = self.state.lock(); let mut state = self.state.lock();
state state.writer.write_all(msg.as_bytes())?;
.writer state.writer.flush()?;
.write_all(msg.as_bytes()) Ok(())
.expect("error writing to stdin");
state.writer.flush().expect("error flushing child stdin");
} }
fn send_rpc(&self, value: &Value) { fn send_rpc(&self, value: &Value) {