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
This commit is contained in:
parent
e42c81c8eb
commit
da2f6c296a
|
@ -1163,9 +1163,9 @@ void define_command(const ParametersParser& parser, Context& context, const Shel
|
|||
};
|
||||
}
|
||||
|
||||
auto docstring = trim_whitespaces(parser.get_switch("docstring").value_or(StringView{}));
|
||||
auto docstring = trim_indent(parser.get_switch("docstring").value_or(StringView{}));
|
||||
|
||||
cm.register_command(cmd_name, cmd, docstring.str(), desc, flags, CommandHelper{}, completer);
|
||||
cm.register_command(cmd_name, cmd, docstring, desc, flags, CommandHelper{}, completer);
|
||||
}
|
||||
|
||||
const CommandDesc define_command_cmd = {
|
||||
|
@ -1590,7 +1590,7 @@ const CommandDesc declare_option_cmd = {
|
|||
if (parser.get_switch("hidden"))
|
||||
flags = OptionFlags::Hidden;
|
||||
|
||||
auto docstring = trim_whitespaces(parser.get_switch("docstring").value_or(StringView{})).str();
|
||||
auto docstring = trim_indent(parser.get_switch("docstring").value_or(StringView{}));
|
||||
OptionsRegistry& reg = GlobalScope::instance().option_registry();
|
||||
|
||||
|
||||
|
@ -1672,7 +1672,7 @@ const CommandDesc map_key_cmd = {
|
|||
|
||||
KeyList mapping = parse_keys(parser[3]);
|
||||
keymaps.map_key(key[0], keymap_mode, std::move(mapping),
|
||||
trim_whitespaces(parser.get_switch("docstring").value_or("")).str());
|
||||
trim_indent(parser.get_switch("docstring").value_or("")));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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\:)");
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ namespace Kakoune
|
|||
{
|
||||
|
||||
StringView trim_whitespaces(StringView str);
|
||||
String trim_indent(StringView str);
|
||||
|
||||
String escape(StringView str, StringView characters, char escape);
|
||||
String unescape(StringView str, StringView characters, char escape);
|
||||
|
|
Loading…
Reference in New Issue
Block a user