diff --git a/Cargo.lock b/Cargo.lock index 98331680..6453381c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -261,6 +261,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33a7e468e750fa4b6be660e8b5651ad47372e8fb114030b594c2d75d48c5ffd0" dependencies = [ "clap", + "clap_lex", + "is_executable", + "shlex", ] [[package]] @@ -1117,6 +1120,15 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "is_executable" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa9acdc6d67b75e626ad644734e8bc6df893d9cd2a834129065d3dd6158ea9c8" +dependencies = [ + "winapi", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.1" diff --git a/Cargo.toml b/Cargo.toml index acf1ad88..01820baf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ license = "MIT" keywords = ["julia"] categories = ["command-line-utilities"] edition = "2021" +rust-version = "1.80" default-run = "juliaup" authors = ["David Anthoff "] exclude = [ @@ -27,7 +28,7 @@ codegen-units = 1 [dependencies] clap = { version = "4.5", features = ["derive"] } -clap_complete = "4.5" +clap_complete = { version = "4.5", features = ["unstable-dynamic"] } dirs = "6.0.0" dunce = "1.0" serde = { version = "1.0", features = ["derive"] } diff --git a/README.md b/README.md index 1ab04d18..eff445f7 100644 --- a/README.md +++ b/README.md @@ -123,7 +123,6 @@ Here are some of the things you can do with `juliaup`: - `juliaup override set --path foo/bar lts` sets a directory override for the path `foo/bar` to the `lts` channel. - `juliaup override unset --path foo/bar` removes a directory override for the path `foo/bar`. - `juliaup override unset --nonexistent` removes all directory overrides for paths that no longer exist. -- `juliaup completions bash > ~/.local/share/bash-completion/completions/juliaup` generates Bash completions for `juliaup` and saves them to a file. To use them, simply source this file in your `~/.bashrc`. Other supported shells are `zsh`, `fish`, `elvish` and `powershell`. - `juliaup` shows you what other commands are available. The available system provided channels are: @@ -169,6 +168,19 @@ the `JULIAUP_DEPOT_PATH` environment variable. Caution: Previous versions of Jul Juliaup by default downloads julia binary tarballs from the official server "https://julialang-s3.julialang.org". If requested, the environment variable `JULIAUP_SERVER` can be used to tell Juliaup to use a third-party mirror server. +## Shell completions + +To generate shell completions, load `COMPLETE=$SHELL juliaup` at shell launch. For example, with bash, it could look like `source <(COMPLETE=bash juliaup)`. + +For more specific information on adding completions to your shell, see https://docs.rs/clap_complete/latest/clap_complete/env/index.html + +Note: MacOS ships with an ancient version of bash that does not support process substitution. To work around this, you can create a temporary file and `source` that instead like: + +```bash +COMPLETE=bash juliaup > /tmp/juliaup_completion.sh +source /tmp/juliaup_completion.sh +``` + ## Development guides For juliaup developers, information on how to build juliaup locally, update julia versions, and release updates diff --git a/src/bin/juliaup.rs b/src/bin/juliaup.rs index 33835acf..6c67b503 100644 --- a/src/bin/juliaup.rs +++ b/src/bin/juliaup.rs @@ -1,8 +1,8 @@ use anyhow::{Context, Result}; -use clap::Parser; +use clap::{CommandFactory, Parser}; +use clap_complete::CompleteEnv; use juliaup::cli::{ConfigSubCmd, Juliaup, OverrideSubCmd, SelfSubCmd}; use juliaup::command_api::run_command_api; -use juliaup::command_completions::run_command_completions; #[cfg(not(windows))] use juliaup::command_config_symlinks::run_command_config_symlinks; use juliaup::command_config_versionsdbupdate::run_command_config_versionsdbupdate; @@ -37,6 +37,8 @@ use juliaup::command_selfuninstall::run_command_selfuninstall_unavailable; use log::info; fn main() -> Result<()> { + CompleteEnv::with_factory(|| Juliaup::command()).complete(); + human_panic::setup_panic!( human_panic::Metadata::new("Juliaup", env!("CARGO_PKG_VERSION")) .support("https://github.com/JuliaLang/juliaup") @@ -148,6 +150,5 @@ fn main() -> Result<()> { #[cfg(not(feature = "selfupdate"))] SelfSubCmd::Uninstall {} => run_command_selfuninstall_unavailable(), }, - Juliaup::Completions { shell } => run_command_completions(shell), } } diff --git a/src/cli.rs b/src/cli.rs index 5d7bc76a..95451dff 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,7 +1,7 @@ use clap::{Parser, ValueEnum}; #[derive(Parser)] -#[clap(name = "Juliaup", version)] +#[clap(name = "juliaup", version)] #[command( after_help = "To launch a specific Julia version, use `julia +{channel}` e.g. `julia +1.6`. Entering just `julia` uses the default channel set via `juliaup default`." @@ -50,8 +50,6 @@ pub enum Juliaup { Info {}, #[clap(subcommand, name = "self")] SelfSubCmd(SelfSubCmd), - /// Generate tab-completion scripts for your shell - Completions { shell: clap_complete::Shell }, // This is used for the cron jobs that we create. By using this UUID for the command // We can identify the cron jobs that were created by juliaup for uninstall purposes #[cfg(feature = "selfupdate")] diff --git a/src/command_completions.rs b/src/command_completions.rs deleted file mode 100644 index b24627b8..00000000 --- a/src/command_completions.rs +++ /dev/null @@ -1,16 +0,0 @@ -use crate::cli; -use anyhow::Result; -use clap::CommandFactory; -use clap_complete::Shell; -use cli::Juliaup; -use std::io; - -pub fn run_command_completions(shell: Shell) -> Result<()> { - clap_complete::generate( - shell, - &mut Juliaup::command(), - "juliaup", - &mut io::stdout().lock(), - ); - Ok(()) -} diff --git a/src/lib.rs b/src/lib.rs index 92675479..6b5c2f72 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,7 +3,6 @@ use anyhow::Context; pub mod cli; pub mod command_add; pub mod command_api; -pub mod command_completions; pub mod command_config_backgroundselfupdate; pub mod command_config_modifypath; pub mod command_config_startupselfupdate;