summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMaxime Coste <frrrwww@gmail.com>2016-03-08 13:56:37 +0000
committerMaxime Coste <frrrwww@gmail.com>2016-03-08 13:56:37 +0000
commit21ae66215163976ea4c826dcdf55e04ddce54748 (patch)
tree527d0c769a77a8cb35644a9f42ed2a5f90e60b1a /src
parentead68653508473e2b7651fdf9c4d7eceb902bbdb (diff)
Use ranked match based completion for command names
Diffstat (limited to 'src')
-rw-r--r--src/alias_registry.cc2
-rw-r--r--src/alias_registry.hh3
-rw-r--r--src/command_manager.cc51
-rw-r--r--src/command_manager.hh2
-rw-r--r--src/containers.hh76
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<std::pair<StringView, StringView>> AliasRegistry::flatten_aliases() const
res = m_parent->flatten_aliases();
for (auto& alias : m_aliases)
{
- if (not contains(transformed(res, [](const std::pair<StringView, StringView>& 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<StringView> aliases_for(StringView command) const;
- Vector<std::pair<StringView, StringView>> flatten_aliases() const;
+ using AliasDesc = std::pair<StringView, StringView>;
+ Vector<AliasDesc> 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<std::forward_iterator_tag,
typename Iterator::value_type>
{
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<decltype(begin(std::declval<Container>())), 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<typename Container, typename Filter>
FilteredContainer<Container, Filter> filtered(Container&& container, Filter filter)
{
- return FilteredContainer<Container, Filter>(container, std::move(filter));
+ return {container, std::move(filter)};
}
template<typename I, typename T>
@@ -94,7 +94,7 @@ struct TransformedIterator : std::iterator<std::forward_iterator_tag,
typename std::remove_reference<TransformedResult<Iterator, Transform>>::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<Iterator, Transform> { return m_transform(*m_it); }
TransformedIterator& operator++() { ++m_it; return *this; }
@@ -117,16 +117,15 @@ private:
Transform m_transform;
};
-
template<typename Container, typename Transform>
struct TransformedContainer
{
using iterator = TransformedIterator<decltype(begin(std::declval<Container>())), 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<typename Container, typename Transform>
TransformedContainer<Container, Transform> transformed(Container&& container, Transform transform)
{
- return TransformedContainer<Container, Transform>(container, std::move(transform));
+ return {container, std::move(transform)};
+}
+
+template<typename Iterator1, typename Iterator2, typename ValueType = typename Iterator1::value_type>
+struct ConcatenatedIterator : std::iterator<std::forward_iterator_tag, ValueType>
+{
+ static_assert(std::is_convertible<typename Iterator1::value_type, ValueType>::value, "");
+ static_assert(std::is_convertible<typename Iterator2::value_type, ValueType>::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<Iterator1>()) 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<typename Container1, typename Container2>
+struct ConcatenatedContainer
+{
+ using iterator = ConcatenatedIterator<decltype(begin(std::declval<Container1>())),
+ decltype(begin(std::declval<Container2>()))>;
+
+ 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<typename Container1, typename Container2>
+ConcatenatedContainer<Container1, Container2> concatenated(Container1&& container1, Container2&& container2)
+{
+ return {container1, container2};
}
// Todo: move that into the following functions once we can remove the decltype