From 9fc4ec3ef8e9bb674fea00e124c91b5a32155893 Mon Sep 17 00:00:00 2001 From: Moritz Neeb Date: Sun, 22 Oct 2023 22:00:10 +0200 Subject: [PATCH] method extraction and vertical whitespace --- visidata/features/cmdpalette.py | 58 +++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 24 deletions(-) diff --git a/visidata/features/cmdpalette.py b/visidata/features/cmdpalette.py index 1e7df16d7..4a5a47428 100644 --- a/visidata/features/cmdpalette.py +++ b/visidata/features/cmdpalette.py @@ -6,6 +6,12 @@ vd.option('disp_cmdpal_max', 5, 'max number of suggestions for command palette') +def _longname_executor(name): + def _exec(v, i): + raise AcceptInput(name) + return _exec + + def _format_match(s, positions): out = list(s) for p in positions: @@ -13,6 +19,28 @@ def _format_match(s, positions): return "".join(out) +def _fuzzy_match(description, row, words): + longname_score, desc_score = 0, 0 + positions_name = set() + positions_desc = set() + for word in words: + result_name = vd.fuzzymatch(row.longname, word) + result_desc = vd.fuzzymatch(description.lower(), word) + # if a word matches neither, we can skip the row + if result_name.start == -1 and result_desc.start == -1: + longname_score, desc_score = 0, 0 + break + longname_score = longname_score + result_name.score + desc_score = desc_score + result_desc.score + if result_name.positions: + positions_name.update(result_name.positions) + if result_desc.positions: + positions_desc.update(result_desc.positions) + # prefer if match is either fully on longname or on description + score = longname_score ** 2 + desc_score ** 2 + return score, positions_desc, positions_name + + @BaseSheet.api def inputLongname(sheet): max_matches = vd.options.disp_cmdpal_max @@ -24,35 +52,13 @@ def inputLongname(sheet): Match = collections.namedtuple('Match', 'name formatted_name keystrokes description score') bindings = dict() - def longname_executor(name): - def _exec(v, i): - raise AcceptInput(name) - return _exec - def cmdpal_matcher(value): # collect data matches = [] words = value.lower().split() for row in this_sheets_help.rows: description = this_sheets_help.cmddict[(row.sheet, row.longname)].helpstr - longname_score, desc_score = 0, 0 - positions_name = set() - positions_desc = set() - for word in words: - result_name = vd.fuzzymatch(row.longname, word) - result_desc = vd.fuzzymatch(description.lower(), word) - # if a word matches neither, we can skip the row - if result_name.start == -1 and result_desc.start == -1: - score = 0 - break - longname_score = longname_score+result_name.score - desc_score = desc_score+result_desc.score - if result_name.positions: - positions_name.update(result_name.positions) - if result_desc.positions: - positions_desc.update(result_desc.positions) - # prefer if match is either fully on longname or on description - score = longname_score**2 + desc_score**2 + score, positions_desc, positions_name = _fuzzy_match(description, row, words) if score > 0: keystrokes = this_sheets_help.revbinds.get(row.longname, [None])[0] formatted_name = f'[:onclick {row.longname}]{_format_match(row.longname, positions_name)}[/]' @@ -63,11 +69,12 @@ def cmdpal_matcher(value): # do the drawing h, w = sheet._scr.getmaxyx() n = min(len(matches), max_matches) + for i in range(n): m = matches[i] if i < 9: trigger_key = f'{i+1}' - bindings[trigger_key] = longname_executor(m.name) + bindings[trigger_key] = _longname_executor(m.name) else: trigger_key = ' ' buffer = ' '*(len(label)-2) @@ -81,6 +88,7 @@ def cmdpal_matcher(value): debug_info = f'[{m.score}]' match_summary = debug_info + match_summary[len(debug_info):] clipdraw(sheet._scr, h-(n+1)+i, 0, match_summary, colors.color_cmdpalette, w=120) + # add some empty rows for visual appeal and dropping previous (not-anymore-)matches for i in range(max_matches-n): try: @@ -90,6 +98,8 @@ def cmdpal_matcher(value): # TODO: bug: terminal not high enough => will break. return None + + return vd.input(label, completer=CompleteKey(sorted(longnames)), type='longname', updater=cmdpal_matcher, bindings=bindings)