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
```
This commit is contained in:
Silvano Cerza 2024-07-12 18:11:50 +02:00 committed by GitHub
parent 2a50bc94ca
commit 2ccb7ed305
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 75 additions and 6 deletions

View file

@ -241,6 +241,10 @@ pub enum Commands {
#[derive(Args, Debug)] #[derive(Args, Debug)]
pub struct HelpArgs { pub struct HelpArgs {
/// Disable pager when printing help
#[arg(long)]
pub no_pager: bool,
pub command: Option<Vec<String>>, pub command: Option<Vec<String>>,
} }

View file

@ -11,7 +11,7 @@ use super::ExitStatus;
use crate::printer::Printer; use crate::printer::Printer;
use uv_cli::Cli; use uv_cli::Cli;
pub(crate) fn help(query: &[String], printer: Printer) -> Result<ExitStatus> { pub(crate) fn help(query: &[String], printer: Printer, no_pager: bool) -> Result<ExitStatus> {
let mut uv = Cli::command(); let mut uv = Cli::command();
// It is very important to build the command before beginning inspection or subcommands // 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<ExitStatus> {
}; };
let is_terminal = std::io::stdout().is_terminal(); 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 // When using less, we use the command name as the file name and can support colors
let prompt = format!("help: uv {}", query.join(" ")); let prompt = format!("help: uv {}", query.join(" "));
spawn_pager("less", &["-R", "-P", &prompt], &help_ansi)?; 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 // When using more, we skip the ANSI color codes
spawn_pager("more", &[], &help)?; spawn_pager("more", &[], &help)?;
} else { } else {

View file

@ -157,9 +157,11 @@ async fn run(cli: Cli) -> Result<ExitStatus> {
let cache = Cache::from_settings(cache_settings.no_cache, cache_settings.cache_dir)?; let cache = Cache::from_settings(cache_settings.no_cache, cache_settings.cache_dir)?;
match *cli.command { match *cli.command {
Commands::Help(args) => { Commands::Help(args) => commands::help(
commands::help(args.command.unwrap_or_default().as_slice(), printer) args.command.unwrap_or_default().as_slice(),
} printer,
args.no_pager,
),
Commands::Pip(PipNamespace { Commands::Pip(PipNamespace {
command: PipCommand::Compile(args), command: PipCommand::Compile(args),
}) => { }) => {

View file

@ -660,6 +660,68 @@ fn help_with_version() {
----- stdout ----- ----- stdout -----
uv [VERSION] ([COMMIT] DATE) 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] <COMMAND>
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 <COLOR_CHOICE>
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 <PYTHON_PREFERENCE>
Whether to prefer using Python from uv or on the system [possible values: only-managed,
installed, managed, system, only-system]
--python-fetch <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 <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 <command>` for more information on a specific command.
----- stderr ----- ----- stderr -----
"###); "###);
} }