mirror of
https://github.com/uutils/coreutils
synced 2024-12-14 15:22:38 +00:00
nl: fix zero padding of negative line numbers
This commit is contained in:
parent
e15e03a2bf
commit
d7d2ad52db
2 changed files with 48 additions and 53 deletions
|
@ -9,7 +9,6 @@
|
||||||
use clap::{crate_version, Arg, ArgAction, Command};
|
use clap::{crate_version, Arg, ArgAction, Command};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{stdin, BufRead, BufReader, Read};
|
use std::io::{stdin, BufRead, BufReader, Read};
|
||||||
use std::iter::repeat;
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use uucore::error::{FromIo, UResult, USimpleError};
|
use uucore::error::{FromIo, UResult, USimpleError};
|
||||||
use uucore::{format_usage, help_about, help_section, help_usage};
|
use uucore::{format_usage, help_about, help_section, help_usage};
|
||||||
|
@ -95,6 +94,19 @@ impl<T: AsRef<str>> From<T> for NumberFormat {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl NumberFormat {
|
||||||
|
// Turns a line number into a `String` with at least `min_width` chars,
|
||||||
|
// formatted according to the `NumberFormat`s variant.
|
||||||
|
fn format(&self, number: i64, min_width: usize) -> String {
|
||||||
|
match self {
|
||||||
|
Self::Left => format!("{number:<min_width$}"),
|
||||||
|
Self::Right => format!("{number:>min_width$}"),
|
||||||
|
Self::RightZero if number < 0 => format!("-{0:0>1$}", number.abs(), min_width - 1),
|
||||||
|
Self::RightZero => format!("{number:0>min_width$}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub mod options {
|
pub mod options {
|
||||||
pub const HELP: &str = "help";
|
pub const HELP: &str = "help";
|
||||||
pub const FILE: &str = "file";
|
pub const FILE: &str = "file";
|
||||||
|
@ -263,13 +275,7 @@ pub fn uu_app() -> Command {
|
||||||
fn nl<T: Read>(reader: &mut BufReader<T>, settings: &Settings) -> UResult<()> {
|
fn nl<T: Read>(reader: &mut BufReader<T>, settings: &Settings) -> UResult<()> {
|
||||||
let regexp: regex::Regex = regex::Regex::new(r".?").unwrap();
|
let regexp: regex::Regex = regex::Regex::new(r".?").unwrap();
|
||||||
let mut line_no = settings.starting_line_number;
|
let mut line_no = settings.starting_line_number;
|
||||||
let mut line_no_width = line_no.len();
|
|
||||||
let line_no_width_initial = line_no_width;
|
|
||||||
let mut empty_line_count: u64 = 0;
|
let mut empty_line_count: u64 = 0;
|
||||||
let fill_char = match settings.number_format {
|
|
||||||
NumberFormat::RightZero => '0',
|
|
||||||
_ => ' ',
|
|
||||||
};
|
|
||||||
// Initially, we use the body's line counting settings
|
// Initially, we use the body's line counting settings
|
||||||
let mut regex_filter = match settings.body_numbering {
|
let mut regex_filter = match settings.body_numbering {
|
||||||
NumberingStyle::NumberForRegularExpression(ref re) => re,
|
NumberingStyle::NumberForRegularExpression(ref re) => re,
|
||||||
|
@ -322,10 +328,9 @@ fn nl<T: Read>(reader: &mut BufReader<T>, settings: &Settings) -> UResult<()> {
|
||||||
match *match matched_groups {
|
match *match matched_groups {
|
||||||
3 => {
|
3 => {
|
||||||
// This is a header, so we may need to reset the
|
// This is a header, so we may need to reset the
|
||||||
// line number and the line width
|
// line number
|
||||||
if settings.renumber {
|
if settings.renumber {
|
||||||
line_no = settings.starting_line_number;
|
line_no = settings.starting_line_number;
|
||||||
line_no_width = line_no_width_initial;
|
|
||||||
}
|
}
|
||||||
&settings.header_numbering
|
&settings.header_numbering
|
||||||
}
|
}
|
||||||
|
@ -375,26 +380,17 @@ fn nl<T: Read>(reader: &mut BufReader<T>, settings: &Settings) -> UResult<()> {
|
||||||
// way, start counting empties from zero once more.
|
// way, start counting empties from zero once more.
|
||||||
empty_line_count = 0;
|
empty_line_count = 0;
|
||||||
// A line number is to be printed.
|
// A line number is to be printed.
|
||||||
let w = if settings.number_width > line_no_width {
|
println!(
|
||||||
settings.number_width - line_no_width
|
"{}{}{}",
|
||||||
} else {
|
settings
|
||||||
0
|
.number_format
|
||||||
};
|
.format(line_no, settings.number_width),
|
||||||
let fill: String = repeat(fill_char).take(w).collect();
|
settings.number_separator,
|
||||||
match settings.number_format {
|
line
|
||||||
NumberFormat::Left => println!(
|
);
|
||||||
"{1}{0}{2}{3}",
|
// Now update the line number for the (potential) next
|
||||||
fill, line_no, settings.number_separator, line
|
|
||||||
),
|
|
||||||
_ => println!(
|
|
||||||
"{0}{1}{2}{3}",
|
|
||||||
fill, line_no, settings.number_separator, line
|
|
||||||
),
|
|
||||||
}
|
|
||||||
// Now update the variables for the (potential) next
|
|
||||||
// line.
|
// line.
|
||||||
line_no += settings.line_increment;
|
line_no += settings.line_increment;
|
||||||
line_no_width = line_no.len();
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -415,38 +411,25 @@ fn pass_all(_: &str, _: ®ex::Regex) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
trait Length {
|
|
||||||
fn len(&self) -> usize;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Length for i64 {
|
|
||||||
// Returns the length in `char`s.
|
|
||||||
fn len(&self) -> usize {
|
|
||||||
if *self == 0 {
|
|
||||||
return 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
let sign_len = if *self < 0 { 1 } else { 0 };
|
|
||||||
(0..).take_while(|i| 10i64.pow(*i) <= self.abs()).count() + sign_len
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_len() {
|
fn test_format() {
|
||||||
assert_eq!((-1).len(), 2);
|
assert_eq!(NumberFormat::Left.format(12, 1), "12");
|
||||||
assert_eq!((-10).len(), 3);
|
assert_eq!(NumberFormat::Left.format(-12, 1), "-12");
|
||||||
assert_eq!((-100).len(), 4);
|
assert_eq!(NumberFormat::Left.format(12, 4), "12 ");
|
||||||
assert_eq!((-1000).len(), 5);
|
assert_eq!(NumberFormat::Left.format(-12, 4), "-12 ");
|
||||||
|
|
||||||
assert_eq!(0.len(), 1);
|
assert_eq!(NumberFormat::Right.format(12, 1), "12");
|
||||||
|
assert_eq!(NumberFormat::Right.format(-12, 1), "-12");
|
||||||
|
assert_eq!(NumberFormat::Right.format(12, 4), " 12");
|
||||||
|
assert_eq!(NumberFormat::Right.format(-12, 4), " -12");
|
||||||
|
|
||||||
assert_eq!(1.len(), 1);
|
assert_eq!(NumberFormat::RightZero.format(12, 1), "12");
|
||||||
assert_eq!(10.len(), 2);
|
assert_eq!(NumberFormat::RightZero.format(-12, 1), "-12");
|
||||||
assert_eq!(100.len(), 3);
|
assert_eq!(NumberFormat::RightZero.format(12, 4), "0012");
|
||||||
assert_eq!(1000.len(), 4);
|
assert_eq!(NumberFormat::RightZero.format(-12, 4), "-012");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,6 +114,18 @@ fn test_number_format_rz() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_number_format_rz_with_negative_line_number() {
|
||||||
|
for arg in ["-nrz", "--number-format=rz"] {
|
||||||
|
new_ucmd!()
|
||||||
|
.arg(arg)
|
||||||
|
.arg("-v-12")
|
||||||
|
.pipe_in("test")
|
||||||
|
.succeeds()
|
||||||
|
.stdout_is("-00012\ttest\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_invalid_number_format() {
|
fn test_invalid_number_format() {
|
||||||
for arg in ["-ninvalid", "--number-format=invalid"] {
|
for arg in ["-ninvalid", "--number-format=invalid"] {
|
||||||
|
|
Loading…
Reference in a new issue