lsp_server/
stdio.rs

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
12/// Creates an LSP connection via stdio.
13pub(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
48// Creates an IoThreads
49pub(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}