Skip to content

Commit

Permalink
allow passing env vars to language server
Browse files Browse the repository at this point in the history
  • Loading branch information
pr2502 committed May 16, 2024
1 parent b8bad11 commit 0e828ee
Show file tree
Hide file tree
Showing 9 changed files with 75 additions and 6 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).


## [Unreleased]

### Added
- configuration option `pass_environment` which specifies a list of env var names to be passed from ra-multiplex client proxy to the spawned language server (rust-analyzer)


## [v0.2.4] - 2024-05-15

### Fixed
Expand Down
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,18 @@ connect = ["127.0.0.1", 27631] # same as `listen`
# is documented in the `env_logger` documentation here:
# <https://docs.rs/env_logger/0.9.0/env_logger/index.html#enabling-logging>
log_filters = "info"

# environemnt variable names passed from `ra-multiplex client` to the server
#
# by default no variables are passed. and all servers are spawned in
# the same environment as the `ra-multiplex server` is. when a name like
# "LD_LIBRARY_PATH" is specifified the proxy reads the variable value from its
# environment and passes it to the server which then passes it on to the server
# executable.
#
# if "PATH" is specified here then the PATH from the client environment is
# going to be used for looking up a relative `--server-path`.
pass_environment = []
```


Expand Down
1 change: 1 addition & 0 deletions defaults.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ gc_interval = 10
listen = ["127.0.0.1", 27631]
connect = ["127.0.0.1", 27631]
log_filters = "info"
pass_environment = []
18 changes: 15 additions & 3 deletions src/client.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::collections::BTreeMap;
use std::io::ErrorKind;
use std::sync::Arc;

Expand Down Expand Up @@ -62,11 +63,16 @@ pub async fn process(

debug!(?options, "lspmux initialization");
match options.method {
ext::Request::Connect { server, args, cwd } => {
ext::Request::Connect {
server,
args,
env,
cwd,
} => {
connect(
port,
instance_map,
(server, args, cwd),
(server, args, env, cwd),
req,
init_params,
reader,
Expand Down Expand Up @@ -164,7 +170,12 @@ async fn reload(
async fn connect(
port: u16,
instance_map: Arc<Mutex<InstanceMap>>,
(server, args, cwd): (String, Vec<String>, Option<String>),
(server, args, env, cwd): (
String,
Vec<String>,
BTreeMap<String, String>,
Option<String>,
),
req: Request,
init_params: InitializeParams,
mut reader: LspReader<BufReader<OwnedReadHalf>>,
Expand All @@ -178,6 +189,7 @@ async fn connect(
let key = InstanceKey {
server,
args,
env,
workspace_root,
};
let instance = instance::get_or_spawn(instance_map, key, init_params).await?;
Expand Down
9 changes: 9 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::collections::BTreeSet;
use std::fs;
use std::net::{IpAddr, Ipv4Addr};

Expand Down Expand Up @@ -32,6 +33,10 @@ mod default {
pub fn log_filters() -> String {
"info".to_owned()
}

pub fn pass_environment() -> BTreeSet<String> {
BTreeSet::new()
}
}

mod de {
Expand Down Expand Up @@ -96,6 +101,9 @@ pub struct Config {

#[serde(default = "default::log_filters")]
pub log_filters: String,

#[serde(default = "default::pass_environment")]
pub pass_environment: BTreeSet<String>,
}

#[cfg(test)]
Expand All @@ -121,6 +129,7 @@ impl Default for Config {
listen: default::listen(),
connect: default::connect(),
log_filters: default::log_filters(),
pass_environment: default::pass_environment(),
}
}
}
Expand Down
6 changes: 6 additions & 0 deletions src/ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,12 @@ pub async fn status(config: &Config, json: bool) -> Result<()> {
println!("- Instance");
println!(" pid: {}", instance.pid);
println!(" server: {:?} {:?}", instance.server, instance.args);
if !instance.env.is_empty() {
println!(" server env:");
for (key, val) in instance.env {
println!(" {key} = {val}");
}
}
println!(" path: {:?}", instance.workspace_root);
let now = time::OffsetDateTime::now_utc().unix_timestamp();
println!(" last used: {}s ago", now - instance.last_used);
Expand Down
5 changes: 4 additions & 1 deletion src/instance.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use std::collections::hash_map::Entry;
use std::collections::{HashMap, HashSet};
use std::collections::{BTreeMap, HashMap, HashSet};
use std::io::ErrorKind;
use std::ops::Deref;
use std::path::Path;
Expand Down Expand Up @@ -31,6 +31,7 @@ use crate::lsp::{self, ext};
pub struct InstanceKey {
pub server: String,
pub args: Vec<String>,
pub env: BTreeMap<String, String>,
pub workspace_root: String,
}

Expand Down Expand Up @@ -310,6 +311,7 @@ impl Instance {
pid: self.pid,
server: self.key.server.clone(),
args: self.key.args.clone(),
env: self.key.env.clone(),
workspace_root: self.key.workspace_root.clone(),
last_used: self.last_used.load(Ordering::Relaxed),
clients,
Expand Down Expand Up @@ -422,6 +424,7 @@ async fn spawn(
) -> Result<Arc<Instance>> {
let mut child = Command::new(&key.server)
.args(&key.args)
.envs(&key.env)
.current_dir(&key.workspace_root)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
Expand Down
9 changes: 8 additions & 1 deletion src/lsp/ext.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! LSP-mux (ra-multiplex) specific protocol extensions
use std::collections::BTreeMap;
use std::str::FromStr;

use anyhow::{bail, Context, Result};
Expand Down Expand Up @@ -123,10 +124,15 @@ pub enum Request {
server: String,

/// Arguments which will be passed to the language server, defaults to an
/// empty list if omited.
/// empty list if omitted.
#[serde(default = "Vec::new")]
args: Vec<String>,

/// Environment variables which will be set for the language server,
/// defaults to an empty set if omitted.
#[serde(default = "BTreeMap::new", skip_serializing_if = "BTreeMap::is_empty")]
env: BTreeMap<String, String>,

/// Current working directory of the proxy command. This is only used as
/// fallback if the client doesn't provide any workspace root.
#[serde(skip_serializing_if = "Option::is_none")]
Expand Down Expand Up @@ -159,6 +165,7 @@ pub struct Instance {
pub pid: u32,
pub server: String,
pub args: Vec<String>,
pub env: BTreeMap<String, String>,
pub workspace_root: String,
pub registered_dyn_capabilities: Vec<String>,
pub last_used: i64,
Expand Down
15 changes: 14 additions & 1 deletion src/proxy.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::collections::BTreeMap;
use std::env;
use std::pin::Pin;
use std::task::{Context, Poll};
Expand Down Expand Up @@ -58,6 +59,13 @@ pub async fn run(config: &Config, server: String, args: Vec<String>) -> Result<(
.ok()
.and_then(|path| path.to_str().map(String::from));

let mut env = BTreeMap::new();
for key in &config.pass_environment {
if let Ok(val) = std::env::var(key) {
env.insert(key.clone(), val);
}
}

let mut stream = TcpStream::connect(config.connect)
.await
.context("connect")?;
Expand All @@ -79,7 +87,12 @@ pub async fn run(config: &Config, server: String, args: Vec<String>) -> Result<(
.lsp_mux
.get_or_insert_with(|| LspMuxOptions {
version: LspMuxOptions::PROTOCOL_VERSION.to_owned(),
method: Request::Connect { server, args, cwd },
method: Request::Connect {
server,
args,
env,
cwd,
},
});
req.params = serde_json::to_value(params).expect("BUG: invalid data");

Expand Down

0 comments on commit 0e828ee

Please sign in to comment.