Skip to content

Commit fcf3410

Browse files
committed
Added ability to colorize all aspects of SimpleTables
1 parent 84e7a49 commit fcf3410

File tree

4 files changed

+266
-64
lines changed

4 files changed

+266
-64
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
and/or data text. This allows for things like nesting an AlternatingTable in another AlternatingTable.
1010
* AlternatingTable no longer applies background color to outer borders. This was done to improve appearance
1111
since the background color extended beyond the borders of the table.
12-
* Added ability to colorize all aspects of `BorderedTables` and `AlternatingTables`.
12+
* Added ability to colorize all aspects of `AlternatingTables`, `BorderedTables`, and `SimpleTables`.
1313
* Added support for 8-bit/256-colors with the `cmd2.EightBitFg` and `cmd2.EightBitBg` classes.
1414
* Added support for 24-bit/RGB colors with the `cmd2.RgbFg` and `cmd2.RgbBg` classes.
1515
* Removed dependency on colorama.

cmd2/table_creator.py

Lines changed: 74 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -80,15 +80,15 @@ def __init__(
8080
:param header_horiz_align: horizontal alignment of header cells (defaults to left)
8181
:param header_vert_align: vertical alignment of header cells (defaults to bottom)
8282
:param override_header_style: if True, then the table is allowed to apply text styles to the header, which may
83-
interfere with any styles the header already has. If False, the header is printed as is.
84-
Table classes which apply style to headers must respect this flag. See the BorderedTable
85-
class for an example of this. (defaults to True)
83+
conflict with any styles the header already has. If False, the header is printed as is.
84+
Table classes which apply style to headers must account for the value of this flag.
85+
(defaults to True)
8686
:param data_horiz_align: horizontal alignment of data cells (defaults to left)
8787
:param data_vert_align: vertical alignment of data cells (defaults to top)
8888
:param override_data_style: if True, then the table is allowed to apply text styles to the data, which may
89-
interfere with any styles the data already has. If False, the data is printed as is.
90-
Table classes which apply style to data must respect this flag. See the BorderedTable
91-
class for an example of this. (defaults to True)
89+
conflict with any styles the data already has. If False, the data is printed as is.
90+
Table classes which apply style to data must account for the value of this flag.
91+
(defaults to True)
9292
:param max_data_lines: maximum lines allowed in a data cell. If line count exceeds this, then the final
9393
line displayed will be truncated with an ellipsis. (defaults to INFINITY)
9494
:raises: ValueError if width is less than 1
@@ -549,7 +549,14 @@ class SimpleTable(TableCreator):
549549
"""
550550

551551
def __init__(
552-
self, cols: Sequence[Column], *, column_spacing: int = 2, tab_width: int = 4, divider_char: Optional[str] = '-'
552+
self,
553+
cols: Sequence[Column],
554+
*,
555+
column_spacing: int = 2,
556+
tab_width: int = 4,
557+
divider_char: Optional[str] = '-',
558+
header_bg: Optional[ansi.BgColor] = None,
559+
data_bg: Optional[ansi.BgColor] = None,
553560
) -> None:
554561
"""
555562
SimpleTable initializer
@@ -560,14 +567,19 @@ def __init__(
560567
then it will be converted to one space.
561568
:param divider_char: optional character used to build the header divider row. Set this to blank or None if you don't
562569
want a divider row. Defaults to dash. (Cannot be a line breaking character)
563-
:raises: ValueError if column_spacing is less than 0
570+
:param header_bg: optional background color for header cells (defaults to None)
571+
:param data_bg: optional background color for data cells (defaults to None)
564572
:raises: ValueError if tab_width is less than 1
573+
:raises: ValueError if column_spacing is less than 0
565574
:raises: TypeError if divider_char is longer than one character
566575
:raises: ValueError if divider_char is an unprintable character
567576
"""
577+
super().__init__(cols, tab_width=tab_width)
578+
568579
if column_spacing < 0:
569580
raise ValueError("Column spacing cannot be less than 0")
570-
self.inter_cell = column_spacing * SPACE
581+
582+
self.column_spacing = column_spacing
571583

572584
if divider_char == '':
573585
divider_char = None
@@ -580,8 +592,29 @@ def __init__(
580592
if divider_char_width == -1:
581593
raise ValueError("Divider character is an unprintable character")
582594

583-
super().__init__(cols, tab_width=tab_width)
584595
self.divider_char = divider_char
596+
self.header_bg = header_bg
597+
self.data_bg = data_bg
598+
599+
def apply_header_bg(self, value: Any) -> str:
600+
"""
601+
If defined, apply the header background color to header text
602+
:param value: object whose text is to be colored
603+
:return: formatted text
604+
"""
605+
if self.header_bg is None:
606+
return str(value)
607+
return ansi.style(value, bg=self.header_bg)
608+
609+
def apply_data_bg(self, value: Any) -> str:
610+
"""
611+
If defined, apply the data background color to data text
612+
:param value: object whose text is to be colored
613+
:return: formatted data string
614+
"""
615+
if self.data_bg is None:
616+
return str(value)
617+
return ansi.style(value, bg=self.data_bg)
585618

586619
@classmethod
587620
def base_width(cls, num_cols: int, *, column_spacing: int = 2) -> int:
@@ -608,17 +641,28 @@ def base_width(cls, num_cols: int, *, column_spacing: int = 2) -> int:
608641

609642
def total_width(self) -> int:
610643
"""Calculate the total display width of this table"""
611-
base_width = self.base_width(len(self.cols), column_spacing=ansi.style_aware_wcswidth(self.inter_cell))
644+
base_width = self.base_width(len(self.cols), column_spacing=self.column_spacing)
612645
data_width = sum(col.width for col in self.cols)
613646
return base_width + data_width
614647

615648
def generate_header(self) -> str:
616649
"""Generate table header with an optional divider row"""
617650
header_buf = io.StringIO()
618651

652+
fill_char = self.apply_header_bg(SPACE)
653+
inter_cell = self.apply_header_bg(self.column_spacing * SPACE)
654+
655+
# Apply background color to header text in Columns which allow it
656+
to_display: List[Any] = []
657+
for index, col in enumerate(self.cols):
658+
if col.override_header_style:
659+
to_display.append(self.apply_header_bg(col.header))
660+
else:
661+
to_display.append(col.header)
662+
619663
# Create the header labels
620-
header = self.generate_row(inter_cell=self.inter_cell)
621-
header_buf.write(header)
664+
header_labels = self.generate_row(row_data=to_display, fill_char=fill_char, inter_cell=inter_cell)
665+
header_buf.write(header_labels)
622666

623667
# Add the divider if necessary
624668
divider = self.generate_divider()
@@ -641,7 +685,18 @@ def generate_data_row(self, row_data: Sequence[Any]) -> str:
641685
:param row_data: data with an entry for each column in the row
642686
:return: data row string
643687
"""
644-
return self.generate_row(row_data=row_data, inter_cell=self.inter_cell)
688+
fill_char = self.apply_data_bg(SPACE)
689+
inter_cell = self.apply_data_bg(self.column_spacing * SPACE)
690+
691+
# Apply background color to data text in Columns which allow it
692+
to_display: List[Any] = []
693+
for index, col in enumerate(self.cols):
694+
if col.override_data_style:
695+
to_display.append(self.apply_data_bg(row_data[index]))
696+
else:
697+
to_display.append(row_data[index])
698+
699+
return self.generate_row(row_data=to_display, fill_char=fill_char, inter_cell=inter_cell)
645700

646701
def generate_table(self, table_data: Sequence[Sequence[Any]], *, include_header: bool = True, row_spacing: int = 1) -> str:
647702
"""
@@ -665,9 +720,11 @@ def generate_table(self, table_data: Sequence[Sequence[Any]], *, include_header:
665720
if len(table_data) > 0:
666721
table_buf.write('\n')
667722

723+
row_divider = utils.align_left('', fill_char=self.apply_data_bg(SPACE), width=self.total_width()) + '\n'
724+
668725
for index, row_data in enumerate(table_data):
669726
if index > 0 and row_spacing > 0:
670-
table_buf.write(row_spacing * '\n')
727+
table_buf.write(row_spacing * row_divider)
671728

672729
row = self.generate_data_row(row_data)
673730
table_buf.write(row)
@@ -707,6 +764,7 @@ def __init__(
707764
:param border_fg: optional foreground color for borders (defaults to None)
708765
:param header_bg: optional background color for header cells (defaults to None)
709766
:param data_bg: optional background color for data cells (defaults to None)
767+
:raises: ValueError if tab_width is less than 1
710768
:raises: ValueError if padding is less than 0
711769
"""
712770
super().__init__(cols, tab_width=tab_width)
@@ -1003,6 +1061,7 @@ def __init__(
10031061
:param header_bg: optional background color for header cells (defaults to None)
10041062
:param odd_bg: optional background color for odd numbered data rows (defaults to None)
10051063
:param even_bg: optional background color for even numbered data rows (defaults to StdBg.DARK_GRAY)
1064+
:raises: ValueError if tab_width is less than 1
10061065
:raises: ValueError if padding is less than 0
10071066
"""
10081067
super().__init__(

0 commit comments

Comments
 (0)