Skip to content

Commit

Permalink
Introduce the 'completion_extra_word_chars' option
Browse files Browse the repository at this point in the history
This string option is used to get all the additional characters
that should be considered as "word" character for the purpose of
insert mode completion.

Fixes #758
  • Loading branch information
mawww committed Aug 24, 2016
1 parent 9124851 commit 3f0415c
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 13 deletions.
3 changes: 3 additions & 0 deletions README.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -899,6 +899,9 @@ Some options are built in Kakoune, and can be used to control it's behaviour:
where the completion apply in the buffer.
* `static_words` _str-list_: list of words that are always added to completion
candidates when completing words in insert mode.
* `completions_extra_word_chars` _str_: a string containing all additional character
that should be considered as word character for the purpose of insert mode
completion.
* `autoreload` _enum(yes|no|ask)_: auto reload the buffers when an external
modification is detected.
* `debug` _flags(hooks|shell|profile)_: dump various debug information in
Expand Down
10 changes: 7 additions & 3 deletions doc/manpages/options.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,13 @@ Builtin options
to define where the completion apply in the buffer, and the
other strings are the candidates

*static_words* 'str-list':::
list of words that are always added to completion candidates
when completing words in insert mode
*static_words* 'str-list'::
list of words that are always added to completion candidates
when completing words in insert mode

*completions_extra_word_chars* 'str'::
a string containing all additional character that should be considered
as word character for the purpose of insert mode completion.

*autoreload* 'enum(yes|no|ask)'::
auto reload the buffers when an external modification is detected
Expand Down
9 changes: 6 additions & 3 deletions src/insert_completer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,15 @@ WordDB& get_word_db(const Buffer& buffer)
template<bool other_buffers>
InsertCompletion complete_word(const SelectionList& sels, const OptionManager& options)
{
StringView extra_word_char = options["completion_extra_word_char"].get<String>();
auto is_word_pred = [extra_word_char](Codepoint c) { return is_word(c) or contains(extra_word_char, c); };

const Buffer& buffer = sels.buffer();
ByteCoord cursor_pos = sels.main().cursor();

using Utf8It = utf8::iterator<BufferIterator>;
Utf8It pos{buffer.iterator_at(cursor_pos), buffer};
if (pos == buffer.begin() or not is_word(*(pos-1)))
if (pos == buffer.begin() or not is_word_pred(*(pos-1)))
return {};

ByteCoord word_begin;
Expand All @@ -92,7 +95,7 @@ InsertCompletion complete_word(const SelectionList& sels, const OptionManager& o
Utf8It end{buffer.iterator_at(sels[i].cursor()), buffer};
Utf8It begin = end-1;
if (not skip_while_reverse(begin, buffer.begin(),
[](Codepoint c) { return is_word(c); }))
[&](Codepoint c) { return is_word_pred(c); }))
++begin;

if (i == sels.main_index())
Expand All @@ -101,7 +104,7 @@ InsertCompletion complete_word(const SelectionList& sels, const OptionManager& o
prefix = buffer.string(word_begin, end.base().coord());
}

skip_while(end, buffer.end(), [](Codepoint c) { return is_word(c); });
skip_while(end, buffer.end(), [&](Codepoint c) { return is_word_pred(c); });

auto word = buffer.string(begin.base().coord(), end.base().coord());
++sel_word_counts[word];
Expand Down
3 changes: 3 additions & 0 deletions src/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,9 @@ void register_options()
"%val{bufname} %val{cursor_line}:%val{cursor_char_column} "_str);
reg.declare_option("debug", "various debug flags", DebugFlags::None);
reg.declare_option("readonly", "prevent buffers from being modified", false);
reg.declare_option("completion_extra_word_char",
"Additional characters to be considered as words for insert completion",
""_str);
}

struct convert_to_client_mode
Expand Down
51 changes: 46 additions & 5 deletions src/word_db.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace Kakoune

using WordList = Vector<StringView>;

static WordList get_words(StringView content)
static WordList get_words(StringView content, StringView extra_word_chars)
{
WordList res;
using Utf8It = utf8::iterator<const char*>;
Expand All @@ -19,7 +19,7 @@ static WordList get_words(StringView content)
for (Utf8It it{word_start, content}, end{content.end(), content}; it != end; ++it)
{
Codepoint c = *it;
const bool word = is_word(c);
const bool word = is_word(c) or contains(extra_word_chars, c);
if (not in_word and word)
{
word_start = it.base();
Expand All @@ -36,9 +36,14 @@ static WordList get_words(StringView content)
return res;
}

static StringView get_extra_word_chars(const Buffer& buffer)
{
return buffer.options()["completion_extra_word_char"].get<String>();
}

void WordDB::add_words(StringView line)
{
for (auto& w : get_words(line))
for (auto& w : get_words(line, get_extra_word_chars(*m_buffer)))
{
auto it = m_words.find(w);
if (it == m_words.end())
Expand All @@ -56,7 +61,7 @@ void WordDB::add_words(StringView line)

void WordDB::remove_words(StringView line)
{
for (auto& w : get_words(line))
for (auto& w : get_words(line, get_extra_word_chars(*m_buffer)))
{
auto it = m_words.find(w);
kak_assert(it != m_words.end() and it->second.refcount > 0);
Expand All @@ -66,14 +71,44 @@ void WordDB::remove_words(StringView line)
}

WordDB::WordDB(const Buffer& buffer)
: m_buffer{&buffer}, m_timestamp{buffer.timestamp()}
: m_buffer{&buffer}
{
buffer.options().register_watcher(*this);
rebuild_db();
}

WordDB::WordDB(WordDB&& other)
: m_buffer{std::move(other.m_buffer)},
m_lines{std::move(other.m_lines)},
m_words{std::move(other.m_words)},
m_timestamp{other.m_timestamp}
{
kak_assert(m_buffer);
m_buffer->options().unregister_watcher(other);
other.m_buffer = nullptr;

m_buffer->options().register_watcher(*this);
}

WordDB::~WordDB()
{
if (m_buffer)
m_buffer->options().unregister_watcher(*this);
}

void WordDB::rebuild_db()
{
auto& buffer = *m_buffer;

m_words.clear();
m_lines.clear();
m_lines.reserve((int)buffer.line_count());
for (auto line = 0_line, end = buffer.line_count(); line < end; ++line)
{
m_lines.push_back(buffer.line_storage(line));
add_words(m_lines.back()->strview());
}
m_timestamp = buffer.timestamp();
}

void WordDB::update_db()
Expand Down Expand Up @@ -118,6 +153,12 @@ void WordDB::update_db()
m_lines = std::move(new_lines);
}

void WordDB::on_option_changed(const Option& option)
{
if (option.name() == "completion_extra_word_char")
rebuild_db();
}

int WordDB::get_word_occurences(StringView word) const
{
auto it = m_words.find(word);
Expand Down
9 changes: 7 additions & 2 deletions src/word_db.hh
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ namespace Kakoune
using RankedMatchList = Vector<RankedMatch>;

// maintain a database of words available in a buffer
class WordDB
class WordDB : public OptionManagerWatcher
{
public:
WordDB(const Buffer& buffer);
~WordDB();
WordDB(const WordDB&) = delete;
WordDB(WordDB&&) = default;
WordDB(WordDB&&);

RankedMatchList find_matching(StringView str);

Expand All @@ -28,6 +29,10 @@ private:
void add_words(StringView line);
void remove_words(StringView line);

void rebuild_db();

void on_option_changed(const Option& option) override;

struct WordInfo
{
StringDataPtr word;
Expand Down

0 comments on commit 3f0415c

Please sign in to comment.