From 861690435049c49e49e8746e9bee4b9a48c2c17a Mon Sep 17 00:00:00 2001 From: Ensis Date: Sun, 10 Jun 2018 12:05:17 +0200 Subject: [PATCH] Add autocompletion for logins in the visit prompt --- completer.py | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++ menu_screen.py | 17 +++++++++++++--- 2 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 completer.py diff --git a/completer.py b/completer.py new file mode 100644 index 0000000..9db7b12 --- /dev/null +++ b/completer.py @@ -0,0 +1,55 @@ +class LoginCompleter: + """ A loop-based completion system for logins """ + def __init__(self, menu): + self.s = "" + self.logins = None + self.completions = [] + # completion_id has a value of -1 for the base user input + # and between 0 and len(completions)-1 for completions + self.completion_id = -1 + self.completion_base = "" + self.menu = menu + + def initialize(self): + """ Initialise the list of completable logins """ + garden = self.menu.user_data.retrieve_garden_from_db() + self.logins = set() + for plant_id in garden: + if not garden[plant_id]: + continue + entry = garden[plant_id] + if "owner" in entry: + self.logins.add(entry["owner"]) + self.logins = sorted(list(self.logins)) + + def update_input(self, s): + """ Update the user input and reset completion base """ + self.s = s + self.completion_base = self.s + self.completion_id = -1 + + def complete(self, direction = 1): + """ + Returns the completed string from the user input + Loops forward in the list of logins if direction is positive, and + backwards if direction is negative + """ + def loginFilter(x): + return x.startswith(self.s) & (x != self.s) + + # Refresh possible completions after the user edits + if self.completion_id == -1: + if self.logins is None: + self.initialize() + self.completion_base = self.s + self.completions = list(filter(loginFilter, self.logins)) + + self.completion_id += direction + # Loop from the back + if self.completion_id == -2: + self.completion_id = len(self.completions) - 1 + # If we are at the base input, return it + if self.completion_id == -1 or self.completion_id == len(self.completions): + self.completion_id = -1 + return self.completion_base + return self.completions[self.completion_id] diff --git a/menu_screen.py b/menu_screen.py index b05d572..0a5b63a 100644 --- a/menu_screen.py +++ b/menu_screen.py @@ -10,6 +10,7 @@ import json import sqlite3 import string import re +import completer class CursedMenu(object): #TODO: name your plant @@ -644,20 +645,30 @@ class CursedMenu(object): visitor_block = 'nobody :(' return visitor_block - def get_user_string(self, xpos=3, ypos=15, filterfunc=str.isalnum): + def get_user_string(self, xpos=3, ypos=15, filterfunc=str.isalnum, completer=None): # filter allowed characters using filterfunc, alphanumeric by default user_string = "" user_input = 0 + if completer: + completer = completer(self) while user_input != 10: user_input = self.screen.getch() # osx and unix backspace chars... if user_input == 127 or user_input == 263: if len(user_string) > 0: user_string = user_string[:-1] + if completer: + completer.update_input(user_string) self.screen.addstr(ypos, xpos, " " * (self.maxx-xpos-1)) - if user_input < 256 and user_input != 10: + elif user_input in [ord('\t'), curses.KEY_BTAB] and completer: + direction = 1 if user_input == ord('\t') else -1 + user_string = completer.complete(direction) + self.screen.addstr(ypos, xpos, " " * (self.maxx-xpos-1)) + elif user_input < 256 and user_input != 10: if filterfunc(chr(user_input)): user_string += chr(user_input) + if completer: + completer.update_input(user_string) self.screen.addstr(ypos, xpos, str(user_string)) self.screen.refresh() return user_string @@ -674,7 +685,7 @@ class CursedMenu(object): weekly_visitor_text = self.get_weekly_visitors() self.draw_info_text("this week you've been visited by: ", 6) self.draw_info_text(weekly_visitor_text, 7) - guest_garden = self.get_user_string() + guest_garden = self.get_user_string(completer = completer.LoginCompleter) if not guest_garden: self.clear_info_pane() return None