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

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

68 statements  

1from __future__ import annotations 

2 

3from typing import TYPE_CHECKING, Callable, Iterable, List, Tuple, Union, cast 

4 

5from prompt_toolkit.mouse_events import MouseEvent 

6 

7if TYPE_CHECKING: 

8 from typing_extensions import Protocol 

9 

10 from prompt_toolkit.key_binding.key_bindings import NotImplementedOrNone 

11 

12__all__ = [ 

13 "OneStyleAndTextTuple", 

14 "StyleAndTextTuples", 

15 "MagicFormattedText", 

16 "AnyFormattedText", 

17 "to_formatted_text", 

18 "is_formatted_text", 

19 "Template", 

20 "merge_formatted_text", 

21 "FormattedText", 

22] 

23 

24OneStyleAndTextTuple = Union[ 

25 Tuple[str, str], Tuple[str, str, Callable[[MouseEvent], "NotImplementedOrNone"]] 

26] 

27 

28# List of (style, text) tuples. 

29StyleAndTextTuples = List[OneStyleAndTextTuple] 

30 

31 

32if TYPE_CHECKING: 

33 from typing_extensions import TypeGuard 

34 

35 class MagicFormattedText(Protocol): 

36 """ 

37 Any object that implements ``__pt_formatted_text__`` represents formatted 

38 text. 

39 """ 

40 

41 def __pt_formatted_text__(self) -> StyleAndTextTuples: ... 

42 

43 

44AnyFormattedText = Union[ 

45 str, 

46 "MagicFormattedText", 

47 StyleAndTextTuples, 

48 Callable[[], "AnyFormattedText"], 

49 None, 

50] 

51 

52 

53def to_formatted_text( 

54 value: AnyFormattedText, style: str = "", auto_convert: bool = False 

55) -> FormattedText: 

56 """ 

57 Convert the given value (which can be formatted text) into a list of text 

58 fragments. (Which is the canonical form of formatted text.) The outcome is 

59 always a `FormattedText` instance, which is a list of (style, text) tuples. 

60 

61 It can take a plain text string, an `HTML` or `ANSI` object, anything that 

62 implements `__pt_formatted_text__` or a callable that takes no arguments and 

63 returns one of those. 

64 

65 :param style: An additional style string which is applied to all text 

66 fragments. 

67 :param auto_convert: If `True`, also accept other types, and convert them 

68 to a string first. 

69 """ 

70 result: FormattedText | StyleAndTextTuples 

71 

72 if value is None: 

73 result = [] 

74 elif isinstance(value, str): 

75 result = [("", value)] 

76 elif isinstance(value, list): 

77 result = value # StyleAndTextTuples 

78 elif hasattr(value, "__pt_formatted_text__"): 

79 result = cast("MagicFormattedText", value).__pt_formatted_text__() 

80 elif callable(value): 

81 return to_formatted_text(value(), style=style) 

82 elif auto_convert: 

83 result = [("", f"{value}")] 

84 else: 

85 raise ValueError( 

86 "No formatted text. Expecting a unicode object, " 

87 f"HTML, ANSI or a FormattedText instance. Got {value!r}" 

88 ) 

89 

90 # Apply extra style. 

91 if style: 

92 result = cast( 

93 StyleAndTextTuples, 

94 [(style + " " + item_style, *rest) for item_style, *rest in result], 

95 ) 

96 

97 # Make sure the result is wrapped in a `FormattedText`. Among other 

98 # reasons, this is important for `print_formatted_text` to work correctly 

99 # and distinguish between lists and formatted text. 

100 if isinstance(result, FormattedText): 

101 return result 

102 else: 

103 return FormattedText(result) 

104 

105 

106def is_formatted_text(value: object) -> TypeGuard[AnyFormattedText]: 

107 """ 

108 Check whether the input is valid formatted text (for use in assert 

109 statements). 

110 In case of a callable, it doesn't check the return type. 

111 """ 

112 if callable(value): 

113 return True 

114 if isinstance(value, (str, list)): 

115 return True 

116 if hasattr(value, "__pt_formatted_text__"): 

117 return True 

118 return False 

119 

120 

121class FormattedText(StyleAndTextTuples): 

122 """ 

123 A list of ``(style, text)`` tuples. 

124 

125 (In some situations, this can also be ``(style, text, mouse_handler)`` 

126 tuples.) 

127 """ 

128 

129 def __pt_formatted_text__(self) -> StyleAndTextTuples: 

130 return self 

131 

132 def __repr__(self) -> str: 

133 return f"FormattedText({super().__repr__()})" 

134 

135 

136class Template: 

137 """ 

138 Template for string interpolation with formatted text. 

139 

140 Example:: 

141 

142 Template(' ... {} ... ').format(HTML(...)) 

143 

144 :param text: Plain text. 

145 """ 

146 

147 def __init__(self, text: str) -> None: 

148 assert "{0}" not in text 

149 self.text = text 

150 

151 def format(self, *values: AnyFormattedText) -> AnyFormattedText: 

152 def get_result() -> AnyFormattedText: 

153 # Split the template in parts. 

154 parts = self.text.split("{}") 

155 assert len(parts) - 1 == len(values) 

156 

157 result = FormattedText() 

158 for part, val in zip(parts, values): 

159 result.append(("", part)) 

160 result.extend(to_formatted_text(val)) 

161 result.append(("", parts[-1])) 

162 return result 

163 

164 return get_result 

165 

166 

167def merge_formatted_text(items: Iterable[AnyFormattedText]) -> AnyFormattedText: 

168 """ 

169 Merge (Concatenate) several pieces of formatted text together. 

170 """ 

171 

172 def _merge_formatted_text() -> AnyFormattedText: 

173 result = FormattedText() 

174 for i in items: 

175 result.extend(to_formatted_text(i)) 

176 return result 

177 

178 return _merge_formatted_text