1
1
mirror of https://github.com/mawww/kakoune.git synced 2024-09-11 13:00:41 +03:00

Compare commits

...

6 Commits

Author SHA1 Message Date
Johannes Altmanninger
e1865b900b
Merge 09cd7207c0 into 700265b25d 2024-06-12 22:56:24 +00:00
Johannes Altmanninger
09cd7207c0 Use menu behavior when completing %opt/%val expansions
Now that the completions include closing delimiters, this is actually
useful because we can type

	echo %val{bufn<ret>

and it will do the right thing.

Don't include register expansions because we currently don't offer
completions for all registers. (We could add that fairly easily.
We'd want to handle some interesting edge cases.  For example query
%reg| should be completed to %reg|:| but also %reg||||.)

File expansions of files that contain a quoting delimiter will be
wrong but that's an unrelated problem, and also pretty minor since
%file{} is rarely used interactively.
2023-05-09 11:32:37 +02:00
Johannes Altmanninger
52b8828a06 Add closing delimiter to completions of %opt/%file/%reg/%val expansion
This looks a bit weird but it's exactly what the user needs to type
anyway.  Adding the closing delimiter later (when the completion is
accepted) would be less predictable.
2023-05-09 11:32:37 +02:00
Johannes Altmanninger
9dde483741 Teach token about its closing delimiter
Will use in the next commit.
2023-05-09 11:32:37 +02:00
Johannes Altmanninger
c6e022725f Use "" instead of {} to initialize empty tokens' contents
Makes it a bit easier to see which constructor argument is which.
2023-05-09 11:32:37 +02:00
Johannes Altmanninger
9ad39c5263 Complete possible expansions in prompt
When typing %, suggest possible expansion types.
This is pretty minor, happy to drop it.
2023-05-09 11:32:37 +02:00
2 changed files with 42 additions and 20 deletions

View File

@ -280,6 +280,8 @@ Token parse_percent_token(ParseState& state, bool throw_on_unterminated)
if (throw_on_unterminated)
throw parse_error{format("expected a string delimiter after '%{}'",
type_name)};
if (at_end)
return {Token::Type::UnknownExpand, type_start - state.str.begin(), type_name.str()};
return {};
}
@ -307,7 +309,7 @@ Token parse_percent_token(ParseState& state, bool throw_on_unterminated)
it->opening, it->closing)};
}
return {type, byte_pos, std::move(quoted.content), quoted.terminated};
return {type, byte_pos, std::move(quoted.content), {{(Codepoint)it->closing, quoted.terminated}}};
}
else
{
@ -322,7 +324,7 @@ Token parse_percent_token(ParseState& state, bool throw_on_unterminated)
opening_delimiter, opening_delimiter)};
}
return {type, byte_pos, std::move(quoted.content), quoted.terminated};
return {type, byte_pos, std::move(quoted.content), {{opening_delimiter, quoted.terminated}}};
}
}
@ -431,7 +433,7 @@ Optional<Token> CommandParser::read_token(bool throw_on_unterminated)
return Token{c == '"' ? Token::Type::Expand
: Token::Type::RawQuoted,
start - line.begin(), std::move(quoted.content),
quoted.terminated};
{{(Codepoint)c, quoted.terminated}}};
}
else if (c == '%')
{
@ -440,7 +442,7 @@ Optional<Token> CommandParser::read_token(bool throw_on_unterminated)
}
else if (is_command_separator(c))
return Token{Token::Type::CommandSeparator,
++m_state.pos - line.begin(), {}};
++m_state.pos - line.begin(), ""};
else
{
if (c == '\\' and m_state.pos + 1 != m_state.str.end())
@ -659,37 +661,51 @@ static Completions complete_expansion(const Context& context, CompletionFlags fl
Token token, ByteCount start,
ByteCount cursor_pos, ByteCount pos_in_token)
{
CandidateList candidates;
switch (token.type) {
case Token::Type::RegisterExpand:
return { start, cursor_pos,
RegisterManager::instance().complete_register_name(
token.content, pos_in_token) };
candidates = RegisterManager::instance().complete_register_name(token.content, pos_in_token);
break;
case Token::Type::OptionExpand:
return { start, cursor_pos,
GlobalScope::instance().option_registry().complete_option_name(
token.content, pos_in_token) };
candidates = GlobalScope::instance().option_registry().complete_option_name(token.content, pos_in_token);
break;
case Token::Type::ShellExpand:
return offset_pos(shell_complete(context, flags, token.content,
pos_in_token), start);
case Token::Type::ValExpand:
return { start, cursor_pos,
ShellManager::instance().complete_env_var(
token.content, pos_in_token) };
candidates = ShellManager::instance().complete_env_var(token.content, pos_in_token);
break;
case Token::Type::FileExpand:
{
const auto& ignored_files = context.options()["ignored_files"].get<Regex>();
return { start, cursor_pos, complete_filename(
token.content, ignored_files, pos_in_token, FilenameFlags::Expand) };
candidates = complete_filename(token.content, ignored_files, pos_in_token, FilenameFlags::Expand);
break;
}
case Token::Type::UnknownExpand:
return { start, cursor_pos, Kakoune::complete(token.content, cursor_pos, Array{"exp", "file", "opt", "reg", "sh", "val"}) };
default:
kak_assert(false);
throw runtime_error("unknown expansion");
}
for (auto &c : candidates)
{
if ((token.type == Token::Type::ValExpand and c.ends_with("_")) // opt_, reg_, client_env_
or (token.type == Token::Type::FileExpand and c.ends_with("/")))
continue;
kak_assert(not token.terminator->present);
c += to_string(token.terminator->character);
}
auto completions_flags = token.type == Token::Type::RegisterExpand
? Completions::Flags::None : Completions::Flags::Menu;
return { start, cursor_pos, candidates, completions_flags };
}
static Completions complete_expand(const Context& context, CompletionFlags flags,
@ -706,7 +722,7 @@ static Completions complete_expand(const Context& context, CompletionFlags flags
else
{
auto token = parse_percent_token(state, false);
if (token.terminated)
if (token.terminator and token.terminator->present)
continue;
if (token.type == Token::Type::Raw or token.type == Token::Type::RawQuoted)
return {};
@ -771,11 +787,11 @@ Completions CommandManager::Completer::operator()(
}
if (is_last_token)
tokens.push_back({Token::Type::Raw, prefix.length(), {}});
tokens.push_back({Token::Type::Raw, prefix.length(), ""});
kak_assert(not tokens.empty());
const auto& token = tokens.back();
if (token.terminated) // do not complete past explicit token close
if (token.terminator and token.terminator->present) // do not complete past explicit token close
return Completions{};
const ByteCount start = token.pos;
@ -797,6 +813,7 @@ Completions CommandManager::Completer::operator()(
case Token::Type::ShellExpand:
case Token::Type::ValExpand:
case Token::Type::FileExpand:
case Token::Type::UnknownExpand:
return complete_expansion(context, flags, token, start, cursor_pos, pos_in_token);
case Token::Type::Raw:

View File

@ -52,13 +52,18 @@ struct Token
ValExpand,
ArgExpand,
FileExpand,
CommandSeparator
CommandSeparator,
UnknownExpand
};
Type type;
ByteCount pos;
String content;
bool terminated = false;
struct Terminator {
Codepoint character;
bool present;
};
Optional<Terminator> terminator{};
};
struct ParseState