use std::{
error::Error,
io::{BufRead, BufReader, Write},
process::{Child, ChildStdin, Command, Stdio},
thread::JoinHandle,
};
use winit::event_loop::EventLoopProxy;
use crate::{
AppMessage, Rpc,
json_ui::{self, Response},
};
pub struct Kakoune {
child: Child,
stdin: ChildStdin,
join_handle: JoinHandle<()>,
}
impl Kakoune {
pub fn new(event_loop_proxy: EventLoopProxy<AppMessage>) -> Self {
let mut args: Vec<String> = std::env::args().collect();
args.remove(0);
args.insert(0, String::from("json"));
args.insert(0, String::from("-ui"));
let mut child = Command::new("kak")
.args(&args[..])
.stdout(Stdio::piped())
.stdin(Stdio::piped())
.spawn()
.expect("Failed to spawn Kakoune");
let mut stdout = BufReader::new(child.stdout.take().expect("Failed to get Kakoune stdout"));
let stdin = child.stdin.take().expect("Failed to get stdin");
let join_handle = std::thread::spawn(move || {
let mut buf = String::new();
loop {
buf.clear();
let Ok(read) = stdout.read_line(&mut buf) else {
break;
};
if read == 0 {
break;
}
let content: Rpc<json_ui::Request> =
serde_json::from_str(&buf).expect("Kakoune json_ui is broken");
if event_loop_proxy
.send_event(AppMessage::Kakoune(content.inner))
.is_err()
{
return;
}
}
_ = event_loop_proxy.send_event(AppMessage::Exit);
});
Self {
child,
stdin,
join_handle,
}
}
pub fn send_response(&mut self, resp: Response) -> Result<(), Box<dyn Error>> {
let resp = serde_json::to_string(&Rpc::from(resp)).unwrap();
self.stdin.write_all(resp.as_bytes())?;
self.stdin.write_all(b"\n")?;
Ok(())
}
pub fn join(mut self) {
self.child.kill().unwrap();
self.child.wait().unwrap();
self.join_handle.join().unwrap();
}
}