|
1 | 1 | import re |
2 | 2 | import os |
3 | 3 | import sys |
| 4 | +import itertools |
4 | 5 | from shutil import get_terminal_size |
5 | 6 | from dataclasses import dataclass |
6 | 7 | from textwrap import wrap |
@@ -69,40 +70,54 @@ class PrettyReport: |
69 | 70 | """, re.VERBOSE) |
70 | 71 |
|
71 | 72 | def __init__(self, fd=None): |
72 | | - width = config.get_settings("aura.text-output-width", "auto") |
73 | 73 | self.term_width = get_terminal_size(fallback=(120, 24))[0] |
74 | 74 |
|
75 | | - if width == "auto": |
76 | | - self.width = self.term_width |
| 75 | + if "AURA_TERM_WIDTH" in os.environ: |
| 76 | + self.width = int(os.environ["AURA_TERM_WIDTH"]) |
77 | 77 | else: |
78 | | - self.width = int(width or 120) |
| 78 | + width = config.get_settings("aura.text-output-width", "auto") |
| 79 | + if width == "auto": |
| 80 | + self.width = self.term_width |
| 81 | + else: |
| 82 | + self.width = int(width or 120) |
79 | 83 |
|
80 | 84 | self.fd = fd |
81 | 85 |
|
82 | 86 | @classmethod |
83 | 87 | def ansi_length(cls, line:str): |
84 | 88 | return len(cls.ANSI_RE.sub("", line)) |
85 | 89 |
|
86 | | - def print_separator(self, sep="\u2504", left="\u251C", right="\u2524"): |
87 | | - secho(f"{left}{sep*(self.width-2)}{right}", file=self.fd, color=TTY_COLORS) |
| 90 | + def print_separator(self, sep="\u2504", left="\u251C", right="\u2524", width=None): |
| 91 | + if width is None: |
| 92 | + width = self.width |
| 93 | + |
| 94 | + secho(f"{left}{sep*(width-2)}{right}", file=self.fd, color=TTY_COLORS) |
88 | 95 |
|
89 | 96 | def print_thick_separator(self): |
90 | 97 | self.print_separator(left="\u255E", sep="\u2550", right="\u2561") |
91 | 98 |
|
92 | | - def print_top_separator(self): |
93 | | - self.print_separator(left="\u2552", sep="\u2550", right="\u2555") |
| 99 | + def print_top_separator(self, **kwargs): |
| 100 | + self.print_separator(left="\u2552", sep="\u2550", right="\u2555", **kwargs) |
94 | 101 |
|
95 | | - def print_bottom_separator(self): |
96 | | - self.print_separator(left="\u2558", sep="\u2550", right="\u255B") |
| 102 | + def print_bottom_separator(self, **kwargs): |
| 103 | + self.print_separator(left="\u2558", sep="\u2550", right="\u255B", **kwargs) |
| 104 | + |
| 105 | + def generate_heading(self, text, left="\u251C", right="\u2524", infill="\u2591", width=None): |
| 106 | + if width is None: |
| 107 | + width = self.width - len(left) - len(right) - 2 |
97 | 108 |
|
98 | | - def print_heading(self, text, left="\u251C", right="\u2524", infill="\u2591"): |
99 | 109 | text_len = self.ansi_length(text) |
100 | | - ljust = (self.width-4-text_len)//2 |
101 | | - rjust = self.width-4-text_len-ljust |
102 | | - secho(f"{left}{infill*ljust} {text} {infill*rjust}{right}", file=self.fd, color=TTY_COLORS) |
| 110 | + ljust = (width - text_len) // 2 |
| 111 | + rjust = width - text_len - ljust |
| 112 | + return f"{left}{infill*ljust} {text} {infill*rjust}{right}" |
| 113 | + |
| 114 | + def print_heading(self, *args, **kwargs): |
| 115 | + secho(self.generate_heading(*args, **kwargs), file=self.fd, color=TTY_COLORS) |
103 | 116 |
|
104 | | - def align(self, line, pos=-1, left="\u2502 ", right=" \u2502"): |
105 | | - line = self._align_text(line, self.width - len(left) - len(right), pos=pos) |
| 117 | + def align(self, line, pos=-1, left="\u2502 ", right=" \u2502", width=None): |
| 118 | + if width is None: |
| 119 | + width = self.width |
| 120 | + line = self._align_text(line, width - len(left) - len(right), pos=pos) |
106 | 121 | secho(f"{left}{line}{right}", file=self.fd, color=TTY_COLORS) |
107 | 122 |
|
108 | 123 | def wrap(self, text, left="\u2502 ", right=" \u2502"): |
@@ -136,6 +151,34 @@ def _align_text(self, text, width, pos=-1): |
136 | 151 | else: |
137 | 152 | return " " * (remaining_len - content_len) + text |
138 | 153 |
|
| 154 | + def print_tables(self, *tables): |
| 155 | + table_widths = [t.width+2 for t in tables] |
| 156 | + |
| 157 | + self.print_top_separator() |
| 158 | + |
| 159 | + titles = [t.metadata.get("title", "N/A") for t in tables] |
| 160 | + tparts = [tuple(self.generate_heading(title, width=w, left="", right="") for w, title in zip(table_widths, titles))] |
| 161 | + |
| 162 | + for idx, rows in enumerate(itertools.zip_longest(*tables, fillvalue="")): |
| 163 | + |
| 164 | + full_row = [] |
| 165 | + |
| 166 | + for ridx, row in enumerate(rows): |
| 167 | + text = " \u2506 ".join(self._align_text(c.pretty, width=tables[ridx].col_len[cidx]) for cidx, c in enumerate(row)) |
| 168 | + text = self._align_text(text, width=table_widths[ridx]+2) |
| 169 | + |
| 170 | + full_row.append(text) |
| 171 | + |
| 172 | + tparts.append(full_row) |
| 173 | + |
| 174 | + for idx, tpart in enumerate(tparts): |
| 175 | + self.align(" \u2551 ".join(tpart)) |
| 176 | + if idx == 0: |
| 177 | + self.print_thick_separator() |
| 178 | + |
| 179 | + self.print_bottom_separator() |
| 180 | + |
| 181 | + |
139 | 182 |
|
140 | 183 | @dataclass() |
141 | 184 | class TextBase: |
@@ -224,7 +267,7 @@ def imports_to_tree(self, items: list) -> dict: |
224 | 267 |
|
225 | 268 | return root |
226 | 269 |
|
227 | | - def output_table(self, table): |
| 270 | + def output_table(self, table: Table): |
228 | 271 | out = PrettyReport(fd=self._fd) |
229 | 272 | out.print_top_separator() |
230 | 273 |
|
@@ -405,8 +448,8 @@ def __exit__(self, exc_type, exc_val, exc_tb): |
405 | 448 | def output_diff(self, diff_analyzer): |
406 | 449 | out = PrettyReport(fd=self._fd) |
407 | 450 |
|
408 | | - for table in diff_analyzer.tables: |
409 | | - self.output_table(table) |
| 451 | + if diff_analyzer.tables: |
| 452 | + out.print_tables(*diff_analyzer.tables) |
410 | 453 |
|
411 | 454 | for diff in self.filtered(diff_analyzer.diffs): |
412 | 455 | out.print_separator(left="\u2552", sep="\u2550", right="\u2555") |
|
0 commit comments