Open brupelo opened 5 years ago
First, notice that the highlighting need not be connected to the fuzzyfinder itself. To get the highlighting functionality, it would therefore suffice to define a function which highlights a given substring in an iterable, which can then be used on the fuzzyfinder results. The highlighting of strings is achieved by prepending and appending to the given substring certain special strings, where the prepended string activates a certain style and the appended string deactivates it. For instance, you can use ANSI escape codes for printing highlighted strings to the terminal, or HTML tags for displaying highlighted strings in the browser (like in the fuzzysort example you provided).
def highlight_substring(substring, collection, highlight):
"""Highlight first occurrences of substring in elements of collection.
Args:
substring (str): Substring to highlight.
collection (iterable): Iterable of strings in which to highlight substring.
highlight (tuple): Tuple of strings, where the first element activates
a style and the second element deactivates it.
Yields:
String from collection, with first occurrence of substring surrounded
by highlight strings.
"""
style, reset_style = highlight
for item in collection:
highlighted_item = ""
substring_iter = iter(substring)
take_next = True
for item_char in item:
if take_next:
try:
substring_char = next(substring_iter)
except StopIteration:
substring_char = "I am not equal to any single character"
else:
take_next = False
if item_char.lower() == substring_char.lower():
highlighted_item += style + item_char + reset_style
take_next = True
else:
highlighted_item += item_char
yield highlighted_item
Now, you may want to create a wrapper function around highlight_substring
and fuzzyfinder
to obtain a fuzzyfinder with the highlighting functionality built in. Notice that highlight_substring
is actually a generator function, which makes the wrapper have a consistent return type.
from fuzzyfinder import fuzzyfinder
def highlighting_fuzzyfinder(
input, collection, accessor=lambda x: x, sort_results=True, highlight=None
):
"""Find strings matching input, and maybe highlight matching substring."""
results = fuzzyfinder(
input, collection, accessor=accessor, sort_results=sort_results
)
if highlight:
return highlight_substring(input, results, highlight)
else:
return results
It should prove convenient to define some constants with the special styling strings. Here, I organized the constants into classes, but plain old strings will do as well.
class ANSI:
"""ANSI escape codes for styling."""
RESET_STYLE = "\033[0m"
BOLD = "\033[1m"
UNDERLINE = "\033[4m"
GREEN = "\033[32m"
GREEN_BG = "\033[42m"
class HTML:
"""HTML tags for styling."""
BOLD = "<b>"
RESET_BOLD = "</b>"
GREEN_BG = "<mark style='background:#00FF00'>"
RESET_GREEN_BG = "</mark>"
Here are some highlighted matches printed to the terminal:
Here are some highlighted matches displayed in the browser:
Tested in Python 3.11.
Hi, first of all, let me tell you the code of your library is really cool because of the simplicity!
Now, I was wondering if you knew how to modify it slightly so the results would be highlighted like SublimeText, TextMate or similars...
To see what I mean take a look to fuzzysort:
which has an interface such as:
So, any ideas how to add a "highlight" feature?