@@ -237,33 +237,37 @@ const kyamlFoldStr = "\\\n"
237237func (ky * Encoder ) renderString (val string , indent int , flags flagMask , out io.Writer ) error {
238238 lazyQuote := flags & flagLazyQuote != 0
239239 compact := flags & flagCompact != 0
240+ multi := strings .Contains (val , "\n " )
240241
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 )
248244 return nil
249245 }
250246
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+
253254 //
254255 // The rest of this is borrowed from Go's strconv.Quote implementation.
255-
256- s := val
256+ //
257257
258258 // accumulate into a buffer
259259 buf := & bytes.Buffer {}
260260
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+ }
263266
264267 // Iterating a string with invalid UTF8 returns RuneError rather than the
265268 // bytes, so we iterate the string and decode the runes. This is a bit
266269 // slower, but gives us a better result.
270+ s := val
267271 for width := 0 ; len (s ) > 0 ; s = s [width :] {
268272 r := rune (s [0 ])
269273 width = 1
@@ -275,15 +279,17 @@ func (ky *Encoder) renderString(val string, indent int, flags flagMask, out io.W
275279 fmt .Fprintf (buf , "%02x" , s [0 ])
276280 continue
277281 }
278- ky .appendEscapedRune (r , indent , buf )
282+ ky .appendEscapedRune (r , indent , newline , buf )
279283 }
280284
281285 // closing quote
282286 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 )
285292 }
286- ky .writeIndent (indent , buf )
287293 fmt .Fprint (buf , `"` )
288294
289295 fmt .Fprint (out , buf .String ())
@@ -433,7 +439,7 @@ func parseTimestamp(s string) (time.Time, bool) {
433439}
434440
435441// 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 ) {
437443 afterNewline := buf .Bytes ()[len (buf .Bytes ())- 1 ] == '\n'
438444
439445 if afterNewline {
@@ -469,14 +475,25 @@ func (ky *Encoder) appendEscapedRune(r rune, indent int, buf *bytes.Buffer) {
469475 case '\f' :
470476 buf .WriteString (`\f` )
471477 case '\n' :
472- buf .WriteString (`\n` )
473- buf .WriteString (kyamlFoldStr )
478+ buf .WriteString (newline )
474479 case '\r' :
475480 buf .WriteString (`\r` )
476481 case '\t' :
477482 buf .WriteString (`\t` )
478483 case '\v' :
479484 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` )
480497 default :
481498 const hexits = "0123456789abcdef"
482499 switch {
0 commit comments