Spaces:
Sleeping
Sleeping
from __future__ import annotations | |
from typing import TYPE_CHECKING, Iterable, List, TypeVar, cast, overload | |
from prompt_toolkit.formatted_text.base import OneStyleAndTextTuple | |
if TYPE_CHECKING: | |
from typing_extensions import SupportsIndex | |
__all__ = [ | |
"explode_text_fragments", | |
] | |
_T = TypeVar("_T", bound=OneStyleAndTextTuple) | |
class _ExplodedList(List[_T]): | |
""" | |
Wrapper around a list, that marks it as 'exploded'. | |
As soon as items are added or the list is extended, the new items are | |
automatically exploded as well. | |
""" | |
exploded = True | |
def append(self, item: _T) -> None: | |
self.extend([item]) | |
def extend(self, lst: Iterable[_T]) -> None: | |
super().extend(explode_text_fragments(lst)) | |
def insert(self, index: SupportsIndex, item: _T) -> None: | |
raise NotImplementedError # TODO | |
# TODO: When creating a copy() or [:], return also an _ExplodedList. | |
def __setitem__(self, index: SupportsIndex, value: _T) -> None: ... | |
def __setitem__(self, index: slice, value: Iterable[_T]) -> None: ... | |
def __setitem__( | |
self, index: SupportsIndex | slice, value: _T | Iterable[_T] | |
) -> None: | |
""" | |
Ensure that when `(style_str, 'long string')` is set, the string will be | |
exploded. | |
""" | |
if not isinstance(index, slice): | |
int_index = index.__index__() | |
index = slice(int_index, int_index + 1) | |
if isinstance(value, tuple): # In case of `OneStyleAndTextTuple`. | |
value = cast("List[_T]", [value]) | |
super().__setitem__(index, explode_text_fragments(value)) | |
def explode_text_fragments(fragments: Iterable[_T]) -> _ExplodedList[_T]: | |
""" | |
Turn a list of (style_str, text) tuples into another list where each string is | |
exactly one character. | |
It should be fine to call this function several times. Calling this on a | |
list that is already exploded, is a null operation. | |
:param fragments: List of (style, text) tuples. | |
""" | |
# When the fragments is already exploded, don't explode again. | |
if isinstance(fragments, _ExplodedList): | |
return fragments | |
result: list[_T] = [] | |
for style, string, *rest in fragments: | |
for c in string: | |
result.append((style, c, *rest)) # type: ignore | |
return _ExplodedList(result) | |