8 changed files with 429 additions and 151 deletions
@ -0,0 +1,126 @@ |
|||||
|
# bsv - Backup, Synchronization, Versioning |
||||
|
# Copyright (C) 2023 Simon Boyé |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify |
||||
|
# it under the terms of the GNU Affero General Public License as published by |
||||
|
# the Free Software Foundation, either version 3 of the License, or |
||||
|
# (at your option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU Affero General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU Affero General Public License |
||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>. |
||||
|
from __future__ import annotations |
||||
|
|
||||
|
from typing import Any, Callable, TypeVar |
||||
|
|
||||
|
from rich.console import Console |
||||
|
from rich.text import Text |
||||
|
|
||||
|
|
||||
|
_console: Console | None = None |
||||
|
def get_console() -> Console: |
||||
|
assert _console is not None |
||||
|
return _console |
||||
|
|
||||
|
_error_console: Console | None = None |
||||
|
def get_error_console() -> Console: |
||||
|
assert _error_console is not None |
||||
|
return _error_console |
||||
|
|
||||
|
|
||||
|
def init_consoles(color: str="auto"): |
||||
|
global _console |
||||
|
global _error_console |
||||
|
|
||||
|
assert _console is None |
||||
|
assert _error_console is None |
||||
|
|
||||
|
kwargs: dict[str, Any] = { |
||||
|
"tab_size": 4, |
||||
|
} |
||||
|
match color: |
||||
|
case "always": |
||||
|
kwargs["force_terminal"] = True |
||||
|
case "auto": |
||||
|
pass |
||||
|
case "never": |
||||
|
kwargs["no_color"] = True |
||||
|
|
||||
|
_console = Console( |
||||
|
**kwargs, |
||||
|
) |
||||
|
_error_console = Console( |
||||
|
stderr = True, |
||||
|
**kwargs, |
||||
|
) |
||||
|
|
||||
|
|
||||
|
PromptType = TypeVar("PromptType") |
||||
|
|
||||
|
class NoDefaultType: |
||||
|
def __repr__(self): |
||||
|
return "NoDefault" |
||||
|
NoDefault = NoDefaultType() |
||||
|
|
||||
|
def prompt( |
||||
|
prompt: str, |
||||
|
factory: Callable[[str], PromptType], |
||||
|
*, |
||||
|
console: Console | None = None, |
||||
|
default: PromptType | NoDefaultType = NoDefault, |
||||
|
show_default: bool = True, |
||||
|
) -> PromptType: |
||||
|
if console is None: |
||||
|
console = get_console() |
||||
|
|
||||
|
prompt_text = Text(prompt, style="prompt") |
||||
|
prompt_text.end = "" |
||||
|
if show_default and default is not NoDefault: |
||||
|
prompt_text.append(" ") |
||||
|
prompt_text.append(f"({default})", style="prompt.default") |
||||
|
prompt_text.append(": ") |
||||
|
|
||||
|
while True: |
||||
|
try: |
||||
|
value = console.input(prompt_text) |
||||
|
except KeyboardInterrupt: |
||||
|
console.print("") |
||||
|
raise |
||||
|
|
||||
|
if not value and not isinstance(default, NoDefaultType): |
||||
|
return default |
||||
|
try: |
||||
|
return factory(value) |
||||
|
except ValueError as err: |
||||
|
console.print(err) |
||||
|
|
||||
|
def prompt_confirmation(prompt: str, *, console: Console | None=None, default: bool=True) -> bool: |
||||
|
if console is None: |
||||
|
console = get_console() |
||||
|
|
||||
|
prompt_text = Text(prompt, style="prompt") |
||||
|
prompt_text.end = "" |
||||
|
prompt_text.append(" ") |
||||
|
if default: |
||||
|
prompt_text.append("(Y/n)", style="prompt.default") |
||||
|
else: |
||||
|
prompt_text.append("(y/N)", style="prompt.default") |
||||
|
prompt_text.append(": ") |
||||
|
|
||||
|
while True: |
||||
|
try: |
||||
|
value = console.input(prompt_text).strip().lower() |
||||
|
except KeyboardInterrupt: |
||||
|
console.print("") |
||||
|
raise |
||||
|
|
||||
|
if not value and not isinstance(default, NoDefaultType): |
||||
|
return default |
||||
|
if value not in "yn": |
||||
|
console.print("Please answer 'y' or 'n'.") |
||||
|
else: |
||||
|
return value == "y" |
||||
Loading…
Reference in new issue