Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Retain single line breaks #159

Merged
merged 2 commits into from
Feb 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
25 changes: 13 additions & 12 deletions docs/config-file.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,18 +57,19 @@ The basic formatter is a barebones formatter that simply takes the data provided

### Configuration

| Key | Type | Default | Description |
|:-------------------------|:---------------|:--------|:------------|
| `indent` | int | 2 | The indentation level in spaces to use for the formatted yaml|
| `include_document_start` | bool | false | Include `---` at document start |
| `line_ending` | `lf` or `crlf` | `crlf` on Windows, `lf` otherwise | Parse and write the file with "lf" or "crlf" line endings. This setting will be overwritten by the global `line_ending`. |
| `retain_line_breaks` | bool | false | Retain line breaks in formatted yaml |
| `disallow_anchors` | bool | false | If true, reject any YAML anchors or aliases found in the document. |
| `max_line_length` | int | 0 | Set the maximum line length (see notes below). if not set, defaults to 0 which means no limit. |
| `scan_folded_as_literal` | bool | false | Option that will preserve newlines in folded block scalars (blocks that start with `>`). |
| `indentless_arrays` | bool | false | Render `-` array items (block sequence items) without an increased indent. |
| `drop_merge_tag` | bool | false | Assume that any well formed merge using just a `<<` token will be a merge, and drop the `!!merge` tag from the formatted result. |
| `pad_line_comments` | int | 1 | The number of padding spaces to insert before line comments. |
| Key | Type | Default | Description |
|:----------------------------|:---------------|:--------|:------------|
| `indent` | int | 2 | The indentation level in spaces to use for the formatted yaml. |
| `include_document_start` | bool | false | Include `---` at document start. |
| `line_ending` | `lf` or `crlf` | `crlf` on Windows, `lf` otherwise | Parse and write the file with "lf" or "crlf" line endings. This setting will be overwritten by the global `line_ending`. |
| `retain_line_breaks` | bool | false | Retain line breaks in formatted yaml. |
| `retain_line_breaks_single` | bool | false | (NOTE: Takes precedence over `retain_line_breaks`) Retain line breaks in formatted yaml, but only keep a single line in groups of many blank lines. |
| `disallow_anchors` | bool | false | If true, reject any YAML anchors or aliases found in the document. |
| `max_line_length` | int | 0 | Set the maximum line length (see notes below). if not set, defaults to 0 which means no limit. |
| `scan_folded_as_literal` | bool | false | Option that will preserve newlines in folded block scalars (blocks that start with `>`). |
| `indentless_arrays` | bool | false | Render `-` array items (block sequence items) without an increased indent. |
| `drop_merge_tag` | bool | false | Assume that any well formed merge using just a `<<` token will be a merge, and drop the `!!merge` tag from the formatted result. |
| `pad_line_comments` | int | 1 | The number of padding spaces to insert before line comments. |

### Note on `max_line_length`

Expand Down
21 changes: 11 additions & 10 deletions formatters/basic/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,17 @@ import (
)

type Config struct {
Indent int `mapstructure:"indent"`
IncludeDocumentStart bool `mapstructure:"include_document_start"`
LineEnding yamlfmt.LineBreakStyle `mapstructure:"line_ending"`
LineLength int `mapstructure:"max_line_length"`
RetainLineBreaks bool `mapstructure:"retain_line_breaks"`
DisallowAnchors bool `mapstructure:"disallow_anchors"`
ScanFoldedAsLiteral bool `mapstructure:"scan_folded_as_literal"`
IndentlessArrays bool `mapstructure:"indentless_arrays"`
DropMergeTag bool `mapstructure:"drop_merge_tag"`
PadLineComments int `mapstructure:"pad_line_comments"`
Indent int `mapstructure:"indent"`
IncludeDocumentStart bool `mapstructure:"include_document_start"`
LineEnding yamlfmt.LineBreakStyle `mapstructure:"line_ending"`
LineLength int `mapstructure:"max_line_length"`
RetainLineBreaks bool `mapstructure:"retain_line_breaks"`
RetainLineBreaksSingle bool `mapstructure:"retain_line_breaks_single"`
DisallowAnchors bool `mapstructure:"disallow_anchors"`
ScanFoldedAsLiteral bool `mapstructure:"scan_folded_as_literal"`
IndentlessArrays bool `mapstructure:"indentless_arrays"`
DropMergeTag bool `mapstructure:"drop_merge_tag"`
PadLineComments int `mapstructure:"pad_line_comments"`
}

func DefaultConfig() *Config {
Expand Down
4 changes: 2 additions & 2 deletions formatters/basic/features.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@ import (

func ConfigureFeaturesFromConfig(config *Config) yamlfmt.FeatureList {
features := []yamlfmt.Feature{}
if config.RetainLineBreaks {
if config.RetainLineBreaks || config.RetainLineBreaksSingle {
lineSep, err := config.LineEnding.Separator()
if err != nil {
lineSep = "\n"
}
featLineBreak := hotfix.MakeFeatureRetainLineBreak(lineSep)
featLineBreak := hotfix.MakeFeatureRetainLineBreak(lineSep, config.RetainLineBreaksSingle)
features = append(features, featLineBreak)
}
return features
Expand Down
48 changes: 35 additions & 13 deletions formatters/basic/formatter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,12 +125,13 @@ func TestEmojiSupport(t *testing.T) {

func TestRetainLineBreaks(t *testing.T) {
testCases := []struct {
desc string
name string
input string
expect string
single bool
}{
{
desc: "basic",
name: "basic",
input: `a: 1

b: 2`,
Expand All @@ -140,7 +141,7 @@ b: 2
`,
},
{
desc: "multi-doc",
name: "multi-doc",
input: `a: 1

# tail comment
Expand All @@ -154,7 +155,7 @@ b: 2
`,
},
{
desc: "literal string",
name: "literal string",
input: `a: 1

shell: |
Expand All @@ -175,7 +176,7 @@ shell: |
`,
},
{
desc: "multi level nested literal string",
name: "multi level nested literal string",
input: `a: 1
x:
y:
Expand All @@ -192,20 +193,41 @@ x:

# bye
echo "hello, world"
`,
},
{
name: "retain single line break",
single: true,
input: `a: 1




b: 2


c: 3
`,
expect: `a: 1

b: 2

c: 3
`,
},
}
config := basic.DefaultConfig()
config.RetainLineBreaks = true
f := newFormatter(config)
for _, c := range testCases {
t.Run(c.desc, func(t *testing.T) {
got, err := f.Format([]byte(c.input))
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
config := basic.DefaultConfig()
config.RetainLineBreaks = true
config.RetainLineBreaksSingle = tc.single
f := newFormatter(config)
got, err := f.Format([]byte(tc.input))
if err != nil {
t.Fatalf("expected formatting to pass, returned error: %v", err)
}
if string(got) != c.expect {
t.Fatalf("didn't retain line breaks\nresult: %v\nexpect %s", string(got), c.expect)
if string(got) != tc.expect {
t.Fatalf("didn't retain line breaks\nresult: %v\nexpect %s", string(got), tc.expect)
}
})
}
Expand Down
18 changes: 12 additions & 6 deletions internal/hotfix/retain_line_break.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,31 +42,37 @@ func (p *paddinger) adjust(txt string) {
}
}

func MakeFeatureRetainLineBreak(linebreakStr string) yamlfmt.Feature {
func MakeFeatureRetainLineBreak(linebreakStr string, chomp bool) yamlfmt.Feature {
return yamlfmt.Feature{
Name: "Retain Line Breaks",
BeforeAction: replaceLineBreakFeature(linebreakStr),
BeforeAction: replaceLineBreakFeature(linebreakStr, chomp),
AfterAction: restoreLineBreakFeature(linebreakStr),
}
}

func replaceLineBreakFeature(newlineStr string) yamlfmt.FeatureFunc {
func replaceLineBreakFeature(newlineStr string, chomp bool) yamlfmt.FeatureFunc {
return func(content []byte) ([]byte, error) {
var buf bytes.Buffer
reader := bytes.NewReader(content)
scanner := bufio.NewScanner(reader)
var inLineBreaks bool
var padding paddinger
for scanner.Scan() {
txt := scanner.Text()
padding.adjust(txt)
if strings.TrimSpace(txt) == "" { // line break or empty space line.
if chomp && inLineBreaks {
continue
}
buf.WriteString(padding.String()) // prepend some padding incase literal multiline strings.
buf.WriteString(lineBreakPlaceholder)
buf.WriteString(newlineStr)
continue
inLineBreaks = true
} else {
buf.WriteString(txt)
buf.WriteString(newlineStr)
inLineBreaks = false
}
buf.WriteString(txt)
buf.WriteString(newlineStr)
}
return buf.Bytes(), scanner.Err()
}
Expand Down