test_formatted_text.py 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. from __future__ import annotations
  2. from prompt_toolkit.formatted_text import (
  3. ANSI,
  4. HTML,
  5. FormattedText,
  6. PygmentsTokens,
  7. Template,
  8. merge_formatted_text,
  9. to_formatted_text,
  10. )
  11. from prompt_toolkit.formatted_text.utils import split_lines
  12. def test_basic_html():
  13. html = HTML("<i>hello</i>")
  14. assert to_formatted_text(html) == [("class:i", "hello")]
  15. html = HTML("<i><b>hello</b></i>")
  16. assert to_formatted_text(html) == [("class:i,b", "hello")]
  17. html = HTML("<i><b>hello</b>world<strong>test</strong></i>after")
  18. assert to_formatted_text(html) == [
  19. ("class:i,b", "hello"),
  20. ("class:i", "world"),
  21. ("class:i,strong", "test"),
  22. ("", "after"),
  23. ]
  24. # It's important that `to_formatted_text` returns a `FormattedText`
  25. # instance. Otherwise, `print_formatted_text` won't recognize it and will
  26. # print a list literal instead.
  27. assert isinstance(to_formatted_text(html), FormattedText)
  28. def test_html_with_fg_bg():
  29. html = HTML('<style bg="ansired">hello</style>')
  30. assert to_formatted_text(html) == [
  31. ("bg:ansired", "hello"),
  32. ]
  33. html = HTML('<style bg="ansired" fg="#ff0000">hello</style>')
  34. assert to_formatted_text(html) == [
  35. ("fg:#ff0000 bg:ansired", "hello"),
  36. ]
  37. html = HTML(
  38. '<style bg="ansired" fg="#ff0000">hello <world fg="ansiblue">world</world></style>'
  39. )
  40. assert to_formatted_text(html) == [
  41. ("fg:#ff0000 bg:ansired", "hello "),
  42. ("class:world fg:ansiblue bg:ansired", "world"),
  43. ]
  44. def test_ansi_formatting():
  45. value = ANSI("\x1b[32mHe\x1b[45mllo")
  46. assert to_formatted_text(value) == [
  47. ("ansigreen", "H"),
  48. ("ansigreen", "e"),
  49. ("ansigreen bg:ansimagenta", "l"),
  50. ("ansigreen bg:ansimagenta", "l"),
  51. ("ansigreen bg:ansimagenta", "o"),
  52. ]
  53. # Bold and italic.
  54. value = ANSI("\x1b[1mhe\x1b[0mllo")
  55. assert to_formatted_text(value) == [
  56. ("bold", "h"),
  57. ("bold", "e"),
  58. ("", "l"),
  59. ("", "l"),
  60. ("", "o"),
  61. ]
  62. # Zero width escapes.
  63. value = ANSI("ab\001cd\002ef")
  64. assert to_formatted_text(value) == [
  65. ("", "a"),
  66. ("", "b"),
  67. ("[ZeroWidthEscape]", "cd"),
  68. ("", "e"),
  69. ("", "f"),
  70. ]
  71. assert isinstance(to_formatted_text(value), FormattedText)
  72. def test_ansi_256_color():
  73. assert to_formatted_text(ANSI("\x1b[38;5;124mtest")) == [
  74. ("#af0000", "t"),
  75. ("#af0000", "e"),
  76. ("#af0000", "s"),
  77. ("#af0000", "t"),
  78. ]
  79. def test_ansi_true_color():
  80. assert to_formatted_text(ANSI("\033[38;2;144;238;144m$\033[0;39;49m ")) == [
  81. ("#90ee90", "$"),
  82. ("ansidefault bg:ansidefault", " "),
  83. ]
  84. def test_ansi_interpolation():
  85. # %-style interpolation.
  86. value = ANSI("\x1b[1m%s\x1b[0m") % "hello\x1b"
  87. assert to_formatted_text(value) == [
  88. ("bold", "h"),
  89. ("bold", "e"),
  90. ("bold", "l"),
  91. ("bold", "l"),
  92. ("bold", "o"),
  93. ("bold", "?"),
  94. ]
  95. value = ANSI("\x1b[1m%s\x1b[0m") % ("\x1bhello",)
  96. assert to_formatted_text(value) == [
  97. ("bold", "?"),
  98. ("bold", "h"),
  99. ("bold", "e"),
  100. ("bold", "l"),
  101. ("bold", "l"),
  102. ("bold", "o"),
  103. ]
  104. value = ANSI("\x1b[32m%s\x1b[45m%s") % ("He", "\x1bllo")
  105. assert to_formatted_text(value) == [
  106. ("ansigreen", "H"),
  107. ("ansigreen", "e"),
  108. ("ansigreen bg:ansimagenta", "?"),
  109. ("ansigreen bg:ansimagenta", "l"),
  110. ("ansigreen bg:ansimagenta", "l"),
  111. ("ansigreen bg:ansimagenta", "o"),
  112. ]
  113. # Format function.
  114. value = ANSI("\x1b[32m{0}\x1b[45m{1}").format("He\x1b", "llo")
  115. assert to_formatted_text(value) == [
  116. ("ansigreen", "H"),
  117. ("ansigreen", "e"),
  118. ("ansigreen", "?"),
  119. ("ansigreen bg:ansimagenta", "l"),
  120. ("ansigreen bg:ansimagenta", "l"),
  121. ("ansigreen bg:ansimagenta", "o"),
  122. ]
  123. value = ANSI("\x1b[32m{a}\x1b[45m{b}").format(a="\x1bHe", b="llo")
  124. assert to_formatted_text(value) == [
  125. ("ansigreen", "?"),
  126. ("ansigreen", "H"),
  127. ("ansigreen", "e"),
  128. ("ansigreen bg:ansimagenta", "l"),
  129. ("ansigreen bg:ansimagenta", "l"),
  130. ("ansigreen bg:ansimagenta", "o"),
  131. ]
  132. value = ANSI("\x1b[32m{:02d}\x1b[45m{:.3f}").format(3, 3.14159)
  133. assert to_formatted_text(value) == [
  134. ("ansigreen", "0"),
  135. ("ansigreen", "3"),
  136. ("ansigreen bg:ansimagenta", "3"),
  137. ("ansigreen bg:ansimagenta", "."),
  138. ("ansigreen bg:ansimagenta", "1"),
  139. ("ansigreen bg:ansimagenta", "4"),
  140. ("ansigreen bg:ansimagenta", "2"),
  141. ]
  142. def test_interpolation():
  143. value = Template(" {} ").format(HTML("<b>hello</b>"))
  144. assert to_formatted_text(value) == [
  145. ("", " "),
  146. ("class:b", "hello"),
  147. ("", " "),
  148. ]
  149. value = Template("a{}b{}c").format(HTML("<b>hello</b>"), "world")
  150. assert to_formatted_text(value) == [
  151. ("", "a"),
  152. ("class:b", "hello"),
  153. ("", "b"),
  154. ("", "world"),
  155. ("", "c"),
  156. ]
  157. def test_html_interpolation():
  158. # %-style interpolation.
  159. value = HTML("<b>%s</b>") % "&hello"
  160. assert to_formatted_text(value) == [("class:b", "&hello")]
  161. value = HTML("<b>%s</b>") % ("<hello>",)
  162. assert to_formatted_text(value) == [("class:b", "<hello>")]
  163. value = HTML("<b>%s</b><u>%s</u>") % ("<hello>", "</world>")
  164. assert to_formatted_text(value) == [("class:b", "<hello>"), ("class:u", "</world>")]
  165. # Format function.
  166. value = HTML("<b>{0}</b><u>{1}</u>").format("'hello'", '"world"')
  167. assert to_formatted_text(value) == [("class:b", "'hello'"), ("class:u", '"world"')]
  168. value = HTML("<b>{a}</b><u>{b}</u>").format(a="hello", b="world")
  169. assert to_formatted_text(value) == [("class:b", "hello"), ("class:u", "world")]
  170. value = HTML("<b>{:02d}</b><u>{:.3f}</u>").format(3, 3.14159)
  171. assert to_formatted_text(value) == [("class:b", "03"), ("class:u", "3.142")]
  172. def test_merge_formatted_text():
  173. html1 = HTML("<u>hello</u>")
  174. html2 = HTML("<b>world</b>")
  175. result = merge_formatted_text([html1, html2])
  176. assert to_formatted_text(result) == [
  177. ("class:u", "hello"),
  178. ("class:b", "world"),
  179. ]
  180. def test_pygments_tokens():
  181. text = [
  182. (("A", "B"), "hello"), # Token.A.B
  183. (("C", "D", "E"), "hello"), # Token.C.D.E
  184. ((), "world"), # Token
  185. ]
  186. assert to_formatted_text(PygmentsTokens(text)) == [
  187. ("class:pygments.a.b", "hello"),
  188. ("class:pygments.c.d.e", "hello"),
  189. ("class:pygments", "world"),
  190. ]
  191. def test_split_lines():
  192. lines = list(split_lines([("class:a", "line1\nline2\nline3")]))
  193. assert lines == [
  194. [("class:a", "line1")],
  195. [("class:a", "line2")],
  196. [("class:a", "line3")],
  197. ]
  198. def test_split_lines_2():
  199. lines = list(
  200. split_lines([("class:a", "line1"), ("class:b", "line2\nline3\nline4")])
  201. )
  202. assert lines == [
  203. [("class:a", "line1"), ("class:b", "line2")],
  204. [("class:b", "line3")],
  205. [("class:b", "line4")],
  206. ]
  207. def test_split_lines_3():
  208. "Edge cases: inputs ending with newlines."
  209. # -1-
  210. lines = list(split_lines([("class:a", "line1\nline2\n")]))
  211. assert lines == [
  212. [("class:a", "line1")],
  213. [("class:a", "line2")],
  214. [("class:a", "")],
  215. ]
  216. # -2-
  217. lines = list(split_lines([("class:a", "\n")]))
  218. assert lines == [
  219. [],
  220. [("class:a", "")],
  221. ]
  222. # -3-
  223. lines = list(split_lines([("class:a", "")]))
  224. assert lines == [
  225. [("class:a", "")],
  226. ]