mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 11:37:44 +00:00
pr: add +page and -column
This commit is contained in:
parent
5c6c524334
commit
847046f3de
3 changed files with 81 additions and 8 deletions
|
@ -14,6 +14,7 @@ time = "0.1.40"
|
|||
chrono = "0.4.6"
|
||||
quick-error = "1.2.2"
|
||||
itertools = "0.7.8"
|
||||
regex = "1.0.1"
|
||||
|
||||
[dependencies.uucore]
|
||||
path = "../uucore"
|
||||
|
|
71
src/pr/pr.rs
71
src/pr/pr.rs
|
@ -13,6 +13,7 @@ extern crate quick_error;
|
|||
extern crate chrono;
|
||||
extern crate getopts;
|
||||
extern crate itertools;
|
||||
extern crate regex;
|
||||
extern crate uucore;
|
||||
|
||||
use chrono::offset::Local;
|
||||
|
@ -22,6 +23,7 @@ use getopts::{Matches, Options};
|
|||
use itertools::structs::KMergeBy;
|
||||
use itertools::{GroupBy, Itertools};
|
||||
use quick_error::ResultExt;
|
||||
use regex::Regex;
|
||||
use std::convert::From;
|
||||
use std::fs::{metadata, File, Metadata};
|
||||
use std::io::{stderr, stdin, stdout, BufRead, BufReader, Lines, Read, Stdin, Stdout, Write};
|
||||
|
@ -322,7 +324,11 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
|||
opts.optflag("", "help", "display this help and exit");
|
||||
opts.optflag("V", "version", "output version information and exit");
|
||||
|
||||
let matches = match opts.parse(&args[1..]) {
|
||||
// Remove -column option as getopts cannot parse things like -3 etc
|
||||
let re = Regex::new(r"^-\d+").unwrap();
|
||||
let opt_args: Vec<&String> = args.iter().filter(|i| !re.is_match(i)).collect();
|
||||
|
||||
let matches = match opts.parse(&opt_args[1..]) {
|
||||
Ok(m) => m,
|
||||
Err(e) => panic!("Invalid options\n{}", e),
|
||||
};
|
||||
|
@ -332,7 +338,14 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
|||
return 0;
|
||||
}
|
||||
|
||||
let mut files: Vec<String> = matches.free.clone();
|
||||
let mut files: Vec<String> = matches
|
||||
.free
|
||||
.clone()
|
||||
.iter()
|
||||
.filter(|i| !i.starts_with('+') && !i.starts_with('-'))
|
||||
.map(|i| i.to_string())
|
||||
.collect();
|
||||
|
||||
// -n value is optional if -n <path> is given the opts gets confused
|
||||
// if -n is used just before file path it might be captured as value of -n
|
||||
if matches.opt_str(NUMBERING_MODE_OPTION).is_some() {
|
||||
|
@ -360,7 +373,8 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
|||
};
|
||||
|
||||
for file_group in file_groups {
|
||||
let result_options: Result<OutputOptions, PrError> = build_options(&matches, &file_group);
|
||||
let result_options: Result<OutputOptions, PrError> =
|
||||
build_options(&matches, &file_group, args.join(" "));
|
||||
if result_options.is_err() {
|
||||
print_error(&matches, result_options.err().unwrap());
|
||||
return 1;
|
||||
|
@ -427,6 +441,11 @@ fn print_usage(opts: &mut Options, matches: &Matches) -> i32 {
|
|||
that do not fit into a text column are truncated.
|
||||
Lines are not truncated under single column output.";
|
||||
println!("{}", opts.usage(usage));
|
||||
println!(" +page \t\tBegin output at page number page of the formatted input.");
|
||||
println!(
|
||||
" -column \t\tProduce multi-column output. Refer --{}",
|
||||
COLUMN_OPTION
|
||||
);
|
||||
if matches.free.is_empty() {
|
||||
return 1;
|
||||
}
|
||||
|
@ -447,7 +466,11 @@ fn parse_usize(matches: &Matches, opt: &str) -> Option<Result<usize, PrError>> {
|
|||
.map(from_parse_error_to_pr_error)
|
||||
}
|
||||
|
||||
fn build_options(matches: &Matches, paths: &Vec<String>) -> Result<OutputOptions, PrError> {
|
||||
fn build_options(
|
||||
matches: &Matches,
|
||||
paths: &Vec<String>,
|
||||
free_args: String,
|
||||
) -> Result<OutputOptions, PrError> {
|
||||
let invalid_pages_map = |i: String| {
|
||||
let unparsed_value: String = matches.opt_str(PAGE_RANGE_OPTION).unwrap();
|
||||
i.parse::<usize>().map_err(|_e| {
|
||||
|
@ -547,6 +570,19 @@ fn build_options(matches: &Matches, paths: &Vec<String>) -> Result<OutputOptions
|
|||
file_last_modified_time(paths.get(0).unwrap())
|
||||
};
|
||||
|
||||
// +page option is less priority than --pages
|
||||
let flags = &matches.free.join(" ");
|
||||
let re = Regex::new(r"\s*\+(\d+)\s*").unwrap();
|
||||
let start_page_in_plus_option: usize = match re.captures(&free_args).map(|i| {
|
||||
let unparsed_num = i.get(1).unwrap().as_str().trim();
|
||||
unparsed_num.parse::<usize>().map_err(|_e| {
|
||||
PrError::EncounteredErrors(format!("invalid {} argument '{}'", "+", unparsed_num))
|
||||
})
|
||||
}) {
|
||||
Some(res) => res?,
|
||||
_ => 1,
|
||||
};
|
||||
|
||||
let start_page: usize = match matches
|
||||
.opt_str(PAGE_RANGE_OPTION)
|
||||
.map(|i| {
|
||||
|
@ -556,7 +592,7 @@ fn build_options(matches: &Matches, paths: &Vec<String>) -> Result<OutputOptions
|
|||
.map(invalid_pages_map)
|
||||
{
|
||||
Some(res) => res?,
|
||||
_ => 1,
|
||||
_ => start_page_in_plus_option,
|
||||
};
|
||||
|
||||
let end_page: Option<usize> = match matches
|
||||
|
@ -608,9 +644,28 @@ fn build_options(matches: &Matches, paths: &Vec<String>) -> Result<OutputOptions
|
|||
.opt_str(COLUMN_SEPARATOR_OPTION)
|
||||
.unwrap_or(DEFAULT_COLUMN_SEPARATOR.to_string());
|
||||
|
||||
let column_mode_options: Option<ColumnModeOptions> = match parse_usize(matches, COLUMN_OPTION) {
|
||||
Some(res) => Some(ColumnModeOptions {
|
||||
columns: res?,
|
||||
let re_col = Regex::new(r"\s*-(\d+)\s*").unwrap();
|
||||
|
||||
let start_column_option: Option<usize> = match re_col.captures(&free_args).map(|i| {
|
||||
let unparsed_num = i.get(1).unwrap().as_str().trim();
|
||||
unparsed_num.parse::<usize>().map_err(|_e| {
|
||||
PrError::EncounteredErrors(format!("invalid {} argument '{}'", "-", unparsed_num))
|
||||
})
|
||||
}) {
|
||||
Some(res) => Some(res?),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
// --column has more priority than -column
|
||||
|
||||
let column_option_value: Option<usize> = match parse_usize(matches, COLUMN_OPTION) {
|
||||
Some(res) => Some(res?),
|
||||
_ => start_column_option,
|
||||
};
|
||||
|
||||
let column_mode_options: Option<ColumnModeOptions> = match column_option_value {
|
||||
Some(columns) => Some(ColumnModeOptions {
|
||||
columns,
|
||||
width: column_width,
|
||||
column_separator,
|
||||
across_mode,
|
||||
|
|
|
@ -257,6 +257,15 @@ fn test_with_page_range() {
|
|||
expected_test_file_path,
|
||||
vec![(&"{last_modified_time}".to_string(), &value)],
|
||||
);
|
||||
|
||||
new_ucmd!()
|
||||
.args(&["+15", test_file_path])
|
||||
.succeeds()
|
||||
.stdout_is_templated_fixture(
|
||||
expected_test_file_path,
|
||||
vec![(&"{last_modified_time}".to_string(), &value)],
|
||||
);
|
||||
|
||||
new_ucmd!()
|
||||
.args(&["--pages=15:17", test_file_path])
|
||||
.succeeds()
|
||||
|
@ -336,6 +345,14 @@ fn test_with_column() {
|
|||
expected_test_file_path,
|
||||
vec![(&"{last_modified_time}".to_string(), &value)],
|
||||
);
|
||||
|
||||
new_ucmd!()
|
||||
.args(&["--pages=3:5", "-3", "-n", test_file_path])
|
||||
.succeeds()
|
||||
.stdout_is_templated_fixture(
|
||||
expected_test_file_path,
|
||||
vec![(&"{last_modified_time}".to_string(), &value)],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue