|
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 |
|
|
|
|
|
|
|
@overload |
|
def __setitem__(self, index: SupportsIndex, value: _T) -> None: |
|
... |
|
|
|
@overload |
|
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): |
|
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. |
|
""" |
|
|
|
if isinstance(fragments, _ExplodedList): |
|
return fragments |
|
|
|
result: list[_T] = [] |
|
|
|
for style, string, *rest in fragments: |
|
for c in string: |
|
result.append((style, c, *rest)) |
|
|
|
return _ExplodedList(result) |
|
|