diff options
author | Dan Davison <dandavison7@gmail.com> | 2021-11-11 10:49:23 -0500 |
---|---|---|
committer | Dan Davison <dandavison7@gmail.com> | 2021-11-15 21:01:32 -0500 |
commit | 57cabdcb6502afe5a05f9d53f3a6bcbf60a7ff5f (patch) | |
tree | ff9b9cb7b60a91513c561553fcbe237ee507ccc7 | |
parent | 9a929e1ff3cc07c166e8719d1dc5dabc650ec131 (diff) |
Support precision specifier in run-time format strings
-rw-r--r-- | src/features/line_numbers.rs | 31 | ||||
-rw-r--r-- | src/format.rs | 51 |
2 files changed, 73 insertions, 9 deletions
diff --git a/src/features/line_numbers.rs b/src/features/line_numbers.rs index 0cc4ebfb..7082d05d 100644 --- a/src/features/line_numbers.rs +++ b/src/features/line_numbers.rs @@ -266,14 +266,22 @@ fn format_and_paint_line_number_field<'a>( .as_ref() .unwrap_or(&Align::Center); match placeholder.placeholder { - Some(Placeholder::NumberMinus) => ansi_strings.push(styles[Minus].paint( - format_line_number(line_numbers[Minus], alignment_spec, width, None, config), - )), + Some(Placeholder::NumberMinus) => { + ansi_strings.push(styles[Minus].paint(format_line_number( + line_numbers[Minus], + alignment_spec, + width, + placeholder.precision, + None, + config, + ))) + } Some(Placeholder::NumberPlus) => { ansi_strings.push(styles[Plus].paint(format_line_number( line_numbers[Plus], alignment_spec, width, + placeholder.precision, Some(plus_file), config, ))) @@ -292,10 +300,11 @@ fn format_line_number( line_number: Option<usize>, alignment: &Align, width: usize, + precision: Option<usize>, plus_file: Option<&str>, config: &config::Config, ) -> String { - let pad = |n| format::pad(n, width, alignment); + let pad = |n| format::pad(n, width, alignment, precision); match (line_number, config.hyperlinks, plus_file) { (None, _, _) => pad(""), (Some(n), true, Some(file)) => { @@ -332,6 +341,7 @@ pub mod tests { placeholder: Some(Placeholder::NumberMinus), alignment_spec: None, width: None, + precision: None, suffix: "".into(), prefix_len: 0, suffix_len: 0, @@ -348,6 +358,7 @@ pub mod tests { placeholder: Some(Placeholder::NumberPlus), alignment_spec: None, width: Some(4), + precision: None, suffix: "".into(), prefix_len: 0, suffix_len: 0, @@ -364,6 +375,7 @@ pub mod tests { placeholder: Some(Placeholder::NumberPlus), alignment_spec: Some(Align::Right), width: Some(4), + precision: None, suffix: "".into(), prefix_len: 0, suffix_len: 0, @@ -380,6 +392,7 @@ pub mod tests { placeholder: Some(Placeholder::NumberPlus), alignment_spec: Some(Align::Right), width: Some(4), + precision: None, suffix: "".into(), prefix_len: 0, suffix_len: 0, @@ -396,6 +409,7 @@ pub mod tests { placeholder: Some(Placeholder::NumberPlus), alignment_spec: Some(Align::Right), width: Some(4), + precision: None, suffix: "@@".into(), prefix_len: 2, suffix_len: 2, @@ -413,6 +427,7 @@ pub mod tests { placeholder: Some(Placeholder::NumberMinus), alignment_spec: Some(Align::Left), width: Some(3), + precision: None, suffix: "@@---{np:_>4}**".into(), prefix_len: 2, suffix_len: 15, @@ -422,6 +437,7 @@ pub mod tests { placeholder: Some(Placeholder::NumberPlus), alignment_spec: Some(Align::Right), width: Some(4), + precision: None, suffix: "**".into(), prefix_len: 5, suffix_len: 2, @@ -439,6 +455,7 @@ pub mod tests { placeholder: None, alignment_spec: None, width: None, + precision: None, suffix: "__@@---**".into(), prefix_len: 0, suffix_len: 9, @@ -455,12 +472,14 @@ pub mod tests { placeholder: Some(Placeholder::NumberMinus), alignment_spec: Some(Align::Left), width: Some(4), + precision: None, suffix: "|".into(), prefix_len: 2, suffix_len: 1, }] ); } + #[test] fn test_line_number_format_odd_width_two() { assert_eq!( @@ -475,6 +494,7 @@ pub mod tests { placeholder: Some(Placeholder::NumberMinus), alignment_spec: Some(Align::Left), width: Some(4), + precision: None, suffix: "+{np:<4}|".into(), prefix_len: 2, suffix_len: 9, @@ -484,6 +504,7 @@ pub mod tests { placeholder: Some(Placeholder::NumberPlus), alignment_spec: Some(Align::Left), width: Some(4), + precision: None, suffix: "|".into(), prefix_len: 1, suffix_len: 1, @@ -500,6 +521,7 @@ pub mod tests { placeholder: None, alignment_spec: None, width: None, + precision: None, suffix: "|++|".into(), prefix_len: 1, suffix_len: 4, @@ -522,6 +544,7 @@ pub mod tests { placeholder: Some(Placeholder::NumberMinus), alignment_spec: None, width: None, + precision: None, suffix: long.into(), suffix_len: long.len(), },] diff --git a/src/format.rs b/src/format.rs index bbc6e9f5..ab0e856f 100644 --- a/src/format.rs +++ b/src/format.rs @@ -55,6 +55,7 @@ pub struct FormatStringPlaceholderData<'a> { pub placeholder: Option<Placeholder<'a>>, pub alignment_spec: Option<Align>, pub width: Option<usize>, + pub precision: Option<usize>, pub suffix: SmolStr, pub suffix_len: usize, } @@ -90,6 +91,9 @@ pub fn make_placeholder_regex(labels: &[&str]) -> Regex { ([<^>]) # 3: Alignment spec )? # (\d+) # 4: Width + (?: # Start optional precision (non-capturing) + \.(\d+) # 5: Precision + )? # )? # \}} ", @@ -134,6 +138,11 @@ pub fn parse_line_number_format<'a>( .parse() .unwrap_or_else(|_| panic!("Invalid width in format string: {}", format_string)) }), + precision: captures.get(5).map(|m| { + m.as_str().parse().unwrap_or_else(|_| { + panic!("Invalid precision in format string: {}", format_string) + }) + }), suffix, suffix_len, }); @@ -156,10 +165,42 @@ pub fn parse_line_number_format<'a>( format_data } -pub fn pad(s: &str, width: usize, alignment: &Align) -> String { - match alignment { - Align::Left => format!("{0:<1$}", s, width), - Align::Center => format!("{0:^1$}", s, width), - Align::Right => format!("{0:>1$}", s, width), +// Note that in this case of a string `s`, `precision` means "max width". +// See https://doc.rust-lang.org/std/fmt/index.html +pub fn pad(s: &str, width: usize, alignment: &Align, precision: Option<usize>) -> String { + match precision { + None => match alignment { + Align::Left => format!("{0:<1$}", s, width), + Align::Center => format!("{0:^1$}", s, width), + Align::Right => format!("{0:>1$}", s, width), + }, + Some(precision) => match alignment { + Align::Left => format!("{0:<1$.2$}", s, width, precision), + Align::Center => format!("{0:^1$.2$}", s, width, precision), + Align::Right => format!("{0:>1$.2$}", s, width, precision), + }, + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_placeholder_regex() { + let regex = make_placeholder_regex(&["placeholder"]); + assert_eq!( + parse_line_number_format("prefix {placeholder:<15.14} suffix", ®ex, false), + vec![FormatStringPlaceholderData { + prefix: "prefix ".into(), + placeholder: Some(Placeholder::Str("placeholder")), + alignment_spec: Some(Align::Left), + width: Some(15), + precision: Some(14), + suffix: " suffix".into(), + prefix_len: 7, + suffix_len: 7, + }] + ); } } |