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
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
1"""Python grapheme, emoji, and sequence-aware ljust, rjust, center()."""
2from __future__ import annotations
4from typing import Literal
6# local
7from ._width import width
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.
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``.
39 .. versionadded:: 0.8.0
40 :returns: Text padded on the right to reach ``dest_width``.
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.
45 Text wider than ``dest_width`` is returned unchanged. Clip to ``dest_width`` if needed::
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'
53 .. versionadded:: 0.3.0
55 Example::
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
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.
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``.
103 .. versionadded:: 0.8.0
104 :returns: Text padded on the left to reach ``dest_width``.
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::
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'
116 Text wider than ``dest_width`` is returned unchanged. Clip to ``dest_width`` if needed::
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'
124 .. versionadded:: 0.3.0
126 Example::
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
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.
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``.
175 .. versionadded:: 0.8.0
176 :returns: Text padded on both sides to reach ``dest_width``.
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>`_.
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::
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 '
193 Text wider than ``dest_width`` is returned unchanged. Clip to ``dest_width`` if needed::
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'
201 .. versionadded:: 0.3.0
203 Example::
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