From e22f6517f80f2a384f8f0a92be93ecdd32635547 Mon Sep 17 00:00:00 2001 From: can1357 Date: Sun, 28 Jun 2026 17:05:27 +0200 Subject: [PATCH] refactor: migrated format_usage to pi-uutils-ctx - Implement an argv-independent `format_usage` within `pi-uutils-ctx`. - Update all vendor crates to import the function from the new location. Fixes #3727 --- crates/pi-uutils-ctx/src/lib.rs | 37 +++++++++++++++++++++++++++++ crates/vendor/uu-cat/src/cat.rs | 2 +- crates/vendor/uu-head/src/cli.rs | 2 +- crates/vendor/uu-ls/src/ls.rs | 3 +-- crates/vendor/uu-mkdir/src/mkdir.rs | 2 +- crates/vendor/uu-mv/src/mv.rs | 2 +- crates/vendor/uu-rm/src/rm.rs | 3 ++- crates/vendor/uu-sort/src/sort.rs | 3 ++- crates/vendor/uu-tail/src/args.rs | 2 +- crates/vendor/uu-uniq/src/uniq.rs | 2 +- crates/vendor/uu-wc/src/wc.rs | 2 +- 11 files changed, 49 insertions(+), 11 deletions(-) diff --git a/crates/pi-uutils-ctx/src/lib.rs b/crates/pi-uutils-ctx/src/lib.rs index a29e533b8..7288ae37b 100644 --- a/crates/pi-uutils-ctx/src/lib.rs +++ b/crates/pi-uutils-ctx/src/lib.rs @@ -270,3 +270,40 @@ pub fn stderr() -> CtxStderr { pub fn stdin() -> CtxStdin { CtxStdin } + +/// Generate the usage string for clap without evaluating argv-dependent +/// statics. +/// +/// This is a panic-safe, argv-independent replacement for +/// `uucore::format_usage`. It indents all but the first line by 7 spaces to +/// align with clap's "Usage: " prefix. Callers must provide explicit usage +/// strings (with actual command names) and avoid `{}` placeholders. +#[must_use] +pub fn format_usage(s: &str) -> String { + debug_assert!( + !s.contains("{}"), + "format_usage shim does not support placeholder '{{}}' - use explicit command names instead" + ); + s.replace('\n', "\n ") +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_format_usage_indentation() { + let usage = "cat [OPTION]... [FILE]...\nSome descriptive text\nAnother line"; + let formatted = format_usage(usage); + assert_eq!( + formatted, + "cat [OPTION]... [FILE]...\n Some descriptive text\n Another line" + ); + } + + #[test] + fn test_format_usage_empty() { + let formatted = format_usage(""); + assert_eq!(formatted, ""); + } +} diff --git a/crates/vendor/uu-cat/src/cat.rs b/crates/vendor/uu-cat/src/cat.rs index 910dab0a9..81af0c300 100644 --- a/crates/vendor/uu-cat/src/cat.rs +++ b/crates/vendor/uu-cat/src/cat.rs @@ -15,12 +15,12 @@ use std::{ use clap::{Arg, ArgAction, ArgMatches, Command}; use memchr::memchr2; +use pi_uutils_ctx::format_usage; use thiserror::Error; use uucore::{ display::Quotable, error::{UResult, strip_errno}, fast_inc::fast_inc_one, - format_usage, }; // Allocate 32 digits for the line number. diff --git a/crates/vendor/uu-head/src/cli.rs b/crates/vendor/uu-head/src/cli.rs index f4164ee31..b025c4d4a 100644 --- a/crates/vendor/uu-head/src/cli.rs +++ b/crates/vendor/uu-head/src/cli.rs @@ -6,7 +6,7 @@ use std::ffi::OsString; use clap::{Arg, ArgAction, Command}; -use uucore::format_usage; +use pi_uutils_ctx::format_usage; pub mod options { pub const BYTES: &str = "BYTES"; diff --git a/crates/vendor/uu-ls/src/ls.rs b/crates/vendor/uu-ls/src/ls.rs index 633244553..da0ec1957 100644 --- a/crates/vendor/uu-ls/src/ls.rs +++ b/crates/vendor/uu-ls/src/ls.rs @@ -25,7 +25,7 @@ use clap::{ builder::{NonEmptyStringValueParser, PossibleValue, ValueParser}, }; use lscolors::Colorable; -use pi_uutils_ctx::CtxStdout; +use pi_uutils_ctx::{CtxStdout, format_usage}; #[cfg(unix)] use rustc_hash::FxHashMap; use rustc_hash::FxHashSet; @@ -35,7 +35,6 @@ use uucore::libc::{S_IXGRP, S_IXOTH, S_IXUSR}; use uucore::{ display::Quotable, error::{UError, UResult}, - format_usage, fs::FileInformation, fsext::metadata_get_time, os_str_as_bytes_lossy, diff --git a/crates/vendor/uu-mkdir/src/mkdir.rs b/crates/vendor/uu-mkdir/src/mkdir.rs index 849fae5ee..b52c225d8 100644 --- a/crates/vendor/uu-mkdir/src/mkdir.rs +++ b/crates/vendor/uu-mkdir/src/mkdir.rs @@ -12,6 +12,7 @@ use std::{ }; use clap::{Arg, ArgAction, ArgMatches, Command, builder::ValueParser, parser::ValuesRef}; +use pi_uutils_ctx::format_usage; #[cfg(all(unix, target_os = "linux"))] use uucore::error::FromIo; #[cfg(not(windows))] @@ -19,7 +20,6 @@ use uucore::mode; use uucore::{ display::Quotable, error::{UResult, USimpleError}, - format_usage, fs::dir_strip_dot_for_creation, }; diff --git a/crates/vendor/uu-mv/src/mv.rs b/crates/vendor/uu-mv/src/mv.rs index b165ed7ff..191713e59 100644 --- a/crates/vendor/uu-mv/src/mv.rs +++ b/crates/vendor/uu-mv/src/mv.rs @@ -34,6 +34,7 @@ use std::{ use clap::{Arg, ArgAction, ArgMatches, Command, builder::ValueParser, error::ErrorKind}; use fs_extra::dir::get_size as dir_get_size; use indicatif::{MultiProgress, ProgressBar, ProgressStyle}; +use pi_uutils_ctx::format_usage; #[cfg(all(unix, not(any(target_os = "macos", target_os = "redox"))))] use rustc_hash::FxHashMap; use rustc_hash::FxHashSet; @@ -52,7 +53,6 @@ use uucore::{ backup_control::{self, source_is_target_backup}, display::Quotable, error::{FromIo, UError, UResult, USimpleError, UUsageError}, - format_usage, fs::{ MissingHandling, ResolveMode, are_hardlinks_or_one_way_symlink_to_same_file, are_hardlinks_to_same_file, canonicalize, path_ends_with_terminator, diff --git a/crates/vendor/uu-rm/src/rm.rs b/crates/vendor/uu-rm/src/rm.rs index ef4d5ab93..0420973ac 100644 --- a/crates/vendor/uu-rm/src/rm.rs +++ b/crates/vendor/uu-rm/src/rm.rs @@ -23,11 +23,12 @@ use clap::{ parser::ValueSource, }; use indicatif::{ProgressBar, ProgressStyle}; +use pi_uutils_ctx::format_usage; use thiserror::Error; use uucore::{ display::Quotable, error::{FromIo, UError, UResult}, - format_usage, os_str_as_bytes, + os_str_as_bytes, parser::shortcut_value_parser::ShortcutValueParser, }; diff --git a/crates/vendor/uu-sort/src/sort.rs b/crates/vendor/uu-sort/src/sort.rs index 7cabe1a20..fdd82ee18 100644 --- a/crates/vendor/uu-sort/src/sort.rs +++ b/crates/vendor/uu-sort/src/sort.rs @@ -45,6 +45,7 @@ use custom_str_cmp::custom_str_cmp; use ext_sort::ext_sort; use foldhash::{HashMap, SharedSeed, fast::FoldHasher}; use numeric_str_cmp::{NumInfo, NumInfoParseSettings, human_numeric_str_cmp, numeric_str_cmp}; +use pi_uutils_ctx::format_usage; use rand::{RngExt as _, rng}; #[cfg(not(target_os = "wasi"))] use rayon::slice::ParallelSliceMut; @@ -55,7 +56,7 @@ use uucore::{ display::Quotable, error::{FromIo, UError, UResult, USimpleError, UUsageError, strip_errno}, extendedbigdecimal::ExtendedBigDecimal, - format_usage, i18n, + i18n, i18n::{datetime::get_locale_months, decimal::locale_decimal_separator}, line_ending::LineEnding, parser::{ diff --git a/crates/vendor/uu-tail/src/args.rs b/crates/vendor/uu-tail/src/args.rs index a3d1e48a5..8bef818a0 100644 --- a/crates/vendor/uu-tail/src/args.rs +++ b/crates/vendor/uu-tail/src/args.rs @@ -8,9 +8,9 @@ use std::{ffi::OsString, io::Write, time::Duration}; use clap::{Arg, ArgAction, ArgMatches, Command, value_parser}; +use pi_uutils_ctx::format_usage; use uucore::{ error::{UError, UResult, USimpleError, UUsageError}, - format_usage, parser::{ parse_signed_num::{SignPrefix, parse_signed_num_max}, parse_size::ParseSizeError, diff --git a/crates/vendor/uu-uniq/src/uniq.rs b/crates/vendor/uu-uniq/src/uniq.rs index 1a055e00d..0e4e71679 100644 --- a/crates/vendor/uu-uniq/src/uniq.rs +++ b/crates/vendor/uu-uniq/src/uniq.rs @@ -15,10 +15,10 @@ use clap::{ builder::ValueParser, error::{ContextKind, Error, ErrorKind}, }; +use pi_uutils_ctx::format_usage; use uucore::{ display::Quotable, error::{FromIo, UResult, USimpleError}, - format_usage, parser::shortcut_value_parser::ShortcutValueParser, posix::{OBSOLETE, posix_version}, }; diff --git a/crates/vendor/uu-wc/src/wc.rs b/crates/vendor/uu-wc/src/wc.rs index e8dbd6a3c..6b32feb08 100644 --- a/crates/vendor/uu-wc/src/wc.rs +++ b/crates/vendor/uu-wc/src/wc.rs @@ -21,13 +21,13 @@ use std::{ }; use clap::{Arg, ArgAction, ArgMatches, Command, builder::ValueParser}; +use pi_uutils_ctx::format_usage; use thiserror::Error; use unicode_width::UnicodeWidthChar; use utf8::{BufReadDecoder, BufReadDecoderError}; use uucore::{ display::Quotable, error::{FromIo, UError, UResult}, - format_usage, hardware::{HardwareFeature, HasHardwareFeatures as _, SimdPolicy}, parser::shortcut_value_parser::ShortcutValueParser, quoting_style::{self, QuotingStyle},