@@ -237,33 +237,37 @@ const kyamlFoldStr = "\\\n"
237
237
func (ky * Encoder ) renderString (val string , indent int , flags flagMask , out io.Writer ) error {
238
238
lazyQuote := flags & flagLazyQuote != 0
239
239
compact := flags & flagCompact != 0
240
+ multi := strings .Contains (val , "\n " )
240
241
241
- // If no newlines, just use standard Go quoting.
242
- if compact || ! strings .Contains (val , "\n " ) {
243
- if lazyQuote && ! needsQuotes (val ) {
244
- fmt .Fprint (out , val )
245
- } else {
246
- fmt .Fprint (out , strconv .Quote (val ))
247
- }
242
+ if ! multi && lazyQuote && ! needsQuotes (val ) {
243
+ fmt .Fprint (out , val )
248
244
return nil
249
245
}
250
246
251
- // The input has at least one newline. We will use YAML's line folding to
252
- // make the output more readable.
247
+ // What to print when we find a newline in the input.
248
+ newline := "\\ n"
249
+ if ! compact {
250
+ // We use YAML's line folding to make the output more readable.
251
+ newline += kyamlFoldStr
252
+ }
253
+
253
254
//
254
255
// The rest of this is borrowed from Go's strconv.Quote implementation.
255
-
256
- s := val
256
+ //
257
257
258
258
// accumulate into a buffer
259
259
buf := & bytes.Buffer {}
260
260
261
- // opening quote and fold
262
- fmt .Fprint (buf , `"` , kyamlFoldStr )
261
+ // opening quote
262
+ fmt .Fprint (buf , `"` )
263
+ if multi && ! compact {
264
+ fmt .Fprint (buf , kyamlFoldStr )
265
+ }
263
266
264
267
// Iterating a string with invalid UTF8 returns RuneError rather than the
265
268
// bytes, so we iterate the string and decode the runes. This is a bit
266
269
// slower, but gives us a better result.
270
+ s := val
267
271
for width := 0 ; len (s ) > 0 ; s = s [width :] {
268
272
r := rune (s [0 ])
269
273
width = 1
@@ -275,15 +279,17 @@ func (ky *Encoder) renderString(val string, indent int, flags flagMask, out io.W
275
279
fmt .Fprintf (buf , "%02x" , s [0 ])
276
280
continue
277
281
}
278
- ky .appendEscapedRune (r , indent , buf )
282
+ ky .appendEscapedRune (r , indent , newline , buf )
279
283
}
280
284
281
285
// closing quote
282
286
afterNewline := buf .Bytes ()[len (buf .Bytes ())- 1 ] == '\n'
283
- if ! afterNewline {
284
- fmt .Fprint (buf , kyamlFoldStr )
287
+ if multi && ! compact {
288
+ if ! afterNewline {
289
+ fmt .Fprint (buf , kyamlFoldStr )
290
+ }
291
+ ky .writeIndent (indent , buf )
285
292
}
286
- ky .writeIndent (indent , buf )
287
293
fmt .Fprint (buf , `"` )
288
294
289
295
fmt .Fprint (out , buf .String ())
@@ -433,7 +439,7 @@ func parseTimestamp(s string) (time.Time, bool) {
433
439
}
434
440
435
441
// We use a buffer here so we can peek backwards.
436
- func (ky * Encoder ) appendEscapedRune (r rune , indent int , buf * bytes.Buffer ) {
442
+ func (ky * Encoder ) appendEscapedRune (r rune , indent int , newline string , buf * bytes.Buffer ) {
437
443
afterNewline := buf .Bytes ()[len (buf .Bytes ())- 1 ] == '\n'
438
444
439
445
if afterNewline {
@@ -469,14 +475,25 @@ func (ky *Encoder) appendEscapedRune(r rune, indent int, buf *bytes.Buffer) {
469
475
case '\f' :
470
476
buf .WriteString (`\f` )
471
477
case '\n' :
472
- buf .WriteString (`\n` )
473
- buf .WriteString (kyamlFoldStr )
478
+ buf .WriteString (newline )
474
479
case '\r' :
475
480
buf .WriteString (`\r` )
476
481
case '\t' :
477
482
buf .WriteString (`\t` )
478
483
case '\v' :
479
484
buf .WriteString (`\v` )
485
+ case '\x00' :
486
+ buf .WriteString (`\0` )
487
+ case '\x1b' :
488
+ buf .WriteString (`\e` )
489
+ case '\x85' :
490
+ buf .WriteString (`\N` )
491
+ case '\xa0' :
492
+ buf .WriteString (`\_` )
493
+ case '\u2028' :
494
+ buf .WriteString (`\L` )
495
+ case '\u2029' :
496
+ buf .WriteString (`\P` )
480
497
default :
481
498
const hexits = "0123456789abcdef"
482
499
switch {
0 commit comments