mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-29 03:57:44 +00:00
more: implement arguments -u/--plain and -F/--from-line
This commit is contained in:
parent
82f5fec688
commit
479340306e
2 changed files with 60 additions and 26 deletions
|
@ -50,10 +50,11 @@ pub mod options {
|
||||||
pub const FILES: &str = "files";
|
pub const FILES: &str = "files";
|
||||||
}
|
}
|
||||||
|
|
||||||
const MULTI_FILE_TOP_PROMPT: &str = "::::::::::::::\n{}\n::::::::::::::\n";
|
const MULTI_FILE_TOP_PROMPT: &str = "\r::::::::::::::\n\r{}\n\r::::::::::::::\n";
|
||||||
|
|
||||||
struct Options {
|
struct Options {
|
||||||
clean_print: bool,
|
clean_print: bool,
|
||||||
|
from_line: usize,
|
||||||
lines: Option<u16>,
|
lines: Option<u16>,
|
||||||
print_over: bool,
|
print_over: bool,
|
||||||
silent: bool,
|
silent: bool,
|
||||||
|
@ -72,8 +73,13 @@ impl Options {
|
||||||
(None, Some(number)) if number > 0 => Some(number + 1),
|
(None, Some(number)) if number > 0 => Some(number + 1),
|
||||||
(_, _) => None,
|
(_, _) => None,
|
||||||
};
|
};
|
||||||
|
let from_line = match matches.get_one::<usize>(options::FROM_LINE).copied() {
|
||||||
|
Some(number) if number > 1 => number - 1,
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
Self {
|
Self {
|
||||||
clean_print: matches.get_flag(options::CLEAN_PRINT),
|
clean_print: matches.get_flag(options::CLEAN_PRINT),
|
||||||
|
from_line,
|
||||||
lines,
|
lines,
|
||||||
print_over: matches.get_flag(options::PRINT_OVER),
|
print_over: matches.get_flag(options::PRINT_OVER),
|
||||||
silent: matches.get_flag(options::SILENT),
|
silent: matches.get_flag(options::SILENT),
|
||||||
|
@ -90,7 +96,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
Err(e) => return Err(e.into()),
|
Err(e) => return Err(e.into()),
|
||||||
};
|
};
|
||||||
|
|
||||||
let options = Options::from(&matches);
|
let mut options = Options::from(&matches);
|
||||||
|
|
||||||
let mut buff = String::new();
|
let mut buff = String::new();
|
||||||
|
|
||||||
|
@ -115,9 +121,6 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
format!("cannot open {}: No such file or directory", file.quote()),
|
format!("cannot open {}: No such file or directory", file.quote()),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
if length > 1 {
|
|
||||||
buff.push_str(&MULTI_FILE_TOP_PROMPT.replace("{}", file.to_str().unwrap()));
|
|
||||||
}
|
|
||||||
let opened_file = match File::open(file) {
|
let opened_file = match File::open(file) {
|
||||||
Err(why) => {
|
Err(why) => {
|
||||||
terminal::disable_raw_mode().unwrap();
|
terminal::disable_raw_mode().unwrap();
|
||||||
|
@ -130,14 +133,21 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
};
|
};
|
||||||
let mut reader = BufReader::new(opened_file);
|
let mut reader = BufReader::new(opened_file);
|
||||||
reader.read_to_string(&mut buff).unwrap();
|
reader.read_to_string(&mut buff).unwrap();
|
||||||
more(&buff, &mut stdout, next_file.copied(), &options)?;
|
more(
|
||||||
|
&buff,
|
||||||
|
&mut stdout,
|
||||||
|
length > 1,
|
||||||
|
file.to_str(),
|
||||||
|
next_file.copied(),
|
||||||
|
&mut options,
|
||||||
|
)?;
|
||||||
buff.clear();
|
buff.clear();
|
||||||
}
|
}
|
||||||
reset_term(&mut stdout);
|
reset_term(&mut stdout);
|
||||||
} else if !std::io::stdin().is_terminal() {
|
} else if !std::io::stdin().is_terminal() {
|
||||||
stdin().read_to_string(&mut buff).unwrap();
|
stdin().read_to_string(&mut buff).unwrap();
|
||||||
let mut stdout = setup_term();
|
let mut stdout = setup_term();
|
||||||
more(&buff, &mut stdout, None, &options)?;
|
more(&buff, &mut stdout, false, None, None, &mut options)?;
|
||||||
reset_term(&mut stdout);
|
reset_term(&mut stdout);
|
||||||
} else {
|
} else {
|
||||||
return Err(UUsageError::new(1, "bad usage"));
|
return Err(UUsageError::new(1, "bad usage"));
|
||||||
|
@ -179,6 +189,22 @@ pub fn uu_app() -> Command {
|
||||||
.help("Squeeze multiple blank lines into one")
|
.help("Squeeze multiple blank lines into one")
|
||||||
.action(ArgAction::SetTrue),
|
.action(ArgAction::SetTrue),
|
||||||
)
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new(options::PLAIN)
|
||||||
|
.short('u')
|
||||||
|
.long(options::PLAIN)
|
||||||
|
.action(ArgAction::SetTrue)
|
||||||
|
.hide(true),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new(options::FROM_LINE)
|
||||||
|
.short('F')
|
||||||
|
.long(options::FROM_LINE)
|
||||||
|
.num_args(1)
|
||||||
|
.value_name("number")
|
||||||
|
.value_parser(value_parser!(usize))
|
||||||
|
.help("Display file beginning from line number"),
|
||||||
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(options::LINES)
|
Arg::new(options::LINES)
|
||||||
.short('n')
|
.short('n')
|
||||||
|
@ -191,7 +217,6 @@ pub fn uu_app() -> Command {
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(options::NUMBER)
|
Arg::new(options::NUMBER)
|
||||||
.long(options::NUMBER)
|
.long(options::NUMBER)
|
||||||
.required(false)
|
|
||||||
.num_args(1)
|
.num_args(1)
|
||||||
.value_parser(value_parser!(u16).range(0..))
|
.value_parser(value_parser!(u16).range(0..))
|
||||||
.help("Same as --lines"),
|
.help("Same as --lines"),
|
||||||
|
@ -210,21 +235,6 @@ pub fn uu_app() -> Command {
|
||||||
.long(options::NO_PAUSE)
|
.long(options::NO_PAUSE)
|
||||||
.help("Suppress pause after form feed"),
|
.help("Suppress pause after form feed"),
|
||||||
)
|
)
|
||||||
.arg(
|
|
||||||
Arg::new(options::PLAIN)
|
|
||||||
.short('u')
|
|
||||||
.long(options::PLAIN)
|
|
||||||
.help("Suppress underlining and bold"),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::new(options::FROM_LINE)
|
|
||||||
.short('F')
|
|
||||||
.allow_hyphen_values(true)
|
|
||||||
.required(false)
|
|
||||||
.takes_value(true)
|
|
||||||
.value_name("number")
|
|
||||||
.help("Display file beginning from line number"),
|
|
||||||
)
|
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(options::PATTERN)
|
Arg::new(options::PATTERN)
|
||||||
.short('P')
|
.short('P')
|
||||||
|
@ -273,8 +283,10 @@ fn reset_term(_: &mut usize) {}
|
||||||
fn more(
|
fn more(
|
||||||
buff: &str,
|
buff: &str,
|
||||||
stdout: &mut Stdout,
|
stdout: &mut Stdout,
|
||||||
|
multiple_file: bool,
|
||||||
|
file: Option<&str>,
|
||||||
next_file: Option<&str>,
|
next_file: Option<&str>,
|
||||||
options: &Options,
|
options: &mut Options,
|
||||||
) -> UResult<()> {
|
) -> UResult<()> {
|
||||||
let (cols, mut rows) = terminal::size().unwrap();
|
let (cols, mut rows) = terminal::size().unwrap();
|
||||||
if let Some(number) = options.lines {
|
if let Some(number) = options.lines {
|
||||||
|
@ -284,7 +296,22 @@ fn more(
|
||||||
let lines = break_buff(buff, usize::from(cols));
|
let lines = break_buff(buff, usize::from(cols));
|
||||||
|
|
||||||
let mut pager = Pager::new(rows, lines, next_file, options);
|
let mut pager = Pager::new(rows, lines, next_file, options);
|
||||||
|
|
||||||
|
if multiple_file {
|
||||||
|
execute!(stdout, terminal::Clear(terminal::ClearType::CurrentLine)).unwrap();
|
||||||
|
stdout.write_all(
|
||||||
|
MULTI_FILE_TOP_PROMPT
|
||||||
|
.replace("{}", file.unwrap_or_default())
|
||||||
|
.as_bytes(),
|
||||||
|
)?;
|
||||||
|
pager.content_rows -= 3;
|
||||||
|
}
|
||||||
pager.draw(stdout, None);
|
pager.draw(stdout, None);
|
||||||
|
if multiple_file {
|
||||||
|
options.from_line = 0;
|
||||||
|
pager.content_rows += 3;
|
||||||
|
}
|
||||||
|
|
||||||
if pager.should_close() {
|
if pager.should_close() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
@ -406,7 +433,7 @@ impl<'a> Pager<'a> {
|
||||||
fn new(rows: u16, lines: Vec<String>, next_file: Option<&'a str>, options: &Options) -> Self {
|
fn new(rows: u16, lines: Vec<String>, next_file: Option<&'a str>, options: &Options) -> Self {
|
||||||
let line_count = lines.len();
|
let line_count = lines.len();
|
||||||
Self {
|
Self {
|
||||||
upper_mark: 0,
|
upper_mark: options.from_line,
|
||||||
content_rows: rows.saturating_sub(1),
|
content_rows: rows.saturating_sub(1),
|
||||||
lines,
|
lines,
|
||||||
next_file,
|
next_file,
|
||||||
|
@ -535,7 +562,6 @@ impl<'a> Pager<'a> {
|
||||||
};
|
};
|
||||||
|
|
||||||
let status = format!("--More--({status_inner})");
|
let status = format!("--More--({status_inner})");
|
||||||
|
|
||||||
let banner = match (self.silent, wrong_key) {
|
let banner = match (self.silent, wrong_key) {
|
||||||
(true, Some(key)) => format!(
|
(true, Some(key)) => format!(
|
||||||
"{status} [Unknown key: '{key}'. Press 'h' for instructions. (unimplemented)]"
|
"{status} [Unknown key: '{key}'. Press 'h' for instructions. (unimplemented)]"
|
||||||
|
|
|
@ -21,9 +21,15 @@ fn test_valid_arg() {
|
||||||
new_ucmd!().arg("-s").succeeds();
|
new_ucmd!().arg("-s").succeeds();
|
||||||
new_ucmd!().arg("--squeeze").succeeds();
|
new_ucmd!().arg("--squeeze").succeeds();
|
||||||
|
|
||||||
|
new_ucmd!().arg("-u").succeeds();
|
||||||
|
new_ucmd!().arg("--plain").succeeds();
|
||||||
|
|
||||||
new_ucmd!().arg("-n").arg("10").succeeds();
|
new_ucmd!().arg("-n").arg("10").succeeds();
|
||||||
new_ucmd!().arg("--lines").arg("0").succeeds();
|
new_ucmd!().arg("--lines").arg("0").succeeds();
|
||||||
new_ucmd!().arg("--number").arg("0").succeeds();
|
new_ucmd!().arg("--number").arg("0").succeeds();
|
||||||
|
|
||||||
|
new_ucmd!().arg("-F").arg("10").succeeds();
|
||||||
|
new_ucmd!().arg("--from-line").arg("0").succeeds();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,6 +40,8 @@ fn test_invalid_arg() {
|
||||||
|
|
||||||
new_ucmd!().arg("--lines").arg("-10").fails();
|
new_ucmd!().arg("--lines").arg("-10").fails();
|
||||||
new_ucmd!().arg("--number").arg("-10").fails();
|
new_ucmd!().arg("--number").arg("-10").fails();
|
||||||
|
|
||||||
|
new_ucmd!().arg("--from-line").arg("-10").fails();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue