1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-09-14 19:16:17 +00:00

pr: let type inference do its works

This commit is contained in:
Terts Diepraam 2021-05-29 18:58:23 +02:00
parent 12287fcc9c
commit 0913a77667

View file

@ -17,9 +17,8 @@ use itertools::Itertools;
use quick_error::ResultExt; use quick_error::ResultExt;
use regex::Regex; use regex::Regex;
use std::convert::From; use std::convert::From;
use std::fs::{metadata, File, Metadata}; use std::fs::{metadata, File};
use std::io::{stdin, stdout, BufRead, BufReader, Lines, Read, Stdin, Stdout, Write}; use std::io::{stdin, stdout, BufRead, BufReader, Lines, Read, Stdout, Write};
use std::num::ParseIntError;
#[cfg(unix)] #[cfg(unix)]
use std::os::unix::fs::FileTypeExt; use std::os::unix::fs::FileTypeExt;
@ -381,7 +380,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
opts.optflag("", "help", "display this help and exit"); opts.optflag("", "help", "display this help and exit");
opts.optflag("V", "version", "output version information and exit"); opts.optflag("V", "version", "output version information and exit");
let opt_args: Vec<String> = recreate_arguments(&args); let opt_args = recreate_arguments(&args);
let matches = match opts.parse(&opt_args[1..]) { let matches = match opts.parse(&opt_args[1..]) {
Ok(m) => m, Ok(m) => m,
@ -393,7 +392,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
return 0; return 0;
} }
let mut files: Vec<String> = matches.free.clone(); let mut files = matches.free.clone();
if files.is_empty() { if files.is_empty() {
//For stdin //For stdin
files.insert(0, FILE_STDIN.to_owned()); files.insert(0, FILE_STDIN.to_owned());
@ -403,30 +402,29 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
return print_usage(&mut opts, &matches); return print_usage(&mut opts, &matches);
} }
let file_groups: Vec<Vec<String>> = if matches.opt_present(options::MERGE_FILES_PRINT) { let file_groups: Vec<_> = if matches.opt_present(options::MERGE_FILES_PRINT) {
vec![files] vec![files]
} else { } else {
files.into_iter().map(|i| vec![i]).collect() files.into_iter().map(|i| vec![i]).collect()
}; };
for file_group in file_groups { for file_group in file_groups {
let result_options: Result<OutputOptions, PrError> = let result_options = build_options(&matches, &file_group, args.join(" "));
build_options(&matches, &file_group, args.join(" "));
if result_options.is_err() { if result_options.is_err() {
print_error(&matches, result_options.err().unwrap()); print_error(&matches, result_options.err().unwrap());
return 1; return 1;
} }
let options: &OutputOptions = &result_options.unwrap(); let options = &result_options.unwrap();
let cmd_result: Result<i32, PrError> = if file_group.len() == 1 { let cmd_result = if file_group.len() == 1 {
pr(&file_group.get(0).unwrap(), options) pr(&file_group.get(0).unwrap(), options)
} else { } else {
mpr(&file_group, options) mpr(&file_group, options)
}; };
let status: i32 = match cmd_result { let status = match cmd_result {
Err(error) => { Err(error) => {
print_error(&matches, error); print_error(&matches, error);
1 1
@ -447,12 +445,11 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
/// * `args` - Command line arguments /// * `args` - Command line arguments
fn recreate_arguments(args: &[String]) -> Vec<String> { fn recreate_arguments(args: &[String]) -> Vec<String> {
let column_page_option = Regex::new(r"^[-+]\d+.*").unwrap(); let column_page_option = Regex::new(r"^[-+]\d+.*").unwrap();
let num_regex: Regex = Regex::new(r"(.\d+)|(\d+)|^[^-]$").unwrap(); let num_regex = Regex::new(r"(.\d+)|(\d+)|^[^-]$").unwrap();
//let a_file: Regex = Regex::new(r"^[^-+].*").unwrap(); //let a_file: Regex = Regex::new(r"^[^-+].*").unwrap();
let n_regex: Regex = Regex::new(r"^-n\s*$").unwrap(); let n_regex = Regex::new(r"^-n\s*$").unwrap();
let mut arguments = args.to_owned(); let mut arguments = args.to_owned();
let num_option: Option<(usize, &String)> = let num_option = args.iter().find_position(|x| n_regex.is_match(x.trim()));
args.iter().find_position(|x| n_regex.is_match(x.trim()));
if let Some((pos, _value)) = num_option { if let Some((pos, _value)) = num_option {
let num_val_opt = args.get(pos + 1); let num_val_opt = args.get(pos + 1);
if num_val_opt.is_some() && !num_regex.is_match(num_val_opt.unwrap()) { if num_val_opt.is_some() && !num_regex.is_match(num_val_opt.unwrap()) {
@ -529,7 +526,7 @@ fn parse_usize(matches: &Matches, opt: &str) -> Option<Result<usize, PrError>> {
let from_parse_error_to_pr_error = |value_to_parse: (String, String)| { let from_parse_error_to_pr_error = |value_to_parse: (String, String)| {
let i = value_to_parse.0; let i = value_to_parse.0;
let option = value_to_parse.1; let option = value_to_parse.1;
i.parse::<usize>().map_err(|_e| { i.parse().map_err(|_e| {
PrError::EncounteredErrors(format!("invalid {} argument '{}'", option, i)) PrError::EncounteredErrors(format!("invalid {} argument '{}'", option, i))
}) })
}; };
@ -547,27 +544,25 @@ fn build_options(
let form_feed_used = matches.opt_present(options::FORM_FEED_OPTION) let form_feed_used = matches.opt_present(options::FORM_FEED_OPTION)
|| matches.opt_present(options::FORM_FEED_OPTION_SMALL); || matches.opt_present(options::FORM_FEED_OPTION_SMALL);
let is_merge_mode: bool = matches.opt_present(options::MERGE_FILES_PRINT); let is_merge_mode = matches.opt_present(options::MERGE_FILES_PRINT);
if is_merge_mode && matches.opt_present(options::COLUMN_OPTION) { if is_merge_mode && matches.opt_present(options::COLUMN_OPTION) {
let err_msg: String = let err_msg = String::from("cannot specify number of columns when printing in parallel");
String::from("cannot specify number of columns when printing in parallel");
return Err(PrError::EncounteredErrors(err_msg)); return Err(PrError::EncounteredErrors(err_msg));
} }
if is_merge_mode && matches.opt_present(options::ACROSS_OPTION) { if is_merge_mode && matches.opt_present(options::ACROSS_OPTION) {
let err_msg: String = let err_msg = String::from("cannot specify both printing across and printing in parallel");
String::from("cannot specify both printing across and printing in parallel");
return Err(PrError::EncounteredErrors(err_msg)); return Err(PrError::EncounteredErrors(err_msg));
} }
let merge_files_print: Option<usize> = if matches.opt_present(options::MERGE_FILES_PRINT) { let merge_files_print = if matches.opt_present(options::MERGE_FILES_PRINT) {
Some(paths.len()) Some(paths.len())
} else { } else {
None None
}; };
let header: String = matches.opt_str(options::STRING_HEADER_OPTION).unwrap_or( let header = matches.opt_str(options::STRING_HEADER_OPTION).unwrap_or(
if is_merge_mode || paths[0] == FILE_STDIN { if is_merge_mode || paths[0] == FILE_STDIN {
String::new() String::new()
} else { } else {
@ -575,22 +570,22 @@ fn build_options(
}, },
); );
let default_first_number: usize = NumberingMode::default().first_number; let default_first_number = NumberingMode::default().first_number;
let first_number: usize = parse_usize(matches, options::FIRST_LINE_NUMBER_OPTION) let first_number = parse_usize(matches, options::FIRST_LINE_NUMBER_OPTION)
.unwrap_or(Ok(default_first_number))?; .unwrap_or(Ok(default_first_number))?;
let number: Option<NumberingMode> = matches let number = matches
.opt_str(options::NUMBERING_MODE_OPTION) .opt_str(options::NUMBERING_MODE_OPTION)
.map(|i| { .map(|i| {
let parse_result: Result<usize, ParseIntError> = i.parse::<usize>(); let parse_result = i.parse::<usize>();
let separator: String = if parse_result.is_err() { let separator = if parse_result.is_err() {
i[0..1].to_string() i[0..1].to_string()
} else { } else {
NumberingMode::default().separator NumberingMode::default().separator
}; };
let width: usize = match parse_result { let width = match parse_result {
Ok(res) => res, Ok(res) => res,
Err(_) => i[1..] Err(_) => i[1..]
.parse::<usize>() .parse::<usize>()
@ -605,24 +600,24 @@ fn build_options(
}) })
.or_else(|| { .or_else(|| {
if matches.opt_present(options::NUMBERING_MODE_OPTION) { if matches.opt_present(options::NUMBERING_MODE_OPTION) {
return Some(NumberingMode::default()); Some(NumberingMode::default())
} } else {
None None
}
}); });
let double_space: bool = matches.opt_present(options::DOUBLE_SPACE_OPTION); let double_space = matches.opt_present(options::DOUBLE_SPACE_OPTION);
let content_line_separator: String = if double_space { let content_line_separator = if double_space {
"\n".repeat(2) "\n".repeat(2)
} else { } else {
"\n".to_string() "\n".to_string()
}; };
let line_separator: String = "\n".to_string(); let line_separator = "\n".to_string();
let last_modified_time: String = if is_merge_mode || paths[0].eq(FILE_STDIN) { let last_modified_time = if is_merge_mode || paths[0].eq(FILE_STDIN) {
let datetime: DateTime<Local> = Local::now(); let datetime = Local::now();
datetime.format("%b %d %H:%M %Y").to_string() datetime.format("%b %d %H:%M %Y").to_string()
} else { } else {
file_last_modified_time(paths.get(0).unwrap()) file_last_modified_time(paths.get(0).unwrap())
@ -630,9 +625,9 @@ fn build_options(
// +page option is less priority than --pages // +page option is less priority than --pages
let page_plus_re = Regex::new(r"\s*\+(\d+:*\d*)\s*").unwrap(); let page_plus_re = Regex::new(r"\s*\+(\d+:*\d*)\s*").unwrap();
let start_page_in_plus_option: usize = match page_plus_re.captures(&free_args).map(|i| { let start_page_in_plus_option = match page_plus_re.captures(&free_args).map(|i| {
let unparsed_num = i.get(1).unwrap().as_str().trim(); let unparsed_num = i.get(1).unwrap().as_str().trim();
let x: Vec<&str> = unparsed_num.split(':').collect(); let x: Vec<_> = unparsed_num.split(':').collect();
x[0].to_string().parse::<usize>().map_err(|_e| { x[0].to_string().parse::<usize>().map_err(|_e| {
PrError::EncounteredErrors(format!("invalid {} argument '{}'", "+", unparsed_num)) PrError::EncounteredErrors(format!("invalid {} argument '{}'", "+", unparsed_num))
}) })
@ -641,12 +636,12 @@ fn build_options(
_ => 1, _ => 1,
}; };
let end_page_in_plus_option: Option<usize> = match page_plus_re let end_page_in_plus_option = match page_plus_re
.captures(&free_args) .captures(&free_args)
.map(|i| i.get(1).unwrap().as_str().trim()) .map(|i| i.get(1).unwrap().as_str().trim())
.filter(|i| i.contains(':')) .filter(|i| i.contains(':'))
.map(|unparsed_num| { .map(|unparsed_num| {
let x: Vec<&str> = unparsed_num.split(':').collect(); let x: Vec<_> = unparsed_num.split(':').collect();
x[1].to_string().parse::<usize>().map_err(|_e| { x[1].to_string().parse::<usize>().map_err(|_e| {
PrError::EncounteredErrors(format!("invalid {} argument '{}'", "+", unparsed_num)) PrError::EncounteredErrors(format!("invalid {} argument '{}'", "+", unparsed_num))
}) })
@ -656,16 +651,16 @@ fn build_options(
}; };
let invalid_pages_map = |i: String| { let invalid_pages_map = |i: String| {
let unparsed_value: String = matches.opt_str(options::PAGE_RANGE_OPTION).unwrap(); let unparsed_value = matches.opt_str(options::PAGE_RANGE_OPTION).unwrap();
i.parse::<usize>().map_err(|_e| { i.parse::<usize>().map_err(|_e| {
PrError::EncounteredErrors(format!("invalid --pages argument '{}'", unparsed_value)) PrError::EncounteredErrors(format!("invalid --pages argument '{}'", unparsed_value))
}) })
}; };
let start_page: usize = match matches let start_page = match matches
.opt_str(options::PAGE_RANGE_OPTION) .opt_str(options::PAGE_RANGE_OPTION)
.map(|i| { .map(|i| {
let x: Vec<&str> = i.split(':').collect(); let x: Vec<_> = i.split(':').collect();
x[0].to_string() x[0].to_string()
}) })
.map(invalid_pages_map) .map(invalid_pages_map)
@ -674,11 +669,11 @@ fn build_options(
_ => start_page_in_plus_option, _ => start_page_in_plus_option,
}; };
let end_page: Option<usize> = match matches let end_page = match matches
.opt_str(options::PAGE_RANGE_OPTION) .opt_str(options::PAGE_RANGE_OPTION)
.filter(|i: &String| i.contains(':')) .filter(|i| i.contains(':'))
.map(|i: String| { .map(|i| {
let x: Vec<&str> = i.split(':').collect(); let x: Vec<_> = i.split(':').collect();
x[1].to_string() x[1].to_string()
}) })
.map(invalid_pages_map) .map(invalid_pages_map)
@ -701,30 +696,30 @@ fn build_options(
LINES_PER_PAGE LINES_PER_PAGE
}; };
let page_length: usize = let page_length =
parse_usize(matches, options::PAGE_LENGTH_OPTION).unwrap_or(Ok(default_lines_per_page))?; parse_usize(matches, options::PAGE_LENGTH_OPTION).unwrap_or(Ok(default_lines_per_page))?;
let page_length_le_ht: bool = page_length < (HEADER_LINES_PER_PAGE + TRAILER_LINES_PER_PAGE); let page_length_le_ht = page_length < (HEADER_LINES_PER_PAGE + TRAILER_LINES_PER_PAGE);
let display_header_and_trailer: bool = let display_header_and_trailer =
!(page_length_le_ht) && !matches.opt_present(options::NO_HEADER_TRAILER_OPTION); !(page_length_le_ht) && !matches.opt_present(options::NO_HEADER_TRAILER_OPTION);
let content_lines_per_page: usize = if page_length_le_ht { let content_lines_per_page = if page_length_le_ht {
page_length page_length
} else { } else {
page_length - (HEADER_LINES_PER_PAGE + TRAILER_LINES_PER_PAGE) page_length - (HEADER_LINES_PER_PAGE + TRAILER_LINES_PER_PAGE)
}; };
let page_separator_char: String = if matches.opt_present(options::FORM_FEED_OPTION) { let page_separator_char = if matches.opt_present(options::FORM_FEED_OPTION) {
let bytes = vec![FF]; let bytes = vec![FF];
String::from_utf8(bytes).unwrap() String::from_utf8(bytes).unwrap()
} else { } else {
"\n".to_string() "\n".to_string()
}; };
let across_mode: bool = matches.opt_present(options::ACROSS_OPTION); let across_mode = matches.opt_present(options::ACROSS_OPTION);
let column_separator: String = match matches.opt_str(options::COLUMN_STRING_SEPARATOR_OPTION) { let column_separator = match matches.opt_str(options::COLUMN_STRING_SEPARATOR_OPTION) {
Some(x) => Some(x), Some(x) => Some(x),
None => matches.opt_str(options::COLUMN_CHAR_SEPARATOR_OPTION), None => matches.opt_str(options::COLUMN_CHAR_SEPARATOR_OPTION),
} }
@ -738,10 +733,10 @@ fn build_options(
DEFAULT_COLUMN_WIDTH DEFAULT_COLUMN_WIDTH
}; };
let column_width: usize = let column_width =
parse_usize(matches, options::COLUMN_WIDTH_OPTION).unwrap_or(Ok(default_column_width))?; parse_usize(matches, options::COLUMN_WIDTH_OPTION).unwrap_or(Ok(default_column_width))?;
let page_width: Option<usize> = if matches.opt_present(options::JOIN_LINES_OPTION) { let page_width = if matches.opt_present(options::JOIN_LINES_OPTION) {
None None
} else { } else {
match parse_usize(matches, options::PAGE_WIDTH_OPTION) { match parse_usize(matches, options::PAGE_WIDTH_OPTION) {
@ -752,7 +747,7 @@ fn build_options(
let re_col = Regex::new(r"\s*-(\d+)\s*").unwrap(); 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 start_column_option = match re_col.captures(&free_args).map(|i| {
let unparsed_num = i.get(1).unwrap().as_str().trim(); let unparsed_num = i.get(1).unwrap().as_str().trim();
unparsed_num.parse::<usize>().map_err(|_e| { unparsed_num.parse::<usize>().map_err(|_e| {
PrError::EncounteredErrors(format!("invalid {} argument '{}'", "-", unparsed_num)) PrError::EncounteredErrors(format!("invalid {} argument '{}'", "-", unparsed_num))
@ -764,22 +759,21 @@ fn build_options(
// --column has more priority than -column // --column has more priority than -column
let column_option_value: Option<usize> = match parse_usize(matches, options::COLUMN_OPTION) { let column_option_value = match parse_usize(matches, options::COLUMN_OPTION) {
Some(res) => Some(res?), Some(res) => Some(res?),
_ => start_column_option, _ => start_column_option,
}; };
let column_mode_options: Option<ColumnModeOptions> = let column_mode_options = column_option_value.map(|columns| ColumnModeOptions {
column_option_value.map(|columns| ColumnModeOptions {
columns, columns,
width: column_width, width: column_width,
column_separator, column_separator,
across_mode, across_mode,
}); });
let offset_spaces: String = let offset_spaces =
" ".repeat(parse_usize(matches, options::OFFSET_SPACES_OPTION).unwrap_or(Ok(0))?); " ".repeat(parse_usize(matches, options::OFFSET_SPACES_OPTION).unwrap_or(Ok(0))?);
let join_lines: bool = matches.opt_present(options::JOIN_LINES_OPTION); let join_lines = matches.opt_present(options::JOIN_LINES_OPTION);
let col_sep_for_printing = column_mode_options let col_sep_for_printing = column_mode_options
.as_ref() .as_ref()
@ -793,7 +787,7 @@ fn build_options(
let columns_to_print = merge_files_print let columns_to_print = merge_files_print
.unwrap_or_else(|| column_mode_options.as_ref().map(|i| i.columns).unwrap_or(1)); .unwrap_or_else(|| column_mode_options.as_ref().map(|i| i.columns).unwrap_or(1));
let line_width: Option<usize> = if join_lines { let line_width = if join_lines {
None None
} else if columns_to_print > 1 { } else if columns_to_print > 1 {
Some( Some(
@ -830,12 +824,12 @@ fn build_options(
fn open(path: &str) -> Result<Box<dyn Read>, PrError> { fn open(path: &str) -> Result<Box<dyn Read>, PrError> {
if path == FILE_STDIN { if path == FILE_STDIN {
let stdin: Stdin = stdin(); let stdin = stdin();
return Ok(Box::new(stdin) as Box<dyn Read>); return Ok(Box::new(stdin) as Box<dyn Read>);
} }
metadata(path) metadata(path)
.map(|i: Metadata| { .map(|i| {
let path_string = path.to_string(); let path_string = path.to_string();
match i.file_type() { match i.file_type() {
#[cfg(unix)] #[cfg(unix)]
@ -859,9 +853,9 @@ fn open(path: &str) -> Result<Box<dyn Read>, PrError> {
fn split_lines_if_form_feed(file_content: Result<String, IOError>) -> Vec<FileLine> { fn split_lines_if_form_feed(file_content: Result<String, IOError>) -> Vec<FileLine> {
file_content file_content
.map(|content| { .map(|content| {
let mut lines: Vec<FileLine> = Vec::new(); let mut lines = Vec::new();
let mut f_occurred: usize = 0; let mut f_occurred = 0;
let mut chunk: Vec<u8> = Vec::new(); let mut chunk = Vec::new();
for byte in content.as_bytes() { for byte in content.as_bytes() {
if byte == &FF { if byte == &FF {
f_occurred += 1; f_occurred += 1;
@ -897,11 +891,9 @@ fn split_lines_if_form_feed(file_content: Result<String, IOError>) -> Vec<FileLi
} }
fn pr(path: &str, options: &OutputOptions) -> Result<i32, PrError> { fn pr(path: &str, options: &OutputOptions) -> Result<i32, PrError> {
let lines: Lines<BufReader<Box<dyn Read>>> = let lines = BufReader::with_capacity(READ_BUFFER_SIZE, open(path)?).lines();
BufReader::with_capacity(READ_BUFFER_SIZE, open(path)?).lines();
let pages: Box<dyn Iterator<Item = (usize, Vec<FileLine>)>> = let pages = read_stream_and_create_pages(options, lines, 0);
read_stream_and_create_pages(options, lines, 0);
for page_with_page_number in pages { for page_with_page_number in pages {
let page_number = page_with_page_number.0 + 1; let page_number = page_with_page_number.0 + 1;
@ -917,24 +909,24 @@ fn read_stream_and_create_pages(
lines: Lines<BufReader<Box<dyn Read>>>, lines: Lines<BufReader<Box<dyn Read>>>,
file_id: usize, file_id: usize,
) -> Box<dyn Iterator<Item = (usize, Vec<FileLine>)>> { ) -> Box<dyn Iterator<Item = (usize, Vec<FileLine>)>> {
let start_page: usize = options.start_page; let start_page = options.start_page;
let start_line_number: usize = get_start_line_number(options); let start_line_number = get_start_line_number(options);
let last_page: Option<usize> = options.end_page; let last_page = options.end_page;
let lines_needed_per_page: usize = lines_to_read_for_page(options); let lines_needed_per_page = lines_to_read_for_page(options);
Box::new( Box::new(
lines lines
.map(split_lines_if_form_feed) .map(split_lines_if_form_feed)
.flatten() .flatten()
.enumerate() .enumerate()
.map(move |i: (usize, FileLine)| FileLine { .map(move |(i, line)| FileLine {
line_number: i.0 + start_line_number, line_number: i + start_line_number,
file_id, file_id,
..i.1 ..line
}) // Add line number and file_id }) // Add line number and file_id
.batching(move |it| { .batching(move |it| {
let mut first_page: Vec<FileLine> = Vec::new(); let mut first_page = Vec::new();
let mut page_with_lines: Vec<Vec<FileLine>> = Vec::new(); let mut page_with_lines = Vec::new();
for line in it { for line in it {
let form_feeds_after = line.form_feeds_after; let form_feeds_after = line.form_feeds_after;
first_page.push(line); first_page.push(line);
@ -961,15 +953,14 @@ fn read_stream_and_create_pages(
}) // Create set of pages as form feeds could lead to empty pages }) // Create set of pages as form feeds could lead to empty pages
.flatten() // Flatten to pages from page sets .flatten() // Flatten to pages from page sets
.enumerate() // Assign page number .enumerate() // Assign page number
.skip_while(move |x: &(usize, Vec<FileLine>)| { .skip_while(move |(x, _)| {
// Skip the not needed pages // Skip the not needed pages
let current_page = x.0 + 1; let current_page = x + 1;
current_page < start_page current_page < start_page
}) })
.take_while(move |x: &(usize, Vec<FileLine>)| { .take_while(move |(x, _)| {
// Take only the required pages // Take only the required pages
let current_page = x.0 + 1; let current_page = x + 1;
current_page >= start_page current_page >= start_page
&& (last_page.is_none() || current_page <= last_page.unwrap()) && (last_page.is_none() || current_page <= last_page.unwrap())
@ -988,14 +979,13 @@ fn mpr(paths: &[String], options: &OutputOptions) -> Result<i32, PrError> {
let file_line_groups = paths let file_line_groups = paths
.iter() .iter()
.enumerate() .enumerate()
.map(|indexed_path: (usize, &String)| { .map(|(i, path)| {
let lines = let lines = BufReader::with_capacity(READ_BUFFER_SIZE, open(path).unwrap()).lines();
BufReader::with_capacity(READ_BUFFER_SIZE, open(indexed_path.1).unwrap()).lines();
read_stream_and_create_pages(options, lines, indexed_path.0) read_stream_and_create_pages(options, lines, i)
.map(move |x: (usize, Vec<FileLine>)| { .map(move |(x, line)| {
let file_line = x.1; let file_line = line;
let page_number = x.0 + 1; let page_number = x + 1;
file_line file_line
.into_iter() .into_iter()
.map(|fl| FileLine { .map(|fl| FileLine {
@ -1007,17 +997,17 @@ fn mpr(paths: &[String], options: &OutputOptions) -> Result<i32, PrError> {
}) })
.flatten() .flatten()
}) })
.kmerge_by(|a: &FileLine, b: &FileLine| { .kmerge_by(|a, b| {
if a.group_key == b.group_key { if a.group_key == b.group_key {
a.line_number < b.line_number a.line_number < b.line_number
} else { } else {
a.group_key < b.group_key a.group_key < b.group_key
} }
}) })
.group_by(|file_line: &FileLine| file_line.group_key); .group_by(|file_line| file_line.group_key);
let start_page: usize = options.start_page; let start_page = options.start_page;
let mut lines: Vec<FileLine> = Vec::new(); let mut lines = Vec::new();
let mut page_counter = start_page; let mut page_counter = start_page;
for (_key, file_line_group) in file_line_groups.into_iter() { for (_key, file_line_group) in file_line_groups.into_iter() {
@ -1044,9 +1034,9 @@ fn print_page(lines: &[FileLine], options: &OutputOptions, page: usize) -> Resul
let line_separator = options.line_separator.as_bytes(); let line_separator = options.line_separator.as_bytes();
let page_separator = options.page_separator_char.as_bytes(); let page_separator = options.page_separator_char.as_bytes();
let header: Vec<String> = header_content(options, page); let header = header_content(options, page);
let trailer_content: Vec<String> = trailer_content(options); let trailer_content = trailer_content(options);
let out: &mut Stdout = &mut stdout(); let out = &mut stdout();
out.lock(); out.lock();
for x in header { for x in header {
@ -1057,7 +1047,7 @@ fn print_page(lines: &[FileLine], options: &OutputOptions, page: usize) -> Resul
let lines_written = write_columns(lines, options, out)?; let lines_written = write_columns(lines, options, out)?;
for index in 0..trailer_content.len() { for index in 0..trailer_content.len() {
let x: &String = trailer_content.get(index).unwrap(); let x = trailer_content.get(index).unwrap();
out.write_all(x.as_bytes())?; out.write_all(x.as_bytes())?;
if index + 1 != trailer_content.len() { if index + 1 != trailer_content.len() {
out.write_all(line_separator)?; out.write_all(line_separator)?;
@ -1084,7 +1074,7 @@ fn write_columns(
let columns = options let columns = options
.merge_files_print .merge_files_print
.unwrap_or_else(|| get_columns(options)); .unwrap_or_else(|| get_columns(options));
let line_width: Option<usize> = options.line_width; let line_width = options.line_width;
let mut lines_printed = 0; let mut lines_printed = 0;
let feed_line_present = options.form_feed_used; let feed_line_present = options.form_feed_used;
let mut not_found_break = false; let mut not_found_break = false;
@ -1095,9 +1085,9 @@ fn write_columns(
.map(|i| i.across_mode) .map(|i| i.across_mode)
.unwrap_or(false); .unwrap_or(false);
let mut filled_lines: Vec<Option<&FileLine>> = Vec::new(); let mut filled_lines = Vec::new();
if options.merge_files_print.is_some() { if options.merge_files_print.is_some() {
let mut offset: usize = 0; let mut offset = 0;
for col in 0..columns { for col in 0..columns {
let mut inserted = 0; let mut inserted = 0;
for i in offset..lines.len() { for i in offset..lines.len() {
@ -1116,7 +1106,7 @@ fn write_columns(
} }
} }
let table: Vec<Vec<Option<&FileLine>>> = (0..content_lines_per_page) let table: Vec<Vec<_>> = (0..content_lines_per_page)
.map(move |a| { .map(move |a| {
(0..columns) (0..columns)
.map(|i| { .map(|i| {
@ -1134,7 +1124,7 @@ fn write_columns(
}) })
.collect(); .collect();
let blank_line: FileLine = FileLine::default(); let blank_line = FileLine::default();
for row in table { for row in table {
let indexes = row.len(); let indexes = row.len();
for (i, cell) in row.iter().enumerate() { for (i, cell) in row.iter().enumerate() {
@ -1147,7 +1137,7 @@ fn write_columns(
not_found_break = true; not_found_break = true;
break; break;
} else if cell.is_some() { } else if cell.is_some() {
let file_line: &FileLine = cell.unwrap(); let file_line = cell.unwrap();
out.write_all( out.write_all(
get_line_for_printing(&options, file_line, columns, i, &line_width, indexes) get_line_for_printing(&options, file_line, columns, i, &line_width, indexes)
@ -1176,7 +1166,7 @@ fn get_line_for_printing(
) -> String { ) -> String {
// Check this condition // Check this condition
let blank_line = String::new(); let blank_line = String::new();
let fmtd_line_number: String = get_fmtd_line_number(&options, file_line.line_number, index); let fmtd_line_number = get_fmtd_line_number(&options, file_line.line_number, index);
let mut complete_line = format!( let mut complete_line = format!(
"{}{}", "{}{}",
@ -1184,9 +1174,9 @@ fn get_line_for_printing(
file_line.line_content.as_ref().unwrap() file_line.line_content.as_ref().unwrap()
); );
let offset_spaces: &String = &options.offset_spaces; let offset_spaces = &options.offset_spaces;
let tab_count: usize = complete_line.chars().filter(|i| i == &TAB).count(); let tab_count = complete_line.chars().filter(|i| i == &TAB).count();
let display_length = complete_line.len() + (tab_count * 7); let display_length = complete_line.len() + (tab_count * 7);
@ -1245,7 +1235,7 @@ fn get_fmtd_line_number(opts: &OutputOptions, line_number: usize, index: usize)
/// * `page` - A reference to page number /// * `page` - A reference to page number
fn header_content(options: &OutputOptions, page: usize) -> Vec<String> { fn header_content(options: &OutputOptions, page: usize) -> Vec<String> {
if options.display_header_and_trailer { if options.display_header_and_trailer {
let first_line: String = format!( let first_line = format!(
"{} {} Page {}", "{} {} Page {}",
options.last_modified_time, options.header, page options.last_modified_time, options.header, page
); );