Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/wcwidth/align.py: 29%

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

24 statements  

1"""Python grapheme, emoji, and sequence-aware ljust, rjust, center().""" 

2from __future__ import annotations 

3 

4from typing import Literal 

5 

6# local 

7from ._width import width 

8 

9 

10def ljust( 

11 text: str, 

12 dest_width: int, 

13 fillchar: str = ' ', 

14 *, 

15 control_codes: Literal['parse', 'strict', 'ignore'] = 'parse', 

16 ambiguous_width: int = 1, 

17 term_program: bool | str = False, 

18) -> str: 

19 r""" 

20 Return text left-justified in a string of given display width. 

21 

22 :param text: String to justify, may contain terminal sequences. 

23 :param dest_width: Desired displayed width of result in terminal cells, which 

24 ``text`` can exceed. Use :func:`wcwidth.clip` to ensure ``text`` does not 

25 exceed ``dest_width``. 

26 :param fillchar: Single character for padding (default space). Must have 

27 display width of 1. Unicode characters like ``'·'`` are acceptable. 

28 The width is not validated. 

29 :param control_codes: How to handle control sequences when measuring. 

30 Passed to :func:`width` for measurement. 

31 :param ambiguous_width: Width to use for East Asian Ambiguous (A) 

32 characters. Default is ``1`` (narrow). Set to ``2`` for CJK contexts. 

33 :param term_program: Terminal software identifier for table correction. 

34 ``False`` (default) disables override lookup. ``True`` reads the 

35 ``TERM_PROGRAM`` or ``TERM`` environment variable for auto-detection. 

36 Accepts a canonical terminal name matching :func:`list_term_programs`, 

37 such as from XTVERSION_, ENQ_, or ``TERM_PROGRAM``. 

38 

39 .. versionadded:: 0.8.0 

40 :returns: Text padded on the right to reach ``dest_width``. 

41 

42 Tabs are measured as though ``text`` begins at column 0. It is suggested to first use 

43 :func:`str.expandtabs` or :func:`wcwidth.clip` to expand tabs before applying text alignment. 

44 

45 Text wider than ``dest_width`` is returned unchanged. Clip to ``dest_width`` if needed:: 

46 

47 >>> from wcwidth import clip 

48 >>> ljust('abcdefghi', 2) # wider than dest_width, unchanged 

49 'abcdefghi' 

50 >>> ljust(clip('abcdefghi', 0, 2), 2) # clipped to dest_width 

51 'ab' 

52 

53 .. versionadded:: 0.3.0 

54 

55 Example:: 

56 

57 >>> ljust('hi', 5) 

58 'hi ' 

59 >>> ljust('\x1b[31mhi\x1b[0m', 5) 

60 '\x1b[31mhi\x1b[0m ' 

61 >>> ljust('\U0001F468\u200D\U0001F469\u200D\U0001F467', 6) 

62 '👨‍👩‍👧 ' 

63 >>> ljust('\U0001F468\u200D\U0001F469\u200D\U0001F467', 6, term_program='VTE') 

64 '👨\u200d👩\u200d👧' 

65 """ 

66 if text.isascii() and text.isprintable(): 

67 text_width = len(text) 

68 else: 

69 text_width = width(text, control_codes=control_codes, ambiguous_width=ambiguous_width, 

70 term_program=term_program) 

71 padding_cells = max(0, dest_width - text_width) 

72 return text + fillchar * padding_cells 

73 

74 

75def rjust( 

76 text: str, 

77 dest_width: int, 

78 fillchar: str = ' ', 

79 *, 

80 control_codes: Literal['parse', 'strict', 'ignore'] = 'parse', 

81 ambiguous_width: int = 1, 

82 term_program: bool | str = False, 

83) -> str: 

84 r""" 

85 Return text right-justified in a string of given display width. 

86 

87 :param text: String to justify, may contain terminal sequences. 

88 :param dest_width: Desired displayed width of result in terminal cells, which ``text`` can 

89 exceed. Use :func:`wcwidth.clip` to ensure ``text`` does not exceed ``dest_width``. 

90 :param fillchar: Single character for padding (default space). Must have 

91 display width of 1. Unicode characters like ``'·'`` are acceptable. 

92 The width is not validated. 

93 :param control_codes: How to handle control sequences when measuring. 

94 Passed to :func:`width` for measurement. 

95 :param ambiguous_width: Width to use for East Asian Ambiguous (A) 

96 characters. Default is ``1`` (narrow). Set to ``2`` for CJK contexts. 

97 :param term_program: Terminal software identifier for table correction. 

98 ``False`` (default) disables override lookup. ``True`` reads the 

99 ``TERM_PROGRAM`` or ``TERM`` environment variable for auto-detection. 

100 Accepts a canonical terminal name matching :func:`list_term_programs`, 

101 such as from XTVERSION_, ENQ_, or ``TERM_PROGRAM``. 

102 

103 .. versionadded:: 0.8.0 

104 :returns: Text padded on the left to reach ``dest_width``. 

105 

106 Tabs are measured as though ``text`` begins at column 0. The ``fillchar`` placed before a tab by 

107 right-justified text moves any tabs to a later stop and produces an incorrect alignment result. 

108 It is suggested never to align text containing a tab, calling :func:`str.expandtabs` or 

109 :func:`wcwidth.clip` (which also expands tabs) if necessary:: 

110 

111 >>> rjust('a\tbc', 12) # when displayed, becomes width of 10, wrong 

112 ' a\tbc' 

113 >>> rjust('a\tbc'.expandtabs(), 12) # properly displayed as width of 12 

114 ' a bc' 

115 

116 Text wider than ``dest_width`` is returned unchanged. Clip to ``dest_width`` if needed:: 

117 

118 >>> from wcwidth import clip 

119 >>> rjust('abcdefghi', 2) # wider than dest_width, unchanged 

120 'abcdefghi' 

121 >>> rjust(clip('abcdefghi', 0, 2), 2) # clipped to dest_width 

122 'ab' 

123 

124 .. versionadded:: 0.3.0 

125 

126 Example:: 

127 

128 >>> rjust('hi', 5) 

129 ' hi' 

130 >>> rjust('\x1b[31mhi\x1b[0m', 5) 

131 ' \x1b[31mhi\x1b[0m' 

132 >>> rjust('\U0001F468\u200D\U0001F469\u200D\U0001F467', 6) 

133 ' 👨‍👩‍👧' 

134 >>> rjust('\U0001F468\u200D\U0001F469\u200D\U0001F467', 6, term_program='VTE') 

135 '👨\u200d👩\u200d👧' 

136 """ 

137 if text.isascii() and text.isprintable(): 

138 text_width = len(text) 

139 else: 

140 text_width = width(text, control_codes=control_codes, ambiguous_width=ambiguous_width, 

141 term_program=term_program) 

142 padding_cells = max(0, dest_width - text_width) 

143 return fillchar * padding_cells + text 

144 

145 

146def center( 

147 text: str, 

148 dest_width: int, 

149 fillchar: str = ' ', 

150 *, 

151 control_codes: Literal['parse', 'strict', 'ignore'] = 'parse', 

152 ambiguous_width: int = 1, 

153 term_program: bool | str = False, 

154) -> str: 

155 r""" 

156 Return text centered in a string of given display width. 

157 

158 :param text: String to center, may contain terminal sequences. 

159 :param dest_width: Desired displayed width of result in terminal cells, which 

160 ``text`` can exceed. Use :func:`wcwidth.clip` to ensure ``text`` does not 

161 exceed ``dest_width``. 

162 :param fillchar: Single character for padding (default space). Must have 

163 display width of 1. Unicode characters like ``'·'`` are acceptable. 

164 The width is not validated. 

165 :param control_codes: How to handle control sequences when measuring. 

166 Passed to :func:`width` for measurement. 

167 :param ambiguous_width: Width to use for East Asian Ambiguous (A) 

168 characters. Default is ``1`` (narrow). Set to ``2`` for CJK contexts. 

169 :param term_program: Terminal software identifier for table correction. 

170 ``False`` (default) disables override lookup. ``True`` reads the 

171 ``TERM_PROGRAM`` or ``TERM`` environment variable for auto-detection. 

172 Accepts a canonical terminal name matching :func:`list_term_programs`, 

173 such as from XTVERSION_, ENQ_, or ``TERM_PROGRAM``. 

174 

175 .. versionadded:: 0.8.0 

176 :returns: Text padded on both sides to reach ``dest_width``. 

177 

178 For odd-width padding, the extra cell fills in the same cell position as 

179 Python's :meth:`str.center` behavior (the left side when ``dest_width`` is 

180 odd, the right side when ``dest_width`` is even). 

181 See `the eccentric str.center <https://jazcap53.github.io/pythons-eccentric-strcenter.html>`_. 

182 

183 Tabs are measured as though ``text`` begins at column 0. The ``fillchar`` placed before a tab by 

184 centered text moves any tabs to a later stop and produces an incorrect alignment result. It is 

185 suggested never to align text containing a tab, calling :func:`str.expandtabs` or 

186 :func:`wcwidth.clip` (which also expands tabs) if necessary:: 

187 

188 >>> center('a\tbc', 12) # when displayed, becomes width of 11, wrong 

189 ' a\tbc ' 

190 >>> center('a\tbc'.expandtabs(), 12) # properly displayed as width of 12 

191 ' a bc ' 

192 

193 Text wider than ``dest_width`` is returned unchanged. Clip to ``dest_width`` if needed:: 

194 

195 >>> from wcwidth import clip 

196 >>> center('abcdefghi', 2) # wider than dest_width, unchanged 

197 'abcdefghi' 

198 >>> center(clip('abcdefghi', 0, 2), 2) # clipped to dest_width 

199 'ab' 

200 

201 .. versionadded:: 0.3.0 

202 

203 Example:: 

204 

205 >>> center('hi', 6) 

206 ' hi ' 

207 >>> center('\x1b[31mhi\x1b[0m', 6) 

208 ' \x1b[31mhi\x1b[0m ' 

209 >>> center('\U0001F468\u200D\U0001F469\u200D\U0001F467', 6) 

210 ' 👨‍👩‍👧 ' 

211 >>> center('\U0001F468\u200D\U0001F469\u200D\U0001F467', 6, term_program='VTE') 

212 '👨\u200d👩\u200d👧' 

213 """ 

214 if text.isascii() and text.isprintable(): 

215 text_width = len(text) 

216 else: 

217 text_width = width(text, control_codes=control_codes, ambiguous_width=ambiguous_width, 

218 term_program=term_program) 

219 total_padding = max(0, dest_width - text_width) 

220 # matching https://jazcap53.github.io/pythons-eccentric-strcenter.html 

221 left_pad = total_padding // 2 + (total_padding & dest_width & 1) 

222 right_pad = total_padding - left_pad 

223 return fillchar * left_pad + text + fillchar * right_pad