1use std::{
2 io::{self, stdin, stdout},
3 thread,
4};
5
6use log::debug;
7
8use crossbeam_channel::{bounded, Receiver, Sender};
9
10use crate::Message;
11
12pub(crate) fn stdio_transport() -> (Sender<Message>, Receiver<Message>, IoThreads) {
14 let (writer_sender, writer_receiver) = bounded::<Message>(0);
15 let writer = thread::Builder::new()
16 .name("LspServerWriter".to_owned())
17 .spawn(move || {
18 let stdout = stdout();
19 let mut stdout = stdout.lock();
20 writer_receiver.into_iter().try_for_each(|it| it.write(&mut stdout))
21 })
22 .unwrap();
23 let (reader_sender, reader_receiver) = bounded::<Message>(0);
24 let reader = thread::Builder::new()
25 .name("LspServerReader".to_owned())
26 .spawn(move || {
27 let stdin = stdin();
28 let mut stdin = stdin.lock();
29 while let Some(msg) = Message::read(&mut stdin)? {
30 let is_exit = matches!(&msg, Message::Notification(n) if n.is_exit());
31
32 debug!("sending message {:#?}", msg);
33 if let Err(e) = reader_sender.send(msg) {
34 return Err(io::Error::new(io::ErrorKind::Other, e));
35 }
36
37 if is_exit {
38 break;
39 }
40 }
41 Ok(())
42 })
43 .unwrap();
44 let threads = IoThreads { reader, writer };
45 (writer_sender, reader_receiver, threads)
46}
47
48pub(crate) fn make_io_threads(
50 reader: thread::JoinHandle<io::Result<()>>,
51 writer: thread::JoinHandle<io::Result<()>>,
52) -> IoThreads {
53 IoThreads { reader, writer }
54}
55
56pub struct IoThreads {
57 reader: thread::JoinHandle<io::Result<()>>,
58 writer: thread::JoinHandle<io::Result<()>>,
59}
60
61impl IoThreads {
62 pub fn join(self) -> io::Result<()> {
63 match self.reader.join() {
64 Ok(r) => r?,
65 Err(err) => std::panic::panic_any(err),
66 }
67 match self.writer.join() {
68 Ok(r) => r,
69 Err(err) => {
70 std::panic::panic_any(err);
71 }
72 }
73 }
74}