From 71db024a3b248ec9e5b378efd434ca22465c15af Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 24 Mar 2018 11:49:34 +0530 Subject: [PATCH] Add history based completion to the ask kitten --- kittens/ask/main.py | 76 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 71 insertions(+), 5 deletions(-) diff --git a/kittens/ask/main.py b/kittens/ask/main.py index 9bd1c5939..173762bf3 100644 --- a/kittens/ask/main.py +++ b/kittens/ask/main.py @@ -3,15 +3,66 @@ # License: GPL v3 Copyright: 2018, Kovid Goyal import json +import os import readline import sys from gettext import gettext as _ from kitty.cli import parse_args +from kitty.constants import cache_dir from ..tui.operations import alternate_screen, styled +def get_history_items(): + return list(map(readline.get_history_item, range(1, readline.get_current_history_length() + 1))) + + +def sort_key(item): + return len(item), item.lower() + + +class HistoryCompleter: + + def __init__(self, name=None): + self.matches = [] + self.history_path = None + if name: + ddir = os.path.join(cache_dir(), 'ask') + try: + os.makedirs(ddir) + except FileExistsError: + pass + self.history_path = os.path.join(ddir, name) + + def complete(self, text, state): + response = None + if state == 0: + history_values = get_history_items() + if text: + self.matches = sorted( + (h for h in history_values if h and h.startswith(text)), key=sort_key) + else: + self.matches = [] + try: + response = self.matches[state] + except IndexError: + response = None + return response + + def __enter__(self): + if self.history_path: + if os.path.exists(self.history_path): + readline.read_history_file(self.history_path) + readline.set_completer(self.complete) + readline.parse_and_bind('tab: complete') + return self + + def __exit__(self, *a): + if self.history_path: + readline.write_history_file(self.history_path) + + def option_text(): return '''\ --type -t @@ -23,24 +74,29 @@ Type of input. Defaults to asking for a line of text. --message -m The message to display to the user. If not specified a default message is shown. + + +--name -n +The name for this question. Used to store history of previous answers which can +be used for completions and via the browse history readline bindings. ''' -def main(args=sys.argv): +def real_main(args): msg = 'Ask the user for input' try: args, items = parse_args(args[1:], option_text, '', msg, 'kitty ask') except SystemExit as e: print(e.args[0], file=sys.stderr) input('Press enter to quit...') - return 1 + raise SystemExit(1) - with alternate_screen(): + readline.read_init_file() + + with alternate_screen(), HistoryCompleter(args.name): if args.message: print(styled(args.message), bold=True) - readline.read_init_file() - prompt = ': ' if args.type == 'line': prompt = _('Enter line: ') @@ -49,3 +105,13 @@ def main(args=sys.argv): except (KeyboardInterrupt, EOFError): return print('OK:', json.dumps(ans)) + + +def main(args=sys.argv): + try: + real_main(args) + except Exception: + import traceback + traceback.print_exc() + input('Press enter to quit...') + raise SystemExit(1)