textual-autocomplete
textual-autocomplete copied to clipboard
Bug in example: incorrect sorting by match at start of text
https://github.com/darrenburns/textual-autocomplete/blob/e289c56fadb5e5b024693f0214fc22a17c5c9c02/examples/custom_meta.py#L79-L80
This should be:
# Favour items that start with the Input value, pull them to the top
ordered = sorted(matches, key=lambda v: v.main.plain.lower().startswith(input_state.value.lower()), reverse=True)
or:
# Favour items that start with the Input value, pull them to the top
ordered = sorted(matches, key=lambda v: not v.main.plain.lower().startswith(input_state.value.lower()))
You might not have noticed the negative affect of the sort being backwards because of the missing lowercasing (a bug hiding a bug).
As a side note, I created a bug myself when extending the code to use two sequential sorts:
# Only keep matches that contain the Input value as a substring
matches = [c for c in items if input_state.value.lower() in c.main.plain.lower() + c.right_meta.plain.lower()]
# Favour items that start with the Input value, pull them to the top
# Keywords starting with the Input value are less important than the main text starting with it,
# so sort by the more important criteria last.
ordered = sorted(matches, key=lambda v: v.right_meta.plain.lower().startswith(input_state.value.lower()), reverse=True)
ordered = sorted(matches, key=lambda v: v.main.plain.lower().startswith(input_state.value.lower()), reverse=True)
return ordered
The second sort failed because when I copied the line of code I was still passing the original matches but it would need to be passed ordered. If it used just one variable (matches) I wouldn't have run into this problem:
# Only keep matches that contain the Input value as a substring
matches = [c for c in items if input_state.value.lower() in c.main.plain.lower() + c.right_meta.plain.lower()]
# Favour items that start with the Input value, pull them to the top
# Keywords starting with the Input value are less important than the main text starting with it,
# so sort by the more important criteria last.
matches = sorted(matches, key=lambda v: v.right_meta.plain.lower().startswith(input_state.value.lower()), reverse=True)
matches = sorted(matches, key=lambda v: v.main.plain.lower().startswith(input_state.value.lower()), reverse=True)
return matches
(And it doesn't make sense to have matches, partially_ordered, ordered; imagine trying to keep that up!)
So it could make the example slightly more malleable. Just a little tweak that I would recommend.