diff options
| author | Frank LENORMAND <lenormf@gmail.com> | 2019-07-23 13:09:41 +0300 |
|---|---|---|
| committer | Frank LENORMAND <lenormf@gmail.com> | 2019-07-25 12:28:04 +0300 |
| commit | da2f6c296ae3ee280ffaca3937c6ae35c78d1e38 (patch) | |
| tree | 99a0aebefcddaf2b109c2fc4eb7e29af9b52bd01 /src/string_utils.cc | |
| parent | e42c81c8eb53a6562f0d7313a6a9a92d8360238f (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.cc | 38 |
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\:)"); |
