ra_multiplex/
proxy.rs

1use std::collections::BTreeMap;
2use std::env;
3
4use anyhow::{bail, Context as _, Result};
5use tokio::io::{self, BufStream};
6
7use crate::config::Config;
8use crate::lsp::ext::{LspMuxOptions, Request};
9use crate::lsp::jsonrpc::Message;
10use crate::lsp::transport::{LspReader, LspWriter};
11use crate::lsp::{InitializationOptions, InitializeParams};
12use crate::socketwrapper::Stream;
13
14pub async fn run(config: &Config, server: String, args: Vec<String>) -> Result<()> {
15    let cwd = env::current_dir()
16        .ok()
17        .and_then(|path| path.to_str().map(String::from));
18
19    let mut env = BTreeMap::new();
20    for key in &config.pass_environment {
21        if let Ok(val) = std::env::var(key) {
22            env.insert(key.clone(), val);
23        }
24    }
25
26    let mut stream = Stream::connect(&config.connect)
27        .await
28        .context("connecting to server")?;
29    let mut stdio = BufStream::new(io::join(io::stdin(), io::stdout()));
30
31    // Wait for the client to send `initialize` request.
32    let mut reader = LspReader::new(&mut stdio, "client");
33    let mut req = match reader.read_message().await?.context("stdin closed")? {
34        Message::Request(req) if req.method == "initialize" => req,
35        _ => bail!("first client message was not initialize request"),
36    };
37
38    // Patch `initializationOptions` with our own data.
39    let mut params = serde_json::from_value::<InitializeParams>(req.params)
40        .context("parse initialize request params")?;
41    params
42        .initialization_options
43        .get_or_insert_with(InitializationOptions::default)
44        .lsp_mux
45        .get_or_insert_with(|| LspMuxOptions {
46            version: LspMuxOptions::PROTOCOL_VERSION.to_owned(),
47            method: Request::Connect {
48                server,
49                args,
50                env,
51                cwd,
52            },
53        });
54    req.params = serde_json::to_value(params).expect("BUG: invalid data");
55
56    // Forward the modified `initialize` request.
57    let mut writer = LspWriter::new(&mut stream, "lspmux");
58    writer
59        .write_message(&req.into())
60        .await
61        .context("forward initialize request")?;
62
63    // Forward everything else unmodified.
64    io::copy_bidirectional(&mut stream, &mut stdio)
65        .await
66        .context("io error")?;
67    Ok(())
68}