diff --git a/crates/languages/src/rust.rs b/crates/languages/src/rust.rs index d9d37fc459..b5c710dc5c 100644 --- a/crates/languages/src/rust.rs +++ b/crates/languages/src/rust.rs @@ -10,7 +10,13 @@ use project::project_settings::ProjectSettings; use regex::Regex; use settings::Settings; use smol::fs::{self, File}; -use std::{any::Any, borrow::Cow, env::consts, path::PathBuf, sync::Arc}; +use std::{ + any::Any, + borrow::Cow, + env::consts, + path::{Path, PathBuf}, + sync::Arc, +}; use task::{ static_source::{Definition, TaskDefinitions}, TaskVariables, VariableName, @@ -333,25 +339,17 @@ impl ContextProvider for RustContextProvider { ) -> Result { let mut context = SymbolContextProvider.build_context(location.clone(), cx)?; - if let Some(path) = location.buffer.read(cx).file().and_then(|file| { - let local_file = file.as_local()?.abs_path(cx); - local_file.parent().map(PathBuf::from) - }) { - let Some(pkgid) = std::process::Command::new("cargo") - .current_dir(path) - .arg("pkgid") - .output() - .log_err() - else { - return Ok(context); - }; - let package_name = String::from_utf8(pkgid.stdout) - .map(|name| name.trim().to_owned()) - .ok(); - - if let Some(package_name) = package_name { - context.insert(RUST_PACKAGE_TASK_VARIABLE.clone(), package_name); - } + let local_abs_path = location + .buffer + .read(cx) + .file() + .and_then(|file| Some(file.as_local()?.abs_path(cx))); + if let Some(package_name) = local_abs_path + .as_deref() + .and_then(|local_abs_path| local_abs_path.parent()) + .and_then(human_readable_package_name) + { + context.insert(RUST_PACKAGE_TASK_VARIABLE.clone(), package_name); } Ok(context) @@ -408,6 +406,38 @@ impl ContextProvider for RustContextProvider { } } +fn human_readable_package_name(package_directory: &Path) -> Option { + fn split_off_suffix(input: &str, suffix_start: char) -> &str { + match input.rsplit_once(suffix_start) { + Some((without_suffix, _)) => without_suffix, + None => input, + } + } + + let pkgid = String::from_utf8( + std::process::Command::new("cargo") + .current_dir(package_directory) + .arg("pkgid") + .output() + .log_err()? + .stdout, + ) + .ok()?; + // For providing local `cargo check -p $pkgid` task, we do not need most of the information we have returned. + // Output example in the root of Zed project: + // ```bash + // ❯ cargo pkgid zed + // path+file:///absolute/path/to/project/zed/crates/zed#0.131.0 + // ``` + // Extrarct the package name from the output according to the spec: + // https://doc.rust-lang.org/cargo/reference/pkgid-spec.html#specification-grammar + let mut package_name = pkgid.trim(); + package_name = split_off_suffix(package_name, '#'); + package_name = split_off_suffix(package_name, '?'); + let (_, package_name) = package_name.rsplit_once('/')?; + Some(package_name.to_string()) +} + async fn get_cached_server_binary(container_dir: PathBuf) -> Option { maybe!(async { let mut last = None;