diff --git a/README.md b/README.md index 39a60bcf6..92b8085f9 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,7 @@ Gomplate is an alternative that will let you process templates which also includ - [`trim`](#trim) - [`urlParse`](#urlparse) - [`has`](#has) + - [`indent`](#indent) - [`json`](#json) - [`jsonArray`](#jsonarray) - [`yaml`](#yaml) @@ -459,6 +460,27 @@ $ gomplate -d vault:///secret/foo < input.tmpl The secret is 'foo: bar' ``` +#### `indent` + +Indents a given string with the given indentation pattern. If the input string has multiple lines, each line will be indented. + +##### Example + +This function can be especially useful when adding YAML snippets into other YAML documents, where indentation is important: + +_`input.tmpl`:_ +``` +foo: +{{ `{"bar": {"baz": 2}}` | json | toYAML | indent " " }} +``` + +```console +$ gomplate -f input.tmpl +foo: + bar: + baz: 2 +``` + #### `json` Converts a JSON string into an object. Only works for JSON Objects (not Arrays or other valid JSON types). This can be used to access properties of JSON objects. diff --git a/gomplate.go b/gomplate.go index eb778ea48..28e623ab4 100644 --- a/gomplate.go +++ b/gomplate.go @@ -53,6 +53,7 @@ func NewGomplate(data *Data, leftDelim, rightDelim string) *Gomplate { "yaml": typeconv.YAML, "yamlArray": typeconv.YAMLArray, "slice": typeconv.Slice, + "indent": typeconv.indent, "join": typeconv.Join, "toJSON": typeconv.ToJSON, "toJSONPretty": typeconv.toJSONPretty, diff --git a/test/integration/typeconv_funcs.bats b/test/integration/typeconv_funcs.bats index c080a2ad7..14921117b 100644 --- a/test/integration/typeconv_funcs.bats +++ b/test/integration/typeconv_funcs.bats @@ -29,3 +29,11 @@ function teardown () { \"hello\": \"world\" }" ]] } + +@test "indent" { + gomplate -i '{{ indent " " "hello world" }}{{ "hello\nmultiline\nworld" | indent " " }}' + [ "$status" -eq 0 ] + [[ "${output}" == " hello world hello + multiline + world" ]] +} diff --git a/typeconv.go b/typeconv.go index fb8c0e5fc..76739b3f3 100644 --- a/typeconv.go +++ b/typeconv.go @@ -99,6 +99,21 @@ func (t *TypeConv) Slice(args ...interface{}) []interface{} { return args } +// Indent - indent each line of the string with the given indent string +func (t *TypeConv) indent(indent, s string) string { + var res []byte + bol := true + for i := 0; i < len(s); i++ { + c := s[i] + if bol && c != '\n' { + res = append(res, indent...) + } + res = append(res, c) + bol = c == '\n' + } + return string(res) +} + // Join concatenates the elements of a to create a single string. // The separator string sep is placed between elements in the resulting string. // diff --git a/typeconv_test.go b/typeconv_test.go index ae2424ce0..85620b7cd 100644 --- a/typeconv_test.go +++ b/typeconv_test.go @@ -169,3 +169,16 @@ func TestHas(t *testing.T) { assert.False(t, ty.Has(in, "bar")) assert.True(t, ty.Has(in["baz"], "qux")) } + +func TestIndent(t *testing.T) { + ty := new(TypeConv) + actual := "hello\nworld\n!" + expected := " hello\n world\n !" + assert.Equal(t, expected, ty.indent(" ", actual)) + + assert.Equal(t, "\n", ty.indent(" ", "\n")) + + assert.Equal(t, " foo\n", ty.indent(" ", "foo\n")) + + assert.Equal(t, " foo", ty.indent(" ", "foo")) +}