|
"""Module contains spinner related resources. |
|
|
|
Note: |
|
The spinner is not a standalone spinner to run in the terminal |
|
but rather a `prompt_toolkit` :class:`~prompt_toolkit.layout.Window` that displays a spinner. |
|
|
|
Use library such as `yaspin <https://github.com/pavdmyt/yaspin>`_ if you need a plain spinner. |
|
""" |
|
import asyncio |
|
from typing import TYPE_CHECKING, Callable, List, NamedTuple, Optional, Tuple, Union |
|
|
|
from prompt_toolkit.filters.utils import to_filter |
|
from prompt_toolkit.layout.containers import ConditionalContainer, Window |
|
from prompt_toolkit.layout.controls import FormattedTextControl |
|
|
|
if TYPE_CHECKING: |
|
from prompt_toolkit.filters.base import Filter |
|
|
|
__all__ = ["SPINNERS", "SpinnerWindow"] |
|
|
|
|
|
class SPINNERS(NamedTuple): |
|
"""Presets of spinner patterns. |
|
|
|
See Also: |
|
https://github.com/pavdmyt/yaspin/blob/master/yaspin/data/spinners.json |
|
|
|
This only contains some basic ones thats ready to use. For more patterns, checkout the |
|
URL above. |
|
|
|
Examples: |
|
>>> from InquirerPy import inquirer |
|
>>> from InquirerPy.spinner import SPINNERS |
|
>>> inquirer.select(message="", choices=lambda _: [1, 2, 3], spinner_pattern=SPINNERS.dots) |
|
""" |
|
|
|
dots = ["β ", "β ", "β Ή", "β Έ", "β Ό", "β ΄", "β ¦", "β §", "β ", "β "] |
|
dots2 = ["β£Ύ", "β£½", "β£»", "β’Ώ", "β‘Ώ", "β£", "β£―", "β£·"] |
|
line = ["-", "\\", "|", "/"] |
|
line2 = ["β ", "-", "β", "β", "β", "-"] |
|
pipe = ["β€", "β", "β΄", "β", "β", "β", "β¬", "β"] |
|
star = ["βΆ", "βΈ", "βΉ", "βΊ", "βΉ", "β·"] |
|
star2 = ["+", "x", "*"] |
|
flip = ["_", "_", "_", "-", "`", "`", "'", "Β΄", "-", "_", "_", "_"] |
|
hamburger = ["β±", "β²", "β΄"] |
|
grow_vertical = ["β", "β", "β", "β
", "β", "β", "β", "β
", "β", "β"] |
|
grow_horizontal = ["β", "β", "β", "β", "β", "β", "β", "β", "β", "β", "β", "β"] |
|
box_bounce = ["β", "β", "β", "β"] |
|
triangle = ["β’", "β£", "β€", "β₯"] |
|
arc = ["β", "β ", "β", "β", "β‘", "β"] |
|
circle = ["β‘", "β", "β "] |
|
|
|
|
|
class SpinnerWindow(ConditionalContainer): |
|
"""Conditional `prompt_toolkit` :class:`~prompt_toolkit.layout.Window` that displays a spinner. |
|
|
|
Args: |
|
loading: A :class:`~prompt_toolkit.filters.Condition` to indicate if the spinner should be visible. |
|
redraw: A redraw function (i.e. :meth:`~prompt_toolkit.application.Application.invalidate`) to refresh the UI. |
|
pattern: List of pattern to display as the spinner. |
|
delay: Spinner refresh frequency. |
|
text: Loading text to display. |
|
""" |
|
|
|
def __init__( |
|
self, |
|
loading: "Filter", |
|
redraw: Callable[[], None], |
|
pattern: Optional[Union[List[str], SPINNERS]] = None, |
|
delay: float = 0.1, |
|
text: str = "", |
|
) -> None: |
|
self._loading = to_filter(loading) |
|
self._spinning = False |
|
self._redraw = redraw |
|
self._pattern = pattern or SPINNERS.line |
|
self._char = self._pattern[0] |
|
self._delay = delay |
|
self._text = text or "Loading ..." |
|
|
|
super().__init__( |
|
content=Window(content=FormattedTextControl(text=self._get_text)), |
|
filter=self._loading, |
|
) |
|
|
|
def _get_text(self) -> List[Tuple[str, str]]: |
|
"""Dynamically get the text for the :class:`~prompt_toolkit.layout.Window`. |
|
|
|
Returns: |
|
Formatted text. |
|
""" |
|
return [ |
|
("class:spinner_pattern", self._char), |
|
("", " "), |
|
("class:spinner_text", self._text), |
|
] |
|
|
|
async def start(self) -> None: |
|
"""Start the spinner.""" |
|
if self._spinning: |
|
return |
|
self._spinning = True |
|
while self._loading(): |
|
for char in self._pattern: |
|
await asyncio.sleep(self._delay) |
|
self._char = char |
|
self._redraw() |
|
self._spinning = False |
|
|