// for converting from JSON to jinja values
#include <nlohmann/json.hpp>
+#include <sstream>
#include <string>
#include <cctype>
#include <vector>
return args.get_pos(0);
}},
{"tojson", tojson},
- {"indent", [](const func_args &) -> value {
- throw not_implemented_exception("String indent builtin not implemented");
+ {"indent", [](const func_args &args) -> value {
+ args.ensure_count(1, 4);
+ value val_input = args.get_pos(0);
+ value val_width = args.get_kwarg_or_pos("width", 1);
+ const bool first = args.get_kwarg_or_pos("first", 2)->as_bool(); // undefined == false
+ const bool blank = args.get_kwarg_or_pos("blank", 3)->as_bool(); // undefined == false
+ if (!is_val<value_string>(val_input)) {
+ throw raised_exception("indent() first argument must be a string");
+ }
+ std::string indent;
+ if (is_val<value_int>(val_width)) {
+ indent.assign(val_width->as_int(), ' ');
+ } else if (is_val<value_string>(val_width)) {
+ indent = val_width->as_string().str();
+ } else {
+ indent = " ";
+ }
+ std::string indented;
+ std::string input = val_input->as_string().str();
+ std::istringstream iss = std::istringstream(input);
+ std::string line;
+ while (std::getline(iss, line)) {
+ if (!indented.empty()) {
+ indented.push_back('\n');
+ }
+ if ((indented.empty() ? first : (!line.empty() || blank))) {
+ indented += indent;
+ }
+ indented += line;
+ }
+ if (!input.empty() && input.back() == '\n') {
+ indented.push_back('\n');
+ if (blank) {
+ indented += indent;
+ }
+ }
+
+ auto res = mk_val<value_string>(indented);
+ res->val_str.mark_input_based_on(val_input->as_string());
+ return res;
}},
{"join", [](const func_args &) -> value {
throw not_implemented_exception("String join builtin not implemented");
"{\n \"a\": 1,\n \"b\": [\n 1,\n 2\n ]\n}"
);
+ test_template(t, "indent",
+ "{{ data|indent(2) }}",
+ {{ "data", "foo\nbar" }},
+ "foo\n bar"
+ );
+
+ test_template(t, "indent first only",
+ "{{ data|indent(width=3,first=true) }}",
+ {{ "data", "foo\nbar" }},
+ " foo\n bar"
+ );
+
+ test_template(t, "indent blank lines and first line",
+ "{{ data|indent(width=5,blank=true,first=true) }}",
+ {{ "data", "foo\n\nbar" }},
+ " foo\n \n bar"
+ );
+
+ test_template(t, "indent with default width",
+ "{{ data|indent() }}",
+ {{ "data", "foo\nbar" }},
+ "foo\n bar"
+ );
+
+ test_template(t, "indent with no newline",
+ "{{ data|indent }}",
+ {{ "data", "foo" }},
+ "foo"
+ );
+
+ test_template(t, "indent with trailing newline",
+ "{{ data|indent(blank=true) }}",
+ {{ "data", "foo\n" }},
+ "foo\n "
+ );
+
+ test_template(t, "indent with string",
+ "{{ data|indent(width='>>>>') }}",
+ {{ "data", "foo\nbar" }},
+ "foo\n>>>>bar"
+ );
+
test_template(t, "chained filters",
"{{ ' HELLO '|trim|lower }}",
json::object(),