use std::process::Stdio;
use tokio::{
io::{AsyncBufReadExt, AsyncWriteExt, BufReader, BufWriter},
process::{Child, ChildStdin, ChildStdout, Command},
sync::mpsc::{error::TryRecvError, unbounded_channel, UnboundedReceiver, UnboundedSender},
};
struct LSPClient {
_process: Child,
}
#[tokio::main]
async fn main() {
tokio::spawn(trigger()).await.ok();
}
async fn trigger() {
let (_client, tx_send, _tx_recv) = start_server().await;
tx_send.send("initialize".as_bytes().to_vec()).ok();
}
async fn start_server() -> (LSPClient, UnboundedSender<Vec<u8>>, UnboundedSender<Vec<u8>>) {
let mut process = Command::new("/home/suryateja/.config/mystudio-ide/lsp/rust-analyzer")
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.kill_on_drop(true)
.spawn()
.expect("Unable to spawn process");
let proc_id = process.id().expect("Unable to fetch process id");
println!("proc id: {}", proc_id);
let stdin = process.stdin.take().unwrap();
let stdout = process.stdout.take().unwrap();
// let stderr = process.stderr.take().unwrap();
let writer = BufWriter::new(stdin);
let reader = BufReader::new(stdout);
let (tx_send, rx_send) = unbounded_channel::<Vec<u8>>();
let (tx_recv, rx_recv) = unbounded_channel::<Vec<u8>>();
println!("setting up tx,rx");
setup_listeners(reader, writer, rx_send, rx_recv).await;
// Send initialize request
println!("initialize request");
tx_send.send("initialize".as_bytes().to_vec()).ok();
let client = LSPClient { _process: process };
(client, tx_send, tx_recv)
}
async fn setup_listeners(
mut reader: BufReader<ChildStdout>,
mut writer: BufWriter<ChildStdin>,
mut rx_send: UnboundedReceiver<Vec<u8>>,
mut rx_recv: UnboundedReceiver<Vec<u8>>,
) {
let handle_recv = tokio::spawn(async move {
loop {
match rx_recv.try_recv() {
Ok(data) => {
println!("rx_recv got: {:?}", String::from_utf8(data));
let mut buf = String::new();
let _ = reader.read_line(&mut buf);
}
Err(err) => {
eprintln!("rx_recv failed '{}'", err);
if err == TryRecvError::Disconnected {
println!("rx_recv: quitting loop");
break;
}
}
}
}
});
let handle_send = tokio::spawn(async move {
loop {
match rx_send.try_recv() {
Ok(data) => {
println!("rx_send: got something");
let str = String::from_utf8(data).expect("invalid data for parse");
println!("rx_send: sending to LSP: {:?}", str);
_ = writer.write_all(str.as_bytes());
}
Err(err) => {
eprintln!("rx_send failed '{}'", err);
if err == TryRecvError::Disconnected {
println!("rx_recv: quitting loop");
break;
}
}
}
}
});
_ = tokio::spawn(async move {
tokio::spawn(handle_send);
tokio::spawn(handle_recv);
}).await;
}
Errors:
proc id: 5269
setting up tx,rx
rx_recv failed 'receiving on an empty channel'
rx_recv failed 'initialize request
receiving on an empty channel'
rx_recv failed 'receiving on a closed channel'
rx_recv: quitting loop
rx_send failed 'receiving on an empty channel'
rx_send: got something
rx_send: sending to LSP: "initialize"
rx_send failed 'receiving on a closed channel'
rx_recv: quitting loop