diff --git a/src/buffer_manager.cc b/src/buffer_manager.cc index 400c9f5b..943a2085 100644 --- a/src/buffer_manager.cc +++ b/src/buffer_manager.cc @@ -3,6 +3,7 @@ #include "assert.hh" #include "buffer.hh" #include "client_manager.hh" +#include "containers.hh" #include "exception.hh" #include "file.hh" #include "string.hh" @@ -117,27 +118,19 @@ void BufferManager::backup_modified_buffers() CandidateList BufferManager::complete_buffer_name(StringView prefix, ByteCount cursor_pos) { - auto real_prefix = prefix.substr(0, cursor_pos); - const bool include_dirs = contains(real_prefix, '/'); - CandidateList result; - CandidateList subsequence_result; - for (auto& buffer : m_buffers) - { + const bool include_dirs = contains(prefix.substr(0, cursor_pos), '/'); + auto c = transformed(m_buffers, + [include_dirs](const safe_ptr& buffer) -> String { String name = buffer->display_name(); - StringView match_name = name; if (not include_dirs and buffer->flags() & Buffer::Flags::File) { ByteCount pos = name.find_last_of('/'); if (pos != (int)String::npos) - match_name = name.substr(pos+1); + return name.substr(pos+1); } - - if (prefix_match(match_name, real_prefix)) - result.push_back(name); - if (subsequence_match(name, real_prefix)) - subsequence_result.push_back(name); - } - return result.empty() ? subsequence_result : result; + return name; + }); + return complete(prefix, cursor_pos, c, prefix_match, subsequence_match); } void BufferManager::clear_buffer_trash() diff --git a/src/client_manager.cc b/src/client_manager.cc index 66b4bf62..213cc23f 100644 --- a/src/client_manager.cc +++ b/src/client_manager.cc @@ -2,6 +2,7 @@ #include "buffer_manager.hh" #include "command_manager.hh" +#include "containers.hh" #include "event_manager.hh" #include "face_registry.hh" #include "file.hh" @@ -172,19 +173,8 @@ void ClientManager::clear_mode_trashes() const CandidateList ClientManager::complete_client_name(StringView prefix, ByteCount cursor_pos) const { - auto real_prefix = prefix.substr(0, cursor_pos); - CandidateList result; - CandidateList subsequence_result; - for (auto& client : m_clients) - { - const String& name = client->context().name(); - - if (prefix_match(name, real_prefix)) - result.push_back(name); - if (subsequence_match(name, real_prefix)) - subsequence_result.push_back(name); - } - return result.empty() ? subsequence_result : result; + auto c = transformed(m_clients, [](const std::unique_ptr& c){ return c->context().name(); }); + return complete(prefix, cursor_pos, c, prefix_match, subsequence_match); } } diff --git a/src/completion.hh b/src/completion.hh index afaf6fbc..e978d0ac 100644 --- a/src/completion.hh +++ b/src/completion.hh @@ -53,5 +53,43 @@ inline Completions offset_pos(Completions completion, ByteCount offset) std::move(completion.candidates) }; } +namespace detail +{ + template + void do_matches(Str&& str, StringView prefix, + CandidateList* res, Func match_func) + { + if (match_func(str, prefix)) + res->push_back(str); + } + + template + void do_matches(Str&& str, StringView prefix, + CandidateList* res, Func match_func, Rest... rest) + { + do_matches(str, prefix, res, match_func); + do_matches(str, prefix, res+1, rest...); + } +} + +template +CandidateList complete(StringView prefix, ByteCount cursor_pos, + const Container& container, MatchFunc... match_func) +{ + CandidateList res[sizeof...(match_func)]; + auto real_prefix = prefix.substr(0, cursor_pos); + for (const auto& elem : container) + detail::do_matches(elem, real_prefix, res, match_func...); + auto it = find_if(res, [](CandidateList& c) { return not c.empty(); }); + return it == end(res) ? CandidateList{} : std::move(*it); +} + +template +CandidateList complete(StringView prefix, ByteCount cursor_pos, + const Container& container) +{ + return complete(prefix, cursor_pos, container, prefix_match); +} + } #endif // completion_hh_INCLUDED diff --git a/src/face_registry.cc b/src/face_registry.cc index d99937c6..367b99b4 100644 --- a/src/face_registry.cc +++ b/src/face_registry.cc @@ -2,6 +2,7 @@ #include "containers.hh" #include "exception.hh" +#include "containers.hh" namespace Kakoune { @@ -80,16 +81,12 @@ void FaceRegistry::register_alias(const String& name, const String& facedesc, } CandidateList FaceRegistry::complete_alias_name(StringView prefix, - ByteCount cursor_pos) const + ByteCount cursor_pos) const { - CandidateList res; - auto real_prefix = prefix.substr(0, cursor_pos); - for (auto& alias : m_aliases) - { - if (prefix_match(alias.first, real_prefix)) - res.push_back(alias.first); - } - return res; + using ValueType = std::pair; + return complete(prefix, cursor_pos, + transformed(m_aliases, + [](const ValueType& v){ return v.first; })); } FaceRegistry::FaceRegistry() diff --git a/src/function_registry.hh b/src/function_registry.hh index 5f3732ba..cf0ea46e 100644 --- a/src/function_registry.hh +++ b/src/function_registry.hh @@ -5,6 +5,7 @@ #include "id_map.hh" #include "string.hh" #include "exception.hh" +#include "containers.hh" namespace Kakoune { @@ -35,7 +36,8 @@ public: CandidateList complete_name(StringView prefix, ByteCount cursor_pos) { - return m_functions.complete_id(prefix, cursor_pos); + auto c = transformed(m_functions, id_map::get_id); + return complete(prefix, cursor_pos, c); } private: diff --git a/src/highlighter_group.cc b/src/highlighter_group.cc index 20058708..ecaafa95 100644 --- a/src/highlighter_group.cc +++ b/src/highlighter_group.cc @@ -48,11 +48,12 @@ Completions HighlighterGroup::complete_child(StringView path, ByteCount cursor_p return offset_pos(hl.complete_child(path.substr(offset), cursor_pos - offset, group), offset); } - auto condition = [=](const HighlighterMap::value_type& hl) - { - return not group or hl.second->has_children(); - }; - return { 0, 0, m_highlighters.complete_id_if(path, cursor_pos, condition) }; + using ValueType = HighlighterMap::value_type; + auto c = transformed(filtered(m_highlighters, + [=](const ValueType& hl) + { return not group or hl.second->has_children(); }), + HighlighterMap::get_id); + return { 0, 0, complete(path, cursor_pos, c) }; } } diff --git a/src/highlighters.cc b/src/highlighters.cc index 4f999230..a60f70f3 100644 --- a/src/highlighters.cc +++ b/src/highlighters.cc @@ -3,6 +3,7 @@ #include "assert.hh" #include "buffer_utils.hh" #include "context.hh" +#include "containers.hh" #include "display_buffer.hh" #include "face_registry.hh" #include "highlighter_group.hh" @@ -957,7 +958,8 @@ public: return offset_pos(hl.complete_child(path.substr(offset), cursor_pos - offset, group), offset); } - return { 0, 0, m_groups.complete_id(path, cursor_pos) }; + auto container = transformed(m_groups, id_map::get_id); + return { 0, 0, complete(path, cursor_pos, container) }; } static HighlighterAndId create(HighlighterParameters params) diff --git a/src/hook_manager.cc b/src/hook_manager.cc index 70e1c8eb..2fe8bf5c 100644 --- a/src/hook_manager.cc +++ b/src/hook_manager.cc @@ -1,5 +1,6 @@ #include "hook_manager.hh" +#include "containers.hh" #include "context.hh" #include "debug.hh" #include "regex.hh" @@ -26,8 +27,8 @@ CandidateList HookManager::complete_hook_group(StringView prefix, ByteCount pos_ CandidateList res; for (auto& list : m_hook) { - auto candidates = list.second.complete_id(prefix, pos_in_token); - for (auto& c : candidates) + auto container = transformed(list.second, id_map::get_id); + for (auto& c : complete(prefix, pos_in_token, container)) { if (!contains(res, c)) res.push_back(c); diff --git a/src/hook_manager.hh b/src/hook_manager.hh index 5aa52b2f..7a8b9ab7 100644 --- a/src/hook_manager.hh +++ b/src/hook_manager.hh @@ -2,6 +2,7 @@ #define hook_manager_hh_INCLUDED #include "id_map.hh" +#include "completion.hh" #include "unordered_map.hh" namespace Kakoune diff --git a/src/id_map.hh b/src/id_map.hh index a15903c1..7496a21a 100644 --- a/src/id_map.hh +++ b/src/id_map.hh @@ -2,7 +2,6 @@ #define id_map_hh_INCLUDED #include "containers.hh" -#include "completion.hh" #include "string.hh" #include @@ -63,30 +62,7 @@ public: m_content.erase(it, end()); } - template - CandidateList complete_id_if(StringView prefix, - ByteCount cursor_pos, - Condition condition) const - { - auto real_prefix = prefix.substr(0, cursor_pos); - CandidateList result; - for (auto& value : m_content) - { - if (not condition(value)) - continue; - - if (prefix_match(value.first, real_prefix)) - result.push_back(value.first); - } - return result; - } - - CandidateList complete_id(StringView prefix, - ByteCount cursor_pos) const - { - return complete_id_if( - prefix, cursor_pos, [](const value_type&) { return true; }); - } + static const String& get_id(const value_type& v) { return v.first; } bool empty() const { return m_content.empty(); } diff --git a/src/ncurses_ui.cc b/src/ncurses_ui.cc index 0a7dbf38..3b4d5b09 100644 --- a/src/ncurses_ui.cc +++ b/src/ncurses_ui.cc @@ -1,5 +1,6 @@ #include "ncurses_ui.hh" +#include "containers.hh" #include "display_buffer.hh" #include "event_manager.hh" #include "keys.hh" diff --git a/src/option_manager.hh b/src/option_manager.hh index c8fb1d5f..c1f9bd12 100644 --- a/src/option_manager.hh +++ b/src/option_manager.hh @@ -6,7 +6,6 @@ #include "exception.hh" #include "flags.hh" #include "option_types.hh" -#include "utils.hh" #include "regex.hh" namespace Kakoune diff --git a/src/register_manager.cc b/src/register_manager.cc index f9d36ae3..fb4baf81 100644 --- a/src/register_manager.cc +++ b/src/register_manager.cc @@ -1,8 +1,8 @@ #include "register_manager.hh" #include "assert.hh" -#include "id_map.hh" #include "exception.hh" +#include "id_map.hh" namespace Kakoune { diff --git a/src/scope.hh b/src/scope.hh index 0fb99f8d..5cc63b28 100644 --- a/src/scope.hh +++ b/src/scope.hh @@ -5,6 +5,7 @@ #include "hook_manager.hh" #include "keymap_manager.hh" #include "option_manager.hh" +#include "utils.hh" namespace Kakoune {