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