| 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) |
|
|