mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 11:37:44 +00:00
unexpand: implement "tabs" shortcuts
This commit is contained in:
parent
fa51f8b986
commit
edf4fee48f
2 changed files with 88 additions and 4 deletions
|
@ -7,7 +7,7 @@
|
||||||
// * For the full copyright and license information, please view the LICENSE
|
// * For the full copyright and license information, please view the LICENSE
|
||||||
// * file that was distributed with this source code.
|
// * file that was distributed with this source code.
|
||||||
|
|
||||||
// spell-checker:ignore (ToDO) nums aflag uflag scol prevtab amode ctype cwidth nbytes lastcol pctype
|
// spell-checker:ignore (ToDO) nums aflag uflag scol prevtab amode ctype cwidth nbytes lastcol pctype Preprocess
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate uucore;
|
extern crate uucore;
|
||||||
|
@ -97,9 +97,9 @@ struct Options {
|
||||||
|
|
||||||
impl Options {
|
impl Options {
|
||||||
fn new(matches: &clap::ArgMatches) -> Result<Self, ParseError> {
|
fn new(matches: &clap::ArgMatches) -> Result<Self, ParseError> {
|
||||||
let tabstops = match matches.value_of(options::TABS) {
|
let tabstops = match matches.values_of(options::TABS) {
|
||||||
None => vec![DEFAULT_TABSTOP],
|
None => vec![DEFAULT_TABSTOP],
|
||||||
Some(s) => tabstops_parse(s)?,
|
Some(s) => tabstops_parse(&s.collect::<Vec<&str>>().join(","))?,
|
||||||
};
|
};
|
||||||
|
|
||||||
let aflag = (matches.is_present(options::ALL) || matches.is_present(options::TABS))
|
let aflag = (matches.is_present(options::ALL) || matches.is_present(options::TABS))
|
||||||
|
@ -120,13 +120,49 @@ impl Options {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Decide whether the character is either a digit or a comma.
|
||||||
|
fn is_digit_or_comma(c: char) -> bool {
|
||||||
|
c.is_ascii_digit() || c == ','
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Preprocess command line arguments and expand shortcuts. For example, "-7" is expanded to
|
||||||
|
/// "--tabs=7 --first-only" and "-1,3" to "--tabs=1 --tabs=3 --first-only". However, if "-a" or
|
||||||
|
/// "--all" is provided, "--first-only" is omitted.
|
||||||
|
fn expand_shortcuts(args: &[String]) -> Vec<String> {
|
||||||
|
let mut processed_args = Vec::with_capacity(args.len());
|
||||||
|
let mut is_all_arg_provided = false;
|
||||||
|
let mut has_shortcuts = false;
|
||||||
|
|
||||||
|
for arg in args {
|
||||||
|
if arg.starts_with('-') && arg[1..].chars().all(is_digit_or_comma) {
|
||||||
|
arg[1..]
|
||||||
|
.split(',')
|
||||||
|
.filter(|s| !s.is_empty())
|
||||||
|
.for_each(|s| processed_args.push(format!("--tabs={}", s)));
|
||||||
|
has_shortcuts = true;
|
||||||
|
} else {
|
||||||
|
processed_args.push(arg.to_string());
|
||||||
|
|
||||||
|
if arg == "--all" || arg == "-a" {
|
||||||
|
is_all_arg_provided = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if has_shortcuts && !is_all_arg_provided {
|
||||||
|
processed_args.push("--first-only".into());
|
||||||
|
}
|
||||||
|
|
||||||
|
processed_args
|
||||||
|
}
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let args = args
|
let args = args
|
||||||
.collect_str(InvalidEncodingHandling::Ignore)
|
.collect_str(InvalidEncodingHandling::Ignore)
|
||||||
.accept_any();
|
.accept_any();
|
||||||
|
|
||||||
let matches = uu_app().get_matches_from(args);
|
let matches = uu_app().get_matches_from(expand_shortcuts(&args));
|
||||||
|
|
||||||
unexpand(&Options::new(&matches)?).map_err_context(String::new)
|
unexpand(&Options::new(&matches)?).map_err_context(String::new)
|
||||||
}
|
}
|
||||||
|
@ -163,6 +199,7 @@ pub fn uu_app<'a>() -> Command<'a> {
|
||||||
.long(options::TABS)
|
.long(options::TABS)
|
||||||
.help("use comma separated LIST of tab positions or have tabs N characters apart instead of 8 (enables -a)")
|
.help("use comma separated LIST of tab positions or have tabs N characters apart instead of 8 (enables -a)")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
|
.multiple_occurrences(true)
|
||||||
.value_name("N, LIST")
|
.value_name("N, LIST")
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
|
@ -379,3 +416,15 @@ fn unexpand(options: &Options) -> std::io::Result<()> {
|
||||||
}
|
}
|
||||||
output.flush()
|
output.flush()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::is_digit_or_comma;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_is_digit_or_comma() {
|
||||||
|
assert!(is_digit_or_comma('1'));
|
||||||
|
assert!(is_digit_or_comma(','));
|
||||||
|
assert!(!is_digit_or_comma('a'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -156,6 +156,41 @@ fn unexpand_read_from_two_file() {
|
||||||
.success();
|
.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_tabs_shortcut() {
|
||||||
|
new_ucmd!()
|
||||||
|
.arg("-3")
|
||||||
|
.pipe_in(" a b")
|
||||||
|
.run()
|
||||||
|
.stdout_is("\ta b");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_tabs_shortcut_combined_with_all_arg() {
|
||||||
|
fn run_cmd(all_arg: &str) {
|
||||||
|
new_ucmd!()
|
||||||
|
.args(&[all_arg, "-3"])
|
||||||
|
.pipe_in("a b c")
|
||||||
|
.run()
|
||||||
|
.stdout_is("a\tb\tc");
|
||||||
|
}
|
||||||
|
|
||||||
|
let all_args = vec!["-a", "--all"];
|
||||||
|
|
||||||
|
for arg in all_args {
|
||||||
|
run_cmd(arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_comma_separated_tabs_shortcut() {
|
||||||
|
new_ucmd!()
|
||||||
|
.args(&["-a", "-3,9"])
|
||||||
|
.pipe_in("a b c")
|
||||||
|
.run()
|
||||||
|
.stdout_is("a\tb\tc");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_tabs_cannot_be_zero() {
|
fn test_tabs_cannot_be_zero() {
|
||||||
new_ucmd!()
|
new_ucmd!()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue