use serde_json::Value;
use std::{
io::{BufRead, ErrorKind},
sync::mpsc,
thread,
time::Duration,
};
use vize_carton::String;
use super::TsgoLspClient;
impl TsgoLspClient {
pub(crate) fn drain_pending_messages(&mut self) {
while let Some(Ok(msg)) = self.try_read_message_nonblocking() {
self.handle_notification(&msg);
}
}
pub fn wait_for_diagnostics(&mut self, expected_count: usize) {
use std::time::Instant;
let max_wait = Duration::from_secs(30); let idle_timeout = Duration::from_millis(30); let start = Instant::now();
let mut last_message: Option<Instant> = None;
let initial_diag_count = self.diagnostics.len();
loop {
if start.elapsed() > max_wait {
break;
}
let new_diags = self.diagnostics.len() - initial_diag_count;
if new_diags >= expected_count {
thread::sleep(Duration::from_millis(5));
self.drain_pending_messages();
break;
}
if let Some(last) = last_message {
if last.elapsed() > idle_timeout {
break;
}
}
match self.try_read_message_nonblocking() {
Some(Ok(msg)) => {
last_message = Some(Instant::now()); self.handle_notification(&msg);
}
Some(Err(_)) => break,
None => {
thread::sleep(Duration::from_millis(1));
}
}
}
}
pub(crate) fn read_notifications(&mut self) -> Result<(), String> {
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
thread::sleep(Duration::from_millis(50));
let _ = tx.send(());
});
loop {
if rx.try_recv().is_ok() {
break;
}
match self.try_read_message_nonblocking() {
Some(Ok(msg)) => {
let method = msg.get("method").and_then(|m| m.as_str());
self.handle_notification(&msg);
if method == Some("textDocument/publishDiagnostics") {
break;
}
}
Some(Err(_)) => break,
None => {
thread::sleep(Duration::from_millis(1));
}
}
}
Ok(())
}
pub(crate) fn try_read_message_nonblocking(&mut self) -> Option<Result<Value, String>> {
match self.stdout.fill_buf() {
Ok([]) => None, Ok(_) => Some(self.read_message()), Err(e) if e.kind() == ErrorKind::WouldBlock => None, Err(_) => None, }
}
pub(crate) fn handle_notification(&mut self, msg: &Value) {
if let Some(method) = msg.get("method").and_then(|m| m.as_str()) {
if let Some(id) = msg.get("id") {
let response = serde_json::json!({
"jsonrpc": "2.0",
"id": id,
"result": null
});
let _ = self.send_message(&response);
return;
}
if method == "textDocument/publishDiagnostics" {
if let Some(params) = msg.get("params") {
if let (Some(uri), Some(diagnostics)) =
(params.get("uri"), params.get("diagnostics"))
{
if let (Some(uri_str), Some(diag_array)) =
(uri.as_str(), diagnostics.as_array())
{
let diags: Vec<super::LspDiagnostic> = diag_array
.iter()
.filter_map(|d| serde_json::from_value(d.clone()).ok())
.collect();
self.diagnostics.insert(uri_str.into(), diags);
}
}
}
}
}
}
}