summaryrefslogtreecommitdiffstats
path: root/src/prompt_toolkit/layout/utils.py
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 17:35:20 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 17:35:20 +0000
commite106bf94eff07d9a59771d9ccc4406421e18ab64 (patch)
treeedb6545500e39df9c67aa918a6125bffc8ec1aee /src/prompt_toolkit/layout/utils.py
parentInitial commit. (diff)
downloadprompt-toolkit-upstream/3.0.36.tar.xz
prompt-toolkit-upstream/3.0.36.zip
Adding upstream version 3.0.36.upstream/3.0.36upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--src/prompt_toolkit/layout/utils.py80
1 files changed, 80 insertions, 0 deletions
diff --git a/src/prompt_toolkit/layout/utils.py b/src/prompt_toolkit/layout/utils.py
new file mode 100644
index 0000000..cebdf28
--- /dev/null
+++ b/src/prompt_toolkit/layout/utils.py
@@ -0,0 +1,80 @@
+from typing import TYPE_CHECKING, Iterable, List, TypeVar, Union, 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: Union["SupportsIndex", slice], value: Union[_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(cast("Iterable[_T]", 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)