lsp_server/
stdio.rs

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