Add automatic completion display in prompt mode
Controlled by the autoshowcompl option Completers now take a CompletionFlag parameter, used to specify we want fast completion (tag completion can be slow, we do not want to run it if not explicitely wanted by the user).
This commit is contained in:
parent
70e94cb00a
commit
3e1bb777ce
|
@ -394,6 +394,8 @@ Some options are built in kakoune, and can be used to control it's behaviour:
|
|||
candidates exist, enable completion with common prefix.
|
||||
* +incsearch+ _bool_: execute search as it is typed
|
||||
* +autoinfo+ _bool_: display automatic information box for certain commands.
|
||||
* +autoshowcompl+ _bool_: automatically display possible completions when
|
||||
editing a prompt.
|
||||
* +ignored_files+ _regex_: filenames matching this regex wont be considered
|
||||
as candidates on filename completion (except if the text being completed
|
||||
already matches it).
|
||||
|
|
|
@ -410,9 +410,9 @@ public:
|
|||
const bool reverse = (key == Key::BackTab);
|
||||
CandidateList& candidates = m_completions.candidates;
|
||||
// first try, we need to ask our completer for completions
|
||||
if (m_current_completion == -1)
|
||||
if (candidates.empty())
|
||||
{
|
||||
m_completions = m_completer(context(), line,
|
||||
m_completions = m_completer(context(), CompletionFlags::None, line,
|
||||
line.byte_count_to(m_line_editor.cursor_pos()));
|
||||
if (candidates.empty())
|
||||
return;
|
||||
|
@ -451,13 +451,26 @@ public:
|
|||
// when we have only one completion candidate, make next tab complete
|
||||
// from the new content.
|
||||
if (candidates.size() == 1)
|
||||
m_current_completion = -1;
|
||||
candidates.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
context().ui().menu_hide();
|
||||
m_current_completion = -1;
|
||||
m_line_editor.handle_key(key);
|
||||
m_current_completion = -1;
|
||||
context().ui().menu_hide();
|
||||
|
||||
if (context().options()["autoshowcompl"].get<bool>()) try
|
||||
{
|
||||
m_completions = m_completer(context(), CompletionFlags::Fast, line,
|
||||
line.byte_count_to(m_line_editor.cursor_pos()));
|
||||
CandidateList& candidates = m_completions.candidates;
|
||||
if (not candidates.empty())
|
||||
{
|
||||
DisplayCoord menu_pos{ context().ui().dimensions().line, 0_char };
|
||||
context().ui().menu_show(candidates, menu_pos, get_color("MenuForeground"),
|
||||
get_color("MenuBackground"), MenuStyle::Prompt);
|
||||
}
|
||||
} catch (runtime_error&) {}
|
||||
}
|
||||
display();
|
||||
m_callback(line, PromptEvent::Change, context());
|
||||
|
|
|
@ -312,7 +312,7 @@ void CommandManager::execute(const String& command_line,
|
|||
execute_single_command(params, context);
|
||||
}
|
||||
|
||||
Completions CommandManager::complete(const Context& context,
|
||||
Completions CommandManager::complete(const Context& context, CompletionFlags flags,
|
||||
const String& command_line, ByteCount cursor_pos)
|
||||
{
|
||||
TokenPosList pos_info;
|
||||
|
@ -363,13 +363,14 @@ Completions CommandManager::complete(const Context& context,
|
|||
std::vector<String> params;
|
||||
for (auto token_it = tokens.begin()+1; token_it != tokens.end(); ++token_it)
|
||||
params.push_back(token_it->content());
|
||||
result.candidates = command_it->second.completer(context, params,
|
||||
result.candidates = command_it->second.completer(context, flags, params,
|
||||
token_to_complete - 1,
|
||||
cursor_pos_in_token);
|
||||
return result;
|
||||
}
|
||||
|
||||
CandidateList PerArgumentCommandCompleter::operator()(const Context& context,
|
||||
CompletionFlags flags,
|
||||
CommandParameters params,
|
||||
size_t token_to_complete,
|
||||
ByteCount pos_in_token) const
|
||||
|
@ -382,7 +383,7 @@ CandidateList PerArgumentCommandCompleter::operator()(const Context& context,
|
|||
|
||||
const String& argument = token_to_complete < params.size() ?
|
||||
params[token_to_complete] : String();
|
||||
return m_completers[token_to_complete](context, argument, pos_in_token);
|
||||
return m_completers[token_to_complete](context, flags, argument, pos_in_token);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ struct Context;
|
|||
using CommandParameters = memoryview<String>;
|
||||
using Command = std::function<void (CommandParameters, Context& context)>;
|
||||
using CommandCompleter = std::function<CandidateList (const Context& context,
|
||||
CompletionFlags,
|
||||
CommandParameters,
|
||||
size_t, ByteCount)>;
|
||||
|
||||
|
@ -25,6 +26,7 @@ class PerArgumentCommandCompleter
|
|||
{
|
||||
public:
|
||||
using ArgumentCompleter = std::function<CandidateList (const Context&,
|
||||
CompletionFlags flags,
|
||||
const String&, ByteCount)>;
|
||||
using ArgumentCompleterList = memoryview<ArgumentCompleter>;
|
||||
|
||||
|
@ -32,6 +34,7 @@ public:
|
|||
: m_completers(completers.begin(), completers.end()) {}
|
||||
|
||||
CandidateList operator()(const Context& context,
|
||||
CompletionFlags flags,
|
||||
CommandParameters params,
|
||||
size_t token_to_complete,
|
||||
ByteCount pos_in_token) const;
|
||||
|
@ -47,7 +50,7 @@ public:
|
|||
memoryview<String> shell_params = {},
|
||||
const EnvVarMap& env_vars = EnvVarMap{});
|
||||
|
||||
Completions complete(const Context& context,
|
||||
Completions complete(const Context& context, CompletionFlags flags,
|
||||
const String& command_line, ByteCount cursor_pos);
|
||||
|
||||
bool command_defined(const String& command_name) const;
|
||||
|
|
|
@ -405,7 +405,8 @@ void define_command(CommandParameters params, Context& context)
|
|||
CommandCompleter completer;
|
||||
if (parser.has_option("file-completion"))
|
||||
{
|
||||
completer = [](const Context& context, CommandParameters params,
|
||||
completer = [](const Context& context, CompletionFlags flags,
|
||||
CommandParameters params,
|
||||
size_t token_to_complete, ByteCount pos_in_token)
|
||||
{
|
||||
const String& prefix = token_to_complete < params.size() ?
|
||||
|
@ -416,9 +417,12 @@ void define_command(CommandParameters params, Context& context)
|
|||
else if (parser.has_option("shell-completion"))
|
||||
{
|
||||
String shell_cmd = parser.option_value("shell-completion");
|
||||
completer = [=](const Context& context, CommandParameters params,
|
||||
completer = [=](const Context& context, CompletionFlags flags,
|
||||
CommandParameters params,
|
||||
size_t token_to_complete, ByteCount pos_in_token)
|
||||
{
|
||||
if (flags == CompletionFlags::Fast) // no shell on fast completion
|
||||
return CandidateList{};
|
||||
EnvVarMap vars = {
|
||||
{ "token_to_complete", to_string(token_to_complete) },
|
||||
{ "pos_in_token", to_string(pos_in_token) }
|
||||
|
@ -743,8 +747,9 @@ void change_working_directory(CommandParameters params, Context&)
|
|||
template<typename GetRootGroup>
|
||||
CommandCompleter group_rm_completer(GetRootGroup get_root_group)
|
||||
{
|
||||
return [=](const Context& context, CommandParameters params,
|
||||
size_t token_to_complete, ByteCount pos_in_token) {
|
||||
return [=](const Context& context, CompletionFlags flags,
|
||||
CommandParameters params, size_t token_to_complete,
|
||||
ByteCount pos_in_token) {
|
||||
auto& root_group = get_root_group(context);
|
||||
const String& arg = token_to_complete < params.size() ?
|
||||
params[token_to_complete] : String();
|
||||
|
@ -759,8 +764,9 @@ CommandCompleter group_rm_completer(GetRootGroup get_root_group)
|
|||
template<typename FactoryRegistry, typename GetRootGroup>
|
||||
CommandCompleter group_add_completer(GetRootGroup get_root_group)
|
||||
{
|
||||
return [=](const Context& context, CommandParameters params,
|
||||
size_t token_to_complete, ByteCount pos_in_token) {
|
||||
return [=](const Context& context, CompletionFlags flags,
|
||||
CommandParameters params, size_t token_to_complete,
|
||||
ByteCount pos_in_token) {
|
||||
auto& root_group = get_root_group(context);
|
||||
const String& arg = token_to_complete < params.size() ?
|
||||
params[token_to_complete] : String();
|
||||
|
@ -810,7 +816,7 @@ void register_commands()
|
|||
cm.register_commands({"nop"}, [](CommandParameters, Context&){});
|
||||
|
||||
PerArgumentCommandCompleter filename_completer({
|
||||
[](const Context& context, const String& prefix, ByteCount cursor_pos)
|
||||
[](const Context& context, CompletionFlags flags, const String& prefix, ByteCount cursor_pos)
|
||||
{ return complete_filename(prefix, context.options()["ignored_files"].get<Regex>(), cursor_pos); }
|
||||
});
|
||||
cm.register_commands({ "e", "edit" }, edit<false>, filename_completer);
|
||||
|
@ -823,7 +829,7 @@ void register_commands()
|
|||
cm.register_command("wq!", write_and_quit<true>);
|
||||
|
||||
PerArgumentCommandCompleter buffer_completer({
|
||||
[](const Context& context, const String& prefix, ByteCount cursor_pos)
|
||||
[](const Context& context, CompletionFlags flags, const String& prefix, ByteCount cursor_pos)
|
||||
{ return BufferManager::instance().complete_buffername(prefix, cursor_pos); }
|
||||
});
|
||||
cm.register_commands({ "b", "buffer" }, show_buffer, buffer_completer);
|
||||
|
@ -857,7 +863,7 @@ void register_commands()
|
|||
cm.register_command("debug", write_debug_message);
|
||||
|
||||
cm.register_command("set", set_option,
|
||||
[](const Context& context, CommandParameters params, size_t token_to_complete, ByteCount pos_in_token)
|
||||
[](const Context& context, CompletionFlags, CommandParameters params, size_t token_to_complete, ByteCount pos_in_token)
|
||||
{
|
||||
if (token_to_complete == 0)
|
||||
{
|
||||
|
|
|
@ -26,10 +26,15 @@ struct Completions
|
|||
: start(start), end(end) {}
|
||||
};
|
||||
|
||||
typedef std::function<Completions (const Context&,
|
||||
const String&, ByteCount)> Completer;
|
||||
enum class CompletionFlags
|
||||
{
|
||||
None,
|
||||
Fast
|
||||
};
|
||||
using Completer = std::function<Completions (const Context&, CompletionFlags,
|
||||
const String&, ByteCount)>;
|
||||
|
||||
inline Completions complete_nothing(const Context& context,
|
||||
inline Completions complete_nothing(const Context& context, CompletionFlags,
|
||||
const String&, ByteCount cursor_pos)
|
||||
{
|
||||
return Completions(cursor_pos, cursor_pos);
|
||||
|
|
|
@ -249,7 +249,7 @@ void command(Context& context, int)
|
|||
{
|
||||
context.client().prompt(
|
||||
":", get_color("Prompt"),
|
||||
std::bind(&CommandManager::complete, &CommandManager::instance(), _1, _2, _3),
|
||||
std::bind(&CommandManager::complete, &CommandManager::instance(), _1, _2, _3, _4),
|
||||
[](const String& cmdline, PromptEvent event, Context& context) {
|
||||
if (event == PromptEvent::Validate)
|
||||
CommandManager::instance().execute(cmdline, context);
|
||||
|
|
|
@ -116,6 +116,7 @@ GlobalOptions::GlobalOptions()
|
|||
declare_option<bool>("complete_prefix", true);
|
||||
declare_option<bool>("incsearch", true);
|
||||
declare_option<bool>("autoinfo", true);
|
||||
declare_option<bool>("autoshowcompl", true);
|
||||
declare_option<Regex>("ignored_files", Regex{R"(^(\..*|.*\.(o|so|a))$)"});
|
||||
declare_option<String>("filetype", "");
|
||||
declare_option<std::vector<String>>("completions", {});
|
||||
|
|
Loading…
Reference in New Issue
Block a user