Skip to content

Commit

Permalink
Reduce interface, only check for user-installed server
Browse files Browse the repository at this point in the history
  • Loading branch information
mrnugget committed Feb 22, 2024
1 parent 4ca03d1 commit a194d64
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 84 deletions.
16 changes: 5 additions & 11 deletions crates/language/src/language.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ pub mod markdown;
use anyhow::{anyhow, Context, Result};
use async_trait::async_trait;
use collections::{HashMap, HashSet};
use futures::future::BoxFuture;
use gpui::{AppContext, AsyncAppContext, Task};
pub use highlight_map::HighlightMap;
use lazy_static::lazy_static;
Expand All @@ -39,7 +38,7 @@ use serde_json::Value;
use std::{
any::Any,
cell::RefCell,
ffi::OsStr,
ffi::{OsStr, OsString},
fmt::Debug,
hash::Hash,
mem,
Expand Down Expand Up @@ -250,16 +249,11 @@ impl CachedLspAdapter {
pub trait LspAdapterDelegate: Send + Sync {
fn show_notification(&self, message: &str, cx: &mut AppContext);
fn http_client(&self) -> Arc<dyn HttpClient>;
fn which_command<'a>(
&'a self,
command: &'a OsStr,
cx: &AppContext,
) -> BoxFuture<'a, Option<(PathBuf, HashMap<String, String>)>>;
fn build_command<'a>(
&'a self,
command: &'a OsStr,
fn which_command(
&self,
command: OsString,
cx: &AppContext,
) -> BoxFuture<'a, smol::process::Command>;
) -> Task<Option<(PathBuf, HashMap<String, String>)>>;
}

#[async_trait]
Expand Down
6 changes: 1 addition & 5 deletions crates/language/src/language_registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -743,12 +743,8 @@ async fn get_binary(
}

if let Some(task) = adapter.check_if_user_installed(&delegate, &mut cx) {
println!(
"checking if user has language server for {} installed",
language.name()
);
if let Some(binary) = task.await {
println!(
log::info!(
"found user-installed language server for {}. path: {:?}, arguments: {:?}",
language.name(),
binary.path,
Expand Down
78 changes: 26 additions & 52 deletions crates/project/src/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use copilot::Copilot;
use debounced_delay::DebouncedDelay;
use futures::{
channel::mpsc::{self, UnboundedReceiver},
future::{try_join_all, BoxFuture, Shared},
future::{try_join_all, Shared},
select,
stream::FuturesUnordered,
AsyncWriteExt, Future, FutureExt, StreamExt, TryFutureExt,
Expand Down Expand Up @@ -72,7 +72,7 @@ use std::{
cmp::{self, Ordering},
convert::TryInto,
env,
ffi::OsStr,
ffi::OsString,
hash::Hash,
mem,
num::NonZeroU32,
Expand Down Expand Up @@ -9295,14 +9295,16 @@ impl LspAdapterDelegate for ProjectLspAdapterDelegate {
self.http_client.clone()
}

fn which_command<'a>(
&'a self,
command: &'a OsStr,
fn which_command(
&self,
command: OsString,
cx: &AppContext,
) -> BoxFuture<'a, Option<(PathBuf, HashMap<String, String>)>> {
) -> Task<Option<(PathBuf, HashMap<String, String>)>> {
let worktree_abs_path = self.worktree.read(cx).abs_path();
async move {
let shell_env = load_login_shell_environment(&worktree_abs_path)
let command = command.to_owned();

cx.background_executor().spawn(async move {
let shell_env = load_shell_environment(&worktree_abs_path)
.await
.with_context(|| {
format!(
Expand All @@ -9313,56 +9315,19 @@ impl LspAdapterDelegate for ProjectLspAdapterDelegate {

if let Some(shell_env) = shell_env {
let shell_path = shell_env.get("PATH");
match which::which_in(command, shell_path, &worktree_abs_path) {
match which::which_in(&command, shell_path, &worktree_abs_path) {
Ok(command_path) => Some((command_path, shell_env)),
Err(error) => {
log::warn!(
"failed to determine path for command {command:?} in env {shell_env:?}: {error}"
"failed to determine path for command {:?} in env {shell_env:?}: {error}", command.to_string_lossy()
);
None
}
}
} else {
None
}
}
.boxed()
}

fn build_command<'a>(
&'a self,
command: &'a OsStr,
cx: &AppContext,
) -> BoxFuture<'a, smol::process::Command> {
let worktree_abs_path = self.worktree.read(cx).abs_path();
async move {
let shell_env = load_login_shell_environment(&worktree_abs_path)
.await
.with_context(|| {
format!(
"failed to determine load login shell environment in {worktree_abs_path:?}"
)
}).log_err();
let command_path = if let Some(shell_env) = shell_env.as_ref() {
let shell_path = shell_env.get("PATH");
let command_path = which::which_in(command, shell_path, &worktree_abs_path)
.with_context(|| {
format!(
"failed to determine path for command {command:?} in env {shell_env:?}"
)
});
command_path.log_err().unwrap_or_else(|| PathBuf::from(&command))
} else {
PathBuf::from(command)
};

log::info!("resolved language server command {command:?} to {command_path:?}, cwd: {worktree_abs_path:?}");
let mut command = smol::process::Command::new(command_path);
command.envs(shell_env.unwrap_or_default());
command.current_dir(&worktree_abs_path);
command
}
.boxed()
})
}
}

Expand Down Expand Up @@ -9472,25 +9437,34 @@ fn include_text(server: &lsp::LanguageServer) -> bool {
.unwrap_or(false)
}

async fn load_login_shell_environment(dir: &Path) -> Result<HashMap<String, String>> {
async fn load_shell_environment(dir: &Path) -> Result<HashMap<String, String>> {
let marker = "ZED_LOGIN_SHELL_START";
let shell = env::var("SHELL").context(
"SHELL environment variable is not assigned so we can't source login environment variables",
)?;
let output = smol::process::Command::new(&shell)
.args([
"-l",
"-i",
"-c",
&format!("cd {}; echo {marker}; /usr/bin/env -0", dir.display()),
// What we're doing here is to spawn a shell and then `cd` into
// the project directory to get the env in there as if the user
// `cd`'d into it. We do that because tools like direnv, asdf, ...
// hook into `cd` and only set up the env after that.
//
// The `exit 0` is the result of hours of debugging, trying to find out
// why running this command here, without `exit 0`, would mess
// up signal process for our process so that `ctrl-c` doesn't work
// anymore.
// We still don't know why `$SHELL -l -i -c '/usr/bin/env -0'` would
// do that, but it does, and `exit 0` helps.
&format!("cd {dir:?}; echo {marker}; /usr/bin/env -0; exit 0;"),
])
.output()
.await
.context("failed to spawn login shell to source login environment variables")?;
if !output.status.success() {
Err(anyhow!("login shell exited with error"))?;
}

let stdout = String::from_utf8_lossy(&output.stdout);

if let Some(env_output_start) = stdout.find(marker) {
Expand Down
20 changes: 5 additions & 15 deletions crates/zed/src/languages/go.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,20 +64,15 @@ impl super::LspAdapter for GoLspAdapter {
cx: &mut AsyncAppContext,
) -> Option<Task<Option<LanguageServerBinary>>> {
let delegate = delegate.clone();

Some(cx.spawn(|cx| async move {
let command = match cx.update(|cx| delegate.which_command(OsStr::new("gopls"), cx)) {
Ok(task) => task.await,
Err(_) => {
return None;
}
};
match command {
Some((path, env)) => Some(LanguageServerBinary {
match cx.update(|cx| delegate.which_command(OsString::from("gopls"), cx)) {
Ok(task) => task.await.map(|(path, env)| LanguageServerBinary {
path,
arguments: server_binary_arguments(),
env: Some(env),
}),
None => None,
Err(_) => None,
}
}))
}
Expand All @@ -94,12 +89,7 @@ impl super::LspAdapter for GoLspAdapter {

let delegate = delegate.clone();
Some(cx.spawn(|cx| async move {
let install_output = cx
.update(|cx| delegate.build_command(OsStr::new("go"), cx))?
.await
.args(["version"])
.output()
.await;
let install_output = process::Command::new("go").args(["version"]).output().await;
if install_output.is_err() {
if DID_SHOW_NOTIFICATION
.compare_exchange(false, true, SeqCst, SeqCst)
Expand Down
2 changes: 1 addition & 1 deletion crates/zed/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -833,7 +833,7 @@ async fn load_login_shell_environment() -> Result<()> {
// and only trigger after `cd`s been used.
// Since `cd $HOME` is safe (POSIX dicates that $HOME has to be set), we do that
// before getting the `env`.
&format!("cd $HOME; echo {marker}; /usr/bin/env -0"),
&format!("cd $HOME; echo {marker}; /usr/bin/env -0; exit 0"),
])
.output()
.await
Expand Down

0 comments on commit a194d64

Please sign in to comment.