1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 11:37:44 +00:00

Merge branch 'main' into main

This commit is contained in:
hanbings 2024-03-21 22:57:20 +08:00 committed by GitHub
commit c35c96f127
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 142 additions and 19 deletions

View file

@ -19,7 +19,7 @@ concurrency:
env: env:
TERMUX: v0.118.0 TERMUX: v0.118.0
KEY_POSTFIX: nextest+rustc-hash+adb+sshd+upgrade+XGB+inc15 KEY_POSTFIX: nextest+rustc-hash+adb+sshd+upgrade+XGB+inc17
COMMON_EMULATOR_OPTIONS: -no-window -noaudio -no-boot-anim -camera-back none -gpu swiftshader_indirect COMMON_EMULATOR_OPTIONS: -no-window -noaudio -no-boot-anim -camera-back none -gpu swiftshader_indirect
EMULATOR_DISK_SIZE: 12GB EMULATOR_DISK_SIZE: 12GB
EMULATOR_HEAP_SIZE: 2048M EMULATOR_HEAP_SIZE: 2048M
@ -36,7 +36,7 @@ jobs:
cores: [4] # , 6 cores: [4] # , 6
ram: [4096, 8192] ram: [4096, 8192]
api-level: [28] api-level: [28]
target: [default] target: [google_apis_playstore]
arch: [x86, x86_64] # , arm64-v8a arch: [x86, x86_64] # , arm64-v8a
exclude: exclude:
- ram: 8192 - ram: 8192

View file

@ -54,6 +54,7 @@ struct Options {
clean_print: bool, clean_print: bool,
from_line: usize, from_line: usize,
lines: Option<u16>, lines: Option<u16>,
pattern: Option<String>,
print_over: bool, print_over: bool,
silent: bool, silent: bool,
squeeze: bool, squeeze: bool,
@ -75,10 +76,14 @@ impl Options {
Some(number) if number > 1 => number - 1, Some(number) if number > 1 => number - 1,
_ => 0, _ => 0,
}; };
let pattern = matches
.get_one::<String>(options::PATTERN)
.map(|s| s.to_owned());
Self { Self {
clean_print: matches.get_flag(options::CLEAN_PRINT), clean_print: matches.get_flag(options::CLEAN_PRINT),
from_line, from_line,
lines, lines,
pattern,
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),
squeeze: matches.get_flag(options::SQUEEZE), squeeze: matches.get_flag(options::SQUEEZE),
@ -206,6 +211,15 @@ pub fn uu_app() -> Command {
.action(ArgAction::SetTrue) .action(ArgAction::SetTrue)
.hide(true), .hide(true),
) )
.arg(
Arg::new(options::PATTERN)
.short('P')
.long(options::PATTERN)
.allow_hyphen_values(true)
.required(false)
.value_name("pattern")
.help("Display file beginning from pattern match"),
)
.arg( .arg(
Arg::new(options::FROM_LINE) Arg::new(options::FROM_LINE)
.short('F') .short('F')
@ -245,14 +259,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::PATTERN)
.short('P')
.allow_hyphen_values(true)
.required(false)
.takes_value(true)
.help("Display file beginning from pattern match"),
)
*/ */
.arg( .arg(
Arg::new(options::FILES) Arg::new(options::FILES)
@ -307,6 +313,17 @@ fn more(
let mut pager = Pager::new(rows, lines, next_file, options); 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 => {
execute!(stdout, terminal::Clear(terminal::ClearType::CurrentLine))?;
stdout.write_all("\rPattern not found\n".as_bytes())?;
pager.content_rows -= 1;
}
}
}
if multiple_file { if multiple_file {
execute!(stdout, terminal::Clear(terminal::ClearType::CurrentLine)).unwrap(); execute!(stdout, terminal::Clear(terminal::ClearType::CurrentLine)).unwrap();
stdout.write_all( stdout.write_all(
@ -592,6 +609,19 @@ impl<'a> Pager<'a> {
} }
} }
fn search_pattern_in_file(lines: &[String], pattern: &Option<String>) -> Option<usize> {
let pattern = pattern.clone().unwrap_or_default();
if lines.is_empty() || pattern.is_empty() {
return None;
}
for (line_number, line) in lines.iter().enumerate() {
if line.contains(pattern.as_str()) {
return Some(line_number);
}
}
None
}
fn paging_add_back_message(options: &Options, stdout: &mut std::io::Stdout) -> UResult<()> { fn paging_add_back_message(options: &Options, stdout: &mut std::io::Stdout) -> UResult<()> {
if options.lines.is_some() { if options.lines.is_some() {
execute!(stdout, MoveUp(1))?; execute!(stdout, MoveUp(1))?;
@ -640,7 +670,7 @@ fn break_line(line: &str, cols: usize) -> Vec<String> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::break_line; use super::{break_line, search_pattern_in_file};
use unicode_width::UnicodeWidthStr; use unicode_width::UnicodeWidthStr;
#[test] #[test]
@ -688,4 +718,53 @@ mod tests {
// Each 👩🏻‍🔬 is 6 character width it break line to the closest number to 80 => 6 * 13 = 78 // 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])); 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));
}
} }

View file

@ -34,6 +34,9 @@ fn test_valid_arg() {
new_ucmd!().arg("-F").arg("10").succeeds(); new_ucmd!().arg("-F").arg("10").succeeds();
new_ucmd!().arg("--from-line").arg("0").succeeds(); new_ucmd!().arg("--from-line").arg("0").succeeds();
new_ucmd!().arg("-P").arg("something").succeeds();
new_ucmd!().arg("--pattern").arg("-1").succeeds();
} }
} }
@ -151,3 +154,50 @@ fn test_more_error_on_multiple_files() {
.stderr_contains("file3"); .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;
let file = "test_file";
at.write(file, "line1\nline2");
// output only the second line "line2"
scene
.ucmd()
.arg("-P")
.arg("line2")
.arg(file)
.succeeds()
.no_stderr()
.stdout_does_not_contain("line1")
.stdout_contains("line2");
}
}
#[test]
fn test_more_pattern_not_found() {
if std::io::stdout().is_terminal() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;
let file = "test_file";
let file_content = "line1\nline2";
at.write(file, file_content);
scene
.ucmd()
.arg("-P")
.arg("something")
.arg(file)
.succeeds()
.no_stderr()
.stdout_contains("Pattern not found")
.stdout_contains("line1")
.stdout_contains("line2");
}
}

View file

@ -229,13 +229,6 @@ fn test_hex32() {
.stdout_is(expected_output); .stdout_is(expected_output);
} }
// This test fails on Android CI on AVD on Ubuntu Github runners.
// It was never reproducible locally and seems to be very hard to fix.
// Thats why its disabled for android x86*. See uutils issue #5941.
#[cfg(not(all(
target_os = "android",
any(target_arch = "x86", target_arch = "x86_64")
)))]
#[test] #[test]
fn test_f16() { fn test_f16() {
let input: [u8; 14] = [ let input: [u8; 14] = [

View file

@ -1,4 +1,4 @@
#! /usr/bin/python #!/usr/bin/env python3
""" """
Compare the current results to the last results gathered from the main branch to highlight Compare the current results to the last results gathered from the main branch to highlight

View file

@ -1,3 +1,4 @@
#!/usr/bin/env python3
# spell-checker:ignore debuginfo # spell-checker:ignore debuginfo
import subprocess import subprocess
from itertools import product from itertools import product