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:
commit
c35c96f127
6 changed files with 142 additions and 19 deletions
4
.github/workflows/android.yml
vendored
4
.github/workflows/android.yml
vendored
|
@ -19,7 +19,7 @@ concurrency:
|
|||
|
||||
env:
|
||||
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
|
||||
EMULATOR_DISK_SIZE: 12GB
|
||||
EMULATOR_HEAP_SIZE: 2048M
|
||||
|
@ -36,7 +36,7 @@ jobs:
|
|||
cores: [4] # , 6
|
||||
ram: [4096, 8192]
|
||||
api-level: [28]
|
||||
target: [default]
|
||||
target: [google_apis_playstore]
|
||||
arch: [x86, x86_64] # , arm64-v8a
|
||||
exclude:
|
||||
- ram: 8192
|
||||
|
|
|
@ -54,6 +54,7 @@ struct Options {
|
|||
clean_print: bool,
|
||||
from_line: usize,
|
||||
lines: Option<u16>,
|
||||
pattern: Option<String>,
|
||||
print_over: bool,
|
||||
silent: bool,
|
||||
squeeze: bool,
|
||||
|
@ -75,10 +76,14 @@ impl Options {
|
|||
Some(number) if number > 1 => number - 1,
|
||||
_ => 0,
|
||||
};
|
||||
let pattern = matches
|
||||
.get_one::<String>(options::PATTERN)
|
||||
.map(|s| s.to_owned());
|
||||
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),
|
||||
|
@ -206,6 +211,15 @@ pub fn uu_app() -> Command {
|
|||
.action(ArgAction::SetTrue)
|
||||
.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::new(options::FROM_LINE)
|
||||
.short('F')
|
||||
|
@ -245,14 +259,6 @@ pub fn uu_app() -> Command {
|
|||
.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)
|
||||
|
@ -307,6 +313,17 @@ fn more(
|
|||
|
||||
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 {
|
||||
execute!(stdout, terminal::Clear(terminal::ClearType::CurrentLine)).unwrap();
|
||||
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<()> {
|
||||
if options.lines.is_some() {
|
||||
execute!(stdout, MoveUp(1))?;
|
||||
|
@ -640,7 +670,7 @@ fn break_line(line: &str, cols: usize) -> Vec<String> {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::break_line;
|
||||
use super::{break_line, search_pattern_in_file};
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
#[test]
|
||||
|
@ -688,4 +718,53 @@ mod tests {
|
|||
// 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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,9 @@ fn test_valid_arg() {
|
|||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -151,3 +154,50 @@ fn test_more_error_on_multiple_files() {
|
|||
.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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -229,13 +229,6 @@ fn test_hex32() {
|
|||
.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]
|
||||
fn test_f16() {
|
||||
let input: [u8; 14] = [
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#!/usr/bin/env python3
|
||||
# spell-checker:ignore debuginfo
|
||||
import subprocess
|
||||
from itertools import product
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue