|
|
|
#!/usr/bin/env python3
|
|
|
|
from rich.console import Console
|
|
|
|
from rich.markdown import Markdown
|
|
|
|
from rich.padding import Padding
|
|
|
|
from rich.panel import Panel
|
|
|
|
from rich.text import Text
|
|
|
|
from rich.columns import Columns
|
|
|
|
import re
|
|
|
|
|
|
|
|
console = Console()
|
|
|
|
|
|
|
|
|
|
|
|
def print_markdown(text):
|
|
|
|
"""Prints a rich info message. Support Markdown syntax."""
|
|
|
|
|
|
|
|
md = Padding(Markdown(text), 2)
|
|
|
|
console.print(md)
|
|
|
|
|
|
|
|
|
|
|
|
def print_step(text):
|
|
|
|
"""Prints a rich info message."""
|
|
|
|
|
|
|
|
panel = Panel(Text(text, justify="left"))
|
|
|
|
console.print(panel)
|
|
|
|
|
|
|
|
|
|
|
|
def print_table(items):
|
|
|
|
"""Prints items in a table."""
|
|
|
|
|
|
|
|
console.print(Columns([Panel(f"[yellow]{item}", expand=True) for item in items]))
|
|
|
|
|
|
|
|
|
|
|
|
def print_substep(text, style=""):
|
|
|
|
"""Prints a rich info message without the panelling."""
|
|
|
|
console.print(text, style=style)
|
|
|
|
|
|
|
|
|
|
|
|
def handle_input(
|
|
|
|
message: str = "",
|
|
|
|
check_type=False,
|
|
|
|
match: str = "",
|
|
|
|
err_message: str = "",
|
|
|
|
nmin=None,
|
|
|
|
nmax=None,
|
|
|
|
oob_error="",
|
|
|
|
extra_info="",
|
|
|
|
options: list = None,
|
|
|
|
default=NotImplemented,
|
|
|
|
optional=False,
|
|
|
|
):
|
|
|
|
if optional:
|
|
|
|
console.print(message + "\n[green]This is an optional value. Do you want to skip it? (y/n)")
|
|
|
|
if input().casefold().startswith("y"):
|
|
|
|
return default if default is not NotImplemented else ""
|
|
|
|
if default is not NotImplemented:
|
|
|
|
console.print(
|
|
|
|
"[green]"
|
|
|
|
+ message
|
|
|
|
+ '\n[blue bold]The default value is "'
|
|
|
|
+ str(default)
|
|
|
|
+ '"\nDo you want to use it?(y/n)'
|
|
|
|
)
|
|
|
|
if input().casefold().startswith("y"):
|
|
|
|
return default
|
|
|
|
if options is None:
|
|
|
|
match = re.compile(match)
|
|
|
|
console.print("[green bold]" + extra_info, no_wrap=True)
|
|
|
|
while True:
|
|
|
|
console.print(message, end="")
|
|
|
|
user_input = input("").strip()
|
|
|
|
if check_type is not False:
|
|
|
|
try:
|
|
|
|
user_input = check_type(user_input)
|
|
|
|
if (nmin is not None and user_input < nmin) or (
|
|
|
|
nmax is not None and user_input > nmax
|
|
|
|
):
|
|
|
|
# FAILSTATE Input out of bounds
|
|
|
|
console.print("[red]" + oob_error)
|
|
|
|
continue
|
|
|
|
break # Successful type conversion and number in bounds
|
|
|
|
except ValueError:
|
|
|
|
# Type conversion failed
|
|
|
|
console.print("[red]" + err_message)
|
|
|
|
continue
|
|
|
|
elif match != "" and re.match(match, user_input) is None:
|
|
|
|
console.print("[red]" + err_message + "\nAre you absolutely sure it's correct?(y/n)")
|
|
|
|
if input().casefold().startswith("y"):
|
|
|
|
break
|
|
|
|
continue
|
|
|
|
else:
|
|
|
|
# FAILSTATE Input STRING out of bounds
|
|
|
|
if (nmin is not None and len(user_input) < nmin) or (
|
|
|
|
nmax is not None and len(user_input) > nmax
|
|
|
|
):
|
|
|
|
console.print("[red bold]" + oob_error)
|
|
|
|
continue
|
|
|
|
break # SUCCESS Input STRING in bounds
|
|
|
|
return user_input
|
|
|
|
console.print(extra_info, no_wrap=True)
|
|
|
|
while True:
|
|
|
|
console.print(message, end="")
|
|
|
|
user_input = input("").strip()
|
|
|
|
if check_type is not False:
|
|
|
|
try:
|
|
|
|
isinstance(eval(user_input), check_type)
|
|
|
|
return check_type(user_input)
|
|
|
|
except:
|
|
|
|
console.print(
|
|
|
|
"[red bold]"
|
|
|
|
+ err_message
|
|
|
|
+ "\nValid options are: "
|
|
|
|
+ ", ".join(map(str, options))
|
|
|
|
+ "."
|
|
|
|
)
|
|
|
|
continue
|
|
|
|
if user_input in options:
|
|
|
|
return user_input
|
|
|
|
console.print(
|
|
|
|
"[red bold]" + err_message + "\nValid options are: " + ", ".join(map(str, options)) + "."
|
|
|
|
)
|