textual-autocomplete icon indicating copy to clipboard operation
textual-autocomplete copied to clipboard

Bug in example: incorrect sorting by match at start of text

Open 1j01 opened this issue 2 years ago • 0 comments

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.

1j01 avatar Jul 30 '23 19:07 1j01