Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

more: add arguments print over and clean print #4872

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 63 additions & 23 deletions src/uu/more/src/more.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@ use std::{
time::Duration,
};

use clap::{crate_version, Arg, ArgAction, Command};
use clap::{crate_version, Arg, ArgAction, ArgMatches, Command};
use crossterm::event::KeyEventKind;
use crossterm::{
cursor::MoveTo,
event::{self, Event, KeyCode, KeyEvent, KeyModifiers},
execute, queue,
style::Attribute,
terminal,
terminal::{self, Clear, ClearType},
};

use is_terminal::IsTerminal;
Expand Down Expand Up @@ -51,12 +52,34 @@ pub mod options {

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]
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 silent = matches.get_flag(options::SILENT);

if let Some(files) = matches.get_many::<String>(options::FILES) {
let mut stdout = setup_term();
let length = files.len();
Expand All @@ -83,14 +106,14 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
}
let mut reader = BufReader::new(File::open(file).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();
}
reset_term(&mut stdout);
} else if !std::io::stdin().is_terminal() {
stdin().read_to_string(&mut buff).unwrap();
let mut stdout = setup_term();
more(&buff, &mut stdout, None, silent)?;
more(&buff, &mut stdout, None, &options)?;
reset_term(&mut stdout);
} else {
return Err(UUsageError::new(1, "bad usage"));
Expand All @@ -104,13 +127,27 @@ pub fn uu_app() -> Command {
.override_usage(format_usage(USAGE))
.version(crate_version!())
.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::new(options::SILENT)
.short('d')
.long(options::SILENT)
.help("Display help instead of ringing bell")
.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:
/*
.arg(
Expand All @@ -125,18 +162,6 @@ pub fn uu_app() -> Command {
.long(options::NO_PAUSE)
.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::new(options::SQUEEZE)
.short('s')
Expand Down Expand Up @@ -209,7 +234,7 @@ fn setup_term() -> usize {
fn reset_term(stdout: &mut std::io::Stdout) {
terminal::disable_raw_mode().unwrap();
// 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
print!("\r");
stdout.flush().unwrap();
Expand All @@ -219,11 +244,16 @@ fn reset_term(stdout: &mut std::io::Stdout) {
#[inline(always)]
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 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);
if pager.should_close() {
return Ok(());
Expand Down Expand Up @@ -303,6 +333,16 @@ fn more(buff: &str, stdout: &mut Stdout, next_file: Option<&str>, silent: bool)
_ => 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);
}
}
Expand All @@ -320,15 +360,15 @@ struct 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();
Self {
upper_mark: 0,
content_rows: rows.saturating_sub(1),
lines,
next_file,
line_count,
silent,
silent: options.silent,
}
}

Expand Down
12 changes: 12 additions & 0 deletions tests/by-util/test_more.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
fn test_more_dir_arg() {
// Run the test only if there's a valid terminal, else do nothing
Expand Down