Skip to content

Commit b5bdfdc

Browse files
authored
Merge branch 'main' into clap-loca-improv-2
2 parents 12220a7 + 0eb08ef commit b5bdfdc

File tree

12 files changed

+145
-59
lines changed

12 files changed

+145
-59
lines changed

.github/workflows/code-quality.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ jobs:
236236
uses: Swatinem/rust-cache@v2
237237

238238
- name: Setup Python
239-
uses: actions/setup-python@v5
239+
uses: actions/setup-python@v6
240240
with:
241241
python-version: '3.x'
242242

.github/workflows/l10n.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ jobs:
8080
with:
8181
persist-credentials: false
8282
- name: Setup Python
83-
uses: actions/setup-python@v5
83+
uses: actions/setup-python@v6
8484
with:
8585
python-version: '3.x'
8686
- name: Install Mozilla Fluent Linter

Cargo.lock

Lines changed: 17 additions & 17 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/uu/date/src/date.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ const OPT_FILE: &str = "file";
3636
const OPT_DEBUG: &str = "debug";
3737
const OPT_ISO_8601: &str = "iso-8601";
3838
const OPT_RFC_EMAIL: &str = "rfc-email";
39+
const OPT_RFC_822: &str = "rfc-822";
40+
const OPT_RFC_2822: &str = "rfc-2822";
3941
const OPT_RFC_3339: &str = "rfc-3339";
4042
const OPT_SET: &str = "set";
4143
const OPT_REFERENCE: &str = "reference";
@@ -301,6 +303,8 @@ pub fn uu_app() -> Command {
301303
Arg::new(OPT_RFC_EMAIL)
302304
.short('R')
303305
.long(OPT_RFC_EMAIL)
306+
.alias(OPT_RFC_2822)
307+
.alias(OPT_RFC_822)
304308
.help(translate!("date-help-rfc-email"))
305309
.action(ArgAction::SetTrue),
306310
)

src/uu/nl/src/nl.rs

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,7 @@ use std::fs::File;
99
use std::io::{BufRead, BufReader, Read, stdin};
1010
use std::path::Path;
1111
use uucore::error::{FromIo, UResult, USimpleError, set_exit_code};
12-
use uucore::translate;
13-
14-
use uucore::{format_usage, show_error};
12+
use uucore::{format_usage, show_error, translate};
1513

1614
mod helper;
1715

@@ -78,7 +76,7 @@ enum NumberingStyle {
7876
All,
7977
NonEmpty,
8078
None,
81-
Regex(Box<regex::Regex>),
79+
Regex(Box<regex::bytes::Regex>),
8280
}
8381

8482
impl TryFrom<&str> for NumberingStyle {
@@ -89,7 +87,7 @@ impl TryFrom<&str> for NumberingStyle {
8987
"a" => Ok(Self::All),
9088
"t" => Ok(Self::NonEmpty),
9189
"n" => Ok(Self::None),
92-
_ if s.starts_with('p') => match regex::Regex::new(&s[1..]) {
90+
_ if s.starts_with('p') => match regex::bytes::Regex::new(&s[1..]) {
9391
Ok(re) => Ok(Self::Regex(Box::new(re))),
9492
Err(_) => Err(translate!("nl-error-invalid-regex")),
9593
},
@@ -142,19 +140,30 @@ enum SectionDelimiter {
142140
impl SectionDelimiter {
143141
/// A valid section delimiter contains the pattern one to three times,
144142
/// and nothing else.
145-
fn parse(s: &str, pattern: &str) -> Option<Self> {
146-
if s.is_empty() || pattern.is_empty() {
143+
fn parse(bytes: &[u8], pattern: &str) -> Option<Self> {
144+
let pattern = pattern.as_bytes();
145+
146+
if bytes.is_empty() || pattern.is_empty() || bytes.len() % pattern.len() != 0 {
147147
return None;
148148
}
149149

150-
let pattern_count = s.matches(pattern).count();
151-
let is_length_ok = pattern_count * pattern.len() == s.len();
150+
let count = bytes.len() / pattern.len();
151+
if !(1..=3).contains(&count) {
152+
return None;
153+
}
152154

153-
match (pattern_count, is_length_ok) {
154-
(3, true) => Some(Self::Header),
155-
(2, true) => Some(Self::Body),
156-
(1, true) => Some(Self::Footer),
157-
_ => None,
155+
if bytes
156+
.chunks_exact(pattern.len())
157+
.all(|chunk| chunk == pattern)
158+
{
159+
match count {
160+
1 => Some(Self::Footer),
161+
2 => Some(Self::Body),
162+
3 => Some(Self::Header),
163+
_ => unreachable!(),
164+
}
165+
} else {
166+
None
158167
}
159168
}
160169
}
@@ -337,9 +346,21 @@ pub fn uu_app() -> Command {
337346
/// `nl` implements the main functionality for an individual buffer.
338347
fn nl<T: Read>(reader: &mut BufReader<T>, stats: &mut Stats, settings: &Settings) -> UResult<()> {
339348
let mut current_numbering_style = &settings.body_numbering;
349+
let mut line = Vec::new();
350+
351+
loop {
352+
line.clear();
353+
// reads up to and including b'\n'; returns 0 on EOF
354+
let n = reader
355+
.read_until(b'\n', &mut line)
356+
.map_err_context(|| translate!("nl-error-could-not-read-line"))?;
357+
if n == 0 {
358+
break;
359+
}
340360

341-
for line in reader.lines() {
342-
let line = line.map_err_context(|| translate!("nl-error-could-not-read-line"))?;
361+
if line.last().copied() == Some(b'\n') {
362+
line.pop();
363+
}
343364

344365
if line.is_empty() {
345366
stats.consecutive_empty_lines += 1;
@@ -386,11 +407,12 @@ fn nl<T: Read>(reader: &mut BufReader<T>, stats: &mut Stats, settings: &Settings
386407
));
387408
};
388409
println!(
389-
"{}{}{line}",
410+
"{}{}{}",
390411
settings
391412
.number_format
392413
.format(line_number, settings.number_width),
393414
settings.number_separator.to_string_lossy(),
415+
String::from_utf8_lossy(&line),
394416
);
395417
// update line number for the potential next line
396418
match line_number.checked_add(settings.line_increment) {
@@ -399,7 +421,7 @@ fn nl<T: Read>(reader: &mut BufReader<T>, stats: &mut Stats, settings: &Settings
399421
}
400422
} else {
401423
let spaces = " ".repeat(settings.number_width + 1);
402-
println!("{spaces}{line}");
424+
println!("{spaces}{}", String::from_utf8_lossy(&line));
403425
}
404426
}
405427
}

src/uucore/src/lib/mods/locale.rs

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -140,26 +140,20 @@ fn create_bundle(
140140
// Disable Unicode directional isolate characters
141141
bundle.set_use_isolating(false);
142142

143-
// Load common strings from uucore locales directory
144-
if let Some(common_dir) = find_uucore_locales_dir(locales_dir) {
145-
let common_locale_path = common_dir.join(format!("{locale}.ftl"));
146-
if let Ok(common_ftl) = fs::read_to_string(&common_locale_path) {
147-
if let Ok(common_resource) = FluentResource::try_new(common_ftl) {
148-
bundle.add_resource_overriding(common_resource);
149-
}
143+
let mut try_add_resource_from = |dir_opt: Option<std::path::PathBuf>| {
144+
if let Some(resource) = dir_opt
145+
.map(|dir| dir.join(format!("{locale}.ftl")))
146+
.and_then(|locale_path| fs::read_to_string(locale_path).ok())
147+
.and_then(|ftl| fluent_bundle::FluentResource::try_new(ftl).ok())
148+
{
149+
bundle.add_resource_overriding(resource);
150150
}
151-
}
151+
};
152152

153+
// Load common strings from uucore locales directory
154+
try_add_resource_from(find_uucore_locales_dir(locales_dir));
153155
// Then, try to load utility-specific strings from the utility's locale directory
154-
let util_locales_dir = get_locales_dir(util_name).ok();
155-
if let Some(util_dir) = util_locales_dir {
156-
let util_locale_path = util_dir.join(format!("{locale}.ftl"));
157-
if let Ok(util_ftl) = fs::read_to_string(&util_locale_path) {
158-
if let Ok(util_resource) = FluentResource::try_new(util_ftl) {
159-
bundle.add_resource_overriding(util_resource);
160-
}
161-
}
162-
}
156+
try_add_resource_from(get_locales_dir(util_name).ok());
163157

164158
// If we have at least one resource, return the bundle
165159
if bundle.has_message("common-error") || bundle.has_message(&format!("{util_name}-about")) {

tests/by-util/test_cut.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,20 @@ fn test_output_delimiter_with_adjacent_ranges() {
374374
.stdout_only("ab:cd\n");
375375
}
376376

377+
#[test]
378+
fn test_emoji_delim() {
379+
new_ucmd!()
380+
.args(&["-d🗿", "-f1"])
381+
.pipe_in("💐🗿🌹\n")
382+
.succeeds()
383+
.stdout_only("💐\n");
384+
new_ucmd!()
385+
.args(&["-d🗿", "-f2"])
386+
.pipe_in("💐🗿🌹\n")
387+
.succeeds()
388+
.stdout_only("🌹\n");
389+
}
390+
377391
#[cfg(target_os = "linux")]
378392
#[test]
379393
fn test_failed_write_is_reported() {

tests/by-util/test_date.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ fn test_invalid_arg() {
1919

2020
#[test]
2121
fn test_date_email() {
22-
for param in ["--rfc-email", "--rfc-e", "-R"] {
22+
for param in ["--rfc-email", "--rfc-e", "-R", "--rfc-2822", "--rfc-822"] {
2323
new_ucmd!().arg(param).succeeds();
2424
}
2525
}

tests/by-util/test_join.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -566,3 +566,17 @@ fn test_join_non_utf8_paths() {
566566
.stdout_only("a 1 2\n");
567567
}
568568
}
569+
570+
#[test]
571+
fn join_emoji_delim_inner_key() {
572+
let ts = TestScenario::new(util_name!());
573+
let at = &ts.fixtures;
574+
575+
at.write("file1", "a🗿b\n");
576+
at.write("file2", "u🗿b\n");
577+
578+
ts.ucmd()
579+
.args(&["-t🗿", "-1", "2", "-2", "2", "file1", "file2"])
580+
.succeeds()
581+
.stdout_only("b🗿a🗿u\n");
582+
}

tests/by-util/test_ls.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6147,3 +6147,19 @@ fn test_acl_display_symlink() {
61476147
.succeeds()
61486148
.stdout_matches(&re_with_acl);
61496149
}
6150+
6151+
#[test]
6152+
fn ls_emoji_alignment() {
6153+
let scene = TestScenario::new(util_name!());
6154+
let at = &scene.fixtures;
6155+
6156+
at.touch("a");
6157+
at.touch("💐");
6158+
at.touch("漢");
6159+
scene
6160+
.ucmd()
6161+
.succeeds()
6162+
.stdout_contains("a")
6163+
.stdout_contains("💐")
6164+
.stdout_contains("漢");
6165+
}

0 commit comments

Comments
 (0)