Insert mode completion execute completers in order, and supports multiple option

The 'completions' option is gone, just add option=completion_option_name
in the completers list.
This commit is contained in:
Maxime Coste 2014-03-15 03:14:23 +00:00
parent 19f5eb65e8
commit 36b016226c
5 changed files with 72 additions and 33 deletions

View File

@ -523,15 +523,18 @@ Some options are built in Kakoune, and can be used to control it's behaviour:
* +filetype+ _str_: arbitrary string defining the type of the file * +filetype+ _str_: arbitrary string defining the type of the file
filetype dependant actions should hook on this option changing for filetype dependant actions should hook on this option changing for
activation/deactivation. activation/deactivation.
* +completions+ _str-list_: option used for external completion, the
first string should follow the format
_<line>.<column>[+<length>]@<timestamp>_ to define where the completion
apply in the buffer, and the other strings are the candidates.
* +path+ _str-list_: directories to search for gf command. * +path+ _str-list_: directories to search for gf command.
* +completers+ _str-list_: completion systems to use for insert mode * +completers+ _str-list_: completion systems to use for insert mode
completion. Support +option+ which use the +completions+ option, and completion. given completers are tried in order until one generate some
+word=all+ or +word=buffer+ which complete using words in all buffers completion candidates. Existing completers are:
(+word=all+) or only the current one (+word=buffer+) - +word=all+ or +word=buffer+ which complete using words in all buffers
(+word=all+) or only the current one (+word=buffer+)
- +filename+ which tries to detect when a filename is being entered and
provides completion based on local filesystem.
- +option=<opt-name>+ where <opt-name> is a _str-list_ option. The first
element of the list should follow the format:
_<line>.<column>[+<length>]@<timestamp>_ to define where the completion
apply in the buffer, and the other strings are the candidates.
* +autoreload+ _yesnoask_: auto reload the buffers when an external * +autoreload+ _yesnoask_: auto reload the buffers when an external
modification is detected. modification is detected.

View File

@ -1,5 +1,6 @@
decl -hidden str clang_filename decl -hidden str clang_filename
decl str clang_options decl str clang_options
decl str-list clang_completions
def clang-complete %{ def clang-complete %{
%sh{ %sh{
@ -23,12 +24,13 @@ def clang-complete %{
for cmp in ${output}; do for cmp in ${output}; do
completions="${completions}:${cmp}" completions="${completions}:${cmp}"
done done
echo "eval -client $kak_client %[ echo completed; set buffer completions '${completions}' ]" | kak -p ${kak_session} echo "eval -client $kak_client %[ echo completed; set buffer clang_completions '${completions}' ]" | kak -p ${kak_session}
) > /dev/null 2>&1 < /dev/null & ) > /dev/null 2>&1 < /dev/null &
} }
} }
def clang-enable-autocomplete %{ def clang-enable-autocomplete %{
set window completers %sh{ echo "'option=clang_completions:${kak_opt_completers}'" }
hook window -id clang-autocomplete InsertIdle .* %{ try %{ hook window -id clang-autocomplete InsertIdle .* %{ try %{
exec -draft <a-h><a-k>(\.|->|::).$<ret> exec -draft <a-h><a-k>(\.|->|::).$<ret>
echo 'completing...' echo 'completing...'
@ -36,4 +38,7 @@ def clang-enable-autocomplete %{
} } } }
} }
def clang-disable-autocomplete %{ rmhooks window clang-autocomplete } def clang-disable-autocomplete %{
set window completers %sh{ echo "'${kak_opt_completers}'" | sed -e 's/option=clang_completions://g' }
rmhooks window clang-autocomplete
}

View File

@ -31,7 +31,7 @@ def tag-complete %{ eval -draft %{
%sh{ ( %sh{ (
compl=$(readtags -p "$kak_selection" | cut -f 1 | sort | uniq | sed -e 's/:/\\:/g' | sed -e 's/\n/:/g' ) compl=$(readtags -p "$kak_selection" | cut -f 1 | sort | uniq | sed -e 's/:/\\:/g' | sed -e 's/\n/:/g' )
compl="${kak_cursor_line}.${kak_cursor_column}+${#kak_selection}@${kak_timestamp}:${compl}" compl="${kak_cursor_line}.${kak_cursor_column}+${#kak_selection}@${kak_timestamp}:${compl}"
echo "set buffer=$kak_bufname completions '${compl}'" | kak -p ${kak_session} echo "set buffer=$kak_bufname ctags_completions '${compl}'" | kak -p ${kak_session}
) > /dev/null 2>&1 < /dev/null & } ) > /dev/null 2>&1 < /dev/null & }
}} }}

View File

@ -11,6 +11,7 @@
#include "color_registry.hh" #include "color_registry.hh"
#include "file.hh" #include "file.hh"
#include "word_db.hh" #include "word_db.hh"
#include "debug.hh"
#include <unordered_map> #include <unordered_map>
@ -711,12 +712,20 @@ public:
m_context.ui().menu_hide(); m_context.ui().menu_hide();
} }
template<BufferCompletion (BufferCompleter::*complete_func)(const Buffer&, BufferCoord)> template<typename CompleteFunc>
bool try_complete() bool try_complete(CompleteFunc complete_func)
{ {
auto& buffer = m_context.buffer(); auto& buffer = m_context.buffer();
BufferCoord cursor_pos = m_context.selections().main().cursor(); BufferCoord cursor_pos = m_context.selections().main().cursor();
m_completions = (this->*complete_func)(buffer, cursor_pos); try
{
m_completions = complete_func(buffer, cursor_pos);
}
catch (runtime_error& e)
{
write_debug("error while trying to run completer: "_str + e.what());
return false;
}
if (not m_completions.is_valid()) if (not m_completions.is_valid())
return false; return false;
@ -812,9 +821,9 @@ public:
return { begin.coord(), pos.coord(), std::move(res), buffer.timestamp() }; return { begin.coord(), pos.coord(), std::move(res), buffer.timestamp() };
} }
BufferCompletion complete_option(const Buffer& buffer, BufferCoord cursor_pos) BufferCompletion complete_option(const Buffer& buffer, BufferCoord cursor_pos, const String& option_name)
{ {
const StringList& opt = options()["completions"].get<StringList>(); const StringList& opt = options()[option_name].get<StringList>();;
if (opt.empty()) if (opt.empty())
return {}; return {};
@ -868,7 +877,14 @@ public:
private: private:
void on_option_changed(const Option& opt) override void on_option_changed(const Option& opt) override
{ {
if (opt.name() == "completions") auto& completers = options()["completers"].get<StringList>();
StringList option_names;
for (auto& completer : completers)
{
if (completer.substr(0_byte, 7_byte) == "option=")
option_names.emplace_back(completer.substr(7_byte));
}
if (contains(option_names, opt.name()))
{ {
reset(); reset();
setup_ifn(); setup_ifn();
@ -889,18 +905,29 @@ private:
bool setup_ifn() bool setup_ifn()
{ {
using namespace std::placeholders;
if (not m_completions.is_valid()) if (not m_completions.is_valid())
{ {
auto& completers = options()["completers"].get<StringList>(); auto& completers = options()["completers"].get<StringList>();
if (contains(completers, "option") and try_complete<&BufferCompleter::complete_option>()) for (auto& completer : completers)
return true; {
if (contains(completers, "word=buffer") and try_complete<&BufferCompleter::complete_word<false>>()) if (completer == "filename" and
return true; try_complete([this](const Buffer& buffer, BufferCoord cursor_pos)
if (contains(completers, "word=all") and try_complete<&BufferCompleter::complete_word<true>>()) { return complete_filename(buffer, cursor_pos); }))
return true; return true;
if (contains(completers, "filename") and try_complete<&BufferCompleter::complete_filename>()) if (completer.substr(0_byte, 7_byte) == "option=" and
return true; try_complete([&, this](const Buffer& buffer, BufferCoord cursor_pos)
{ return complete_option(buffer, cursor_pos, completer.substr(7_byte)); }))
return true;
if (completer == "word=buffer" and
try_complete([this](const Buffer& buffer, BufferCoord cursor_pos)
{ return complete_word<false>(buffer, cursor_pos); }))
return true;
if (completer == "word=all" and
try_complete([this](const Buffer& buffer, BufferCoord cursor_pos)
{ return complete_word<true>(buffer, cursor_pos); }))
return true;
}
return false; return false;
} }
return true; return true;
@ -946,13 +973,14 @@ public:
if (m_mode == Mode::Complete) if (m_mode == Mode::Complete)
{ {
if (key.key == 'f') if (key.key == 'f')
m_completer.try_complete<&BufferCompleter::complete_filename>(); m_completer.try_complete([this](const Buffer& buffer, BufferCoord cursor_pos)
{ return m_completer.complete_filename(buffer, cursor_pos); });
if (key.key == 'w') if (key.key == 'w')
m_completer.try_complete<&BufferCompleter::complete_word<true>>(); m_completer.try_complete([this](const Buffer& buffer, BufferCoord cursor_pos)
if (key.key == 'o') { return m_completer.complete_word<true>(buffer, cursor_pos); });
m_completer.try_complete<&BufferCompleter::complete_option>();
if (key.key == 'l') if (key.key == 'l')
m_completer.try_complete<&BufferCompleter::complete_line>(); m_completer.try_complete([this](const Buffer& buffer, BufferCoord cursor_pos)
{ return m_completer.complete_line(buffer, cursor_pos); });
m_mode = Mode::Default; m_mode = Mode::Default;
return; return;
} }

View File

@ -133,15 +133,18 @@ GlobalOptions::GlobalOptions()
declare_option<bool>("aligntab", false); declare_option<bool>("aligntab", false);
declare_option<Regex>("ignored_files", Regex{R"(^(\..*|.*\.(o|so|a))$)"}); declare_option<Regex>("ignored_files", Regex{R"(^(\..*|.*\.(o|so|a))$)"});
declare_option<String>("filetype", ""); declare_option<String>("filetype", "");
declare_option<std::vector<String>>("completions", {});
declare_option<std::vector<String>>("path", { "./", "/usr/include" }); declare_option<std::vector<String>>("path", { "./", "/usr/include" });
declare_option<std::vector<String>>("completers", {"option", "filename", "word=buffer"}, declare_option<std::vector<String>>("completers", {"filename", "word=buffer"},
Option::Flags::None, Option::Flags::None,
[](const std::vector<String>& s) { [](const std::vector<String>& s) {
static const auto values = {"option", "word=buffer", "word=all", "filename" }; static const auto values = {"word=buffer", "word=all", "filename" };
for (auto& v : s) for (auto& v : s)
{
if (v.substr(0_byte, 7_byte) == "option=")
continue;
if (not contains(values, v)) if (not contains(values, v))
throw runtime_error(v + " is not a recognised value for completers"); throw runtime_error(v + " is not a recognised value for completers");
}
}); });
declare_option<YesNoAsk>("autoreload", Ask); declare_option<YesNoAsk>("autoreload", Ask);
} }