Add Jinja support for "indent" string filter (#19529)
* Add partial Jinja support for "indent" string filter * Fully implement indent * Add tests for all width variants. * Update tests/test-jinja.cpp Co-authored-by: Sigbjørn Skjæret <sigbjorn.skjaeret@scala.com> * Fix getline ignoring trailing newlines * Update common/jinja/value.cpp Co-authored-by: Sigbjørn Skjæret <sigbjorn.skjaeret@scala.com> * fix first indent condition --------- Co-authored-by: Sigbjørn Skjæret <sigbjorn.skjaeret@scala.com>
This commit is contained in:
parent
e7f2f95c9a
commit
8a70973557
|
|
@ -4,6 +4,7 @@
|
||||||
// for converting from JSON to jinja values
|
// for converting from JSON to jinja values
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
@ -715,8 +716,46 @@ const func_builtins & value_string_t::get_builtins() const {
|
||||||
return args.get_pos(0);
|
return args.get_pos(0);
|
||||||
}},
|
}},
|
||||||
{"tojson", tojson},
|
{"tojson", tojson},
|
||||||
{"indent", [](const func_args &) -> value {
|
{"indent", [](const func_args &args) -> value {
|
||||||
throw not_implemented_exception("String indent builtin not implemented");
|
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 {
|
{"join", [](const func_args &) -> value {
|
||||||
throw not_implemented_exception("String join builtin not implemented");
|
throw not_implemented_exception("String join builtin not implemented");
|
||||||
|
|
|
||||||
|
|
@ -691,6 +691,48 @@ static void test_filters(testing & t) {
|
||||||
"{\n \"a\": 1,\n \"b\": [\n 1,\n 2\n ]\n}"
|
"{\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",
|
test_template(t, "chained filters",
|
||||||
"{{ ' HELLO '|trim|lower }}",
|
"{{ ' HELLO '|trim|lower }}",
|
||||||
json::object(),
|
json::object(),
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue