//! Provides core data types for language toolchains. //! //! A language can have associated toolchains, //! which is a set of tools used to interact with the projects written in said language. //! For example, a Python project can have an associated virtual environment; a Rust project can have a toolchain override. use std::{path::Path, sync::Arc}; use gpui_shared_string::SharedString; use path::rel_path::RelPath; use crate::{LanguageName, ManifestName}; /// Represents a single toolchain. #[derive(Clone, Eq, Debug)] pub struct Toolchain { /// User-facing label pub name: SharedString, /// Absolute path pub path: SharedString, pub language_name: LanguageName, /// Full toolchain data (including language-specific details) pub as_json: serde_json::Value, } impl std::hash::Hash for Toolchain { fn hash(&self, state: &mut H) { let Self { name, path, language_name, as_json: _, } = self; name.hash(state); path.hash(state); language_name.hash(state); } } impl PartialEq for Toolchain { fn eq(&self, other: &Self) -> bool { let Self { name, path, language_name, as_json: _, } = self; // Do not use as_json for comparisons; it shouldn't impact equality, as it's not user-surfaced. // Thus, there could be multiple entries that look the same in the UI. (name, path, language_name).eq(&(&other.name, &other.path, &other.language_name)) } } /// Declares a scope of a toolchain added by user. /// /// When the user adds a toolchain, we give them an option to see that toolchain in: /// - All of their projects /// - A project they're currently in. /// - Only in the subproject they're currently in. #[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] pub enum ToolchainScope { Subproject(Arc, Arc), Project, /// Available in all projects on this box. It wouldn't make sense to show suggestions across machines. Global, } impl ToolchainScope { pub fn label(&self) -> &'static str { match self { ToolchainScope::Subproject(_, _) => "Subproject", ToolchainScope::Project => "Project", ToolchainScope::Global => "Global", } } pub fn description(&self) -> &'static str { match self { ToolchainScope::Subproject(_, _) => { "Available only in the subproject you're currently in." } ToolchainScope::Project => "Available in all locations in your current project.", ToolchainScope::Global => "Available in all of your projects on this machine.", } } } #[derive(Clone, PartialEq, Eq, Hash)] pub struct ToolchainMetadata { /// Returns a term which we should use in UI to refer to toolchains produced by a given `ToolchainLister`. pub term: SharedString, /// A user-facing placeholder describing the semantic meaning of a path to a new toolchain. pub new_toolchain_placeholder: SharedString, /// The name of the manifest file for this toolchain. pub manifest_name: ManifestName, } type DefaultIndex = usize; #[derive(Default, Clone, Debug)] pub struct ToolchainList { pub toolchains: Vec, pub default: Option, pub groups: Box<[(usize, SharedString)]>, } impl ToolchainList { pub fn toolchains(&self) -> &[Toolchain] { &self.toolchains } pub fn default_toolchain(&self) -> Option { self.default.and_then(|ix| self.toolchains.get(ix)).cloned() } pub fn group_for_index(&self, index: usize) -> Option<(usize, SharedString)> { if index >= self.toolchains.len() { return None; } let first_equal_or_greater = self .groups .partition_point(|(group_lower_bound, _)| group_lower_bound <= &index); self.groups .get(first_equal_or_greater.checked_sub(1)?) .cloned() } }