Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/prompt_toolkit/formatted_text/utils.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

27 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 typing import Iterable, cast 

11 

12from prompt_toolkit.utils import get_cwidth 

13 

14from .base import ( 

15 AnyFormattedText, 

16 OneStyleAndTextTuple, 

17 StyleAndTextTuples, 

18 to_formatted_text, 

19) 

20 

21__all__ = [ 

22 "to_plain_text", 

23 "fragment_list_len", 

24 "fragment_list_width", 

25 "fragment_list_to_text", 

26 "split_lines", 

27] 

28 

29 

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

31 """ 

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

33 """ 

34 return fragment_list_to_text(to_formatted_text(value)) 

35 

36 

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

38 """ 

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

40 

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

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

43 """ 

44 ZeroWidthEscape = "[ZeroWidthEscape]" 

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

46 

47 

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

49 """ 

50 Return the character width of this text fragment list. 

51 (Take double width characters into account.) 

52 

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

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

55 """ 

56 ZeroWidthEscape = "[ZeroWidthEscape]" 

57 return sum( 

58 get_cwidth(c) 

59 for item in fragments 

60 for c in item[1] 

61 if ZeroWidthEscape not in item[0] 

62 ) 

63 

64 

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

66 """ 

67 Concatenate all the text parts again. 

68 

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

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

71 """ 

72 ZeroWidthEscape = "[ZeroWidthEscape]" 

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

74 

75 

76def split_lines( 

77 fragments: Iterable[OneStyleAndTextTuple], 

78) -> Iterable[StyleAndTextTuples]: 

79 """ 

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

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

82 

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

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

85 """ 

86 line: StyleAndTextTuples = [] 

87 

88 for style, string, *mouse_handler in fragments: 

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

90 

91 for part in parts[:-1]: 

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

93 yield line 

94 line = [] 

95 

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

97 

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

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

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

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

102 yield line