mirror of
https://github.com/uutils/coreutils.git
synced 2026-06-10 15:48:22 -07:00
Add support for -c short option and fix character mode tab handling (#10530)
This commit adds the `-c` short option for the `--characters` flag and fixes tab handling in character mode. Previously, tabs were only handled in column mode, but now they are properly processed in both character and column modes. The character mode now correctly advances to the next tab stop, handles carriage returns, and backspace characters. Tests have been added to verify the new functionality.
This commit is contained in:
+28
-5
@@ -98,6 +98,7 @@ pub fn uu_app() -> Command {
|
||||
.arg(
|
||||
Arg::new(options::CHARACTERS)
|
||||
.long(options::CHARACTERS)
|
||||
.short('c')
|
||||
.help(translate!("fold-characters-help"))
|
||||
.conflicts_with(options::BYTES)
|
||||
.action(ArgAction::SetTrue),
|
||||
@@ -260,9 +261,31 @@ fn next_tab_stop(col_count: usize) -> usize {
|
||||
|
||||
fn compute_col_count(buffer: &[u8], mode: WidthMode) -> usize {
|
||||
match mode {
|
||||
WidthMode::Characters => std::str::from_utf8(buffer)
|
||||
.map(|s| s.chars().count())
|
||||
.unwrap_or(buffer.len()),
|
||||
WidthMode::Characters => {
|
||||
if let Ok(s) = std::str::from_utf8(buffer) {
|
||||
let mut width = 0;
|
||||
for ch in s.chars() {
|
||||
match ch {
|
||||
'\r' => width = 0,
|
||||
'\t' => width = next_tab_stop(width),
|
||||
'\x08' => width = width.saturating_sub(1),
|
||||
_ => width += 1,
|
||||
}
|
||||
}
|
||||
width
|
||||
} else {
|
||||
let mut width = 0;
|
||||
for &byte in buffer {
|
||||
match byte {
|
||||
CR => width = 0,
|
||||
TAB => width = next_tab_stop(width),
|
||||
0x08 => width = width.saturating_sub(1),
|
||||
_ => width += 1,
|
||||
}
|
||||
}
|
||||
width
|
||||
}
|
||||
}
|
||||
WidthMode::Columns => {
|
||||
if let Ok(s) = std::str::from_utf8(buffer) {
|
||||
let mut width = 0;
|
||||
@@ -382,7 +405,7 @@ fn process_ascii_line<W: Write>(line: &[u8], ctx: &mut FoldContext<'_, W>) -> UR
|
||||
*ctx.col_count = ctx.col_count.saturating_sub(1);
|
||||
idx += 1;
|
||||
}
|
||||
TAB if ctx.mode == WidthMode::Columns => {
|
||||
TAB => {
|
||||
loop {
|
||||
let next_stop = next_tab_stop(*ctx.col_count);
|
||||
if next_stop > ctx.width && !ctx.output.is_empty() {
|
||||
@@ -523,7 +546,7 @@ fn process_utf8_chars<W: Write>(line: &str, ctx: &mut FoldContext<'_, W>) -> URe
|
||||
continue;
|
||||
}
|
||||
|
||||
if ctx.mode == WidthMode::Columns && ch == '\t' {
|
||||
if ch == '\t' {
|
||||
loop {
|
||||
let next_stop = next_tab_stop(*ctx.col_count);
|
||||
if next_stop > ctx.width && !ctx.output.is_empty() {
|
||||
|
||||
@@ -65,6 +65,15 @@ fn test_wide_characters_with_characters_option() {
|
||||
.stdout_is("\u{B250}\u{B250}\u{B250}\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_wide_characters_with_characters_short_option() {
|
||||
new_ucmd!()
|
||||
.args(&["-c", "-w", "5"])
|
||||
.pipe_in("\u{B250}\u{B250}\u{B250}\n")
|
||||
.succeeds()
|
||||
.stdout_is("\u{B250}\u{B250}\u{B250}\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_multiple_wide_characters_in_column_mode() {
|
||||
let wide = '\u{FF1A}';
|
||||
@@ -540,6 +549,24 @@ fn test_fold_after_tab() {
|
||||
.stdout_is("a\tbb\nb\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fold_characters_tab_advances_to_next_tab_stop() {
|
||||
new_ucmd!()
|
||||
.args(&["-c", "-w", "4"])
|
||||
.pipe_in("ab\tcd\n")
|
||||
.succeeds()
|
||||
.stdout_is("ab\n\t\ncd\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fold_characters_tab_with_non_ascii() {
|
||||
new_ucmd!()
|
||||
.args(&["-c", "-w", "2"])
|
||||
.pipe_in("\u{00E9}\tb\n")
|
||||
.succeeds()
|
||||
.stdout_is("\u{00E9}\n\t\nb\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fold_at_tab_as_word_boundary() {
|
||||
new_ucmd!()
|
||||
|
||||
Reference in New Issue
Block a user