Skip to content

Commit

Permalink
ranked match: prefer input order over alphabetical order for user-spe…
Browse files Browse the repository at this point in the history
…cified completions

When using either of

	set-option g completers option=my_option
	prompt -shell-script-candidates ...

While the search text is empty, the completions will be sorted
alphabetically.
This is bad because it means the most important entries are not listed
first, making them harder to select or even spot.

Let's apply input order before resorting to sorting alphabetically.

In theory there is a more elegant solution: sort candidates (except
if they're user input) before passing them to RankedMatch, and then
always use stable sort. However that doesn't work because we use a
heap which doesn't support stable sort.

Closes #1709, #4813
  • Loading branch information
krobelus committed Dec 2, 2023
1 parent d6215dc commit df698f6
Show file tree
Hide file tree
Showing 7 changed files with 44 additions and 9 deletions.
2 changes: 1 addition & 1 deletion rc/tools/doc.kak
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ complete-command doc shell-script-candidates %{
/^\[\[[^\]]+\]\]/ { sub(/^\[\[/, ""); sub(/\]\].*/, ""); print }
' < $page | tr '[A-Z ]' '[a-z-]'
fi;;
esac
esac | sort
}

alias global help doc
32 changes: 27 additions & 5 deletions rc/tools/git.kak
Original file line number Diff line number Diff line change
Expand Up @@ -62,27 +62,49 @@ define-command -params 1.. \
Available commands:
add
apply (alias for "patch git apply")
rm
reset
blame
commit
checkout
commit
diff
edit
grep
hide-blame
hide-diff
init
log
next-hunk
prev-hunk
reset
rm
show
show-branch
show-diff
status
update-diff
grep
} -shell-script-candidates %{
if [ $kak_token_to_complete -eq 0 ]; then
printf "add\napply\nrm\nreset\nblame\ncommit\ncheckout\ndiff\nhide-blame\nhide-diff\nlog\nnext-hunk\nprev-hunk\nshow\nshow-branch\nshow-diff\ninit\nstatus\nupdate-diff\ngrep\nedit\n"
printf %s\\n \
apply \
blame \
checkout \
commit \
diff \
edit \
grep \
hide-blame \
hide-diff \
init \
log \
next-hunk \
prev-hunk \
reset \
rm \
show \
show-branch \
show-diff \
status \
update-diff \
;
else
case "$1" in
commit) printf -- "--amend\n--no-edit\n--all\n--reset-author\n--fixup\n--squash\n"; git ls-files -m ;;
Expand Down
5 changes: 4 additions & 1 deletion rc/tools/man.kak
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,10 @@ define-command -hidden -params ..3 man-impl %{ evaluate-commands %sh{

define-command -params ..1 \
-shell-script-candidates %{
find /usr/share/man/ $(printf %s "${MANPATH}" | sed 's/:/ /') -name '*.[1-8]*' | sed 's,^.*/\(.*\)\.\([1-8][a-zA-Z]*\).*$,\1(\2),'
find /usr/share/man/ $(printf %s "${MANPATH}" |
sed 's/:/ /') -name '*.[1-8]*' |
sed 's,^.*/\(.*\)\.\([1-8][a-zA-Z]*\).*$,\1(\2),' |
sort
} \
-docstring %{
man [<page>]: manpage viewer wrapper
Expand Down
5 changes: 4 additions & 1 deletion src/commands.cc
Original file line number Diff line number Diff line change
Expand Up @@ -337,10 +337,13 @@ struct ShellCandidatesCompleter
{
UsedLetters query_letters = used_letters(query);
Vector<RankedMatch> matches;
for (auto&& candidate : m_candidates)
for (auto&& [i, candidate] : m_candidates | enumerate())
{
if (RankedMatch m{candidate.first, candidate.second, query, query_letters})
{
m.set_input_sequence_number(i);
matches.push_back(m);
}
}

constexpr size_t max_count = 100;
Expand Down
3 changes: 2 additions & 1 deletion src/insert_completer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -298,10 +298,11 @@ InsertCompletion complete_option(const SelectionList& sels,
StringView query = buffer.substr(coord, cursor_pos);
Vector<RankedMatchAndInfo> matches;

for (auto& candidate : opt.list)
for (auto&& [i, candidate] : opt.list | enumerate())
{
if (RankedMatchAndInfo match{std::get<0>(candidate), query})
{
match.set_input_sequence_number(i);
match.on_select = std::get<1>(candidate);
auto& menu = std::get<2>(candidate);
match.menu_entry = not menu.empty() ?
Expand Down
3 changes: 3 additions & 0 deletions src/ranked_match.cc
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,9 @@ bool RankedMatch::operator<(const RankedMatch& other) const
if (m_max_index != other.m_max_index)
return m_max_index < other.m_max_index;

if (m_input_sequence_number != other.m_input_sequence_number)
return m_input_sequence_number < other.m_input_sequence_number;

// Reorder codepoints to improve matching behaviour
auto order = [](Codepoint cp) { return cp == '/' ? 0 : cp; };

Expand Down
3 changes: 3 additions & 0 deletions src/ranked_match.hh
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ struct RankedMatch

explicit operator bool() const { return m_matches; }

void set_input_sequence_number(size_t i) { m_input_sequence_number = i; }

private:
template<typename TestFunc>
RankedMatch(StringView candidate, StringView query, TestFunc test);
Expand All @@ -54,6 +56,7 @@ private:
Flags m_flags = Flags::None;
int m_word_boundary_match_count = 0;
int m_max_index = 0;
size_t m_input_sequence_number = 0;
};

}
Expand Down

0 comments on commit df698f6

Please sign in to comment.