From 0cfaf74aabeef05086b67319359a510bd88fab51 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 1 Jan 2025 18:01:24 +0000 Subject: [PATCH] feat: added completions to more commands (#3910) Fixes #3909 --- docs/cli/index.md | 10 ++-- docs/cli/ls.md | 6 +-- docs/cli/set.md | 4 +- docs/cli/tool.md | 4 +- docs/cli/unset.md | 4 +- docs/cli/which.md | 4 +- e2e/cli/test_registry | 2 +- mise.lock | 8 +-- mise.usage.kdl | 25 +++++++--- src/assets/mise-extra.usage.kdl | 6 +++ src/cli/ls.rs | 26 +++++----- src/cli/registry.rs | 86 +++++++++++++++++++++------------ src/cli/set.rs | 18 ++++++- src/cli/tool.rs | 6 +-- src/cli/unset.rs | 2 +- src/cli/which.rs | 44 ++++++++++++----- xtasks/fig/src/mise.ts | 31 +++++++----- 17 files changed, 181 insertions(+), 105 deletions(-) diff --git a/docs/cli/index.md b/docs/cli/index.md index a1ac4a70dc..7638ddd148 100644 --- a/docs/cli/index.md +++ b/docs/cli/index.md @@ -95,7 +95,7 @@ Can also use `MISE_NO_CONFIG=1` - [`mise install-into `](/cli/install-into.md) - [`mise latest [-i --installed] `](/cli/latest.md) - [`mise link [-f --force] `](/cli/link.md) -- [`mise ls [FLAGS] [PLUGIN]...`](/cli/ls.md) +- [`mise ls [FLAGS] [INSTALLED_TOOL]...`](/cli/ls.md) - [`mise ls-remote [--all] [TOOL@VERSION] [PREFIX]`](/cli/ls-remote.md) - [`mise outdated [FLAGS] [TOOL@VERSION]...`](/cli/outdated.md) - [`mise plugins [FLAGS] `](/cli/plugins.md) @@ -110,7 +110,7 @@ Can also use `MISE_NO_CONFIG=1` - [`mise reshim [-f --force]`](/cli/reshim.md) - [`mise run [FLAGS]`](/cli/run.md) - [`mise self-update [FLAGS] [VERSION]`](/cli/self-update.md) -- [`mise set [--file ] [-g --global] [ENV_VARS]...`](/cli/set.md) +- [`mise set [--file ] [-g --global] [ENV_VAR]...`](/cli/set.md) - [`mise settings [FLAGS] [SETTING] [VALUE] `](/cli/settings.md) - [`mise settings add [-l --local] `](/cli/settings/add.md) - [`mise settings get [-l --local] `](/cli/settings/get.md) @@ -129,14 +129,14 @@ Can also use `MISE_NO_CONFIG=1` - [`mise tasks info [-J --json] `](/cli/tasks/info.md) - [`mise tasks ls [FLAGS]`](/cli/tasks/ls.md) - [`mise tasks run [FLAGS] [TASK] [ARGS]...`](/cli/tasks/run.md) -- [`mise tool [FLAGS] `](/cli/tool.md) +- [`mise tool [FLAGS] `](/cli/tool.md) - [`mise trust [FLAGS] [CONFIG_FILE]`](/cli/trust.md) - [`mise uninstall [-a --all] [-n --dry-run] [INSTALLED_TOOL@VERSION]...`](/cli/uninstall.md) -- [`mise unset [-f --file ] [-g --global] [KEYS]...`](/cli/unset.md) +- [`mise unset [-f --file ] [-g --global] [ENV_KEY]...`](/cli/unset.md) - [`mise unuse [--no-prune] [--global] ...`](/cli/unuse.md) - [`mise upgrade [FLAGS] [TOOL@VERSION]...`](/cli/upgrade.md) - [`mise use [FLAGS] [TOOL@VERSION]...`](/cli/use.md) - [`mise version`](/cli/version.md) - [`mise watch [FLAGS] [TASK] [ARGS]...`](/cli/watch.md) - [`mise where `](/cli/where.md) -- [`mise which [FLAGS] `](/cli/which.md) +- [`mise which [FLAGS] [BIN_NAME]`](/cli/which.md) diff --git a/docs/cli/ls.md b/docs/cli/ls.md index cd0b923a4a..6befafea7d 100644 --- a/docs/cli/ls.md +++ b/docs/cli/ls.md @@ -1,6 +1,6 @@ # `mise ls` -- **Usage**: `mise ls [FLAGS] [PLUGIN]...` +- **Usage**: `mise ls [FLAGS] [INSTALLED_TOOL]...` - **Aliases**: `list` - **Source code**: [`src/cli/ls.rs`](https://github.com/jdx/mise/blob/main/src/cli/ls.rs) @@ -14,9 +14,9 @@ It's a useful command to get the current state of your tools. ## Arguments -### `[PLUGIN]...` +### `[INSTALLED_TOOL]...` -Only show tool versions from [PLUGIN] +Only show tool versions from [TOOL] ## Flags diff --git a/docs/cli/set.md b/docs/cli/set.md index a2b61e8aba..1f833d7f16 100644 --- a/docs/cli/set.md +++ b/docs/cli/set.md @@ -1,6 +1,6 @@ # `mise set` -- **Usage**: `mise set [--file ] [-g --global] [ENV_VARS]...` +- **Usage**: `mise set [--file ] [-g --global] [ENV_VAR]...` - **Source code**: [`src/cli/set.rs`](https://github.com/jdx/mise/blob/main/src/cli/set.rs) Set environment variables in mise.toml @@ -9,7 +9,7 @@ By default, this command modifies `mise.toml` in the current directory. ## Arguments -### `[ENV_VARS]...` +### `[ENV_VAR]...` Environment variable(s) to set e.g.: NODE_ENV=production diff --git a/docs/cli/tool.md b/docs/cli/tool.md index 55675d6740..476f55ba51 100644 --- a/docs/cli/tool.md +++ b/docs/cli/tool.md @@ -1,13 +1,13 @@ # `mise tool` -- **Usage**: `mise tool [FLAGS] ` +- **Usage**: `mise tool [FLAGS] ` - **Source code**: [`src/cli/tool.rs`](https://github.com/jdx/mise/blob/main/src/cli/tool.rs) Gets information about a tool ## Arguments -### `` +### `` Tool name to get information about diff --git a/docs/cli/unset.md b/docs/cli/unset.md index bb9ab2402e..62df989c48 100644 --- a/docs/cli/unset.md +++ b/docs/cli/unset.md @@ -1,6 +1,6 @@ # `mise unset` -- **Usage**: `mise unset [-f --file ] [-g --global] [KEYS]...` +- **Usage**: `mise unset [-f --file ] [-g --global] [ENV_KEY]...` - **Source code**: [`src/cli/unset.rs`](https://github.com/jdx/mise/blob/main/src/cli/unset.rs) Remove environment variable(s) from the config file. @@ -9,7 +9,7 @@ By default, this command modifies `mise.toml` in the current directory. ## Arguments -### `[KEYS]...` +### `[ENV_KEY]...` Environment variable(s) to remove e.g.: NODE_ENV diff --git a/docs/cli/which.md b/docs/cli/which.md index 2900338216..578d0b5615 100644 --- a/docs/cli/which.md +++ b/docs/cli/which.md @@ -1,6 +1,6 @@ # `mise which` -- **Usage**: `mise which [FLAGS] ` +- **Usage**: `mise which [FLAGS] [BIN_NAME]` - **Source code**: [`src/cli/which.rs`](https://github.com/jdx/mise/blob/main/src/cli/which.rs) Shows the path that a tool's bin points to. @@ -9,7 +9,7 @@ Use this to figure out what version of a tool is currently active. ## Arguments -### `` +### `[BIN_NAME]` The bin to look up diff --git a/e2e/cli/test_registry b/e2e/cli/test_registry index a42bf60560..6866b99917 100644 --- a/e2e/cli/test_registry +++ b/e2e/cli/test_registry @@ -1,4 +1,4 @@ #!/usr/bin/env bash assert "mise registry gh" "aqua:cli/cli ubi:cli/cli[exe=gh] asdf:bartlomiejdanek/asdf-github-cli" -assert_contains "mise registry" "gh aqua:cli/cli ubi:cli/cli[exe=gh] asdf:bartlomiejdanek/asdf-github-cli" +assert_contains "mise registry" "gh aqua:cli/cli ubi:cli/cli[exe=gh] asdf:bartlomiejdanek/asdf-github-cli" diff --git a/mise.lock b/mise.lock index 23a3785e8a..812b22c6f0 100644 --- a/mise.lock +++ b/mise.lock @@ -1,13 +1,9 @@ [tools.actionlint] -version = "1.7.4" +version = "1.7.5" backend = "aqua:rhysd/actionlint" [tools.actionlint.checksums] -actionlint-linux-x86_64 = "sha256:39cae525cdb54af5d91dcf27f55e040d37ecea01dd4153490c4dc84f5d251d46" -actionlint-macos-aarch64 = "sha256:f381afca13b39e095e4cee25e2b2abbb39ae8b2848f5ccd2564bf86192c1b661" -"actionlint.exe-windows-x86_64" = "sha256:04ca117d9f33b77731fd3ef6a3670bd6b11b40c1b1cc5b7aaf6c28392d74d2e2" -"actionlint_1.7.4_linux_amd64.tar.gz" = "sha256:fc0a6886bbb9a23a39eeec4b176193cadb54ddbe77cdbb19b637933919545395" -"actionlint_1.7.4_linux_arm64.tar.gz" = "sha256:ede03682dc955381d057dde95bb85ce9ca418122209a8a313b617d4adec56416" +"actionlint_1.7.5_darwin_arm64.tar.gz" = "sha256:397119f9baa3fd9fe195db340b30acdaea532826e19a047a9cc9d96add7c267d" [tools.bun] version = "1.1.42" diff --git a/mise.usage.kdl b/mise.usage.kdl index 6698573c4a..7759bf8f36 100644 --- a/mise.usage.kdl +++ b/mise.usage.kdl @@ -804,7 +804,7 @@ It's a useful command to get the current state of your tools."# } "# flag "-p --plugin" hide=true { - arg "" + arg "" } flag "-c --current" help="Only show tool versions currently specified in a mise.toml" flag "-g --global" help="Only show tool versions currently specified in the global mise.toml" @@ -817,7 +817,7 @@ It's a useful command to get the current state of your tools."# arg "" } flag "--no-header" help="Don't display headers" - arg "[PLUGIN]..." help="Only show tool versions from [PLUGIN]" required=false var=true + arg "[INSTALLED_TOOL]..." help="Only show tool versions from [TOOL]" required=false var=true } cmd "ls-remote" help="List runtime versions available for install." { alias "list-all" "list-remote" hide=true @@ -1025,6 +1025,7 @@ For example, `poetry` is shorthand for `asdf:mise-plugins/mise-poetry`." flag "-b --backend" help="Show only tools for this backend" { arg "" } + flag "--complete" help="Print all tools with descriptions for shell completions" hide=true flag "--hide-aliased" help="Hide aliased tools" arg "[NAME]" help="Show only the specified tool's full name" required=false } @@ -1169,12 +1170,13 @@ By default, this command modifies `mise.toml` in the current directory." long_help "The TOML file to update\n\nDefaults to MISE_DEFAULT_CONFIG_FILENAME environment variable, or `mise.toml`." arg "" } + flag "--complete" help="Render completions" hide=true flag "-g --global" help="Set the environment variable in the global config file" - flag "--remove" help="Remove the environment variable from config file" var=true hide=true { + flag "--remove --rm --unset" help="Remove the environment variable from config file" var=true hide=true { long_help "Remove the environment variable from config file\n\nCan be used multiple times." - arg "" + arg "" } - arg "[ENV_VARS]..." help="Environment variable(s) to set\ne.g.: NODE_ENV=production" required=false var=true + arg "[ENV_VAR]..." help="Environment variable(s) to set\ne.g.: NODE_ENV=production" required=false var=true } cmd "settings" help="Manage settings" { long_help r"Show current settings @@ -1624,7 +1626,7 @@ cmd "tool" help="Gets information about a tool" { flag "--requested" help="Only show requested versions" flag "--config-source" help="Only show config source" flag "--tool-options" help="Only show tool options" - arg "" help="Tool name to get information about" + arg "" help="Tool name to get information about" } cmd "trust" help="Marks a config file as trusted" { long_help r"Marks a config file as trusted @@ -1685,7 +1687,7 @@ By default, this command modifies `mise.toml` in the current directory." arg "" } flag "-g --global" help="Use the global config file" - arg "[KEYS]..." help="Environment variable(s) to remove\ne.g.: NODE_ENV" required=false var=true + arg "[ENV_KEY]..." help="Environment variable(s) to remove\ne.g.: NODE_ENV" required=false var=true } cmd "unuse" help="Removes installed tool versions from mise.toml" { alias "rm" "remove" @@ -2052,12 +2054,13 @@ Use this to figure out what version of a tool is currently active." $ mise which node --version 20.0.0 " + flag "--complete" hide=true flag "--plugin" help="Show the plugin name instead of the path" flag "--version" help="Show the version instead of the path" flag "-t --tool" help="Use a specific tool@version\ne.g.: `mise which npm --tool=node@20`" { arg "" } - arg "" help="The bin to look up" + arg "[BIN_NAME]" help="The bin to look up" required=false } cmd "render-help" hide=true help="internal command to generate markdown from help" cmd "render-mangen" hide=true help="internal command to generate markdown from help" @@ -2066,10 +2069,16 @@ source_code_link_template "https://github.com/jdx/mise/blob/main/src/cli/{{path} complete "alias" run="mise alias ls {{words[PREV]}} | awk '{print $2}'" complete "config_file" type="file" complete "new_plugin" run="mise plugins --all" +complete "installed_tool" run="mise plugins --core --user" complete "plugin" run="mise plugins --core --user" complete "prefix" run="mise ls-remote {{words[PREV]}}" complete "setting" run="mise settings --complete" descriptions=true complete "task" run="mise tasks ls --complete" descriptions=true +complete "tool" run="mise registry --complete" descriptions=true +complete "env_var" run=r#"mise set --complete | awk '{print $1"="}'"# +complete "env_key" run="mise set --complete" +complete "backend" run="mise backends" +complete "bin_name" run="mise which --complete" complete "tool@version" run=r#" cur="{{words[CURRENT]}}" diff --git a/src/assets/mise-extra.usage.kdl b/src/assets/mise-extra.usage.kdl index f909aef627..b248f104d6 100644 --- a/src/assets/mise-extra.usage.kdl +++ b/src/assets/mise-extra.usage.kdl @@ -3,10 +3,16 @@ source_code_link_template "https://github.com/jdx/mise/blob/main/src/cli/{{path} complete "alias" run="mise alias ls {{words[PREV]}} | awk '{print $2}'" complete "config_file" type="file" complete "new_plugin" run="mise plugins --all" +complete "installed_tool" run="mise plugins --core --user" complete "plugin" run="mise plugins --core --user" complete "prefix" run="mise ls-remote {{words[PREV]}}" complete "setting" run="mise settings --complete" descriptions=true complete "task" run="mise tasks ls --complete" descriptions=true +complete "tool" run="mise registry --complete" descriptions=true +complete "env_var" run=r#"mise set --complete | awk '{print $1"="}'"# +complete "env_key" run="mise set --complete" +complete "backend" run="mise backends" +complete "bin_name" run="mise which --complete" complete "tool@version" run=r#" cur="{{words[CURRENT]}}" diff --git a/src/cli/ls.rs b/src/cli/ls.rs index a1a83e4020..4646d5fb64 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -25,12 +25,12 @@ use crate::ui::table::MiseTable; #[derive(Debug, clap::Args)] #[clap(visible_alias = "list", verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Ls { - /// Only show tool versions from [PLUGIN] - #[clap(conflicts_with = "plugin_flag")] - plugin: Option>, + /// Only show tool versions from [TOOL] + #[clap(conflicts_with = "tool_flag")] + installed_tool: Option>, - #[clap(long = "plugin", short, hide = true)] - plugin_flag: Option, + #[clap(long = "plugin", short = 'p', hide = true)] + tool_flag: Option, /// Only show tool versions currently specified in a mise.toml #[clap(long, short)] @@ -62,7 +62,7 @@ pub struct Ls { missing: bool, /// Display versions matching this prefix - #[clap(long, requires = "plugin")] + #[clap(long, requires = "installed_tool")] prefix: Option, /// Don't display headers @@ -73,9 +73,9 @@ pub struct Ls { impl Ls { pub fn run(mut self) -> Result<()> { let config = Config::try_get()?; - self.plugin = self - .plugin - .or_else(|| self.plugin_flag.clone().map(|p| vec![p])); + self.installed_tool = self + .installed_tool + .or_else(|| self.tool_flag.clone().map(|p| vec![p])); self.verify_plugin()?; let mut runtimes = self.get_runtime_list(&config)?; @@ -101,7 +101,7 @@ impl Ls { } fn verify_plugin(&self) -> Result<()> { - if let Some(plugins) = &self.plugin { + if let Some(plugins) = &self.installed_tool { for ba in plugins { if let Some(plugin) = ba.backend()?.plugin() { ensure!(plugin.is_installed(), "{ba} is not installed"); @@ -112,7 +112,7 @@ impl Ls { } fn display_json(&self, runtimes: Vec) -> Result<()> { - if let Some(plugins) = &self.plugin { + if let Some(plugins) = &self.installed_tool { // only runtimes for 1 plugin let runtimes: Vec = runtimes .into_iter() @@ -185,7 +185,7 @@ impl Ls { .list_all_versions()? .into_iter() .map(|(b, tv)| ((b, tv.version.clone()), tv)) - .filter(|((b, _), _)| match &self.plugin { + .filter(|((b, _), _)| match &self.installed_tool { Some(p) => p.contains(b.ba()), None => true, }) @@ -199,7 +199,7 @@ impl Ls { .map(|(k, tv)| (self, k.0, tv.clone(), tv.request.source().clone())) // if it isn't installed and it's not specified, don't show it .filter(|(_ls, p, tv, source)| !source.is_unknown() || p.is_version_installed(tv, true)) - .filter(|(_ls, p, _, _)| match &self.plugin { + .filter(|(_ls, p, _, _)| match &self.installed_tool { Some(backend) => backend.contains(p.ba()), None => true, }) diff --git a/src/cli/registry.rs b/src/cli/registry.rs index bcb46625ca..d9508bcfde 100644 --- a/src/cli/registry.rs +++ b/src/cli/registry.rs @@ -1,10 +1,9 @@ use crate::backend::backend_type::BackendType; use crate::config::SETTINGS; use crate::registry::{RegistryTool, REGISTRY}; -use crate::ui::table; +use crate::ui::table::MiseTable; use eyre::{bail, Result}; use itertools::Itertools; -use tabled::{Table, Tabled}; /// List available tools to install /// @@ -21,6 +20,10 @@ pub struct Registry { #[clap(short, long)] backend: Option, + /// Print all tools with descriptions for shell completions + #[clap(long, hide = true)] + complete: bool, + /// Hide aliased tools #[clap(long)] hide_aliased: bool, @@ -28,6 +31,21 @@ pub struct Registry { impl Registry { pub fn run(self) -> Result<()> { + if let Some(name) = &self.name { + if let Some(rt) = REGISTRY.get(name.as_str()) { + miseprintln!("{}", rt.backends().join(" ")); + } else { + bail!("tool not found in registry: {name}"); + } + } else if self.complete { + self.complete()?; + } else { + self.display_table()?; + } + Ok(()) + } + + fn display_table(&self) -> Result<()> { let filter_backend = |rt: &RegistryTool| { if let Some(backend) = self.backend { rt.backends() @@ -39,38 +57,44 @@ impl Registry { rt.backends() } }; - if let Some(name) = &self.name { - if let Some(rt) = REGISTRY.get(name.as_str()) { - miseprintln!("{}", rt.backends().join(" ")); - } else { - bail!("tool not found in registry: {name}"); - } - } else { - let data = REGISTRY - .iter() - .filter(|(short, _)| !SETTINGS.disable_tools.contains(**short)) - .filter(|(short, rt)| !self.hide_aliased || **short == rt.short) - .map(|(short, rt)| Row::from((short.to_string(), filter_backend(rt).join(" ")))) - .filter(|row| !row.backends.is_empty()) - .sorted_by(|a, b| a.short.cmp(&b.short)); - let mut table = Table::new(data); - table::default_style(&mut table, false); - miseprintln!("{table}"); + let mut table = MiseTable::new(false, &["Tool", "Backends"]); + let data = REGISTRY + .iter() + .filter(|(short, _)| !SETTINGS.disable_tools.contains(**short)) + .filter(|(short, rt)| !self.hide_aliased || **short == rt.short) + .map(|(short, rt)| (short.to_string(), filter_backend(rt).join(" "))) + .filter(|(_, backends)| !backends.is_empty()) + .sorted_by(|(a, _), (b, _)| a.cmp(b)) + .map(|(short, backends)| vec![short, backends]) + .collect_vec(); + for row in data { + table.add_row(row); } - Ok(()) + table.print() } -} -#[derive(Tabled, Eq, PartialEq, Ord, PartialOrd)] -#[tabled(rename_all = "PascalCase")] -struct Row { - short: String, - backends: String, -} - -impl From<(String, String)> for Row { - fn from((short, backends): (String, String)) -> Self { - Self { short, backends } + fn complete(&self) -> Result<()> { + REGISTRY + .iter() + .filter(|(short, _)| !SETTINGS.disable_tools.contains(**short)) + .filter(|(short, rt)| !self.hide_aliased || **short == rt.short) + .map(|(short, rt)| { + ( + short.to_string(), + rt.description + .or(rt.backends().first().cloned()) + .unwrap_or_default(), + ) + }) + .sorted_by(|(a, _), (b, _)| a.cmp(b)) + .for_each(|(short, description)| { + println!( + "{}:{}", + short.replace(":", "\\:"), + description.replace(":", "\\:") + ); + }); + Ok(()) } } diff --git a/src/cli/set.rs b/src/cli/set.rs index 6a2f034491..f71f3f6d93 100644 --- a/src/cli/set.rs +++ b/src/cli/set.rs @@ -25,6 +25,10 @@ pub struct Set { #[clap(long, verbatim_doc_comment, required = false, value_hint = clap::ValueHint::FilePath)] file: Option, + /// Render completions + #[clap(long, hide = true)] + complete: bool, + /// Set the environment variable in the global config file #[clap(short, long, verbatim_doc_comment, overrides_with = "file")] global: bool, @@ -32,17 +36,20 @@ pub struct Set { /// Remove the environment variable from config file /// /// Can be used multiple times. - #[clap(long, value_name = "ENV_VAR", verbatim_doc_comment, aliases = ["rm", "unset"], hide = true)] + #[clap(long, value_name = "ENV_KEY", verbatim_doc_comment, visible_aliases = ["rm", "unset"], hide = true)] remove: Option>, /// Environment variable(s) to set /// e.g.: NODE_ENV=production - #[clap(verbatim_doc_comment)] + #[clap(value_name = "ENV_VAR", verbatim_doc_comment)] env_vars: Option>, } impl Set { pub fn run(self) -> Result<()> { + if self.complete { + return self.complete(); + } match (&self.remove, &self.env_vars) { (None, None) => { return self.list_all(); @@ -86,6 +93,13 @@ impl Set { mise_toml.save() } + fn complete(&self) -> Result<()> { + for ev in self.cur_env()? { + println!("{}", ev.key); + } + Ok(()) + } + fn list_all(self) -> Result<()> { let env = self.cur_env()?; let mut table = tabled::Table::new(env); diff --git a/src/cli/tool.rs b/src/cli/tool.rs index 191f305632..340ba80464 100644 --- a/src/cli/tool.rs +++ b/src/cli/tool.rs @@ -12,7 +12,7 @@ use crate::ui::table; #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Tool { /// Tool name to get information about - backend: BackendArg, + tool: BackendArg, /// Output in JSON format #[clap(long, short = 'J')] json: bool, @@ -57,9 +57,9 @@ impl Tool { pub fn run(self) -> Result<()> { let mut ts = ToolsetBuilder::new().build(&Config::get())?; ts.resolve()?; - let tvl = ts.versions.get(&self.backend); + let tvl = ts.versions.get(&self.tool); let tv = tvl.map(|tvl| tvl.versions.first().unwrap()); - let ba = tv.map(|tv| tv.ba()).unwrap_or_else(|| &self.backend); + let ba = tv.map(|tv| tv.ba()).unwrap_or_else(|| &self.tool); let backend = ba.backend().ok(); let info = ToolInfo { backend: ba.full(), diff --git a/src/cli/unset.rs b/src/cli/unset.rs index 3bcc8abb9b..0afd71dc43 100644 --- a/src/cli/unset.rs +++ b/src/cli/unset.rs @@ -14,7 +14,7 @@ use crate::{config, env}; pub struct Unset { /// Environment variable(s) to remove /// e.g.: NODE_ENV - #[clap(verbatim_doc_comment)] + #[clap(verbatim_doc_comment, value_name = "ENV_KEY")] keys: Vec, /// Specify a file to use instead of `mise.toml` diff --git a/src/cli/which.rs b/src/cli/which.rs index d2d6d4f71c..500f18cd6f 100644 --- a/src/cli/which.rs +++ b/src/cli/which.rs @@ -1,9 +1,10 @@ -use eyre::{bail, Result}; - use crate::cli::args::ToolArg; use crate::config::Config; use crate::dirs::SHIMS; +use crate::file; use crate::toolset::{Toolset, ToolsetBuilder}; +use eyre::{bail, Result}; +use itertools::Itertools; /// Shows the path that a tool's bin points to. /// @@ -12,8 +13,11 @@ use crate::toolset::{Toolset, ToolsetBuilder}; #[clap(verbatim_doc_comment, after_long_help = AFTER_LONG_HELP)] pub struct Which { /// The bin to look up - #[clap()] - pub bin_name: String, + #[clap(required_unless_present = "complete")] + pub bin_name: Option, + + #[clap(long, hide = true)] + pub complete: bool, /// Show the plugin name instead of the path #[clap(long, conflicts_with = "version")] @@ -31,32 +35,48 @@ pub struct Which { impl Which { pub fn run(self) -> Result<()> { + if self.complete { + return self.complete(); + } let ts = self.get_toolset()?; - match ts.which(&self.bin_name) { + let bin_name = self.bin_name.clone().unwrap(); + match ts.which(&bin_name) { Some((p, tv)) => { if self.version { miseprintln!("{}", tv.version); } else if self.plugin { miseprintln!("{p}"); } else { - let path = p.which(&tv, &self.bin_name)?; + let path = p.which(&tv, &bin_name)?; miseprintln!("{}", path.unwrap().display()); } Ok(()) } None => { - if self.has_shim(&self.bin_name) { - bail!("{} is a mise bin however it is not currently active. Use `mise use` to activate it in this directory.", self.bin_name) + if self.has_shim(&bin_name) { + bail!("{bin_name} is a mise bin however it is not currently active. Use `mise use` to activate it in this directory.") } else { - bail!( - "{} is not a mise bin. Perhaps you need to install it first.", - self.bin_name - ) + bail!("{bin_name} is not a mise bin. Perhaps you need to install it first.",) } } } } + fn complete(&self) -> Result<()> { + let ts = self.get_toolset()?; + let bins = ts + .list_paths() + .into_iter() + .flat_map(|p| file::ls(&p).unwrap_or_default()) + .map(|p| p.file_name().unwrap().to_string_lossy().to_string()) + .unique() + .sorted() + .collect_vec(); + for bin in bins { + println!("{}", bin); + } + Ok(()) + } fn get_toolset(&self) -> Result { let config = Config::try_get()?; let mut tsb = ToolsetBuilder::new(); diff --git a/xtasks/fig/src/mise.ts b/xtasks/fig/src/mise.ts index c947247fa0..1142dece96 100644 --- a/xtasks/fig/src/mise.ts +++ b/xtasks/fig/src/mise.ts @@ -460,7 +460,8 @@ const completionSpec: Fig.Spec = { "args": { "name": "tool", "description": "Show aliases for ", - "isOptional": true + "isOptional": true, + "generators": completionGeneratorTemplate(`mise registry --complete`) } }, { @@ -1412,11 +1413,11 @@ const completionSpec: Fig.Spec = { } ], "args": { - "name": "plugin", - "description": "Only show tool versions from [PLUGIN]", + "name": "installed_tool", + "description": "Only show tool versions from [TOOL]", "isOptional": true, "isVariadic": true, - "generators": pluginGenerator + "generators": completionGeneratorTemplate(`mise plugins --core --user`) } }, { @@ -1715,7 +1716,8 @@ const completionSpec: Fig.Spec = { "name": "installed_tool", "description": "Prune only these tools", "isOptional": true, - "isVariadic": true + "isVariadic": true, + "generators": completionGeneratorTemplate(`mise plugins --core --user`) } }, { @@ -1730,7 +1732,8 @@ const completionSpec: Fig.Spec = { "description": "Show only tools for this backend", "isRepeatable": false, "args": { - "name": "backend" + "name": "backend", + "generators": completionGeneratorTemplate(`mise backends`) } }, { @@ -1934,7 +1937,7 @@ const completionSpec: Fig.Spec = { } ], "args": { - "name": "env_vars", + "name": "env_var", "description": "Environment variable(s) to set\ne.g.: NODE_ENV=production", "isOptional": true, "isVariadic": true, @@ -2763,8 +2766,9 @@ const completionSpec: Fig.Spec = { } ], "args": { - "name": "backend", - "description": "Tool name to get information about" + "name": "tool", + "description": "Tool name to get information about", + "generators": completionGeneratorTemplate(`mise registry --complete`) } }, { @@ -2858,10 +2862,11 @@ const completionSpec: Fig.Spec = { } ], "args": { - "name": "keys", + "name": "env_key", "description": "Environment variable(s) to remove\ne.g.: NODE_ENV", "isOptional": true, - "isVariadic": true + "isVariadic": true, + "generators": completionGeneratorTemplate(`mise set --complete`) } }, { @@ -3493,7 +3498,9 @@ const completionSpec: Fig.Spec = { ], "args": { "name": "bin_name", - "description": "The bin to look up" + "description": "The bin to look up", + "isOptional": true, + "generators": completionGeneratorTemplate(`mise which --complete`) } } ],