1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980 |
- 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.
- @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): # 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)
|