Mercurial > repos > guerler > springsuite
comparison planemo/lib/python3.7/site-packages/click/formatting.py @ 0:d30785e31577 draft
"planemo upload commit 6eee67778febed82ddd413c3ca40b3183a3898f1"
| author | guerler |
|---|---|
| date | Fri, 31 Jul 2020 00:18:57 -0400 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:d30785e31577 |
|---|---|
| 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 |
