diff --git a/crates/language/src/toolchain.rs b/crates/language/src/toolchain.rs index d77690c1f70af354548a85e5049d5718b26fedbc..fe8936db084a63d03c208e3cb59f24574d5e9b90 100644 --- a/crates/language/src/toolchain.rs +++ b/crates/language/src/toolchain.rs @@ -31,6 +31,8 @@ pub trait ToolchainLister: Send + Sync { worktree_root: PathBuf, project_env: Option>, ) -> ToolchainList; + // Returns a term which we should use in UI to refer to a toolchain. + fn term(&self) -> SharedString; } #[async_trait(?Send)] diff --git a/crates/languages/src/python.rs b/crates/languages/src/python.rs index 3db79dd29fdbf8dc1289534f0d8a5da52673b626..df158b9c7d2767293415bea359a98cda216c5c19 100644 --- a/crates/languages/src/python.rs +++ b/crates/languages/src/python.rs @@ -2,8 +2,8 @@ use anyhow::ensure; use anyhow::{anyhow, Result}; use async_trait::async_trait; use collections::HashMap; -use gpui::AsyncAppContext; use gpui::{AppContext, Task}; +use gpui::{AsyncAppContext, SharedString}; use language::language_settings::language_settings; use language::LanguageName; use language::LanguageToolchainStore; @@ -498,8 +498,17 @@ fn python_module_name_from_relative_path(relative_path: &str) -> String { .to_string() } -#[derive(Default)] -pub(crate) struct PythonToolchainProvider {} +pub(crate) struct PythonToolchainProvider { + term: SharedString, +} + +impl Default for PythonToolchainProvider { + fn default() -> Self { + Self { + term: SharedString::new_static("Virtual Environment"), + } + } +} static ENV_PRIORITY_LIST: &'static [PythonEnvironmentKind] = &[ // Prioritize non-Conda environments. @@ -604,6 +613,9 @@ impl ToolchainLister for PythonToolchainProvider { groups: Default::default(), } } + fn term(&self) -> SharedString { + self.term.clone() + } } pub struct EnvironmentApi<'a> { diff --git a/crates/picker/src/picker.rs b/crates/picker/src/picker.rs index 119c412b48ccefe57bdc7228cf604ed6ba84c0c1..1cdb5af1af3a40dc348e1ece83240129b39970e4 100644 --- a/crates/picker/src/picker.rs +++ b/crates/picker/src/picker.rs @@ -425,6 +425,19 @@ impl Picker { self.cancel(&menu::Cancel, cx); } + pub fn refresh_placeholder(&mut self, cx: &mut WindowContext<'_>) { + match &self.head { + Head::Editor(view) => { + let placeholder = self.delegate.placeholder_text(cx); + view.update(cx, |this, cx| { + this.set_placeholder_text(placeholder, cx); + cx.notify(); + }); + } + Head::Empty(_) => {} + } + } + pub fn refresh(&mut self, cx: &mut ViewContext) { let query = self.query(cx); self.update_matches(query, cx); diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index 2b18659b7d89a2ac75acaf75c56ceb81f16cbeb3..61a700e5d6e5d2a25ee42d01f657adf04db5579e 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -2464,6 +2464,19 @@ impl Project { Task::ready(None) } } + + pub async fn toolchain_term( + languages: Arc, + language_name: LanguageName, + ) -> Option { + languages + .language_for_name(&language_name.0) + .await + .ok()? + .toolchain_lister() + .map(|lister| lister.term()) + } + pub fn activate_toolchain( &self, worktree_id: WorktreeId, diff --git a/crates/toolchain_selector/src/active_toolchain.rs b/crates/toolchain_selector/src/active_toolchain.rs index e2d0b2c808f043b57cd831dadee3e50d8460075c..c49deed02c2fabcb597bf27fb76fe1ff45659aee 100644 --- a/crates/toolchain_selector/src/active_toolchain.rs +++ b/crates/toolchain_selector/src/active_toolchain.rs @@ -4,14 +4,15 @@ use gpui::{ ViewContext, WeakModel, WeakView, }; use language::{Buffer, BufferEvent, LanguageName, Toolchain}; -use project::WorktreeId; -use ui::{Button, ButtonCommon, Clickable, FluentBuilder, LabelSize, Tooltip}; +use project::{Project, WorktreeId}; +use ui::{Button, ButtonCommon, Clickable, FluentBuilder, LabelSize, SharedString, Tooltip}; use workspace::{item::ItemHandle, StatusItemView, Workspace}; use crate::ToolchainSelector; pub struct ActiveToolchain { active_toolchain: Option, + term: SharedString, workspace: WeakView, active_buffer: Option<(WorktreeId, WeakModel, Subscription)>, _update_toolchain_task: Task>, @@ -22,6 +23,7 @@ impl ActiveToolchain { Self { active_toolchain: None, active_buffer: None, + term: SharedString::new_static("Toolchain"), workspace: workspace.weak_handle(), _update_toolchain_task: Self::spawn_tracker_task(cx), @@ -44,7 +46,17 @@ impl ActiveToolchain { .update(&mut cx, |this, _| Some(this.language()?.name())) .ok() .flatten()?; - + let term = workspace + .update(&mut cx, |workspace, cx| { + let languages = workspace.project().read(cx).languages(); + Project::toolchain_term(languages.clone(), language_name.clone()) + }) + .ok()? + .await?; + let _ = this.update(&mut cx, |this, cx| { + this.term = term; + cx.notify(); + }); let worktree_id = active_file .update(&mut cx, |this, cx| Some(this.file()?.worktree_id(cx))) .ok() @@ -133,6 +145,7 @@ impl ActiveToolchain { impl Render for ActiveToolchain { fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { div().when_some(self.active_toolchain.as_ref(), |el, active_toolchain| { + let term = self.term.clone(); el.child( Button::new("change-toolchain", active_toolchain.name.clone()) .label_size(LabelSize::Small) @@ -143,7 +156,7 @@ impl Render for ActiveToolchain { }); } })) - .tooltip(|cx| Tooltip::text("Select Toolchain", cx)), + .tooltip(move |cx| Tooltip::text(format!("Select {}", &term), cx)), ) }) } diff --git a/crates/toolchain_selector/src/toolchain_selector.rs b/crates/toolchain_selector/src/toolchain_selector.rs index 8a3368f81675d4cc5a4a9c01a83b1107e43a9403..4c31d600ba7eed42231a779c12e51170ee026738 100644 --- a/crates/toolchain_selector/src/toolchain_selector.rs +++ b/crates/toolchain_selector/src/toolchain_selector.rs @@ -126,6 +126,7 @@ pub struct ToolchainSelectorDelegate { workspace: WeakView, worktree_id: WorktreeId, worktree_abs_path_root: Arc, + placeholder_text: Arc, _fetch_candidates_task: Task>, } @@ -144,6 +145,17 @@ impl ToolchainSelectorDelegate { let _fetch_candidates_task = cx.spawn({ let project = project.clone(); move |this, mut cx| async move { + let term = project + .update(&mut cx, |this, _| { + Project::toolchain_term(this.languages().clone(), language_name.clone()) + }) + .ok()? + .await?; + let placeholder_text = format!("Select a {}…", term.to_lowercase()).into(); + let _ = this.update(&mut cx, move |this, cx| { + this.delegate.placeholder_text = placeholder_text; + this.refresh_placeholder(cx); + }); let available_toolchains = project .update(&mut cx, |this, cx| { this.available_toolchains(worktree_id, language_name, cx) @@ -153,6 +165,7 @@ impl ToolchainSelectorDelegate { let _ = this.update(&mut cx, move |this, cx| { this.delegate.candidates = available_toolchains; + if let Some(active_toolchain) = active_toolchain { if let Some(position) = this .delegate @@ -170,7 +183,7 @@ impl ToolchainSelectorDelegate { Some(()) } }); - + let placeholder_text = "Select a toolchain…".to_string().into(); Self { toolchain_selector: language_selector, candidates: Default::default(), @@ -179,6 +192,7 @@ impl ToolchainSelectorDelegate { workspace, worktree_id, worktree_abs_path_root, + placeholder_text, _fetch_candidates_task, } } @@ -196,7 +210,7 @@ impl PickerDelegate for ToolchainSelectorDelegate { type ListItem = ListItem; fn placeholder_text(&self, _cx: &mut WindowContext) -> Arc { - "Select a toolchain...".into() + self.placeholder_text.clone() } fn match_count(&self) -> usize {