diff --git a/crates/languages/src/go.rs b/crates/languages/src/go.rs index 6e2b5d464e..46bd12a268 100644 --- a/crates/languages/src/go.rs +++ b/crates/languages/src/go.rs @@ -15,6 +15,7 @@ use std::{ ffi::{OsStr, OsString}, ops::Range, path::PathBuf, + process::Output, str, sync::{ atomic::{AtomicBool, Ordering::SeqCst}, @@ -35,8 +36,8 @@ impl GoLspAdapter { const SERVER_NAME: LanguageServerName = LanguageServerName::new_static("gopls"); } -static GOPLS_VERSION_REGEX: LazyLock = - LazyLock::new(|| Regex::new(r"\d+\.\d+\.\d+").expect("Failed to create GOPLS_VERSION_REGEX")); +static VERSION_REGEX: LazyLock = + LazyLock::new(|| Regex::new(r"\d+\.\d+\.\d+").expect("Failed to create VERSION_REGEX")); static GO_ESCAPE_SUBTEST_NAME_REGEX: LazyLock = LazyLock::new(|| { Regex::new(r#"[.*+?^${}()|\[\]\\]"#).expect("Failed to create GO_ESCAPE_SUBTEST_NAME_REGEX") @@ -111,11 +112,18 @@ impl super::LspAdapter for GoLspAdapter { container_dir: PathBuf, delegate: &dyn LspAdapterDelegate, ) -> Result { + let go = delegate.which("go".as_ref()).await.unwrap_or("go".into()); + let go_version_output = util::command::new_smol_command(&go) + .args(["version"]) + .output() + .await + .context("failed to get go version via `go version` command`")?; + let go_version = parse_version_output(&go_version_output)?; let version = version.downcast::>().unwrap(); let this = *self; if let Some(version) = *version { - let binary_path = container_dir.join(format!("gopls_{version}")); + let binary_path = container_dir.join(format!("gopls_{version}_go_{go_version}")); if let Ok(metadata) = fs::metadata(&binary_path).await { if metadata.is_file() { remove_matching(&container_dir, |entry| { @@ -139,8 +147,6 @@ impl super::LspAdapter for GoLspAdapter { let gobin_dir = container_dir.join("gobin"); fs::create_dir_all(&gobin_dir).await?; - - let go = delegate.which("go".as_ref()).await.unwrap_or("go".into()); let install_output = util::command::new_smol_command(go) .env("GO111MODULE", "on") .env("GOBIN", &gobin_dir) @@ -164,13 +170,8 @@ impl super::LspAdapter for GoLspAdapter { .output() .await .context("failed to run installed gopls binary")?; - let version_stdout = str::from_utf8(&version_output.stdout) - .context("gopls version produced invalid utf8 output")?; - let version = GOPLS_VERSION_REGEX - .find(version_stdout) - .with_context(|| format!("failed to parse golps version output '{version_stdout}'"))? - .as_str(); - let binary_path = container_dir.join(format!("gopls_{version}")); + let gopls_version = parse_version_output(&version_output)?; + let binary_path = container_dir.join(format!("gopls_{gopls_version}_go_{go_version}")); fs::rename(&installed_binary_path, &binary_path).await?; Ok(LanguageServerBinary { @@ -366,6 +367,18 @@ impl super::LspAdapter for GoLspAdapter { } } +fn parse_version_output(output: &Output) -> Result<&str> { + let version_stdout = + str::from_utf8(&output.stdout).context("version command produced invalid utf8 output")?; + + let version = VERSION_REGEX + .find(version_stdout) + .with_context(|| format!("failed to parse version output '{version_stdout}'"))? + .as_str(); + + Ok(version) +} + async fn get_cached_server_binary(container_dir: PathBuf) -> Option { maybe!(async { let mut last_binary_path = None;