feat: make tables fit within terminal by default (#2426)

This PR adds a `max_width` parameter to MyPrettyTable to restrict the maximum width of its underlying table.

The value can be an integer, "max" (detect automatically the correct width) or None (no width limit)

* Add a new parameter `max_width` to MyPrettyTable to enhance its display for CLI usage

* Fix the description of the Loc printer, and adjust the maximal width.

* bump prettytable

* default all prettytable's to fit within max terminal width

---------

Co-authored-by: alpharush <0xalpharush@protonmail.com>
pull/2289/merge
dm 4 months ago committed by GitHub
parent 7c7b71ff60
commit 48815192f2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      setup.py
  2. 4
      slither/printers/summary/loc.py
  3. 4
      slither/utils/command_line.py
  4. 26
      slither/utils/myprettytable.py

@ -13,7 +13,7 @@ setup(
python_requires=">=3.8", python_requires=">=3.8",
install_requires=[ install_requires=[
"packaging", "packaging",
"prettytable>=3.3.0", "prettytable>=3.10.2",
"pycryptodome>=3.4.6", "pycryptodome>=3.4.6",
"crytic-compile>=0.3.7,<0.4.0", "crytic-compile>=0.3.7,<0.4.0",
# "crytic-compile@git+https://github.com/crytic/crytic-compile.git@master#egg=crytic-compile", # "crytic-compile@git+https://github.com/crytic/crytic-compile.git@master#egg=crytic-compile",

@ -17,8 +17,8 @@ from slither.utils.output import Output
class LocPrinter(AbstractPrinter): class LocPrinter(AbstractPrinter):
ARGUMENT = "loc" ARGUMENT = "loc"
HELP = """Count the total number lines of code (LOC), source lines of code (SLOC), \ HELP = """Count the total number lines of code (LOC), source lines of code (SLOC),
and comment lines of code (CLOC) found in source files (SRC), dependencies (DEP), \ and comment lines of code (CLOC) found in source files (SRC), dependencies (DEP),
and test files (TEST).""" and test files (TEST)."""
WIKI = "https://github.com/trailofbits/slither/wiki/Printer-documentation#loc" WIKI = "https://github.com/trailofbits/slither/wiki/Printer-documentation#loc"

@ -360,8 +360,10 @@ def output_printers(printer_classes: List[Type[AbstractPrinter]]) -> None:
printers_list = sorted(printers_list, key=lambda element: (element[0])) printers_list = sorted(printers_list, key=lambda element: (element[0]))
idx = 1 idx = 1
for (argument, help_info) in printers_list: for (argument, help_info) in printers_list:
table.add_row([str(idx), argument, help_info]) # Clean multi line HELP info
table.add_row([str(idx), argument, " ".join(x.strip() for x in help_info.splitlines())])
idx = idx + 1 idx = idx + 1
print(table) print(table)

@ -1,3 +1,4 @@
from shutil import get_terminal_size
from typing import List, Dict, Union from typing import List, Dict, Union
from prettytable import PrettyTable from prettytable import PrettyTable
@ -7,7 +8,12 @@ from slither.utils.colors import Colors
class MyPrettyTable: class MyPrettyTable:
def __init__(self, field_names: List[str], pretty_align: bool = True): # TODO: True by default? def __init__(
self,
field_names: List[str],
pretty_align: bool = True,
max_width: Union[int, None] = "max", # Default value is "max"
):
self._field_names = field_names self._field_names = field_names
self._rows: List = [] self._rows: List = []
self._options: Dict = {} self._options: Dict = {}
@ -19,6 +25,17 @@ class MyPrettyTable:
else: else:
self._options["set_alignment"] = [] self._options["set_alignment"] = []
self.max_width = None
if max_width == "max":
# We use (0,0) as a fallback to detect if we are not attached to a terminal
# In this case, we fall back to the default behavior (i.e. printing as much as possible)
terminal_column = get_terminal_size((0, 0)).columns
if terminal_column != 0:
# We reduce slightly the max-width to take into account inconsistencies in terminals
self.max_width = terminal_column - 3
else:
self.max_width = max_width
def add_row(self, row: List[Union[str, List[str]]]) -> None: def add_row(self, row: List[Union[str, List[str]]]) -> None:
self._rows.append(row) self._rows.append(row)
@ -28,6 +45,9 @@ class MyPrettyTable:
else: else:
table = PrettyTable(self._field_names) table = PrettyTable(self._field_names)
if self.max_width is not None:
table.max_table_width = self.max_width
for row in self._rows: for row in self._rows:
table.add_row(row) table.add_row(row)
if len(self._options["set_alignment"]): if len(self._options["set_alignment"]):
@ -63,7 +83,5 @@ def make_pretty_table(
table_row = [row] + [body[row][key] for key in headers[1:]] table_row = [row] + [body[row][key] for key in headers[1:]]
table.add_row(table_row) table.add_row(table_row)
if totals: if totals:
table.add_row( table.add_row([total_header] + [sum(body[row][key] for row in body) for key in headers[1:]])
[total_header] + [sum([body[row][key] for row in body]) for key in headers[1:]]
)
return table return table

Loading…
Cancel
Save