Use ranked match based completion for command names
This commit is contained in:
parent
ead6865350
commit
21ae662151
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue
Block a user