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 implement argument pattern #5966

Merged
merged 3 commits into from
Mar 21, 2024
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
97 changes: 88 additions & 9 deletions src/uu/more/src/more.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
clean_print: bool,
from_line: usize,
lines: Option<u16>,
pattern: Option<String>,
print_over: bool,
silent: bool,
squeeze: bool,
Expand All @@ -75,10 +76,14 @@
Some(number) if number > 1 => number - 1,
_ => 0,
};
let pattern = matches

Check warning on line 79 in src/uu/more/src/more.rs

View check run for this annotation

Codecov / codecov/patch

src/uu/more/src/more.rs#L79

Added line #L79 was not covered by tests
.get_one::<String>(options::PATTERN)
.map(|s| s.to_owned());

Check warning on line 81 in src/uu/more/src/more.rs

View check run for this annotation

Codecov / codecov/patch

src/uu/more/src/more.rs#L81

Added line #L81 was not covered by tests
Self {
clean_print: matches.get_flag(options::CLEAN_PRINT),
from_line,
lines,
pattern,
print_over: matches.get_flag(options::PRINT_OVER),
silent: matches.get_flag(options::SILENT),
squeeze: matches.get_flag(options::SQUEEZE),
Expand Down Expand Up @@ -206,6 +211,15 @@
.action(ArgAction::SetTrue)
.hide(true),
)
.arg(
Arg::new(options::PATTERN)

Check warning on line 215 in src/uu/more/src/more.rs

View check run for this annotation

Codecov / codecov/patch

src/uu/more/src/more.rs#L215

Added line #L215 was not covered by tests
.short('P')
.long(options::PATTERN)
.allow_hyphen_values(true)
.required(false)
.value_name("pattern")
.help("Display file beginning from pattern match"),
)
.arg(
Arg::new(options::FROM_LINE)
.short('F')
Expand Down Expand Up @@ -245,14 +259,6 @@
.long(options::NO_PAUSE)
.help("Suppress pause after form feed"),
)
.arg(
Arg::new(options::PATTERN)
.short('P')
.allow_hyphen_values(true)
.required(false)
.takes_value(true)
.help("Display file beginning from pattern match"),
)
*/
.arg(
Arg::new(options::FILES)
Expand Down Expand Up @@ -307,6 +313,17 @@

let mut pager = Pager::new(rows, lines, next_file, options);

if options.pattern.is_some() {
match search_pattern_in_file(&pager.lines, &options.pattern) {
Some(number) => pager.upper_mark = number,
None => {

Check warning on line 319 in src/uu/more/src/more.rs

View check run for this annotation

Codecov / codecov/patch

src/uu/more/src/more.rs#L318-L319

Added lines #L318 - L319 were not covered by tests
execute!(stdout, terminal::Clear(terminal::ClearType::CurrentLine))?;
stdout.write_all("\rPattern not found\n".as_bytes())?;
pager.content_rows -= 1;

Check warning on line 322 in src/uu/more/src/more.rs

View check run for this annotation

Codecov / codecov/patch

src/uu/more/src/more.rs#L322

Added line #L322 was not covered by tests
}
}
}

if multiple_file {
execute!(stdout, terminal::Clear(terminal::ClearType::CurrentLine)).unwrap();
stdout.write_all(
Expand Down Expand Up @@ -592,6 +609,19 @@
}
}

fn search_pattern_in_file(lines: &[String], pattern: &Option<String>) -> Option<usize> {
let pattern = pattern.clone().unwrap_or_default();

Check warning on line 613 in src/uu/more/src/more.rs

View check run for this annotation

Codecov / codecov/patch

src/uu/more/src/more.rs#L612-L613

Added lines #L612 - L613 were not covered by tests
if lines.is_empty() || pattern.is_empty() {
return None;

Check warning on line 615 in src/uu/more/src/more.rs

View check run for this annotation

Codecov / codecov/patch

src/uu/more/src/more.rs#L615

Added line #L615 was not covered by tests
}
for (line_number, line) in lines.iter().enumerate() {
if line.contains(pattern.as_str()) {
return Some(line_number);

Check warning on line 619 in src/uu/more/src/more.rs

View check run for this annotation

Codecov / codecov/patch

src/uu/more/src/more.rs#L619

Added line #L619 was not covered by tests
}
}
None
}

Check warning on line 623 in src/uu/more/src/more.rs

View check run for this annotation

Codecov / codecov/patch

src/uu/more/src/more.rs#L622-L623

Added lines #L622 - L623 were not covered by tests

fn paging_add_back_message(options: &Options, stdout: &mut std::io::Stdout) -> UResult<()> {
if options.lines.is_some() {
execute!(stdout, MoveUp(1))?;
Expand Down Expand Up @@ -640,7 +670,7 @@

#[cfg(test)]
mod tests {
use super::break_line;
use super::{break_line, search_pattern_in_file};
use unicode_width::UnicodeWidthStr;

#[test]
Expand Down Expand Up @@ -688,4 +718,53 @@
// Each 👩🏻‍🔬 is 6 character width it break line to the closest number to 80 => 6 * 13 = 78
assert_eq!((78, 42), (widths[0], widths[1]));
}

#[test]
fn test_search_pattern_empty_lines() {
let lines = vec![];
let pattern = Some(String::from("pattern"));
assert_eq!(None, search_pattern_in_file(&lines, &pattern));
}

#[test]
fn test_search_pattern_empty_pattern() {
let lines = vec![String::from("line1"), String::from("line2")];
let pattern = None;
assert_eq!(None, search_pattern_in_file(&lines, &pattern));
}

#[test]
fn test_search_pattern_found_pattern() {
let lines = vec![
String::from("line1"),
String::from("line2"),
String::from("pattern"),
];
let lines2 = vec![
String::from("line1"),
String::from("line2"),
String::from("pattern"),
String::from("pattern2"),
];
let lines3 = vec![
String::from("line1"),
String::from("line2"),
String::from("other_pattern"),
];
let pattern = Some(String::from("pattern"));
assert_eq!(2, search_pattern_in_file(&lines, &pattern).unwrap());
assert_eq!(2, search_pattern_in_file(&lines2, &pattern).unwrap());
assert_eq!(2, search_pattern_in_file(&lines3, &pattern).unwrap());
}

#[test]
fn test_search_pattern_not_found_pattern() {
let lines = vec![
String::from("line1"),
String::from("line2"),
String::from("something"),
];
let pattern = Some(String::from("pattern"));
assert_eq!(None, search_pattern_in_file(&lines, &pattern));
}
}
50 changes: 50 additions & 0 deletions tests/by-util/test_more.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@

new_ucmd!().arg("-F").arg("10").succeeds();
new_ucmd!().arg("--from-line").arg("0").succeeds();

new_ucmd!().arg("-P").arg("something").succeeds();
new_ucmd!().arg("--pattern").arg("-1").succeeds();

Check warning on line 39 in tests/by-util/test_more.rs

View check run for this annotation

Codecov / codecov/patch

tests/by-util/test_more.rs#L38-L39

Added lines #L38 - L39 were not covered by tests
}
}

Expand Down Expand Up @@ -151,3 +154,50 @@
.stderr_contains("file3");
}
}

#[test]
fn test_more_pattern_found() {
if std::io::stdout().is_terminal() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;

Check warning on line 162 in tests/by-util/test_more.rs

View check run for this annotation

Codecov / codecov/patch

tests/by-util/test_more.rs#L161-L162

Added lines #L161 - L162 were not covered by tests

let file = "test_file";

at.write(file, "line1\nline2");

Check warning on line 166 in tests/by-util/test_more.rs

View check run for this annotation

Codecov / codecov/patch

tests/by-util/test_more.rs#L166

Added line #L166 was not covered by tests

// output only the second line "line2"
scene

Check warning on line 169 in tests/by-util/test_more.rs

View check run for this annotation

Codecov / codecov/patch

tests/by-util/test_more.rs#L169

Added line #L169 was not covered by tests
.ucmd()
.arg("-P")
.arg("line2")
.arg(file)
.succeeds()
.no_stderr()
.stdout_does_not_contain("line1")
.stdout_contains("line2");
}

Check warning on line 178 in tests/by-util/test_more.rs

View check run for this annotation

Codecov / codecov/patch

tests/by-util/test_more.rs#L177-L178

Added lines #L177 - L178 were not covered by tests
}

#[test]
fn test_more_pattern_not_found() {
if std::io::stdout().is_terminal() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;

Check warning on line 185 in tests/by-util/test_more.rs

View check run for this annotation

Codecov / codecov/patch

tests/by-util/test_more.rs#L184-L185

Added lines #L184 - L185 were not covered by tests

let file = "test_file";

let file_content = "line1\nline2";
at.write(file, file_content);

Check warning on line 190 in tests/by-util/test_more.rs

View check run for this annotation

Codecov / codecov/patch

tests/by-util/test_more.rs#L190

Added line #L190 was not covered by tests

scene

Check warning on line 192 in tests/by-util/test_more.rs

View check run for this annotation

Codecov / codecov/patch

tests/by-util/test_more.rs#L192

Added line #L192 was not covered by tests
.ucmd()
.arg("-P")
.arg("something")
.arg(file)
.succeeds()
.no_stderr()
.stdout_contains("Pattern not found")
.stdout_contains("line1")
.stdout_contains("line2");
}

Check warning on line 202 in tests/by-util/test_more.rs

View check run for this annotation

Codecov / codecov/patch

tests/by-util/test_more.rs#L201-L202

Added lines #L201 - L202 were not covered by tests
}
Loading