From 2ccb7ed305257c69597072230052488d558a5871 Mon Sep 17 00:00:00 2001 From: Silvano Cerza <3314350+silvanocerza@users.noreply.github.com> Date: Fri, 12 Jul 2024 18:11:50 +0200 Subject: [PATCH] Add `--no-pager` option in `help` command (#5007) ## Summary Fixes #4941. This PR adds a `--no-pager` option in `help` command to explicitly disable the pager. I noted that the template used for the text printed when calling `help` with no argument or option doesn't show any option. It made sense before this PR since `help` didn't have any available option. Though I'm unsure if it makes sense to update the template as it would make it extremely verbose as all the global options would be shown too. I leave the decision to you. ## Test Plan I ran `cargo run -- help` to verify `--isolated` was visible and it. I ran clippy with `cargo clippy --workspace --all-targets --all-features --locked -- -D warnings` as CI does. I also ran tests locally with: ``` cargo nextest run \ --features python-patch \ --workspace \ --status-level skip --failure-output immediate-final --no-fail-fast -j 12 --final-status-level slow ``` --- crates/uv-cli/src/lib.rs | 4 +++ crates/uv/src/commands/help.rs | 7 ++-- crates/uv/src/lib.rs | 8 +++-- crates/uv/tests/help.rs | 62 ++++++++++++++++++++++++++++++++++ 4 files changed, 75 insertions(+), 6 deletions(-) diff --git a/crates/uv-cli/src/lib.rs b/crates/uv-cli/src/lib.rs index 36b114b64e4f..2035b8a4e825 100644 --- a/crates/uv-cli/src/lib.rs +++ b/crates/uv-cli/src/lib.rs @@ -241,6 +241,10 @@ pub enum Commands { #[derive(Args, Debug)] pub struct HelpArgs { + /// Disable pager when printing help + #[arg(long)] + pub no_pager: bool, + pub command: Option>, } diff --git a/crates/uv/src/commands/help.rs b/crates/uv/src/commands/help.rs index 184274ba9f43..d5ea883bbdcc 100644 --- a/crates/uv/src/commands/help.rs +++ b/crates/uv/src/commands/help.rs @@ -11,7 +11,7 @@ use super::ExitStatus; use crate::printer::Printer; use uv_cli::Cli; -pub(crate) fn help(query: &[String], printer: Printer) -> Result { +pub(crate) fn help(query: &[String], printer: Printer, no_pager: bool) -> Result { let mut uv = Cli::command(); // It is very important to build the command before beginning inspection or subcommands @@ -67,11 +67,12 @@ pub(crate) fn help(query: &[String], printer: Printer) -> Result { }; let is_terminal = std::io::stdout().is_terminal(); - if !is_root && is_terminal && which("less").is_ok() { + let should_page = !no_pager && !is_root && is_terminal; + if should_page && which("less").is_ok() { // When using less, we use the command name as the file name and can support colors let prompt = format!("help: uv {}", query.join(" ")); spawn_pager("less", &["-R", "-P", &prompt], &help_ansi)?; - } else if !is_root && is_terminal && which("more").is_ok() { + } else if should_page && which("more").is_ok() { // When using more, we skip the ANSI color codes spawn_pager("more", &[], &help)?; } else { diff --git a/crates/uv/src/lib.rs b/crates/uv/src/lib.rs index 714b41e7d2cf..971396843ac6 100644 --- a/crates/uv/src/lib.rs +++ b/crates/uv/src/lib.rs @@ -157,9 +157,11 @@ async fn run(cli: Cli) -> Result { let cache = Cache::from_settings(cache_settings.no_cache, cache_settings.cache_dir)?; match *cli.command { - Commands::Help(args) => { - commands::help(args.command.unwrap_or_default().as_slice(), printer) - } + Commands::Help(args) => commands::help( + args.command.unwrap_or_default().as_slice(), + printer, + args.no_pager, + ), Commands::Pip(PipNamespace { command: PipCommand::Compile(args), }) => { diff --git a/crates/uv/tests/help.rs b/crates/uv/tests/help.rs index a42f7c7e95cb..270974caa401 100644 --- a/crates/uv/tests/help.rs +++ b/crates/uv/tests/help.rs @@ -660,6 +660,68 @@ fn help_with_version() { ----- stdout ----- uv [VERSION] ([COMMIT] DATE) + ----- stderr ----- + "###); +} + +#[test] +fn test_with_no_pager() { + let context = TestContext::new_with_versions(&[]); + + // We can't really test whether the --no-pager option works with a snapshot test. + // It's still nice to have a test for the option to confirm the option exists. + uv_snapshot!(context.filters(), context.help().arg("--no-pager"), @r###" + success: true + exit_code: 0 + ----- stdout ----- + An extremely fast Python package manager. + + Usage: uv [OPTIONS] + + Commands: + pip Resolve and install Python packages + tool Run and manage executable Python packages + python Manage Python installations + venv Create a virtual environment + cache Manage the cache + version Display uv's version + help Display documentation for a command + + Options: + -q, --quiet + Do not print any output + -v, --verbose... + Use verbose output + --color + Control colors in output [default: auto] [possible values: auto, always, never] + --native-tls + Whether to load TLS certificates from the platform's native certificate store [env: + UV_NATIVE_TLS=] + --offline + Disable network access, relying only on locally cached data and locally available files + --python-preference + Whether to prefer using Python from uv or on the system [possible values: only-managed, + installed, managed, system, only-system] + --python-fetch + Whether to automatically download Python when required [possible values: automatic, + manual] + --isolated + Avoid discovering a `pyproject.toml` or `uv.toml` file in the current directory or any + parent directories + -n, --no-cache + Avoid reading from or writing to the cache [env: UV_NO_CACHE=] + --cache-dir [CACHE_DIR] + Path to the cache directory [env: UV_CACHE_DIR=] + --config-file + The path to a `uv.toml` file to use for configuration [env: UV_CONFIG_FILE=] + -h, --help + Print help + -V, --version + Print version + + Use `uv help ` for more information on a specific command. + + ----- stderr ----- "###); }