Add support for recursive expansions with %exp{...}

%exp{...} just expands its content the same way double quoted strings
do, but using a named expansion type makes it possible to use the
more quoting mechanism to avoid quoting hell.
This commit is contained in:
Maxime Coste 2023-05-04 12:49:50 +10:00
parent a4918f934c
commit 04780b235b
4 changed files with 21 additions and 9 deletions

View File

@ -427,3 +427,8 @@ everywhere.
A value described as a "quoted list" will follow the rules of Kakoune string
quoting (See <<command-parsing#,`:doc command-parsing`>>). An "unquoted list"
cannot contain any special characters that would require quoting.
== Recursive Expansions
Expansions with the type `exp` expand their content, the same way doubly
quoted strings do.

View File

@ -220,6 +220,8 @@ Token::Type token_type(StringView type_name, bool throw_on_invalid)
return Token::Type::ArgExpand;
else if (type_name == "file")
return Token::Type::FileExpand;
else if (type_name == "exp")
return Token::Type::Expand;
else if (throw_on_invalid)
throw parse_error{format("unknown expand '{}'", type_name)};
else
@ -396,7 +398,7 @@ void expand_token(Token&& token, const Context& context, const ShellContext& she
}
case Token::Type::FileExpand:
return set_target(read_file(content));
case Token::Type::RawEval:
case Token::Type::Expand:
return set_target(expand(content, context, shell_context));
case Token::Type::Raw:
case Token::Type::RawQuoted:
@ -425,7 +427,7 @@ Optional<Token> CommandParser::read_token(bool throw_on_unterminated)
ParseResult quoted = parse_quoted(m_state, c);
if (throw_on_unterminated and not quoted.terminated)
throw parse_error{format("unterminated string {0}...{0}", c)};
return Token{c == '"' ? Token::Type::RawEval
return Token{c == '"' ? Token::Type::Expand
: Token::Type::RawQuoted,
start - line.begin(), std::move(quoted.content),
quoted.terminated};
@ -613,7 +615,7 @@ Optional<CommandInfo> CommandManager::command_info(const Context& context, Strin
{
if (it->type == Token::Type::Raw or
it->type == Token::Type::RawQuoted or
it->type == Token::Type::RawEval)
it->type == Token::Type::Expand)
params.push_back(it->content);
}
String helpstr = cmd->value.helper(context, params);
@ -692,7 +694,7 @@ static Completions complete_expansion(const Context& context, CompletionFlags fl
}
}
static Completions complete_raw_eval(const Context& context, CompletionFlags flags,
static Completions complete_expand(const Context& context, CompletionFlags flags,
StringView prefix, ByteCount start,
ByteCount cursor_pos, ByteCount pos_in_token)
{
@ -849,8 +851,8 @@ Completions CommandManager::complete(const Context& context,
return offset_pos(requote(command.completer(context, flags, params, index, pos_in_token), token.type), start);
}
case Token::Type::RawEval:
return complete_raw_eval(context, flags, token.content, start, cursor_pos, pos_in_token);
case Token::Type::Expand:
return complete_expand(context, flags, token.content, start, cursor_pos, pos_in_token);
default:
break;
}

View File

@ -45,7 +45,7 @@ struct Token
{
Raw,
RawQuoted,
RawEval,
Expand,
ShellExpand,
RegisterExpand,
OptionExpand,

View File

@ -44,6 +44,11 @@ struct {
unsigned int version;
StringView notes;
} constexpr version_notes[] = { {
0,
"» History is now stored linearly instead of in a tree\n"
"» {+u}%exp\\{...}{} expansions provide flexible quoting for expanded "
"strings (as double quoted strings)\n"
}, {
20221031,
"» {+b}<esc>{} does not end macro recording anymore, use {+b}Q{}\n"
"» pipe commands do not append final end-of-lines anymore\n"