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:
parent
a4918f934c
commit
04780b235b
|
@ -427,3 +427,8 @@ everywhere.
|
||||||
A value described as a "quoted list" will follow the rules of Kakoune string
|
A value described as a "quoted list" will follow the rules of Kakoune string
|
||||||
quoting (See <<command-parsing#,`:doc command-parsing`>>). An "unquoted list"
|
quoting (See <<command-parsing#,`:doc command-parsing`>>). An "unquoted list"
|
||||||
cannot contain any special characters that would require quoting.
|
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.
|
||||||
|
|
|
@ -220,6 +220,8 @@ Token::Type token_type(StringView type_name, bool throw_on_invalid)
|
||||||
return Token::Type::ArgExpand;
|
return Token::Type::ArgExpand;
|
||||||
else if (type_name == "file")
|
else if (type_name == "file")
|
||||||
return Token::Type::FileExpand;
|
return Token::Type::FileExpand;
|
||||||
|
else if (type_name == "exp")
|
||||||
|
return Token::Type::Expand;
|
||||||
else if (throw_on_invalid)
|
else if (throw_on_invalid)
|
||||||
throw parse_error{format("unknown expand '{}'", type_name)};
|
throw parse_error{format("unknown expand '{}'", type_name)};
|
||||||
else
|
else
|
||||||
|
@ -396,7 +398,7 @@ void expand_token(Token&& token, const Context& context, const ShellContext& she
|
||||||
}
|
}
|
||||||
case Token::Type::FileExpand:
|
case Token::Type::FileExpand:
|
||||||
return set_target(read_file(content));
|
return set_target(read_file(content));
|
||||||
case Token::Type::RawEval:
|
case Token::Type::Expand:
|
||||||
return set_target(expand(content, context, shell_context));
|
return set_target(expand(content, context, shell_context));
|
||||||
case Token::Type::Raw:
|
case Token::Type::Raw:
|
||||||
case Token::Type::RawQuoted:
|
case Token::Type::RawQuoted:
|
||||||
|
@ -425,7 +427,7 @@ Optional<Token> CommandParser::read_token(bool throw_on_unterminated)
|
||||||
ParseResult quoted = parse_quoted(m_state, c);
|
ParseResult quoted = parse_quoted(m_state, c);
|
||||||
if (throw_on_unterminated and not quoted.terminated)
|
if (throw_on_unterminated and not quoted.terminated)
|
||||||
throw parse_error{format("unterminated string {0}...{0}", c)};
|
throw parse_error{format("unterminated string {0}...{0}", c)};
|
||||||
return Token{c == '"' ? Token::Type::RawEval
|
return Token{c == '"' ? Token::Type::Expand
|
||||||
: Token::Type::RawQuoted,
|
: Token::Type::RawQuoted,
|
||||||
start - line.begin(), std::move(quoted.content),
|
start - line.begin(), std::move(quoted.content),
|
||||||
quoted.terminated};
|
quoted.terminated};
|
||||||
|
@ -613,7 +615,7 @@ Optional<CommandInfo> CommandManager::command_info(const Context& context, Strin
|
||||||
{
|
{
|
||||||
if (it->type == Token::Type::Raw or
|
if (it->type == Token::Type::Raw or
|
||||||
it->type == Token::Type::RawQuoted or
|
it->type == Token::Type::RawQuoted or
|
||||||
it->type == Token::Type::RawEval)
|
it->type == Token::Type::Expand)
|
||||||
params.push_back(it->content);
|
params.push_back(it->content);
|
||||||
}
|
}
|
||||||
String helpstr = cmd->value.helper(context, params);
|
String helpstr = cmd->value.helper(context, params);
|
||||||
|
@ -692,9 +694,9 @@ 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,
|
StringView prefix, ByteCount start,
|
||||||
ByteCount cursor_pos, ByteCount pos_in_token)
|
ByteCount cursor_pos, ByteCount pos_in_token)
|
||||||
{
|
{
|
||||||
ParseState state{prefix, prefix.begin()};
|
ParseState state{prefix, prefix.begin()};
|
||||||
while (state)
|
while (state)
|
||||||
|
@ -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);
|
return offset_pos(requote(command.completer(context, flags, params, index, pos_in_token), token.type), start);
|
||||||
}
|
}
|
||||||
case Token::Type::RawEval:
|
case Token::Type::Expand:
|
||||||
return complete_raw_eval(context, flags, token.content, start, cursor_pos, pos_in_token);
|
return complete_expand(context, flags, token.content, start, cursor_pos, pos_in_token);
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,7 @@ struct Token
|
||||||
{
|
{
|
||||||
Raw,
|
Raw,
|
||||||
RawQuoted,
|
RawQuoted,
|
||||||
RawEval,
|
Expand,
|
||||||
ShellExpand,
|
ShellExpand,
|
||||||
RegisterExpand,
|
RegisterExpand,
|
||||||
OptionExpand,
|
OptionExpand,
|
||||||
|
|
|
@ -44,6 +44,11 @@ struct {
|
||||||
unsigned int version;
|
unsigned int version;
|
||||||
StringView notes;
|
StringView notes;
|
||||||
} constexpr version_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,
|
20221031,
|
||||||
"» {+b}<esc>{} does not end macro recording anymore, use {+b}Q{}\n"
|
"» {+b}<esc>{} does not end macro recording anymore, use {+b}Q{}\n"
|
||||||
"» pipe commands do not append final end-of-lines anymore\n"
|
"» pipe commands do not append final end-of-lines anymore\n"
|
||||||
|
|
Loading…
Reference in New Issue
Block a user