From 21ae66215163976ea4c826dcdf55e04ddce54748 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Tue, 8 Mar 2016 13:56:37 +0000 Subject: [PATCH] Use ranked match based completion for command names --- src/alias_registry.cc | 2 +- src/alias_registry.hh | 3 +- src/command_manager.cc | 51 ++++++++++------------------ src/command_manager.hh | 2 ++ src/containers.hh | 76 ++++++++++++++++++++++++++++++++++++------ 5 files changed, 87 insertions(+), 47 deletions(-) diff --git a/src/alias_registry.cc b/src/alias_registry.cc index 6e92c006..375246a3 100644 --- a/src/alias_registry.cc +++ b/src/alias_registry.cc @@ -57,7 +57,7 @@ Vector> AliasRegistry::flatten_aliases() const res = m_parent->flatten_aliases(); for (auto& alias : m_aliases) { - if (not contains(transformed(res, [](const std::pair& val) { return val.first; }), alias.key)) + if (not contains(transformed(res, [](const AliasDesc& val) { return val.first; }), alias.key)) res.emplace_back(alias.key, alias.value); } return res; diff --git a/src/alias_registry.hh b/src/alias_registry.hh index 7f688e08..5ff093bb 100644 --- a/src/alias_registry.hh +++ b/src/alias_registry.hh @@ -20,7 +20,8 @@ public: using iterator = AliasMap::const_iterator; Vector aliases_for(StringView command) const; - Vector> flatten_aliases() const; + using AliasDesc = std::pair; + Vector flatten_aliases() const; private: friend class Scope; diff --git a/src/command_manager.cc b/src/command_manager.cc index 8dfb5181..65de501c 100644 --- a/src/command_manager.cc +++ b/src/command_manager.cc @@ -512,6 +512,17 @@ CommandInfo CommandManager::command_info(const Context& context, StringView comm return res; } +Completions CommandManager::complete_command_name(const Context& context, + StringView query) const +{ + return{0, query.length(), Kakoune::complete(query, query.length(), concatenated( + transformed(filtered(m_commands, [](const CommandMap::value_type& cmd) + { return not (cmd.second.flags & CommandFlags::Hidden); }), + [](const CommandMap::value_type& cmd) { return StringView{cmd.first}; }), + transformed(context.aliases().flatten_aliases(), + [](AliasRegistry::AliasDesc alias) { return alias.first; })))}; +} + Completions CommandManager::complete(const Context& context, CompletionFlags flags, StringView command_line, @@ -533,33 +544,16 @@ Completions CommandManager::complete(const Context& context, } } + const bool is_last_token = tok_idx == tokens.size(); // command name completion if (tokens.empty() or - (tok_idx == cmd_idx and (tok_idx == tokens.size() or + (tok_idx == cmd_idx and (is_last_token or tokens[tok_idx].type() == Token::Type::Raw or tokens[tok_idx].type() == Token::Type::RawQuoted))) { - const bool is_end_token = tok_idx == tokens.size(); - ByteCount cmd_start = is_end_token ? cursor_pos - : tokens[tok_idx].begin(); - Completions result(cmd_start, cursor_pos); - StringView prefix = command_line.substr(cmd_start, - cursor_pos - cmd_start); - - for (auto& command : m_commands) - { - if (command.second.flags & CommandFlags::Hidden) - continue; - if (prefix_match(command.first, prefix)) - result.candidates.push_back(command.first); - } - for (auto& alias : context.aliases().flatten_aliases()) - { - if (prefix_match(alias.first, prefix)) - result.candidates.push_back(alias.first.str()); - } - std::sort(result.candidates.begin(), result.candidates.end()); - return result; + auto cmd_start = is_last_token ? cursor_pos : tokens[tok_idx].begin(); + StringView query = command_line.substr(cmd_start, cursor_pos - cmd_start); + return offset_pos(complete_command_name(context, query), cmd_start); } kak_assert(not tokens.empty()); @@ -628,18 +622,7 @@ Completions CommandManager::complete(const Context& context, StringView prefix = params[token_to_complete].substr(0, pos_in_token); if (token_to_complete == 0) - { - CandidateList candidates; - for (auto& command : m_commands) - { - if (command.second.flags & CommandFlags::Hidden) - continue; - if (prefix_match(command.first, prefix)) - candidates.push_back(command.first); - } - std::sort(candidates.begin(), candidates.end()); - return {0, pos_in_token, std::move(candidates)}; - } + return complete_command_name(context, prefix); else { const String& command_name = params[0]; diff --git a/src/command_manager.hh b/src/command_manager.hh index dbc87e81..090ed0fb 100644 --- a/src/command_manager.hh +++ b/src/command_manager.hh @@ -130,6 +130,8 @@ private: const ShellContext& shell_context, CharCoord pos) const; + Completions complete_command_name(const Context& context, StringView query) const; + struct CommandDescriptor { Command command; diff --git a/src/containers.hh b/src/containers.hh index 6bf3bea6..871714ef 100644 --- a/src/containers.hh +++ b/src/containers.hh @@ -32,7 +32,7 @@ struct FilteredIterator : std::iterator { FilteredIterator(Filter filter, Iterator it, Iterator end) - : m_it(std::move(it)), m_end(std::move(end)), m_filter(std::move(filter)) + : m_it{std::move(it)}, m_end{std::move(end)}, m_filter{std::move(filter)} { do_filter(); } @@ -70,10 +70,10 @@ struct FilteredContainer { using iterator = FilteredIterator())), Filter>; FilteredContainer(Container& container, Filter filter) - : m_container(container), m_filter(std::move(filter)) {} + : m_container{container}, m_filter{std::move(filter)} {} - iterator begin() const { return iterator(m_filter, m_container.begin(), m_container.end()); } - iterator end() const { return iterator(m_filter, m_container.end(), m_container.end()); } + iterator begin() const { return {m_filter, m_container.begin(), m_container.end()}; } + iterator end() const { return {m_filter, m_container.end(), m_container.end()}; } private: Container& m_container; @@ -83,7 +83,7 @@ private: template FilteredContainer filtered(Container&& container, Filter filter) { - return FilteredContainer(container, std::move(filter)); + return {container, std::move(filter)}; } template @@ -94,7 +94,7 @@ struct TransformedIterator : std::iterator>::type> { TransformedIterator(Transform transform, Iterator it) - : m_it(std::move(it)), m_transform(std::move(transform)) {} + : m_it{std::move(it)}, m_transform{std::move(transform)} {} auto operator*() -> TransformedResult { return m_transform(*m_it); } TransformedIterator& operator++() { ++m_it; return *this; } @@ -117,16 +117,15 @@ private: Transform m_transform; }; - template struct TransformedContainer { using iterator = TransformedIterator())), Transform>; TransformedContainer(Container& container, Transform transform) - : m_container(container), m_transform(std::move(transform)) {} + : m_container{container}, m_transform{std::move(transform)} {} - iterator begin() const { return iterator(m_transform, m_container.begin()); } - iterator end() const { return iterator(m_transform, m_container.end()); } + iterator begin() const { return {m_transform, m_container.begin()}; } + iterator end() const { return {m_transform, m_container.end()}; } private: Container& m_container; @@ -136,7 +135,62 @@ private: template TransformedContainer transformed(Container&& container, Transform transform) { - return TransformedContainer(container, std::move(transform)); + return {container, std::move(transform)}; +} + +template +struct ConcatenatedIterator : std::iterator +{ + static_assert(std::is_convertible::value, ""); + static_assert(std::is_convertible::value, ""); + + ConcatenatedIterator(Iterator1 it1, Iterator1 end1, Iterator2 it2) + : m_it1(std::move(it1)), m_end1(std::move(end1)), m_it2(std::move(it2)) {} + + decltype(*std::declval()) operator*() { return is2() ? *m_it2 : *m_it1; } + ConcatenatedIterator& operator++() { if (is2()) ++m_it2; else ++m_it1; return *this; } + ConcatenatedIterator operator++(int) { auto copy = *this; ++*this; return copy; } + + friend bool operator==(const ConcatenatedIterator& lhs, const ConcatenatedIterator& rhs) + { + return lhs.m_it1 == rhs.m_it1 and lhs.m_end1 == rhs.m_end1 and lhs.m_it2 == rhs.m_it2; + } + + friend bool operator!=(const ConcatenatedIterator& lhs, const ConcatenatedIterator& rhs) + { + return not (lhs == rhs); + } + +private: + bool is2() const { return m_it1 == m_end1; } + + Iterator1 m_it1; + Iterator1 m_end1; + Iterator2 m_it2; +}; + + +template +struct ConcatenatedContainer +{ + using iterator = ConcatenatedIterator())), + decltype(begin(std::declval()))>; + + ConcatenatedContainer(Container1& container1, Container2& container2) + : m_container1{container1}, m_container2{container2} {} + + iterator begin() const { return {m_container1.begin(), m_container1.end(), m_container2.begin()}; } + iterator end() const { return {m_container1.end(), m_container1.end(), m_container2.end()}; } + +private: + Container1& m_container1; + Container2& m_container2; +}; + +template +ConcatenatedContainer concatenated(Container1&& container1, Container2&& container2) +{ + return {container1, container2}; } // Todo: move that into the following functions once we can remove the decltype