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 15, 2024
1 parent b8bad11 commit 8e6d352
Show file tree
Hide file tree
Showing 8 changed files with 58 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
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,5 +1,6 @@
use std::fs;
use std::net::{IpAddr, Ipv4Addr};
use std::collections::BTreeSet;

use anyhow::{Context, Result};
use directories::ProjectDirs;
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
10 changes: 9 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,7 @@ 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 8e6d352

Please sign in to comment.