From ac2469546e91015f172d9b75207121ad06be11fd Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Mon, 27 Dec 2021 13:20:54 -0800 Subject: [PATCH 1/4] Make `StrLitKind` crate public ...and add some serialization methods. --- src/lib.rs | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 2ecd498..6452916 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -238,6 +238,40 @@ impl fmt::Display for Position { } } +#[derive(Clone, Copy)] +enum StrLitKind { + Normal, + Raw(usize), +} + +impl StrLitKind { + fn write_start(self, w: &mut impl std::fmt::Write) -> std::fmt::Result { + match self { + Self::Normal => write!(w, "\""), + Self::Raw(n) => { + write!(w, "r")?; + for _ in 0..n { + write!(w, "#")?; + } + write!(w, "\"") + } + } + } + + fn write_end(self, w: &mut impl std::fmt::Write) -> std::fmt::Result { + match self { + Self::Normal => write!(w, "\""), + Self::Raw(n) => { + write!(w, "\"")?; + for _ in 0..n { + write!(w, "#")?; + } + Ok(()) + } + } + } +} + impl Expect { /// Checks if this expect is equal to `actual`. pub fn assert_eq(&self, actual: &str) { @@ -324,11 +358,6 @@ fn locate_end(lit_to_eof: &str) -> Option { /// (either a quote or a hash). fn find_str_lit_len(str_lit_to_eof: &str) -> Option { use StrLitKind::*; - #[derive(Clone, Copy)] - enum StrLitKind { - Normal, - Raw(usize), - } fn try_find_n_hashes( s: &mut impl Iterator, From e3619a907cce18f71a1374139a0e92d55dd59e6f Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Mon, 27 Dec 2021 13:22:20 -0800 Subject: [PATCH 2/4] Use the minimal number of escapes when updating tests --- src/lib.rs | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 6452916..4497929 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -566,25 +566,31 @@ impl Patchwork { } } -fn format_patch(desired_indent: Option, patch: &str) -> String { - let mut max_hashes = 0; - let mut cur_hashes = 0; - for byte in patch.bytes() { - if byte != b'#' { - cur_hashes = 0; - continue; - } - cur_hashes += 1; - max_hashes = max_hashes.max(cur_hashes); +fn lit_kind_for_patch(patch: &str) -> StrLitKind { + let has_dquote = patch.chars().any(|c| c == '"'); + if !has_dquote { + let has_bslash_or_newline = patch.chars().any(|c| matches!(c, '\\' | '\n')); + return if has_bslash_or_newline { + StrLitKind::Raw(1) + } else { + StrLitKind::Normal + }; } - let hashes = &"#".repeat(max_hashes + 1); + + // Find the maximum number of hashes that follow a double quote in the string. + // We need to use one more than that to delimit the string. + let leading_hashes = |s: &str| s.chars().take_while(|&c| c == '#').count(); + let max_hashes = patch.split('"').map(leading_hashes).max().unwrap(); + StrLitKind::Raw(max_hashes + 1) +} + +fn format_patch(desired_indent: Option, patch: &str) -> String { + let lit_kind = lit_kind_for_patch(patch); let indent = desired_indent.map(|it| " ".repeat(it)); let is_multiline = patch.contains('\n'); let mut buf = String::new(); - buf.push('r'); - buf.push_str(hashes); - buf.push('"'); + lit_kind.write_start(&mut buf).unwrap(); if is_multiline { buf.push('\n'); } @@ -604,8 +610,7 @@ fn format_patch(desired_indent: Option, patch: &str) -> String { buf.push_str(indent); } } - buf.push('"'); - buf.push_str(hashes); + lit_kind.write_end(&mut buf).unwrap(); buf } From 51419ab1e79b0bf2887655dc0dbea144bcd5d7b5 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Mon, 27 Dec 2021 13:25:58 -0800 Subject: [PATCH 3/4] Bless tests --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 4497929..2284a53 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -721,7 +721,7 @@ mod tests { .assert_eq(&patch); let patch = format_patch(Some(4), "single line"); - expect![[r##"r#"single line"#"##]].assert_eq(&patch); + expect![[r#""single line""#]].assert_eq(&patch); } #[test] From 8a355f47c017b601ed368e4b5de2454057837ea8 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Mon, 27 Dec 2021 13:28:49 -0800 Subject: [PATCH 4/4] Add some single-line format patch tests --- src/lib.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 2284a53..0dbbb76 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -712,6 +712,12 @@ mod tests { "#"##]] .assert_eq(&patch); + let patch = format_patch(None, r"hello\tworld"); + expect![[r##"r#"hello\tworld"#"##]].assert_eq(&patch); + + let patch = format_patch(None, "{\"foo\": 42}"); + expect![[r##"r#"{"foo": 42}"#"##]].assert_eq(&patch); + let patch = format_patch(Some(0), "hello\nworld\n"); expect![[r##" r#"