summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Davison <dandavison7@gmail.com>2021-08-28 20:20:41 -0400
committerDan Davison <dandavison7@gmail.com>2021-08-28 21:36:57 -0400
commit6afd3705d801f03772e5d74b7e137edc169d5e8e (patch)
tree5db1a59b35bcaf8a83ef60d1b52e22b72a023534
parent0b8f14503c5bd124554e6fb02f41a30e410a61cd (diff)
Refactor: module for working with format strings
-rw-r--r--src/features/line_numbers.rs132
-rw-r--r--src/format.rs75
-rw-r--r--src/main.rs1
3 files changed, 114 insertions, 94 deletions
diff --git a/src/features/line_numbers.rs b/src/features/line_numbers.rs
index f9189841..c464f8c7 100644
--- a/src/features/line_numbers.rs
+++ b/src/features/line_numbers.rs
@@ -8,6 +8,7 @@ use crate::delta::State;
use crate::features::hyperlinks;
use crate::features::side_by_side;
use crate::features::OptionValueFunction;
+use crate::format;
use crate::style::Style;
pub fn make_feature() -> Vec<(String, OptionValueFunction)> {
@@ -134,28 +135,13 @@ pub fn format_and_paint_line_numbers<'a>(
}
lazy_static! {
- static ref LINE_NUMBERS_PLACEHOLDER_REGEX: Regex = Regex::new(
- r"(?x)
-\{
-(nm|np) # 1: Literal nm or np
-(?: # Start optional format spec (non-capturing)
- : # Literal colon
- (?: # Start optional fill/alignment spec (non-capturing)
- ([^<^>])? # 2: Optional fill character (ignored)
- ([<^>]) # 3: Alignment spec
- )? #
- (\d+) # 4: Width
-)? #
-\}
-"
- )
- .unwrap();
+ static ref LINE_NUMBERS_PLACEHOLDER_REGEX: Regex = format::make_placeholder_regex(&["nm", "np"]);
}
#[derive(Default)]
pub struct LineNumbersData<'a> {
- pub left_format_data: LineNumberFormatData<'a>,
- pub right_format_data: LineNumberFormatData<'a>,
+ pub left_format_data: format::FormatStringData<'a>,
+ pub right_format_data: format::FormatStringData<'a>,
pub hunk_minus_line_number: usize,
pub hunk_plus_line_number: usize,
pub hunk_max_line_number_width: usize,
@@ -164,22 +150,17 @@ pub struct LineNumbersData<'a> {
// Although it's probably unusual, a single format string can contain multiple placeholders. E.g.
// line-numbers-right-format = "{nm} {np}|"
-pub type LineNumberFormatData<'a> = Vec<LineNumberPlaceholderData<'a>>;
-
-#[derive(Debug, Default, PartialEq)]
-pub struct LineNumberPlaceholderData<'a> {
- pub prefix: &'a str,
- pub placeholder: Option<&'a str>,
- pub alignment_spec: Option<&'a str>,
- pub width: Option<usize>,
- pub suffix: &'a str,
-}
-
impl<'a> LineNumbersData<'a> {
pub fn from_format_strings(left_format: &'a str, right_format: &'a str) -> LineNumbersData<'a> {
Self {
- left_format_data: parse_line_number_format(left_format),
- right_format_data: parse_line_number_format(right_format),
+ left_format_data: format::parse_line_number_format(
+ left_format,
+ &*LINE_NUMBERS_PLACEHOLDER_REGEX,
+ ),
+ right_format_data: format::parse_line_number_format(
+ right_format,
+ &*LINE_NUMBERS_PLACEHOLDER_REGEX,
+ ),
hunk_minus_line_number: 0,
hunk_plus_line_number: 0,
hunk_max_line_number_width: 0,
@@ -200,41 +181,9 @@ impl<'a> LineNumbersData<'a> {
}
}
-fn parse_line_number_format(format_string: &str) -> LineNumberFormatData {
- let mut format_data = Vec::new();
- let mut offset = 0;
-
- for captures in LINE_NUMBERS_PLACEHOLDER_REGEX.captures_iter(format_string) {
- let _match = captures.get(0).unwrap();
- format_data.push(LineNumberPlaceholderData {
- prefix: &format_string[offset.._match.start()],
- placeholder: captures.get(1).map(|m| m.as_str()),
- alignment_spec: captures.get(3).map(|m| m.as_str()),
- width: captures.get(4).map(|m| {
- m.as_str()
- .parse()
- .unwrap_or_else(|_| panic!("Invalid width in format string: {}", format_string))
- }),
- suffix: &format_string[_match.end()..],
- });
- offset = _match.end();
- }
- if offset == 0 {
- // No placeholders
- format_data.push(LineNumberPlaceholderData {
- prefix: &format_string[..0],
- placeholder: None,
- alignment_spec: None,
- width: None,
- suffix: &format_string[0..],
- })
- }
- format_data
-}
-
#[allow(clippy::too_many_arguments)]
fn format_and_paint_line_number_field<'a>(
- format_data: &[LineNumberPlaceholderData<'a>],
+ format_data: &[format::FormatStringPlaceholderData<'a>],
style: &Style,
minus_number: Option<usize>,
plus_number: Option<usize>,
@@ -288,22 +237,14 @@ fn format_line_number(
plus_file: Option<&str>,
config: &config::Config,
) -> String {
- let format_n = |n| match alignment {
- "<" => format!("{0:<1$}", n, width),
- "^" => format!("{0:^1$}", n, width),
- ">" => format!("{0:>1$}", n, width),
- _ => unreachable!(),
- };
+ let pad = |n| format::pad(n, width, alignment);
match (line_number, config.hyperlinks, plus_file) {
- (None, _, _) => format_n(""),
- (Some(n), true, Some(file)) => hyperlinks::format_osc8_file_hyperlink(
- file,
- line_number,
- &format_n(&n.to_string()),
- config,
- )
- .to_string(),
- (Some(n), _, _) => format_n(&n.to_string()),
+ (None, _, _) => pad(""),
+ (Some(n), true, Some(file)) => {
+ hyperlinks::format_osc8_file_hyperlink(file, line_number, &pad(&n.to_string()), config)
+ .to_string()
+ }
+ (Some(n), _, _) => pad(&n.to_string()),
}
}
@@ -319,8 +260,8 @@ pub mod tests {
#[test]
fn test_line_number_format_regex_1() {
assert_eq!(
- parse_line_number_format("{nm}"),
- vec![LineNumberPlaceholderData {
+ format::parse_line_number_format("{nm}", &LINE_NUMBERS_PLACEHOLDER_REGEX),
+ vec![format::FormatStringPlaceholderData {
prefix: "",
placeholder: Some("nm"),
alignment_spec: None,
@@ -333,8 +274,8 @@ pub mod tests {
#[test]
fn test_line_number_format_regex_2() {
assert_eq!(
- parse_line_number_format("{np:4}"),
- vec![LineNumberPlaceholderData {
+ format::parse_line_number_format("{np:4}", &LINE_NUMBERS_PLACEHOLDER_REGEX),
+ vec![format::FormatStringPlaceholderData {
prefix: "",
placeholder: Some("np"),
alignment_spec: None,
@@ -347,8 +288,8 @@ pub mod tests {
#[test]
fn test_line_number_format_regex_3() {
assert_eq!(
- parse_line_number_format("{np:>4}"),
- vec![LineNumberPlaceholderData {
+ format::parse_line_number_format("{np:>4}", &LINE_NUMBERS_PLACEHOLDER_REGEX),
+ vec![format::FormatStringPlaceholderData {
prefix: "",
placeholder: Some("np"),
alignment_spec: Some(">"),
@@ -361,8 +302,8 @@ pub mod tests {
#[test]
fn test_line_number_format_regex_4() {
assert_eq!(
- parse_line_number_format("{np:_>4}"),
- vec![LineNumberPlaceholderData {
+ format::parse_line_number_format("{np:_>4}", &LINE_NUMBERS_PLACEHOLDER_REGEX),
+ vec![format::FormatStringPlaceholderData {
prefix: "",
placeholder: Some("np"),
alignment_spec: Some(">"),
@@ -375,8 +316,8 @@ pub mod tests {
#[test]
fn test_line_number_format_regex_5() {
assert_eq!(
- parse_line_number_format("__{np:_>4}@@"),
- vec![LineNumberPlaceholderData {
+ format::parse_line_number_format("__{np:_>4}@@", &LINE_NUMBERS_PLACEHOLDER_REGEX),
+ vec![format::FormatStringPlaceholderData {
prefix: "__",
placeholder: Some("np"),
alignment_spec: Some(">"),
@@ -389,16 +330,19 @@ pub mod tests {
#[test]
fn test_line_number_format_regex_6() {
assert_eq!(
- parse_line_number_format("__{nm:<3}@@---{np:_>4}**"),
+ format::parse_line_number_format(
+ "__{nm:<3}@@---{np:_>4}**",
+ &LINE_NUMBERS_PLACEHOLDER_REGEX
+ ),
vec![
- LineNumberPlaceholderData {
+ format::FormatStringPlaceholderData {
prefix: "__",
placeholder: Some("nm"),
alignment_spec: Some("<"),
width: Some(3),
suffix: "@@---{np:_>4}**",
},
- LineNumberPlaceholderData {
+ format::FormatStringPlaceholderData {
prefix: "@@---",
placeholder: Some("np"),
alignment_spec: Some(">"),
@@ -412,8 +356,8 @@ pub mod tests {
#[test]
fn test_line_number_format_regex_7() {
assert_eq!(
- parse_line_number_format("__@@---**"),
- vec![LineNumberPlaceholderData {
+ format::parse_line_number_format("__@@---**", &LINE_NUMBERS_PLACEHOLDER_REGEX),
+ vec![format::FormatStringPlaceholderData {
prefix: "",
placeholder: None,
alignment_spec: None,
diff --git a/src/format.rs b/src/format.rs
index 8b137891..67d1f509 100644
--- a/src/format.rs
+++ b/src/format.rs
@@ -1 +1,76 @@
+use regex::Regex;
+#[derive(Debug, Default, PartialEq)]
+pub struct FormatStringPlaceholderData<'a> {
+ pub prefix: &'a str,
+ pub placeholder: Option<&'a str>,
+ pub alignment_spec: Option<&'a str>,
+ pub width: Option<usize>,
+ pub suffix: &'a str,
+}
+
+pub type FormatStringData<'a> = Vec<FormatStringPlaceholderData<'a>>;
+
+pub fn make_placeholder_regex(labels: &[&str]) -> Regex {
+ Regex::new(&format!(
+ r"(?x)
+ \{{
+ ({}) # 1: Placeholder labels
+ (?: # Start optional format spec (non-capturing)
+ : # Literal colon
+ (?: # Start optional fill/alignment spec (non-capturing)
+ ([^<^>])? # 2: Optional fill character (ignored)
+ ([<^>]) # 3: Alignment spec
+ )? #
+ (\d+) # 4: Width
+ )? #
+ \}}
+ ",
+ labels.join("|")
+ ))
+ .unwrap()
+}
+
+pub fn parse_line_number_format<'a>(
+ format_string: &'a str,
+ placeholder_regex: &Regex,
+) -> FormatStringData<'a> {
+ let mut format_data = Vec::new();
+ let mut offset = 0;
+
+ for captures in placeholder_regex.captures_iter(format_string) {
+ let _match = captures.get(0).unwrap();
+ format_data.push(FormatStringPlaceholderData {
+ prefix: &format_string[offset.._match.start()],
+ placeholder: captures.get(1).map(|m| m.as_str()),
+ alignment_spec: captures.get(3).map(|m| m.as_str()),
+ width: captures.get(4).map(|m| {
+ m.as_str()
+ .parse()
+ .unwrap_or_else(|_| panic!("Invalid width in format string: {}", format_string))
+ }),
+ suffix: &format_string[_match.end()..],
+ });
+ offset = _match.end();
+ }
+ if offset == 0 {
+ // No placeholders
+ format_data.push(FormatStringPlaceholderData {
+ prefix: &format_string[..0],
+ placeholder: None,
+ alignment_spec: None,
+ width: None,
+ suffix: &format_string[0..],
+ })
+ }
+ format_data
+}
+
+pub fn pad(s: &str, width: usize, alignment: &str) -> String {
+ match alignment {
+ "<" => format!("{0:<1$}", s, width),
+ "^" => format!("{0:^1$}", s, width),
+ ">" => format!("{0:>1$}", s, width),
+ _ => unreachable!(),
+ }
+}
diff --git a/src/main.rs b/src/main.rs
index 07e87e7d..ccf82661 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -15,6 +15,7 @@ mod draw;
mod edits;
mod env;
mod features;
+mod format;
mod git_config;
mod hunk_header;
mod options;