diff --git a/src/cli/backends/ls.rs b/src/cli/backends/ls.rs
new file mode 100644
index 000000000..201a8228a
--- /dev/null
+++ b/src/cli/backends/ls.rs
@@ -0,0 +1,41 @@
+use eyre::Result;
+
+use crate::forge::{self, ForgeType};
+
+/// List built-in backends
+#[derive(Debug, clap::Args)]
+#[clap(visible_alias = "list", after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)]
+pub struct BackendsLs {}
+
+impl BackendsLs {
+ pub fn run(self) -> Result<()> {
+ let mut forges = forge::list_forge_types();
+ forges.retain(|f| *f != ForgeType::Asdf);
+
+ for forge in forges {
+ miseprintln!("{}", forge);
+ }
+ Ok(())
+ }
+}
+
+static AFTER_LONG_HELP: &str = color_print::cstr!(
+ r#"Examples:
+
+ $ mise backends ls
+ cargo
+ go
+ npm
+ pipx
+ ubi
+"#
+);
+
+#[cfg(test)]
+mod tests {
+
+ #[test]
+ fn test_backends_list() {
+ assert_cli_snapshot!("backends", "list");
+ }
+}
diff --git a/src/cli/backends/mod.rs b/src/cli/backends/mod.rs
new file mode 100644
index 000000000..f571ae66d
--- /dev/null
+++ b/src/cli/backends/mod.rs
@@ -0,0 +1,32 @@
+use clap::Subcommand;
+use eyre::Result;
+
+mod ls;
+
+#[derive(Debug, clap::Args)]
+#[clap(about = "Manage backends", visible_alias = "b", aliases = ["backend", "backend-list"])]
+pub struct Backends {
+ #[clap(subcommand)]
+ command: Option,
+}
+
+#[derive(Debug, Subcommand)]
+enum Commands {
+ Ls(ls::BackendsLs),
+}
+
+impl Commands {
+ pub fn run(self) -> Result<()> {
+ match self {
+ Self::Ls(cmd) => cmd.run(),
+ }
+ }
+}
+
+impl Backends {
+ pub fn run(self) -> Result<()> {
+ let cmd = self.command.unwrap_or(Commands::Ls(ls::BackendsLs {}));
+
+ cmd.run()
+ }
+}
diff --git a/src/cli/backends/snapshots/mise__cli__backends__ls__tests__backends_list.snap b/src/cli/backends/snapshots/mise__cli__backends__ls__tests__backends_list.snap
new file mode 100644
index 000000000..c402d45b0
--- /dev/null
+++ b/src/cli/backends/snapshots/mise__cli__backends__ls__tests__backends_list.snap
@@ -0,0 +1,9 @@
+---
+source: src/cli/backends/ls.rs
+expression: output
+---
+cargo
+go
+npm
+pipx
+ubi
diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs
index 756c7d3b2..db17a4772 100644
--- a/src/cli/doctor.rs
+++ b/src/cli/doctor.rs
@@ -10,6 +10,7 @@ use crate::cli::version;
use crate::cli::version::VERSION;
use crate::config::{Config, Settings};
use crate::file::display_path;
+use crate::forge::ForgeType;
use crate::git::Git;
use crate::plugins::core::CORE_PLUGINS;
use crate::plugins::PluginType;
@@ -100,6 +101,7 @@ impl Doctor {
let config = config.as_ref();
section("config_files", render_config_files(config))?;
+ section("backends", render_backends())?;
section("plugins", render_plugins())?;
for plugin in forge::list() {
@@ -239,11 +241,22 @@ fn render_config_files(config: &Config) -> String {
.join("\n")
}
+fn render_backends() -> String {
+ let mut s = vec![];
+ let backends = forge::list_forge_types()
+ .into_iter()
+ .filter(|f| *f != ForgeType::Asdf);
+ for b in backends {
+ s.push(format!("{}", b));
+ }
+ s.join("\n")
+}
+
fn render_plugins() -> String {
let mut s = vec![];
let plugins = forge::list()
.into_iter()
- .filter(|p| p.is_installed())
+ .filter(|p| p.is_installed() && p.get_type() == ForgeType::Asdf)
.collect::>();
let max_plugin_name_len = plugins
.iter()
diff --git a/src/cli/mod.rs b/src/cli/mod.rs
index 1b8e80950..14efd4469 100644
--- a/src/cli/mod.rs
+++ b/src/cli/mod.rs
@@ -8,6 +8,7 @@ mod activate;
mod alias;
pub mod args;
mod asdf;
+pub mod backends;
mod bin_paths;
mod cache;
mod completion;
@@ -62,6 +63,7 @@ pub enum Commands {
Activate(activate::Activate),
Alias(alias::Alias),
Asdf(asdf::Asdf),
+ Backends(backends::Backends),
BinPaths(bin_paths::BinPaths),
Cache(cache::Cache),
Completion(completion::Completion),
@@ -117,6 +119,7 @@ impl Commands {
Self::Activate(cmd) => cmd.run(),
Self::Alias(cmd) => cmd.run(),
Self::Asdf(cmd) => cmd.run(),
+ Self::Backends(cmd) => cmd.run(),
Self::BinPaths(cmd) => cmd.run(),
Self::Cache(cmd) => cmd.run(),
Self::Completion(cmd) => cmd.run(),
diff --git a/src/forge/mod.rs b/src/forge/mod.rs
index e68d1877f..bee30db99 100644
--- a/src/forge/mod.rs
+++ b/src/forge/mod.rs
@@ -1,5 +1,5 @@
use std::collections::BTreeMap;
-use std::fmt::{Debug, Display};
+use std::fmt::{Debug, Display, Formatter};
use std::fs::File;
use std::hash::Hash;
use std::path::{Path, PathBuf};
@@ -12,6 +12,7 @@ use eyre::WrapErr;
use itertools::Itertools;
use rayon::prelude::*;
use regex::Regex;
+use strum::IntoEnumIterator;
use versions::Versioning;
use crate::cli::args::ForgeArg;
@@ -41,7 +42,9 @@ pub type AForge = Arc;
pub type ForgeMap = BTreeMap;
pub type ForgeList = Vec;
-#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, EnumString, AsRefStr, Ord, PartialOrd)]
+#[derive(
+ Debug, PartialEq, Eq, Hash, Clone, Copy, EnumString, EnumIter, AsRefStr, Ord, PartialOrd,
+)]
#[strum(serialize_all = "snake_case")]
pub enum ForgeType {
Asdf,
@@ -52,6 +55,12 @@ pub enum ForgeType {
Ubi,
}
+impl Display for ForgeType {
+ fn fmt(&self, formatter: &mut Formatter) -> std::fmt::Result {
+ write!(formatter, "{}", format!("{:?}", self).to_lowercase())
+ }
+}
+
static FORGES: Mutex