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:
parent
19f5eb65e8
commit
36b016226c
|
@ -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 dependant actions should hook on this option changing for
|
||||
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.
|
||||
* +completers+ _str-list_: completion systems to use for insert mode
|
||||
completion. Support +option+ which use the +completions+ option, and
|
||||
+word=all+ or +word=buffer+ which complete using words in all buffers
|
||||
completion. given completers are tried in order until one generate some
|
||||
completion candidates. Existing completers are:
|
||||
- +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
|
||||
modification is detected.
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
decl -hidden str clang_filename
|
||||
decl str clang_options
|
||||
decl str-list clang_completions
|
||||
|
||||
def clang-complete %{
|
||||
%sh{
|
||||
|
@ -23,12 +24,13 @@ def clang-complete %{
|
|||
for cmp in ${output}; do
|
||||
completions="${completions}:${cmp}"
|
||||
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 &
|
||||
}
|
||||
}
|
||||
|
||||
def clang-enable-autocomplete %{
|
||||
set window completers %sh{ echo "'option=clang_completions:${kak_opt_completers}'" }
|
||||
hook window -id clang-autocomplete InsertIdle .* %{ try %{
|
||||
exec -draft <a-h><a-k>(\.|->|::).$<ret>
|
||||
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
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ def tag-complete %{ eval -draft %{
|
|||
%sh{ (
|
||||
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}"
|
||||
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 & }
|
||||
}}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "color_registry.hh"
|
||||
#include "file.hh"
|
||||
#include "word_db.hh"
|
||||
#include "debug.hh"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
|
@ -711,12 +712,20 @@ public:
|
|||
m_context.ui().menu_hide();
|
||||
}
|
||||
|
||||
template<BufferCompletion (BufferCompleter::*complete_func)(const Buffer&, BufferCoord)>
|
||||
bool try_complete()
|
||||
template<typename CompleteFunc>
|
||||
bool try_complete(CompleteFunc complete_func)
|
||||
{
|
||||
auto& buffer = m_context.buffer();
|
||||
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())
|
||||
return false;
|
||||
|
||||
|
@ -812,9 +821,9 @@ public:
|
|||
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())
|
||||
return {};
|
||||
|
||||
|
@ -868,7 +877,14 @@ public:
|
|||
private:
|
||||
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();
|
||||
setup_ifn();
|
||||
|
@ -889,18 +905,29 @@ private:
|
|||
|
||||
bool setup_ifn()
|
||||
{
|
||||
using namespace std::placeholders;
|
||||
if (not m_completions.is_valid())
|
||||
{
|
||||
auto& completers = options()["completers"].get<StringList>();
|
||||
if (contains(completers, "option") and try_complete<&BufferCompleter::complete_option>())
|
||||
for (auto& completer : completers)
|
||||
{
|
||||
if (completer == "filename" and
|
||||
try_complete([this](const Buffer& buffer, BufferCoord cursor_pos)
|
||||
{ return complete_filename(buffer, cursor_pos); }))
|
||||
return true;
|
||||
if (contains(completers, "word=buffer") and try_complete<&BufferCompleter::complete_word<false>>())
|
||||
if (completer.substr(0_byte, 7_byte) == "option=" and
|
||||
try_complete([&, this](const Buffer& buffer, BufferCoord cursor_pos)
|
||||
{ return complete_option(buffer, cursor_pos, completer.substr(7_byte)); }))
|
||||
return true;
|
||||
if (contains(completers, "word=all") and try_complete<&BufferCompleter::complete_word<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 (contains(completers, "filename") and try_complete<&BufferCompleter::complete_filename>())
|
||||
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 true;
|
||||
|
@ -946,13 +973,14 @@ public:
|
|||
if (m_mode == Mode::Complete)
|
||||
{
|
||||
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')
|
||||
m_completer.try_complete<&BufferCompleter::complete_word<true>>();
|
||||
if (key.key == 'o')
|
||||
m_completer.try_complete<&BufferCompleter::complete_option>();
|
||||
m_completer.try_complete([this](const Buffer& buffer, BufferCoord cursor_pos)
|
||||
{ return m_completer.complete_word<true>(buffer, cursor_pos); });
|
||||
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;
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -133,15 +133,18 @@ GlobalOptions::GlobalOptions()
|
|||
declare_option<bool>("aligntab", false);
|
||||
declare_option<Regex>("ignored_files", Regex{R"(^(\..*|.*\.(o|so|a))$)"});
|
||||
declare_option<String>("filetype", "");
|
||||
declare_option<std::vector<String>>("completions", {});
|
||||
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,
|
||||
[](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)
|
||||
{
|
||||
if (v.substr(0_byte, 7_byte) == "option=")
|
||||
continue;
|
||||
if (not contains(values, v))
|
||||
throw runtime_error(v + " is not a recognised value for completers");
|
||||
}
|
||||
});
|
||||
declare_option<YesNoAsk>("autoreload", Ask);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user