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

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

69 statements  

1from __future__ import annotations 

2 

3from collections.abc import Callable, Iterable 

4from typing import TYPE_CHECKING, Union, cast 

5 

6from prompt_toolkit.mouse_events import MouseEvent 

7 

8if TYPE_CHECKING: 

9 from typing_extensions import Protocol 

10 

11 from prompt_toolkit.key_binding.key_bindings import NotImplementedOrNone 

12 

13__all__ = [ 

14 "OneStyleAndTextTuple", 

15 "StyleAndTextTuples", 

16 "MagicFormattedText", 

17 "AnyFormattedText", 

18 "to_formatted_text", 

19 "is_formatted_text", 

20 "Template", 

21 "merge_formatted_text", 

22 "FormattedText", 

23] 

24 

25OneStyleAndTextTuple = ( 

26 tuple[str, str] | tuple[str, str, Callable[[MouseEvent], "NotImplementedOrNone"]] 

27) 

28 

29 

30# List of (style, text) tuples. 

31StyleAndTextTuples = list[OneStyleAndTextTuple] 

32 

33 

34if TYPE_CHECKING: 

35 from typing import TypeGuard 

36 

37 class MagicFormattedText(Protocol): 

38 """ 

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

40 text. 

41 """ 

42 

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

44 

45 

46AnyFormattedText = Union[ 

47 str, 

48 "MagicFormattedText", 

49 StyleAndTextTuples, 

50 Callable[[], "AnyFormattedText"], 

51 None, 

52] 

53 

54 

55def to_formatted_text( 

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

57) -> FormattedText: 

58 """ 

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

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

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

62 

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

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

65 returns one of those. 

66 

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

68 fragments. 

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

70 to a string first. 

71 """ 

72 result: FormattedText | StyleAndTextTuples 

73 

74 if value is None: 

75 result = [] 

76 elif isinstance(value, str): 

77 result = [("", value)] 

78 elif isinstance(value, list): 

79 result = value # StyleAndTextTuples 

80 elif hasattr(value, "__pt_formatted_text__"): 

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

82 elif callable(value): 

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

84 elif auto_convert: 

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

86 else: 

87 raise ValueError( 

88 f"No formatted text. Expecting a unicode object, HTML, ANSI or a FormattedText instance. Got {value!r}" 

89 ) 

90 

91 # Apply extra style. 

92 if style: 

93 result = cast( 

94 StyleAndTextTuples, 

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

96 ) 

97 

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

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

100 # and distinguish between lists and formatted text. 

101 if isinstance(result, FormattedText): 

102 return result 

103 else: 

104 return FormattedText(result) 

105 

106 

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

108 """ 

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

110 statements). 

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

112 """ 

113 if callable(value): 

114 return True 

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

116 return True 

117 if hasattr(value, "__pt_formatted_text__"): 

118 return True 

119 return False 

120 

121 

122class FormattedText(StyleAndTextTuples): 

123 """ 

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

125 

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

127 tuples.) 

128 """ 

129 

130 def __pt_formatted_text__(self) -> StyleAndTextTuples: 

131 return self 

132 

133 def __repr__(self) -> str: 

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

135 

136 

137class Template: 

138 """ 

139 Template for string interpolation with formatted text. 

140 

141 Example:: 

142 

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

144 

145 :param text: Plain text. 

146 """ 

147 

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

149 assert "{0}" not in text 

150 self.text = text 

151 

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

153 def get_result() -> AnyFormattedText: 

154 # Split the template in parts. 

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

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

157 

158 result = FormattedText() 

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

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

161 result.extend(to_formatted_text(val)) 

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

163 return result 

164 

165 return get_result 

166 

167 

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

169 """ 

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

171 """ 

172 

173 def _merge_formatted_text() -> AnyFormattedText: 

174 result = FormattedText() 

175 for i in items: 

176 result.extend(to_formatted_text(i)) 

177 return result 

178 

179 return _merge_formatted_text