mirror of https://github.com/astral-sh/uv
Respect `NO_COLOR` and always show the command as a header when paging `uv help` output (#16908)
## Summary Fix #16879 and address an additional issue where the pager prompt would be bold regardless of NO_COLOR. <img width="1437" height="483" alt="image" src="https://github.com/user-attachments/assets/7234129a-364b-40c6-834a-57ac34212925" /> ## Test Plan Ran the test suite and manually verified against `less` 679 and `busybox` v1.34.1. Checked with and without `NO_COLOR` on both "normal" `less`, `busybox` `less`, and `more`.
This commit is contained in:
parent
05814f9cd5
commit
efa47adefb
|
|
@ -6,7 +6,7 @@ use std::{fmt::Display, fmt::Write};
|
||||||
use anstream::{ColorChoice, stream::IsTerminal};
|
use anstream::{ColorChoice, stream::IsTerminal};
|
||||||
use anyhow::{Result, anyhow};
|
use anyhow::{Result, anyhow};
|
||||||
use clap::CommandFactory;
|
use clap::CommandFactory;
|
||||||
use itertools::{Either, Itertools};
|
use itertools::Itertools;
|
||||||
use owo_colors::OwoColorize;
|
use owo_colors::OwoColorize;
|
||||||
use which::which;
|
use which::which;
|
||||||
|
|
||||||
|
|
@ -70,9 +70,9 @@ pub(crate) fn help(query: &[String], printer: Printer, no_pager: bool) -> Result
|
||||||
.render_long_help()
|
.render_long_help()
|
||||||
};
|
};
|
||||||
|
|
||||||
let help_ansi = match anstream::Stdout::choice(&std::io::stdout()) {
|
let want_color = match anstream::Stdout::choice(&std::io::stdout()) {
|
||||||
ColorChoice::Always | ColorChoice::AlwaysAnsi => Either::Left(help.ansi()),
|
ColorChoice::Always | ColorChoice::AlwaysAnsi => true,
|
||||||
ColorChoice::Never => Either::Right(help.clone()),
|
ColorChoice::Never => false,
|
||||||
// We just asked anstream for a choice, that can't be auto
|
// We just asked anstream for a choice, that can't be auto
|
||||||
ColorChoice::Auto => unreachable!(),
|
ColorChoice::Auto => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
@ -80,22 +80,19 @@ pub(crate) fn help(query: &[String], printer: Printer, no_pager: bool) -> Result
|
||||||
let is_terminal = std::io::stdout().is_terminal();
|
let is_terminal = std::io::stdout().is_terminal();
|
||||||
let should_page = !no_pager && !is_root && is_terminal;
|
let should_page = !no_pager && !is_root && is_terminal;
|
||||||
|
|
||||||
if should_page {
|
if should_page && let Some(pager) = Pager::try_from_env() {
|
||||||
if let Some(pager) = Pager::try_from_env() {
|
let query = query.join(" ");
|
||||||
let content = if pager.supports_colors() {
|
if want_color && pager.supports_colors() {
|
||||||
help_ansi
|
pager.spawn(format!("{}: {query}", "uv help".bold()), help.ansi())?;
|
||||||
} else {
|
|
||||||
Either::Right(help.clone())
|
|
||||||
};
|
|
||||||
pager.spawn(
|
|
||||||
format!("{}: {}", "uv help".bold(), query.join(" ")),
|
|
||||||
&content,
|
|
||||||
)?;
|
|
||||||
} else {
|
} else {
|
||||||
writeln!(printer.stdout(), "{help_ansi}")?;
|
pager.spawn(format!("uv help: {query}"), help)?;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
writeln!(printer.stdout(), "{help_ansi}")?;
|
if want_color {
|
||||||
|
writeln!(printer.stdout(), "{}", help.ansi())?;
|
||||||
|
} else {
|
||||||
|
writeln!(printer.stdout(), "{help}")?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(ExitStatus::Success)
|
Ok(ExitStatus::Success)
|
||||||
|
|
@ -131,9 +128,9 @@ struct Pager {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PagerKind {
|
impl PagerKind {
|
||||||
fn default_args(&self, prompt: String) -> Vec<String> {
|
fn default_args(&self) -> Vec<String> {
|
||||||
match self {
|
match self {
|
||||||
Self::Less => vec!["-R".to_string(), "-P".to_string(), prompt],
|
Self::Less => vec!["-R".to_string()],
|
||||||
Self::More => vec![],
|
Self::More => vec![],
|
||||||
Self::Other(_) => vec![],
|
Self::Other(_) => vec![],
|
||||||
}
|
}
|
||||||
|
|
@ -183,7 +180,7 @@ impl FromStr for Pager {
|
||||||
|
|
||||||
impl Pager {
|
impl Pager {
|
||||||
/// Display `contents` using the pager.
|
/// Display `contents` using the pager.
|
||||||
fn spawn(self, prompt: String, contents: impl Display) -> Result<()> {
|
fn spawn(self, heading: String, contents: impl Display) -> Result<()> {
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
let command = self
|
let command = self
|
||||||
|
|
@ -193,7 +190,7 @@ impl Pager {
|
||||||
.unwrap_or(OsString::from(self.kind.to_string()));
|
.unwrap_or(OsString::from(self.kind.to_string()));
|
||||||
|
|
||||||
let args = if self.args.is_empty() {
|
let args = if self.args.is_empty() {
|
||||||
self.kind.default_args(prompt)
|
self.kind.default_args()
|
||||||
} else {
|
} else {
|
||||||
self.args
|
self.args
|
||||||
};
|
};
|
||||||
|
|
@ -209,7 +206,10 @@ impl Pager {
|
||||||
.ok_or_else(|| anyhow!("Failed to take child process stdin"))?;
|
.ok_or_else(|| anyhow!("Failed to take child process stdin"))?;
|
||||||
|
|
||||||
let contents = contents.to_string();
|
let contents = contents.to_string();
|
||||||
let writer = std::thread::spawn(move || stdin.write_all(contents.as_bytes()));
|
let writer = std::thread::spawn(move || {
|
||||||
|
let _ = write!(stdin, "{heading}\n\n");
|
||||||
|
let _ = stdin.write_all(contents.as_bytes());
|
||||||
|
});
|
||||||
|
|
||||||
drop(child.wait());
|
drop(child.wait());
|
||||||
drop(writer.join());
|
drop(writer.join());
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue