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

27 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2024-04-20 06:09 +0000

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""" 

7from __future__ import annotations 

8 

9from typing import Iterable, cast 

10 

11from prompt_toolkit.utils import get_cwidth 

12 

13from .base import ( 

14 AnyFormattedText, 

15 OneStyleAndTextTuple, 

16 StyleAndTextTuples, 

17 to_formatted_text, 

18) 

19 

20__all__ = [ 

21 "to_plain_text", 

22 "fragment_list_len", 

23 "fragment_list_width", 

24 "fragment_list_to_text", 

25 "split_lines", 

26] 

27 

28 

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

30 """ 

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

32 """ 

33 return fragment_list_to_text(to_formatted_text(value)) 

34 

35 

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

37 """ 

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

39 

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

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

42 """ 

43 ZeroWidthEscape = "[ZeroWidthEscape]" 

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

45 

46 

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

48 """ 

49 Return the character width of this text fragment list. 

50 (Take double width characters into account.) 

51 

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

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

54 """ 

55 ZeroWidthEscape = "[ZeroWidthEscape]" 

56 return sum( 

57 get_cwidth(c) 

58 for item in fragments 

59 for c in item[1] 

60 if ZeroWidthEscape not in item[0] 

61 ) 

62 

63 

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

65 """ 

66 Concatenate all the text parts again. 

67 

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

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

70 """ 

71 ZeroWidthEscape = "[ZeroWidthEscape]" 

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

73 

74 

75def split_lines( 

76 fragments: Iterable[OneStyleAndTextTuple], 

77) -> Iterable[StyleAndTextTuples]: 

78 """ 

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

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

81 

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

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

84 """ 

85 line: StyleAndTextTuples = [] 

86 

87 for style, string, *mouse_handler in fragments: 

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

89 

90 for part in parts[:-1]: 

91 if part: 

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