Use ranked match based completion for command names

This commit is contained in:
Maxime Coste 2016-03-08 13:56:37 +00:00
parent ead6865350
commit 21ae662151
5 changed files with 87 additions and 47 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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];

View File

@ -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;

View File

@ -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