Skip to content

Commit

Permalink
[custom-completion-sorting] Support optional priority in completions …
Browse files Browse the repository at this point in the history
…options

Closes mawww#1709

This also allows supporting LSP's sortText (to a reasonable extent).
  • Loading branch information
krobelus committed Apr 16, 2023
1 parent 27ba689 commit 30b9b0d
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 15 deletions.
6 changes: 3 additions & 3 deletions src/insert_completer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -301,10 +301,10 @@ InsertCompletion complete_option(const SelectionList& sels,

for (auto& candidate : opt.list)
{
if (RankedMatchAndInfo match{std::get<0>(candidate), query})
auto& [completion, on_select, menu, priority] = candidate;
if (RankedMatchAndInfo match{completion, query, priority})
{
match.on_select = std::get<1>(candidate);
auto& menu = std::get<2>(candidate);
match.on_select = on_select;
match.menu_entry = not menu.empty() ?
parse_display_line(expand_tabs(menu, tabstop, column), faces)
: DisplayLine{String{}, {}};
Expand Down
2 changes: 1 addition & 1 deletion src/insert_completer.hh
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ inline StringView option_type_name(Meta::Type<InsertCompleterDesc>)
return "completer";
}

using CompletionCandidate = std::tuple<String, String, String>;
using CompletionCandidate = std::tuple<String, String, String, Optional<Priority>>;
using CompletionList = PrefixedList<String, CompletionCandidate>;

inline StringView option_type_name(Meta::Type<CompletionList>)
Expand Down
5 changes: 5 additions & 0 deletions src/option_types.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ UnitTest test_option_parsing{[]{
check(Vector<int>{10, 20, 30}, {"10", "20", "30"});
check(HashMap<String, int>{{"foo", 10}, {"b=r", 20}, {"b:z", 30}}, {"foo=10", "b\\=r=20", "b:z=30"});
check(DebugFlags::Keys | DebugFlags::Hooks, {"hooks|keys"});
check(std::tuple<int, Optional<int>, Optional<int>>(1, 2, 3), {"1|2|3"});
std::tuple<int, Optional<int>, Optional<int>> tupleWithNullOptionals{1, {}, {}};
check(tupleWithNullOptionals, {"1||"});
// Can also parse if tuple separators are missing.
kak_assert(option_from_strings(Meta::Type<decltype(tupleWithNullOptionals)>{}, {"1"}) == tupleWithNullOptionals);
}};

}
47 changes: 43 additions & 4 deletions src/option_types.hh
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,22 @@ inline Codepoint option_from_string(Meta::Type<Codepoint>, StringView str)
}
constexpr StringView option_type_name(Meta::Type<Codepoint>) { return "codepoint"; }

template<typename T>
String option_to_string(const Optional<T>& opt, Quoting quoting)
{
if (not opt)
return "";
return option_to_string(*opt, quoting);
}

template<typename T>
Optional<T> option_from_string(Meta::Type<Optional<T>>, StringView str)
{
if (str.empty())
return {};
return option_from_string(Meta::Type<T>{}, str);
}

template<typename T, MemoryDomain domain>
Vector<String> option_to_strings(const Vector<T, domain>& opt)
{
Expand Down Expand Up @@ -225,8 +241,32 @@ String option_to_string(const std::tuple<Types...>& opt, Quoting quoting)
return option_to_string_impl(quoting, opt, std::make_index_sequence<sizeof...(Types)>());
}

template<typename>
struct IsOptionalImpl : std::false_type{};
template<typename T>
struct IsOptionalImpl<Optional<T>> : std::true_type{};

template<typename...>
struct CountTrailingOptionals {};
template<>
struct CountTrailingOptionals<>
{
static constexpr bool all_optional = true;
static constexpr size_t value = 0;
};
template<typename Head, typename... Tail>
struct CountTrailingOptionals<Head, Tail...>
{
static constexpr bool all_optional = IsOptionalImpl<Head>::value
and CountTrailingOptionals<Tail...>::all_optional;
static_assert(not IsOptionalImpl<Head>::value or all_optional,
"non-optional fields cannot follow optional types");
static constexpr size_t value = all_optional ? 1 + sizeof...(Tail) : CountTrailingOptionals<Tail...>::value;
};

template<typename... Types, size_t... I>
std::tuple<Types...> option_from_string_impl(Meta::Type<std::tuple<Types...>>, StringView str,
std::tuple<Types...> option_from_string_impl(Meta::Type<std::tuple<Types...>>,
StringView str,
std::index_sequence<I...>)
{
struct error : runtime_error
Expand All @@ -237,15 +277,14 @@ std::tuple<Types...> option_from_string_impl(Meta::Type<std::tuple<Types...>>, S
};
auto elems = str | split<StringView>(tuple_separator, '\\')
| transform(unescape<tuple_separator, '\\'>)
| static_gather<error, sizeof...(Types)>();
| static_gather<error, sizeof...(Types), false, CountTrailingOptionals<Types...>::value>();
return std::tuple<Types...>{option_from_string(Meta::Type<Types>{}, elems[I])...};
}

template<typename... Types>
std::tuple<Types...> option_from_string(Meta::Type<std::tuple<Types...>>, StringView str)
{
return option_from_string_impl(Meta::Type<std::tuple<Types...>>{}, str,
std::make_index_sequence<sizeof...(Types)>());
return option_from_string_impl(Meta::Type<std::tuple<Types...>>{}, str, std::make_index_sequence<sizeof...(Types)>());
}

template<typename RealType, typename ValueType>
Expand Down
21 changes: 14 additions & 7 deletions src/ranges.hh
Original file line number Diff line number Diff line change
Expand Up @@ -648,34 +648,41 @@ auto gather()
}};
}

template<typename ExceptionType, bool throw_on_extra_elements, size_t... Indexes>
template<typename ExceptionType, bool throw_on_extra_elements, size_t optional_elements, size_t... Indexes>
auto elements()
{
return ViewFactory{[=] (auto&& range) {
using std::begin; using std::end;
using ElementType = std::remove_cvref_t<decltype(*begin(range))>;
auto it = begin(range), end_it = end(range);
auto elem = [&](size_t index) {
if (it == end_it) throw ExceptionType{index};
static_assert(sizeof...(Indexes) >= optional_elements);
if (it == end_it)
{
if (index >= sizeof...(Indexes) - optional_elements)
return ElementType{};
throw ExceptionType{index};
}
return *it++;
};
// Note that initializer lists elements are guaranteed to be sequenced
Array<std::remove_cvref_t<decltype(*begin(range))>, sizeof...(Indexes)> res{{elem(Indexes)...}};
Array<ElementType, sizeof...(Indexes)> res{{elem(Indexes)...}};
if (throw_on_extra_elements and it != end_it)
throw ExceptionType{sizeof...(Indexes)};
return res;
}};
}

template<typename ExceptionType, bool throw_on_extra_elements, size_t... Indexes>
template<typename ExceptionType, bool throw_on_extra_elements, size_t optional_elements, size_t... Indexes>
auto static_gather_impl(std::index_sequence<Indexes...>)
{
return elements<ExceptionType, throw_on_extra_elements, Indexes...>();
return elements<ExceptionType, throw_on_extra_elements, optional_elements, Indexes...>();
}

template<typename ExceptionType, size_t size, bool throw_on_extra_elements = true>
template<typename ExceptionType, size_t size, bool throw_on_extra_elements = true, size_t optional_elements = 0>
auto static_gather()
{
return static_gather_impl<ExceptionType, throw_on_extra_elements>(std::make_index_sequence<size>());
return static_gather_impl<ExceptionType, throw_on_extra_elements, optional_elements>(std::make_index_sequence<size>());
}

}
Expand Down

0 comments on commit 30b9b0d

Please sign in to comment.