From 409ad3fc8514fb2e9632f64942a7bfcd7de35f6c Mon Sep 17 00:00:00 2001 From: Dustin Spicuzza Date: Mon, 23 Jun 2025 00:58:24 -0400 Subject: [PATCH 1/2] marshal: don't escape quotes unnecessarily Only 3 consecutive quotation marks need to be quoted. We choose to quote all quotation marks in a sequence if there are 3 or more consecutive present. Fixes #990 --- marshaler.go | 24 ++++++++++++++++++++++-- marshaler_test.go | 48 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 2 deletions(-) diff --git a/marshaler.go b/marshaler.go index 161acd93..8d7af227 100644 --- a/marshaler.go +++ b/marshaler.go @@ -517,12 +517,32 @@ func (enc *Encoder) encodeQuotedString(multiline bool, b []byte, v string) []byt del = 0x7f ) - for _, r := range []byte(v) { + bv := []byte(v) + for i := 0; i < len(bv); i++ { + r := bv[i] + // for _, r := range []byte(v) { switch r { case '\\': b = append(b, `\\`...) case '"': - b = append(b, `\"`...) + if multiline { + // Quotation marks do not need to be quoted in multiline strings unless + // it contains 3 consecutive. If 3+ quotes appear, quote all of them + // because it's visually better + if i+2 > len(bv) || bv[i+1] != '"' || bv[i+2] != '"' { + b = append(b, r) + } else { + for { + b = append(b, `\"`...) + if i+1 == len(bv) || bv[i+1] != '"' { + break + } + i++ + } + } + } else { + b = append(b, `\"`...) + } case '\b': b = append(b, `\b`...) case '\f': diff --git a/marshaler_test.go b/marshaler_test.go index 9c069a04..b8d81347 100644 --- a/marshaler_test.go +++ b/marshaler_test.go @@ -387,6 +387,54 @@ name = 'Alice' expected: `A = """ hello world""" +`, + }, + { + desc: "multi-line quotation", + v: struct { + A string `toml:",multiline"` + }{ + A: "hello\n\"world\"", + }, + expected: `A = """ +hello +"world"""" +`, + }, + { + desc: "multi-line triple quotation", + v: struct { + A string `toml:",multiline"` + }{ + A: "hello\n\"\"\"world\"", + }, + expected: `A = """ +hello +\"\"\"world"""" +`, + }, + { + desc: "multi-line triple quotation", + v: struct { + A string `toml:",multiline"` + }{ + A: "hello\n\"world\"\"\"", + }, + expected: `A = """ +hello +"world\"\"\"""" +`, + }, + { + desc: "multi-line sextuple quotation", + v: struct { + A string `toml:",multiline"` + }{ + A: "hello\n\"\"\"\"\"\"world\"", + }, + expected: `A = """ +hello +\"\"\"\"\"\"world"""" `, }, { From bc3c2d7a1b35b94512d4eb508b1a4efe855352a0 Mon Sep 17 00:00:00 2001 From: Thomas Pelletier Date: Thu, 21 Aug 2025 08:08:40 +0200 Subject: [PATCH 2/2] Simplify string encoding multiline triple quote --- marshaler.go | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/marshaler.go b/marshaler.go index 8d7af227..7cf26024 100644 --- a/marshaler.go +++ b/marshaler.go @@ -520,7 +520,6 @@ func (enc *Encoder) encodeQuotedString(multiline bool, b []byte, v string) []byt bv := []byte(v) for i := 0; i < len(bv); i++ { r := bv[i] - // for _, r := range []byte(v) { switch r { case '\\': b = append(b, `\\`...) @@ -532,13 +531,8 @@ func (enc *Encoder) encodeQuotedString(multiline bool, b []byte, v string) []byt if i+2 > len(bv) || bv[i+1] != '"' || bv[i+2] != '"' { b = append(b, r) } else { - for { - b = append(b, `\"`...) - if i+1 == len(bv) || bv[i+1] != '"' { - break - } - i++ - } + b = append(b, `\"\"\"`...) + i += 2 } } else { b = append(b, `\"`...)