mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 11:37:44 +00:00
Merge pull request #4872 from Ideflop/more_implement_print_over_and_clean_print
more: add arguments print over and clean print
This commit is contained in:
commit
70765eea82
2 changed files with 75 additions and 23 deletions
|
@ -14,13 +14,14 @@ use std::{
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
use clap::{crate_version, Arg, ArgAction, Command};
|
use clap::{crate_version, Arg, ArgAction, ArgMatches, Command};
|
||||||
use crossterm::event::KeyEventKind;
|
use crossterm::event::KeyEventKind;
|
||||||
use crossterm::{
|
use crossterm::{
|
||||||
|
cursor::MoveTo,
|
||||||
event::{self, Event, KeyCode, KeyEvent, KeyModifiers},
|
event::{self, Event, KeyCode, KeyEvent, KeyModifiers},
|
||||||
execute, queue,
|
execute, queue,
|
||||||
style::Attribute,
|
style::Attribute,
|
||||||
terminal,
|
terminal::{self, Clear, ClearType},
|
||||||
};
|
};
|
||||||
|
|
||||||
use is_terminal::IsTerminal;
|
use is_terminal::IsTerminal;
|
||||||
|
@ -51,12 +52,34 @@ pub mod options {
|
||||||
|
|
||||||
const MULTI_FILE_TOP_PROMPT: &str = "::::::::::::::\n{}\n::::::::::::::\n";
|
const MULTI_FILE_TOP_PROMPT: &str = "::::::::::::::\n{}\n::::::::::::::\n";
|
||||||
|
|
||||||
|
struct Options {
|
||||||
|
silent: bool,
|
||||||
|
clean_print: bool,
|
||||||
|
print_over: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Options {
|
||||||
|
fn from(matches: &ArgMatches) -> Self {
|
||||||
|
Self {
|
||||||
|
silent: matches.get_flag(options::SILENT),
|
||||||
|
clean_print: matches.get_flag(options::CLEAN_PRINT),
|
||||||
|
print_over: matches.get_flag(options::PRINT_OVER),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let matches = uu_app().get_matches_from(args);
|
let args = args.collect_lossy();
|
||||||
|
let matches = match uu_app().try_get_matches_from(&args) {
|
||||||
|
Ok(m) => m,
|
||||||
|
Err(e) => return Err(e.into()),
|
||||||
|
};
|
||||||
|
|
||||||
|
let options = Options::from(&matches);
|
||||||
|
|
||||||
let mut buff = String::new();
|
let mut buff = String::new();
|
||||||
let silent = matches.get_flag(options::SILENT);
|
|
||||||
if let Some(files) = matches.get_many::<String>(options::FILES) {
|
if let Some(files) = matches.get_many::<String>(options::FILES) {
|
||||||
let mut stdout = setup_term();
|
let mut stdout = setup_term();
|
||||||
let length = files.len();
|
let length = files.len();
|
||||||
|
@ -83,14 +106,14 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
}
|
}
|
||||||
let mut reader = BufReader::new(File::open(file).unwrap());
|
let mut reader = BufReader::new(File::open(file).unwrap());
|
||||||
reader.read_to_string(&mut buff).unwrap();
|
reader.read_to_string(&mut buff).unwrap();
|
||||||
more(&buff, &mut stdout, next_file.copied(), silent)?;
|
more(&buff, &mut stdout, next_file.copied(), &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, silent)?;
|
more(&buff, &mut stdout, None, &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"));
|
||||||
|
@ -104,6 +127,13 @@ pub fn uu_app() -> Command {
|
||||||
.override_usage(format_usage(USAGE))
|
.override_usage(format_usage(USAGE))
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.infer_long_args(true)
|
.infer_long_args(true)
|
||||||
|
.arg(
|
||||||
|
Arg::new(options::PRINT_OVER)
|
||||||
|
.short('c')
|
||||||
|
.long(options::PRINT_OVER)
|
||||||
|
.help("Do not scroll, display text and clean line ends")
|
||||||
|
.action(ArgAction::SetTrue),
|
||||||
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(options::SILENT)
|
Arg::new(options::SILENT)
|
||||||
.short('d')
|
.short('d')
|
||||||
|
@ -111,6 +141,13 @@ pub fn uu_app() -> Command {
|
||||||
.help("Display help instead of ringing bell")
|
.help("Display help instead of ringing bell")
|
||||||
.action(ArgAction::SetTrue),
|
.action(ArgAction::SetTrue),
|
||||||
)
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new(options::CLEAN_PRINT)
|
||||||
|
.short('p')
|
||||||
|
.long(options::CLEAN_PRINT)
|
||||||
|
.help("Do not scroll, clean screen and display text")
|
||||||
|
.action(ArgAction::SetTrue),
|
||||||
|
)
|
||||||
// The commented arguments below are unimplemented:
|
// The commented arguments below are unimplemented:
|
||||||
/*
|
/*
|
||||||
.arg(
|
.arg(
|
||||||
|
@ -125,18 +162,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::PRINT_OVER)
|
|
||||||
.short('c')
|
|
||||||
.long(options::PRINT_OVER)
|
|
||||||
.help("Do not scroll, display text and clean line ends"),
|
|
||||||
)
|
|
||||||
.arg(
|
|
||||||
Arg::new(options::CLEAN_PRINT)
|
|
||||||
.short('p')
|
|
||||||
.long(options::CLEAN_PRINT)
|
|
||||||
.help("Do not scroll, clean screen and display text"),
|
|
||||||
)
|
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(options::SQUEEZE)
|
Arg::new(options::SQUEEZE)
|
||||||
.short('s')
|
.short('s')
|
||||||
|
@ -209,7 +234,7 @@ fn setup_term() -> usize {
|
||||||
fn reset_term(stdout: &mut std::io::Stdout) {
|
fn reset_term(stdout: &mut std::io::Stdout) {
|
||||||
terminal::disable_raw_mode().unwrap();
|
terminal::disable_raw_mode().unwrap();
|
||||||
// Clear the prompt
|
// Clear the prompt
|
||||||
queue!(stdout, terminal::Clear(terminal::ClearType::CurrentLine)).unwrap();
|
queue!(stdout, terminal::Clear(ClearType::CurrentLine)).unwrap();
|
||||||
// Move cursor to the beginning without printing new line
|
// Move cursor to the beginning without printing new line
|
||||||
print!("\r");
|
print!("\r");
|
||||||
stdout.flush().unwrap();
|
stdout.flush().unwrap();
|
||||||
|
@ -219,11 +244,16 @@ fn reset_term(stdout: &mut std::io::Stdout) {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn reset_term(_: &mut usize) {}
|
fn reset_term(_: &mut usize) {}
|
||||||
|
|
||||||
fn more(buff: &str, stdout: &mut Stdout, next_file: Option<&str>, silent: bool) -> UResult<()> {
|
fn more(
|
||||||
|
buff: &str,
|
||||||
|
stdout: &mut Stdout,
|
||||||
|
next_file: Option<&str>,
|
||||||
|
options: &Options,
|
||||||
|
) -> UResult<()> {
|
||||||
let (cols, rows) = terminal::size().unwrap();
|
let (cols, rows) = terminal::size().unwrap();
|
||||||
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, silent);
|
let mut pager = Pager::new(rows, lines, next_file, options);
|
||||||
pager.draw(stdout, None);
|
pager.draw(stdout, None);
|
||||||
if pager.should_close() {
|
if pager.should_close() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
@ -313,6 +343,16 @@ fn more(buff: &str, stdout: &mut Stdout, next_file: Option<&str>, silent: bool)
|
||||||
_ => continue,
|
_ => continue,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if options.print_over {
|
||||||
|
execute!(
|
||||||
|
std::io::stdout(),
|
||||||
|
MoveTo(0, 0),
|
||||||
|
Clear(ClearType::FromCursorDown)
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
} else if options.clean_print {
|
||||||
|
execute!(std::io::stdout(), Clear(ClearType::All), MoveTo(0, 0)).unwrap();
|
||||||
|
}
|
||||||
pager.draw(stdout, wrong_key);
|
pager.draw(stdout, wrong_key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -330,7 +370,7 @@ struct Pager<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Pager<'a> {
|
impl<'a> Pager<'a> {
|
||||||
fn new(rows: u16, lines: Vec<String>, next_file: Option<&'a str>, silent: bool) -> 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: 0,
|
||||||
|
@ -338,7 +378,7 @@ impl<'a> Pager<'a> {
|
||||||
lines,
|
lines,
|
||||||
next_file,
|
next_file,
|
||||||
line_count,
|
line_count,
|
||||||
silent,
|
silent: options.silent,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,18 @@ fn test_more_no_arg() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_valid_arg() {
|
||||||
|
if std::io::stdout().is_terminal() {
|
||||||
|
new_ucmd!().arg("-c").succeeds();
|
||||||
|
new_ucmd!().arg("--print-over").succeeds();
|
||||||
|
|
||||||
|
new_ucmd!().arg("-p").succeeds();
|
||||||
|
new_ucmd!().arg("--clean-print").succeeds();
|
||||||
|
} else {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_more_dir_arg() {
|
fn test_more_dir_arg() {
|
||||||
// Run the test only if there's a valid terminal, else do nothing
|
// Run the test only if there's a valid terminal, else do nothing
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue