summaryrefslogtreecommitdiff
path: root/src/string_utils.cc
diff options
context:
space:
mode:
authorFrank LENORMAND <lenormf@gmail.com>2019-07-23 13:09:41 +0300
committerFrank LENORMAND <lenormf@gmail.com>2019-07-25 12:28:04 +0300
commitda2f6c296ae3ee280ffaca3937c6ae35c78d1e38 (patch)
tree99a0aebefcddaf2b109c2fc4eb7e29af9b52bd01 /src/string_utils.cc
parente42c81c8eb53a6562f0d7313a6a9a92d8360238f (diff)
src: De-indent docstrings passed to command/option/mapping definitions
This commit implements formatting behaviour when the first character of a docstring is a newline. In that case, the exact indentation level of the next line will be removed from that line and all subsequent non-empty lines. An error will be returned if a subsequent non-empty line does not have the same indentation level. The docstrings are always trimmed (surrounding whitespaces) whether the first character is a newline or not, as was the case prior to this commit. Example: the following declaration ``` define-command test -docstring %{ test: do something Nothing really. More indented lines. } nop ``` would be rendered as ``` test: do something Nothing really. More indented lines. ``` Related to #2405
Diffstat (limited to 'src/string_utils.cc')
-rw-r--r--src/string_utils.cc38
1 files changed, 38 insertions, 0 deletions
diff --git a/src/string_utils.cc b/src/string_utils.cc
index 3073a870..348526e9 100644
--- a/src/string_utils.cc
+++ b/src/string_utils.cc
@@ -19,6 +19,36 @@ StringView trim_whitespaces(StringView str)
return {beg, end};
}
+String trim_indent(StringView str)
+{
+ if (str.empty())
+ return {};
+ else if (str[0_byte] != '\n')
+ return trim_whitespaces(str).str();
+
+ str = str.substr(1_byte);
+ const CharCount docstring_length = str.char_length();
+
+ CharCount level_indent = 0;
+ while (level_indent < docstring_length
+ and is_horizontal_blank(str[level_indent]))
+ level_indent++;
+
+ if (level_indent >= docstring_length or not level_indent)
+ return trim_whitespaces(str).str();
+
+ const auto str_indent = str.substr(0, level_indent);
+ auto s = str | split<StringView>('\n') | transform([&](auto&& line) {
+ if (line.empty())
+ return line;
+ else if (not prefix_match(line, str_indent))
+ throw runtime_error("inconsistent indentation in the string");
+
+ return line.substr(str_indent.char_length());
+ });
+
+ return trim_whitespaces(join(s, '\n', false)).str();
+}
String escape(StringView str, StringView characters, char escape)
{
@@ -379,6 +409,14 @@ UnitTest test_string{[]()
kak_assert(wrapped2[1] == "unknown");
kak_assert(wrapped2[2] == "type");
+ kak_assert(trim_indent(" ") == "");
+ kak_assert(trim_indent("no-indent") == "no-indent");
+ kak_assert(trim_indent("\nno-indent") == "no-indent");
+ kak_assert(trim_indent("\n indent\n indent") == "indent\nindent");
+ kak_assert(trim_indent("\n indent\n indent") == "indent\n indent");
+
+ kak_expect_throw(runtime_error, trim_indent("\n indent\nno-indent"));
+
kak_assert(escape(R"(\youpi:matin:tchou\:)", ":\\", '\\') == R"(\\youpi\:matin\:tchou\\\:)");
kak_assert(unescape(R"(\\youpi\:matin\:tchou\\\:)", ":\\", '\\') == R"(\youpi:matin:tchou\:)");