Mercurial > repos > shellac > sam_consensus_v3
comparison env/lib/python3.9/site-packages/click/formatting.py @ 0:4f3585e2f14b draft default tip
"planemo upload commit 60cee0fc7c0cda8592644e1aad72851dec82c959"
author | shellac |
---|---|
date | Mon, 22 Mar 2021 18:12:50 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4f3585e2f14b |
---|---|
1 from contextlib import contextmanager | |
2 | |
3 from ._compat import term_len | |
4 from .parser import split_opt | |
5 from .termui import get_terminal_size | |
6 | |
7 # Can force a width. This is used by the test system | |
8 FORCED_WIDTH = None | |
9 | |
10 | |
11 def measure_table(rows): | |
12 widths = {} | |
13 for row in rows: | |
14 for idx, col in enumerate(row): | |
15 widths[idx] = max(widths.get(idx, 0), term_len(col)) | |
16 return tuple(y for x, y in sorted(widths.items())) | |
17 | |
18 | |
19 def iter_rows(rows, col_count): | |
20 for row in rows: | |
21 row = tuple(row) | |
22 yield row + ("",) * (col_count - len(row)) | |
23 | |
24 | |
25 def wrap_text( | |
26 text, width=78, initial_indent="", subsequent_indent="", preserve_paragraphs=False | |
27 ): | |
28 """A helper function that intelligently wraps text. By default, it | |
29 assumes that it operates on a single paragraph of text but if the | |
30 `preserve_paragraphs` parameter is provided it will intelligently | |
31 handle paragraphs (defined by two empty lines). | |
32 | |
33 If paragraphs are handled, a paragraph can be prefixed with an empty | |
34 line containing the ``\\b`` character (``\\x08``) to indicate that | |
35 no rewrapping should happen in that block. | |
36 | |
37 :param text: the text that should be rewrapped. | |
38 :param width: the maximum width for the text. | |
39 :param initial_indent: the initial indent that should be placed on the | |
40 first line as a string. | |
41 :param subsequent_indent: the indent string that should be placed on | |
42 each consecutive line. | |
43 :param preserve_paragraphs: if this flag is set then the wrapping will | |
44 intelligently handle paragraphs. | |
45 """ | |
46 from ._textwrap import TextWrapper | |
47 | |
48 text = text.expandtabs() | |
49 wrapper = TextWrapper( | |
50 width, | |
51 initial_indent=initial_indent, | |
52 subsequent_indent=subsequent_indent, | |
53 replace_whitespace=False, | |
54 ) | |
55 if not preserve_paragraphs: | |
56 return wrapper.fill(text) | |
57 | |
58 p = [] | |
59 buf = [] | |
60 indent = None | |
61 | |
62 def _flush_par(): | |
63 if not buf: | |
64 return | |
65 if buf[0].strip() == "\b": | |
66 p.append((indent or 0, True, "\n".join(buf[1:]))) | |
67 else: | |
68 p.append((indent or 0, False, " ".join(buf))) | |
69 del buf[:] | |
70 | |
71 for line in text.splitlines(): | |
72 if not line: | |
73 _flush_par() | |
74 indent = None | |
75 else: | |
76 if indent is None: | |
77 orig_len = term_len(line) | |
78 line = line.lstrip() | |
79 indent = orig_len - term_len(line) | |
80 buf.append(line) | |
81 _flush_par() | |
82 | |
83 rv = [] | |
84 for indent, raw, text in p: | |
85 with wrapper.extra_indent(" " * indent): | |
86 if raw: | |
87 rv.append(wrapper.indent_only(text)) | |
88 else: | |
89 rv.append(wrapper.fill(text)) | |
90 | |
91 return "\n\n".join(rv) | |
92 | |
93 | |
94 class HelpFormatter(object): | |
95 """This class helps with formatting text-based help pages. It's | |
96 usually just needed for very special internal cases, but it's also | |
97 exposed so that developers can write their own fancy outputs. | |
98 | |
99 At present, it always writes into memory. | |
100 | |
101 :param indent_increment: the additional increment for each level. | |
102 :param width: the width for the text. This defaults to the terminal | |
103 width clamped to a maximum of 78. | |
104 """ | |
105 | |
106 def __init__(self, indent_increment=2, width=None, max_width=None): | |
107 self.indent_increment = indent_increment | |
108 if max_width is None: | |
109 max_width = 80 | |
110 if width is None: | |
111 width = FORCED_WIDTH | |
112 if width is None: | |
113 width = max(min(get_terminal_size()[0], max_width) - 2, 50) | |
114 self.width = width | |
115 self.current_indent = 0 | |
116 self.buffer = [] | |
117 | |
118 def write(self, string): | |
119 """Writes a unicode string into the internal buffer.""" | |
120 self.buffer.append(string) | |
121 | |
122 def indent(self): | |
123 """Increases the indentation.""" | |
124 self.current_indent += self.indent_increment | |
125 | |
126 def dedent(self): | |
127 """Decreases the indentation.""" | |
128 self.current_indent -= self.indent_increment | |
129 | |
130 def write_usage(self, prog, args="", prefix="Usage: "): | |
131 """Writes a usage line into the buffer. | |
132 | |
133 :param prog: the program name. | |
134 :param args: whitespace separated list of arguments. | |
135 :param prefix: the prefix for the first line. | |
136 """ | |
137 usage_prefix = "{:>{w}}{} ".format(prefix, prog, w=self.current_indent) | |
138 text_width = self.width - self.current_indent | |
139 | |
140 if text_width >= (term_len(usage_prefix) + 20): | |
141 # The arguments will fit to the right of the prefix. | |
142 indent = " " * term_len(usage_prefix) | |
143 self.write( | |
144 wrap_text( | |
145 args, | |
146 text_width, | |
147 initial_indent=usage_prefix, | |
148 subsequent_indent=indent, | |
149 ) | |
150 ) | |
151 else: | |
152 # The prefix is too long, put the arguments on the next line. | |
153 self.write(usage_prefix) | |
154 self.write("\n") | |
155 indent = " " * (max(self.current_indent, term_len(prefix)) + 4) | |
156 self.write( | |
157 wrap_text( | |
158 args, text_width, initial_indent=indent, subsequent_indent=indent | |
159 ) | |
160 ) | |
161 | |
162 self.write("\n") | |
163 | |
164 def write_heading(self, heading): | |
165 """Writes a heading into the buffer.""" | |
166 self.write("{:>{w}}{}:\n".format("", heading, w=self.current_indent)) | |
167 | |
168 def write_paragraph(self): | |
169 """Writes a paragraph into the buffer.""" | |
170 if self.buffer: | |
171 self.write("\n") | |
172 | |
173 def write_text(self, text): | |
174 """Writes re-indented text into the buffer. This rewraps and | |
175 preserves paragraphs. | |
176 """ | |
177 text_width = max(self.width - self.current_indent, 11) | |
178 indent = " " * self.current_indent | |
179 self.write( | |
180 wrap_text( | |
181 text, | |
182 text_width, | |
183 initial_indent=indent, | |
184 subsequent_indent=indent, | |
185 preserve_paragraphs=True, | |
186 ) | |
187 ) | |
188 self.write("\n") | |
189 | |
190 def write_dl(self, rows, col_max=30, col_spacing=2): | |
191 """Writes a definition list into the buffer. This is how options | |
192 and commands are usually formatted. | |
193 | |
194 :param rows: a list of two item tuples for the terms and values. | |
195 :param col_max: the maximum width of the first column. | |
196 :param col_spacing: the number of spaces between the first and | |
197 second column. | |
198 """ | |
199 rows = list(rows) | |
200 widths = measure_table(rows) | |
201 if len(widths) != 2: | |
202 raise TypeError("Expected two columns for definition list") | |
203 | |
204 first_col = min(widths[0], col_max) + col_spacing | |
205 | |
206 for first, second in iter_rows(rows, len(widths)): | |
207 self.write("{:>{w}}{}".format("", first, w=self.current_indent)) | |
208 if not second: | |
209 self.write("\n") | |
210 continue | |
211 if term_len(first) <= first_col - col_spacing: | |
212 self.write(" " * (first_col - term_len(first))) | |
213 else: | |
214 self.write("\n") | |
215 self.write(" " * (first_col + self.current_indent)) | |
216 | |
217 text_width = max(self.width - first_col - 2, 10) | |
218 wrapped_text = wrap_text(second, text_width, preserve_paragraphs=True) | |
219 lines = wrapped_text.splitlines() | |
220 | |
221 if lines: | |
222 self.write("{}\n".format(lines[0])) | |
223 | |
224 for line in lines[1:]: | |
225 self.write( | |
226 "{:>{w}}{}\n".format( | |
227 "", line, w=first_col + self.current_indent | |
228 ) | |
229 ) | |
230 | |
231 if len(lines) > 1: | |
232 # separate long help from next option | |
233 self.write("\n") | |
234 else: | |
235 self.write("\n") | |
236 | |
237 @contextmanager | |
238 def section(self, name): | |
239 """Helpful context manager that writes a paragraph, a heading, | |
240 and the indents. | |
241 | |
242 :param name: the section name that is written as heading. | |
243 """ | |
244 self.write_paragraph() | |
245 self.write_heading(name) | |
246 self.indent() | |
247 try: | |
248 yield | |
249 finally: | |
250 self.dedent() | |
251 | |
252 @contextmanager | |
253 def indentation(self): | |
254 """A context manager that increases the indentation.""" | |
255 self.indent() | |
256 try: | |
257 yield | |
258 finally: | |
259 self.dedent() | |
260 | |
261 def getvalue(self): | |
262 """Returns the buffer contents.""" | |
263 return "".join(self.buffer) | |
264 | |
265 | |
266 def join_options(options): | |
267 """Given a list of option strings this joins them in the most appropriate | |
268 way and returns them in the form ``(formatted_string, | |
269 any_prefix_is_slash)`` where the second item in the tuple is a flag that | |
270 indicates if any of the option prefixes was a slash. | |
271 """ | |
272 rv = [] | |
273 any_prefix_is_slash = False | |
274 for opt in options: | |
275 prefix = split_opt(opt)[0] | |
276 if prefix == "/": | |
277 any_prefix_is_slash = True | |
278 rv.append((len(prefix), opt)) | |
279 | |
280 rv.sort(key=lambda x: x[0]) | |
281 | |
282 rv = ", ".join(x[1] for x in rv) | |
283 return rv, any_prefix_is_slash |