Skip to content

Commit

Permalink
Add better sorting of completions
Browse files Browse the repository at this point in the history
  • Loading branch information
Kevin Schmeichel committed Jun 13, 2024
1 parent af5a17d commit e97ca2d
Showing 1 changed file with 42 additions and 32 deletions.
74 changes: 42 additions & 32 deletions mycli/sqlcompleter.py
Original file line number Diff line number Diff line change
Expand Up @@ -372,45 +372,55 @@ def find_matches(text, collection, start_only=False, fuzzy=True, casing=None):
last = last_word(text, include='most_punctuations')
text = last.lower()

completions = []
if casing == 'auto':
casing = 'lower' if last and last[-1].islower() else 'upper'

def apply_case(kw):
if casing is None:
return kw
if casing == 'upper':
return kw.upper()
return kw.lower()

matches = []

if fuzzy:
regex = '.*?'.join(map(escape, text))
pat = compile('(%s)' % regex)
for item in collection:
r = pat.search(item.lower())
if r:
completions.append((len(r.group()), r.start(), item))
matches.append(
(len(r.group()), r.start(), apply_case(item)))
else:
match_end_limit = len(text) if start_only else None
for item in collection:
match_point = item.lower().find(text, 0, match_end_limit)
if match_point >= 0:
completions.append((len(text), match_point, item))

if casing == 'auto':
casing = 'lower' if last and last[-1].islower() else 'upper'
matches.append((len(text), match_point, apply_case(item)))

def apply_case(kw):
if casing == 'upper':
return kw.upper()
return kw.lower()

return (Completion(z if casing is None else apply_case(z), -len(text))
for x, y, z in completions)
return matches

def get_completions(self, document, complete_event, smart_completion=None):
word_before_cursor = document.get_word_before_cursor(WORD=True)

def sorted_completions(matches):
# sort by match point, then match length, then item text
matches = sorted(matches, key=lambda m: (m[1], m[0], m[2].lower()))
return (Completion(z, -len(word_before_cursor))
for x, y, z in matches)

if smart_completion is None:
smart_completion = self.smart_completion

# If smart_completion is off then match any word that starts with
# 'word_before_cursor'.
if not smart_completion:
return self.find_matches(word_before_cursor, self.all_completions,
start_only=True, fuzzy=False)
matches = self.find_matches(word_before_cursor, self.all_completions,
start_only=True, fuzzy=False)
return sorted_completions(matches)

completions = []
matches = []
suggestions = suggest_type(document.text, document.text_before_cursor)

for suggestion in suggestions:
Expand All @@ -431,14 +441,14 @@ def get_completions(self, document, complete_event, smart_completion=None):
]

cols = self.find_matches(word_before_cursor, scoped_cols)
completions.extend(cols)
matches.extend(cols)

elif suggestion['type'] == 'function':
# suggest user-defined functions using substring matching
funcs = self.populate_schema_objects(suggestion['schema'],
'functions')
user_funcs = self.find_matches(word_before_cursor, funcs)
completions.extend(user_funcs)
matches.extend(user_funcs)

# suggest hardcoded functions using startswith matching only if
# there is no schema qualifier. If a schema qualifier is
Expand All @@ -450,77 +460,77 @@ def get_completions(self, document, complete_event, smart_completion=None):
start_only=True,
fuzzy=False,
casing=self.keyword_casing)
completions.extend(predefined_funcs)
matches.extend(predefined_funcs)

elif suggestion['type'] == 'table':
tables = self.populate_schema_objects(suggestion['schema'],
'tables')
tables = self.find_matches(word_before_cursor, tables)
completions.extend(tables)
matches.extend(tables)

elif suggestion['type'] == 'view':
views = self.populate_schema_objects(suggestion['schema'],
'views')
views = self.find_matches(word_before_cursor, views)
completions.extend(views)
matches.extend(views)

elif suggestion['type'] == 'alias':
aliases = suggestion['aliases']
aliases = self.find_matches(word_before_cursor, aliases)
completions.extend(aliases)
matches.extend(aliases)

elif suggestion['type'] == 'database':
dbs = self.find_matches(word_before_cursor, self.databases)
completions.extend(dbs)
matches.extend(dbs)

elif suggestion['type'] == 'keyword':
keywords = self.find_matches(word_before_cursor, self.keywords,
start_only=True,
fuzzy=False,
casing=self.keyword_casing)
completions.extend(keywords)
matches.extend(keywords)

elif suggestion['type'] == 'show':
show_items = self.find_matches(word_before_cursor,
self.show_items,
start_only=False,
fuzzy=True,
casing=self.keyword_casing)
completions.extend(show_items)
matches.extend(show_items)

elif suggestion['type'] == 'change':
change_items = self.find_matches(word_before_cursor,
self.change_items,
start_only=False,
fuzzy=True)
completions.extend(change_items)
matches.extend(change_items)
elif suggestion['type'] == 'user':
users = self.find_matches(word_before_cursor, self.users,
start_only=False,
fuzzy=True)
completions.extend(users)
matches.extend(users)

elif suggestion['type'] == 'special':
special = self.find_matches(word_before_cursor,
self.special_commands,
start_only=True,
fuzzy=False)
completions.extend(special)
matches.extend(special)
elif suggestion['type'] == 'favoritequery':
queries = self.find_matches(word_before_cursor,
FavoriteQueries.instance.list(),
start_only=False, fuzzy=True)
completions.extend(queries)
matches.extend(queries)
elif suggestion['type'] == 'table_format':
formats = self.find_matches(word_before_cursor,
self.table_formats,
start_only=True, fuzzy=False)
completions.extend(formats)
matches.extend(formats)
elif suggestion['type'] == 'file_name':
file_names = self.find_files(word_before_cursor)
completions.extend(file_names)
matches.extend(file_names)

return completions
return sorted_completions(matches)

def find_files(self, word):
"""Yield matching directory or file names.
Expand Down

0 comments on commit e97ca2d

Please sign in to comment.