Repository: google/yamlfmt
Pull request #44 (2022-09-11 10:10:20)

fix: line break format issue after refactor code
I notice my PR for retaining line breaks got refactors. However the original [indentLen func](https://github.com/google/yamlfmt/blob/e05c99fbdf1d44bf9e2780f30fe040ad2274da19/formatters/basic/line_break.go#L62) got removed. It's required. Things got complicated when yaml contains literal multi-line string. If the indent is fixed 2, when it comes to multi-level indent string the format result will be wrong. So the `paddinger` always return the max padding for each line.

This PR fixes the refactor regression issue and explicitly add a test case.


Patch:
diff --git a/formatters/basic/features.go b/formatters/basic/features.go
index 780b895..252591b 100644
--- a/formatters/basic/features.go
+++ b/formatters/basic/features.go
@@ -54,7 +54,7 @@ func ConfigureFeaturesFromConfig(config *Config) yamlfmt.FeatureList {
 		if config.LineEnding == yamlfmt.LineBreakStyleCRLF {
 			linebreakStr = "\r\n"
 		}
-		featLineBreak := hotfix.MakeFeatureRetainLineBreak(linebreakStr, config.Indent)
+		featLineBreak := hotfix.MakeFeatureRetainLineBreak(linebreakStr)
 		features = append(features, featLineBreak)
 	}
 	return features
diff --git a/internal/hotfix/retain_line_break.go b/internal/hotfix/retain_line_break.go
index 49fd9f7..14ed738 100644
--- a/internal/hotfix/retain_line_break.go
+++ b/internal/hotfix/retain_line_break.go
@@ -31,22 +31,26 @@ type paddinger struct {
 	strings.Builder
 }
 
-func (p *paddinger) adjust(size int) {
+func (p *paddinger) adjust(txt string) {
+	var indentSize int
+	for i := 0; i < len(txt) && txt[i] == ' '; i++ { // yaml only allows space to indent.
+		indentSize++
+	}
 	// Grows if the given size is larger than us and always return the max padding.
-	for diff := size - p.Len(); diff > 0; diff-- {
+	for diff := indentSize - p.Len(); diff > 0; diff-- {
 		p.WriteByte(' ')
 	}
 }
 
-func MakeFeatureRetainLineBreak(linebreakStr string, indent int) yamlfmt.Feature {
+func MakeFeatureRetainLineBreak(linebreakStr string) yamlfmt.Feature {
 	return yamlfmt.Feature{
 		Name:         "Retain Line Breaks",
-		BeforeAction: replaceLineBreakFeature(linebreakStr, indent),
+		BeforeAction: replaceLineBreakFeature(linebreakStr),
 		AfterAction:  restoreLineBreakFeature(linebreakStr),
 	}
 }
 
-func replaceLineBreakFeature(newlineStr string, indentSize int) yamlfmt.FeatureFunc {
+func replaceLineBreakFeature(newlineStr string) yamlfmt.FeatureFunc {
 	return func(content []byte) ([]byte, error) {
 		var buf bytes.Buffer
 		reader := bytes.NewReader(content)
@@ -54,7 +58,7 @@ func replaceLineBreakFeature(newlineStr string, indentSize int) yamlfmt.FeatureF
 		var padding paddinger
 		for scanner.Scan() {
 			txt := scanner.Text()
-			padding.adjust(indentSize)
+			padding.adjust(txt)
 			if strings.TrimSpace(txt) == "" { // line break or empty space line.
 				buf.WriteString(padding.String()) // prepend some padding incase literal multiline strings.
 				buf.WriteString(lineBreakPlaceholder)
@@ -62,7 +66,7 @@ func replaceLineBreakFeature(newlineStr string, indentSize int) yamlfmt.FeatureF
 				continue
 			}
 			buf.WriteString(txt)
-			buf.WriteByte('\n')
+			buf.WriteString(newlineStr)
 		}
 		return buf.Bytes(), scanner.Err()
 	}


Test patch:
diff --git a/formatters/basic/formatter_test.go b/formatters/basic/formatter_test.go
index e5d66ed..8c1c010 100644
--- a/formatters/basic/formatter_test.go
+++ b/formatters/basic/formatter_test.go
@@ -173,6 +173,26 @@ shell: |
   # hello, world
     # bye
   echo "hello, world"
+`,
+		},
+		{
+			desc: "multi level nested literal string",
+			input: `a:  1
+x:
+  y:
+    shell: |
+      #!/usr/bin/env bash
+
+        # bye
+      echo "hello, world"`,
+			expect: `a: 1
+x:
+  y:
+    shell: |
+      #!/usr/bin/env bash
+
+        # bye
+      echo "hello, world"
 `,
 		},
 	}