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