Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/prompt_toolkit/formatted_text/utils.py: 43%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

28 statements  

1""" 

2Utilities for manipulating formatted text. 

3 

4When ``to_formatted_text`` has been called, we get a list of ``(style, text)`` 

5tuples. This file contains functions for manipulating such a list. 

6""" 

7 

8from __future__ import annotations 

9 

10from collections.abc import Iterable 

11from typing import cast 

12 

13from prompt_toolkit.utils import get_cwidth 

14 

15from .base import ( 

16 AnyFormattedText, 

17 OneStyleAndTextTuple, 

18 StyleAndTextTuples, 

19 to_formatted_text, 

20) 

21 

22__all__ = [ 

23 "to_plain_text", 

24 "fragment_list_len", 

25 "fragment_list_width", 

26 "fragment_list_to_text", 

27 "split_lines", 

28] 

29 

30 

31def to_plain_text(value: AnyFormattedText) -> str: 

32 """ 

33 Turn any kind of formatted text back into plain text. 

34 """ 

35 return fragment_list_to_text(to_formatted_text(value)) 

36 

37 

38def fragment_list_len(fragments: StyleAndTextTuples) -> int: 

39 """ 

40 Return the amount of characters in this text fragment list. 

41 

42 :param fragments: List of ``(style_str, text)`` or 

43 ``(style_str, text, mouse_handler)`` tuples. 

44 """ 

45 ZeroWidthEscape = "[ZeroWidthEscape]" 

46 return sum(len(item[1]) for item in fragments if ZeroWidthEscape not in item[0]) 

47 

48 

49def fragment_list_width(fragments: StyleAndTextTuples) -> int: 

50 """ 

51 Return the character width of this text fragment list. 

52 (Take double width characters into account.) 

53 

54 :param fragments: List of ``(style_str, text)`` or 

55 ``(style_str, text, mouse_handler)`` tuples. 

56 """ 

57 ZeroWidthEscape = "[ZeroWidthEscape]" 

58 return sum( 

59 get_cwidth(c) 

60 for item in fragments 

61 for c in item[1] 

62 if ZeroWidthEscape not in item[0] 

63 ) 

64 

65 

66def fragment_list_to_text(fragments: StyleAndTextTuples) -> str: 

67 """ 

68 Concatenate all the text parts again. 

69 

70 :param fragments: List of ``(style_str, text)`` or 

71 ``(style_str, text, mouse_handler)`` tuples. 

72 """ 

73 ZeroWidthEscape = "[ZeroWidthEscape]" 

74 return "".join(item[1] for item in fragments if ZeroWidthEscape not in item[0]) 

75 

76 

77def split_lines( 

78 fragments: Iterable[OneStyleAndTextTuple], 

79) -> Iterable[StyleAndTextTuples]: 

80 """ 

81 Take a single list of (style_str, text) tuples and yield one such list for each 

82 line. Just like str.split, this will yield at least one item. 

83 

84 :param fragments: Iterable of ``(style_str, text)`` or 

85 ``(style_str, text, mouse_handler)`` tuples. 

86 """ 

87 line: StyleAndTextTuples = [] 

88 

89 for style, string, *mouse_handler in fragments: 

90 parts = string.split("\n") 

91 

92 for part in parts[:-1]: 

93 line.append(cast(OneStyleAndTextTuple, (style, part, *mouse_handler))) 

94 yield line 

95 line = [] 

96 

97 line.append(cast(OneStyleAndTextTuple, (style, parts[-1], *mouse_handler))) 

98 

99 # Always yield the last line, even when this is an empty line. This ensures 

100 # that when `fragments` ends with a newline character, an additional empty 

101 # line is yielded. (Otherwise, there's no way to differentiate between the 

102 # cases where `fragments` does and doesn't end with a newline.) 

103 yield line