cue/format: indent multiline string literals based on context.
Change-Id: Ic58d29dfa347a2f0b3642e56676c2c944dbb8b2d
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/7283
Reviewed-by: CUE cueckoo <cueckoo@gmail.com>
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cmd/cue/cmd/testdata/script/import_files.txt b/cmd/cue/cmd/testdata/script/import_files.txt
index 76be294..e94b5ac 100644
--- a/cmd/cue/cmd/testdata/script/import_files.txt
+++ b/cmd/cue/cmd/testdata/script/import_files.txt
@@ -8,9 +8,9 @@
replicas: 1
kind: "Service"
name: """
- supplement
- foo
- """
+ supplement
+ foo
+ """
json: "[1, 2]"
-- import/services.jsonl --
{
diff --git a/cmd/cue/cmd/testdata/script/import_hoiststr.txt b/cmd/cue/cmd/testdata/script/import_hoiststr.txt
index d45414c..3a0be7d 100644
--- a/cmd/cue/cmd/testdata/script/import_hoiststr.txt
+++ b/cmd/cue/cmd/testdata/script/import_hoiststr.txt
@@ -14,9 +14,9 @@
"supplement\nfoo": [{
kind: "Service"
name: """
- supplement
- foo
- """
+ supplement
+ foo
+ """
json: json656e63.Marshal(_cue_json)
let _cue_json = [1, 2]
}]
diff --git a/cue/format/printer.go b/cue/format/printer.go
index c9f43a3..0d5ed74 100644
--- a/cue/format/printer.go
+++ b/cue/format/printer.go
@@ -22,6 +22,7 @@
"cuelang.org/go/cue/ast"
"cuelang.org/go/cue/errors"
+ "cuelang.org/go/cue/literal"
"cuelang.org/go/cue/token"
)
@@ -116,6 +117,16 @@
case *ast.BasicLit:
data = x.Value
switch x.Kind {
+ case token.STRING:
+ // TODO: only do this when simplifying. Right now this does not
+ // give the right result, but it should be better if:
+ // 1) simplification is done as a separate step
+ // 2) simplified structs are explicitly referenced separately
+ // in the AST.
+ if p.indent < 6 {
+ data = literal.IndentTabs(data, p.indent+1)
+ }
+
case token.INT:
if len(data) > 1 &&
data[0] == '0' &&
diff --git a/cue/literal/indent.go b/cue/literal/indent.go
new file mode 100644
index 0000000..193ca3b
--- /dev/null
+++ b/cue/literal/indent.go
@@ -0,0 +1,33 @@
+// Copyright 2020 CUE Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package literal
+
+import "strings"
+
+// IndentTabs takes a quoted string and reindents it for the given indentation.
+// If a string is not a multiline string it will return the string as is.
+func IndentTabs(s string, n int) string {
+ indent := tabs(n)
+
+ qi, _, _, err := ParseQuotes(s, s)
+ if err != nil || !qi.multiline || qi.whitespace == indent {
+ return s
+ }
+
+ search := "\n" + qi.whitespace
+ replace := "\n" + indent
+
+ return strings.ReplaceAll(s, search, replace)
+}
diff --git a/cue/literal/indent_test.go b/cue/literal/indent_test.go
new file mode 100644
index 0000000..a10d657
--- /dev/null
+++ b/cue/literal/indent_test.go
@@ -0,0 +1,55 @@
+// Copyright 2020 CUE Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package literal
+
+import (
+ "testing"
+)
+
+func TestIndentTabs(t *testing.T) {
+ testCases := []struct {
+ in string
+ out string
+ }{{
+ in: `"""
+ foo
+ bar
+ """`,
+ out: `"""
+ foo
+ bar
+ """`,
+ }, {
+ in: `"""
+ foo
+ bar
+ """`,
+ out: `"""
+ foo
+ bar
+ """`,
+ }, {
+ in: `""`,
+ out: `""`,
+ }}
+ for _, tc := range testCases {
+ t.Run("", func(t *testing.T) {
+ got := IndentTabs(tc.in, 3)
+ if got != tc.out {
+ t.Errorf("got %s; want %s", got, tc.out)
+ }
+ })
+ }
+}
diff --git a/cue/literal/quote.go b/cue/literal/quote.go
index e39438d..ac997b6 100644
--- a/cue/literal/quote.go
+++ b/cue/literal/quote.go
@@ -45,18 +45,21 @@
// WithTabIndent returns a new Form with indentation set to the given number
// of tabs. The result will be a multiline string.
-func (f Form) WithTabIndent(tabs int) Form {
- if tabs < len(tabIndent) {
- f.indent = tabIndent[:tabs]
- } else {
- f.indent = strings.Repeat("\t", tabs)
- }
+func (f Form) WithTabIndent(n int) Form {
+ f.indent = tabs(n)
f.multiline = true
return f
}
const tabIndent = "\t\t\t\t\t\t\t\t\t\t\t\t"
+func tabs(n int) string {
+ if n < len(tabIndent) {
+ return tabIndent[:n]
+ }
+ return strings.Repeat("\t", n)
+}
+
// WithOptionalIndent is like WithTabIndent, but only returns a multiline
// strings if it doesn't contain any newline characters.
func (f Form) WithOptionalTabIndent(tabs int) Form {
diff --git a/doc/tutorial/kubernetes/quick/services/mon/alertmanager/configmap.cue b/doc/tutorial/kubernetes/quick/services/mon/alertmanager/configmap.cue
index 5f4360e..618b75a 100644
--- a/doc/tutorial/kubernetes/quick/services/mon/alertmanager/configmap.cue
+++ b/doc/tutorial/kubernetes/quick/services/mon/alertmanager/configmap.cue
@@ -15,9 +15,9 @@
slack_configs: [{
channel: "#cloudmon"
text: """
- {{ range .Alerts }}{{ .Annotations.description }}
- {{ end }}
- """
+ {{ range .Alerts }}{{ .Annotations.description }}
+ {{ end }}
+ """
send_resolved: true
}]
}]
diff --git a/internal/core/export/testdata/strings.txtar b/internal/core/export/testdata/strings.txtar
index 75a806f..2e5967c 100644
--- a/internal/core/export/testdata/strings.txtar
+++ b/internal/core/export/testdata/strings.txtar
@@ -10,9 +10,9 @@
-- out/definition --
a: """
- multi
- line
- """
+ multi
+ line
+ """
b: "message: \(a)!"
c: {
d: a
@@ -27,68 +27,68 @@
== Simplified
{
a: """
- multi
- line
- """
- b: """
- message: multi
- line!
- """
- c: {
- d: """
multi
line
"""
+ b: """
+ message: multi
+ line!
+ """
+ c: {
+ d: """
+ multi
+ line
+ """
}
}
== Raw
{
a: """
- multi
- line
- """
- b: """
- message: multi
- line!
- """
- c: {
- d: """
multi
line
"""
+ b: """
+ message: multi
+ line!
+ """
+ c: {
+ d: """
+ multi
+ line
+ """
}
}
== Final
{
a: """
- multi
- line
- """
- b: """
- message: multi
- line!
- """
- c: {
- d: """
multi
line
"""
+ b: """
+ message: multi
+ line!
+ """
+ c: {
+ d: """
+ multi
+ line
+ """
}
}
== All
{
a: """
- multi
- line
- """
- b: """
- message: multi
- line!
- """
- c: {
- d: """
multi
line
"""
+ b: """
+ message: multi
+ line!
+ """
+ c: {
+ d: """
+ multi
+ line
+ """
}
}
diff --git a/internal/third_party/yaml/decode_test.go b/internal/third_party/yaml/decode_test.go
index 9156cda..7b70071 100644
--- a/internal/third_party/yaml/decode_test.go
+++ b/internal/third_party/yaml/decode_test.go
@@ -205,11 +205,11 @@
"scalar: | # Comment\n\n literal\n\n \ttext\n\n",
`scalar: """
- literal
+ literal
- \ttext
+ \ttext
- """`,
+ """`,
},
// Folded block scalar
@@ -217,14 +217,14 @@
"scalar: > # Comment\n\n folded\n line\n \n next\n line\n * one\n * two\n\n last\n line\n\n",
`scalar: """
- folded line
- next line
- * one
- * two
+ folded line
+ next line
+ * one
+ * two
- last line
+ last line
- """`,
+ """`,
},
// Structs
@@ -456,10 +456,10 @@
` Line separator\u2028\` + "\n" +
` Paragraph separator\u2029"` + "\n",
`"""
- Generic line break (no glyph)
- Generic line break (glyphed)
- Line separator\u2028Paragraph separator\u2029
- """`,
+ Generic line break (no glyph)
+ Generic line break (glyphed)
+ Line separator\u2028Paragraph separator\u2029
+ """`,
},
// bug 1243827