forked from Mirror/pmbootstrap
pmb.helpers.cli: add tab completion option for ask() helper (!1875)
Add a helper class that provides readline-based tab completion and an extra optional argument "completion_choices" with possible completion targets. While at this, also improve paramters documentation for ask() func.
This commit is contained in:
parent
804743e65a
commit
7e61e62044
2 changed files with 46 additions and 5 deletions
|
@ -3,14 +3,46 @@
|
||||||
import datetime
|
import datetime
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
|
import readline
|
||||||
|
|
||||||
|
|
||||||
|
class ReadlineTabCompleter:
|
||||||
|
""" Stores intermediate state for completer function """
|
||||||
|
def __init__(self, options):
|
||||||
|
"""
|
||||||
|
:param options: list of possible completions
|
||||||
|
"""
|
||||||
|
self.options = sorted(options)
|
||||||
|
self.matches = []
|
||||||
|
|
||||||
|
def completer_func(self, input_text, iteration):
|
||||||
|
"""
|
||||||
|
:param input_text: text that shall be autocompleted
|
||||||
|
:param iteration: how many times "tab" was hit
|
||||||
|
"""
|
||||||
|
# First time: build match list
|
||||||
|
if iteration == 0:
|
||||||
|
if input_text:
|
||||||
|
self.matches = [s for s in self.options if s and s.startswith(input_text)]
|
||||||
|
else:
|
||||||
|
self.matches = self.options[:]
|
||||||
|
|
||||||
|
# Return the N'th item from the match list, if we have that many.
|
||||||
|
if iteration < len(self.matches):
|
||||||
|
return self.matches[iteration]
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def ask(args, question="Continue?", choices=["y", "n"], default="n",
|
def ask(args, question="Continue?", choices=["y", "n"], default="n",
|
||||||
lowercase_answer=True, validation_regex=None):
|
lowercase_answer=True, validation_regex=None, complete=None):
|
||||||
"""
|
"""
|
||||||
Ask a question on the terminal. When validation_regex is set, the user gets
|
Ask a question on the terminal.
|
||||||
asked until the answer matches the regex.
|
:param question: display prompt
|
||||||
:returns: the user's answer
|
:param choices: short list of possible answers, displayed after prompt if set
|
||||||
|
:param default: default value to return if user doesn't input anything
|
||||||
|
:param lowercase_answer: if True, convert return value to lower case
|
||||||
|
:param validation_regex: if set, keep asking until regex matches
|
||||||
|
:param complete: set to a list to enable tab completion
|
||||||
"""
|
"""
|
||||||
while True:
|
while True:
|
||||||
date = datetime.datetime.now().strftime("%H:%M:%S")
|
date = datetime.datetime.now().strftime("%H:%M:%S")
|
||||||
|
@ -20,7 +52,16 @@ def ask(args, question="Continue?", choices=["y", "n"], default="n",
|
||||||
if default:
|
if default:
|
||||||
question_full += " [" + str(default) + "]"
|
question_full += " [" + str(default) + "]"
|
||||||
|
|
||||||
|
if complete:
|
||||||
|
readline.parse_and_bind('tab: complete')
|
||||||
|
readline.set_completer(ReadlineTabCompleter(complete).completer_func)
|
||||||
|
|
||||||
ret = input(question_full + ": ")
|
ret = input(question_full + ": ")
|
||||||
|
|
||||||
|
# Stop completing (question is answered)
|
||||||
|
if complete:
|
||||||
|
readline.set_completer(None)
|
||||||
|
|
||||||
if lowercase_answer:
|
if lowercase_answer:
|
||||||
ret = ret.lower()
|
ret = ret.lower()
|
||||||
if ret == "":
|
if ret == "":
|
||||||
|
|
|
@ -34,7 +34,7 @@ def fake_answers(monkeypatch, answers):
|
||||||
the second question with "n" and so on.
|
the second question with "n" and so on.
|
||||||
"""
|
"""
|
||||||
def fake_ask(args, question="Continue?", choices=["y", "n"], default="n",
|
def fake_ask(args, question="Continue?", choices=["y", "n"], default="n",
|
||||||
lowercase_answer=True, validation_regex=None):
|
lowercase_answer=True, validation_regex=None, complete=None):
|
||||||
answer = answers.pop(0)
|
answer = answers.pop(0)
|
||||||
logging.info("pmb.helpers.cli.ask() fake answer: " + answer)
|
logging.info("pmb.helpers.cli.ask() fake answer: " + answer)
|
||||||
return answer
|
return answer
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue