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();
|
res = m_parent->flatten_aliases();
|
||||||
for (auto& alias : m_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);
|
res.emplace_back(alias.key, alias.value);
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
|
|
|
@ -20,7 +20,8 @@ public:
|
||||||
using iterator = AliasMap::const_iterator;
|
using iterator = AliasMap::const_iterator;
|
||||||
|
|
||||||
Vector<StringView> aliases_for(StringView command) const;
|
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:
|
private:
|
||||||
friend class Scope;
|
friend class Scope;
|
||||||
|
|
|
@ -512,6 +512,17 @@ CommandInfo CommandManager::command_info(const Context& context, StringView comm
|
||||||
return res;
|
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,
|
Completions CommandManager::complete(const Context& context,
|
||||||
CompletionFlags flags,
|
CompletionFlags flags,
|
||||||
StringView command_line,
|
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
|
// command name completion
|
||||||
if (tokens.empty() or
|
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::Raw or
|
||||||
tokens[tok_idx].type() == Token::Type::RawQuoted)))
|
tokens[tok_idx].type() == Token::Type::RawQuoted)))
|
||||||
{
|
{
|
||||||
const bool is_end_token = tok_idx == tokens.size();
|
auto cmd_start = is_last_token ? cursor_pos : tokens[tok_idx].begin();
|
||||||
ByteCount cmd_start = is_end_token ? cursor_pos
|
StringView query = command_line.substr(cmd_start, cursor_pos - cmd_start);
|
||||||
: tokens[tok_idx].begin();
|
return offset_pos(complete_command_name(context, query), cmd_start);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
kak_assert(not tokens.empty());
|
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);
|
StringView prefix = params[token_to_complete].substr(0, pos_in_token);
|
||||||
|
|
||||||
if (token_to_complete == 0)
|
if (token_to_complete == 0)
|
||||||
{
|
return complete_command_name(context, prefix);
|
||||||
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)};
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const String& command_name = params[0];
|
const String& command_name = params[0];
|
||||||
|
|
|
@ -130,6 +130,8 @@ private:
|
||||||
const ShellContext& shell_context,
|
const ShellContext& shell_context,
|
||||||
CharCoord pos) const;
|
CharCoord pos) const;
|
||||||
|
|
||||||
|
Completions complete_command_name(const Context& context, StringView query) const;
|
||||||
|
|
||||||
struct CommandDescriptor
|
struct CommandDescriptor
|
||||||
{
|
{
|
||||||
Command command;
|
Command command;
|
||||||
|
|
|
@ -32,7 +32,7 @@ struct FilteredIterator : std::iterator<std::forward_iterator_tag,
|
||||||
typename Iterator::value_type>
|
typename Iterator::value_type>
|
||||||
{
|
{
|
||||||
FilteredIterator(Filter filter, Iterator it, Iterator end)
|
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();
|
do_filter();
|
||||||
}
|
}
|
||||||
|
@ -70,10 +70,10 @@ struct FilteredContainer
|
||||||
{
|
{
|
||||||
using iterator = FilteredIterator<decltype(begin(std::declval<Container>())), Filter>;
|
using iterator = FilteredIterator<decltype(begin(std::declval<Container>())), Filter>;
|
||||||
FilteredContainer(Container& container, Filter 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 begin() const { return {m_filter, m_container.begin(), m_container.end()}; }
|
||||||
iterator end() const { return iterator(m_filter, m_container.end(), m_container.end()); }
|
iterator end() const { return {m_filter, m_container.end(), m_container.end()}; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Container& m_container;
|
Container& m_container;
|
||||||
|
@ -83,7 +83,7 @@ private:
|
||||||
template<typename Container, typename Filter>
|
template<typename Container, typename Filter>
|
||||||
FilteredContainer<Container, Filter> filtered(Container&& container, Filter 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>
|
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>
|
typename std::remove_reference<TransformedResult<Iterator, Transform>>::type>
|
||||||
{
|
{
|
||||||
TransformedIterator(Transform transform, Iterator it)
|
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); }
|
auto operator*() -> TransformedResult<Iterator, Transform> { return m_transform(*m_it); }
|
||||||
TransformedIterator& operator++() { ++m_it; return *this; }
|
TransformedIterator& operator++() { ++m_it; return *this; }
|
||||||
|
@ -117,16 +117,15 @@ private:
|
||||||
Transform m_transform;
|
Transform m_transform;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template<typename Container, typename Transform>
|
template<typename Container, typename Transform>
|
||||||
struct TransformedContainer
|
struct TransformedContainer
|
||||||
{
|
{
|
||||||
using iterator = TransformedIterator<decltype(begin(std::declval<Container>())), Transform>;
|
using iterator = TransformedIterator<decltype(begin(std::declval<Container>())), Transform>;
|
||||||
TransformedContainer(Container& container, Transform 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 begin() const { return {m_transform, m_container.begin()}; }
|
||||||
iterator end() const { return iterator(m_transform, m_container.end()); }
|
iterator end() const { return {m_transform, m_container.end()}; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Container& m_container;
|
Container& m_container;
|
||||||
|
@ -136,7 +135,62 @@ private:
|
||||||
template<typename Container, typename Transform>
|
template<typename Container, typename Transform>
|
||||||
TransformedContainer<Container, Transform> transformed(Container&& container, Transform 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
|
// Todo: move that into the following functions once we can remove the decltype
|
||||||
|
|
Loading…
Reference in New Issue
Block a user