Skip to content

Commit fb30e85

Browse files
committed
✨ [Markdown] Add opt to print table in compact mode
1 parent f9a668e commit fb30e85

File tree

6 files changed

+257
-51
lines changed

6 files changed

+257
-51
lines changed

docs/src/man/markdown/markdown_backend.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ that contains the following fields:
7777
- `subtitle_heading_level::Int`: Subtitle heading level.
7878
- `horizontal_line_char::Char`: Character used to draw the horizontal line.
7979
- `line_before_summary_rows::Bool`: Whether to draw a line before the summary rows.
80+
- `compact_table::Bool`: If `true`, the table is printed in a compact format without extra
81+
spaces between columns.
8082

8183
## Markdown Table Style
8284

src/backends/markdown/documentation.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ that contains the following fields:
8686
- `subtitle_heading_level::Int`: Subtitle heading level.
8787
- `horizontal_line_char::Char`: Character used to draw the horizontal line.
8888
- `line_before_summary_rows::Bool`: Whether to draw a line before the summary rows.
89+
- `compact_table::Bool`: If `true`, the table is printed in a compact format without extra
90+
spaces between columns.
8991
9092
## Markdown Table Style
9193

src/backends/markdown/markdown_backend.jl

Lines changed: 64 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -160,73 +160,75 @@ function _markdown__print(
160160

161161
# == Compute the Column Width ==========================================================
162162

163-
row_number_column_width = 0
164-
row_label_column_width = 0
165-
printed_data_column_widths = zeros(Int, num_printed_data_columns)
163+
row_number_column_width = 1
164+
row_label_column_width = 1
165+
printed_data_column_widths = ones(Int, num_printed_data_columns)
166166

167-
if table_data.show_row_number_column
168-
m = if (_is_vertically_cropped(table_data) && (table_data.vertical_crop_mode == :bottom))
169-
table_data.maximum_number_of_rows
170-
else
171-
table_data.num_rows
167+
# We we are printing in compact mode, we do not need to compute the column widths.
168+
if !tf.compact_table
169+
if table_data.show_row_number_column
170+
m = if (_is_vertically_cropped(table_data) && (table_data.vertical_crop_mode == :bottom))
171+
table_data.maximum_number_of_rows
172+
else
173+
table_data.num_rows
174+
end
175+
176+
row_number_column_width = max(
177+
textwidth(decorated_row_number_column_label),
178+
floor(Int, log10(m) + 1)
179+
)
172180
end
173181

174-
row_number_column_width = max(
175-
textwidth(decorated_row_number_column_label),
176-
floor(Int, log10(m) + 1)
177-
)
178-
end
182+
if _has_row_labels(table_data)
183+
row_label_column_width = max(
184+
textwidth(decorated_stubhead_label),
179185

180-
if _has_row_labels(table_data)
181-
row_label_column_width = max(
182-
textwidth(decorated_stubhead_label),
186+
num_printed_data_rows > 0 ? maximum(textwidth, row_labels) : 0,
183187

184-
num_printed_data_rows > 0 ? maximum(textwidth, row_labels) : 0,
188+
if _has_summary_rows(table_data)
189+
maximum(textwidth, table_data.summary_row_labels) +
190+
_markdown__style_textwidth(style.summary_row_label)
191+
else
192+
0
193+
end
194+
)
195+
end
185196

186-
if _has_summary_rows(table_data)
187-
maximum(textwidth, table_data.summary_row_labels) +
188-
_markdown__style_textwidth(style.summary_row_label)
197+
@views for j in last(axes(table_str))
198+
m = if !isnothing(column_labels)
199+
maximum(textwidth, column_labels[:, j])
189200
else
190201
0
191202
end
192-
)
193-
end
194203

195-
@views for j in last(axes(table_str))
196-
m = if !isnothing(column_labels)
197-
maximum(textwidth, column_labels[:, j])
198-
else
199-
0
200-
end
204+
if num_printed_data_rows > 0
205+
m = max(maximum(textwidth, table_str[:, j]), m)
201206

202-
if num_printed_data_rows > 0
203-
m = max(maximum(textwidth, table_str[:, j]), m)
204-
205-
if _has_summary_rows(table_data)
206-
m = max(maximum(textwidth, summary_rows[:, j]), m)
207+
if _has_summary_rows(table_data)
208+
m = max(maximum(textwidth, summary_rows[:, j]), m)
209+
end
207210
end
208-
end
209211

210-
printed_data_column_widths[j] = m
211-
end
212+
printed_data_column_widths[j] = m
213+
end
212214

213-
# Markdown does not support merging rows. Hence, if we have a row group label, we must
214-
# add the information in the first column. Thus, we need to possibly increase this cell
215-
# accordingly.
216-
if _has_row_group_labels(table_data)
217-
m = maximum(x -> textwidth(last(x)), table_data.row_group_labels) +
218-
_markdown__style_textwidth(style.row_group_label)
215+
# Markdown does not support merging rows. Hence, if we have a row group label, we must
216+
# add the information in the first column. Thus, we need to possibly increase this cell
217+
# accordingly.
218+
if _has_row_group_labels(table_data)
219+
m = maximum(x -> textwidth(last(x)), table_data.row_group_labels) +
220+
_markdown__style_textwidth(style.row_group_label)
219221

220-
if table_data.show_row_number_column
221-
row_number_column_width = max(row_number_column_width, m)
222+
if table_data.show_row_number_column
223+
row_number_column_width = max(row_number_column_width, m)
222224

223-
elseif _has_row_labels(table_data)
224-
row_label_column_width = max(row_label_column_width, m)
225+
elseif _has_row_labels(table_data)
226+
row_label_column_width = max(row_label_column_width, m)
225227

226-
else
227-
printed_data_column_widths[1] = max(printed_data_column_widths[1], m)
228+
else
229+
printed_data_column_widths[1] = max(printed_data_column_widths[1], m)
230+
end
228231
end
229-
230232
end
231233

232234
# == Print the Table ===================================================================
@@ -327,7 +329,13 @@ function _markdown__print(
327329
end
328330

329331
print(buf, " ")
330-
_markdown__print_aligned(buf, "", cell_width, alignment)
332+
333+
if !tf.compact_table
334+
_markdown__print_aligned(buf, "", cell_width, alignment)
335+
else
336+
print(buf, "")
337+
end
338+
331339
print(buf, " |")
332340

333341
elseif action == :end_row
@@ -450,7 +458,12 @@ function _markdown__print(
450458

451459
end
452460

453-
_markdown__print_aligned(buf, rendered_cell, cell_width, alignment)
461+
if !tf.compact_table
462+
_markdown__print_aligned(buf, rendered_cell, cell_width, alignment)
463+
else
464+
print(buf, rendered_cell)
465+
end
466+
454467
print(buf, " |")
455468
end
456469
end

src/backends/markdown/types.jl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,12 +102,15 @@ Define the format of the tables printed with the markdown back end.
102102
- `subtitle_heading_level::Int`: Subtitle heading level.
103103
- `horizontal_line_char::Char`: Character used to draw the horizontal line.
104104
- `line_before_summary_rows::Bool`: Whether to draw a line before the summary rows.
105+
- `compact_table::Bool`: If `true`, the table is printed in a compact format without extra
106+
spaces between columns.
105107
"""
106108
@kwdef struct MarkdownTableFormat
107109
title_heading_level::Int = 1
108110
subtitle_heading_level::Int = 2
109111
horizontal_line_char::Char = ''
110112
line_before_summary_rows::Bool = true
113+
compact_table::Bool = false
111114
end
112115

113116
"""

test/backends/markdown/compact.jl

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
## Description #############################################################################
2+
#
3+
# Markdown Back End: Test the compact option.
4+
#
5+
############################################################################################
6+
7+
@testset "Compact Table" verbose = true begin
8+
matrix = [(i, j) for i in 1:3, j in 1:3]
9+
10+
@testset "Without Cropping" begin
11+
expected = """
12+
# Table Title
13+
14+
## Table Subtitle
15+
16+
| **Row** | **Rows** | **Col. 1**<br>`1` | **Merged Column[^1]**<br>`2` | ─ |
17+
|--:|--:|--:|--:|--:|
18+
| 1 | **Row 1** | (1, 1) | (1, 2) | (1, 3) |
19+
| **Row Group** | ─ | ─ | ─ | ─ |
20+
| 2 | **Row 2** | (2, 1) | (2, 2)[^2] | (2, 3) |
21+
| 3 | **Row 3** | (3, 1) | (3, 2) | (3, 3) |
22+
| ─ | ─ | ─ | ─ | ─ |
23+
| | **Summary 1** | 10 | 20 | 30 |
24+
| | **Summary 2** | 20 | 40 | 60 |
25+
26+
[^1]: Footnote in column label
27+
[^2]: Footnote in data
28+
29+
Source Notes
30+
"""
31+
32+
result = pretty_table(
33+
String,
34+
matrix;
35+
backend = :markdown,
36+
column_labels = [["Col. $i" for i in 1:3], ["$i" for i in 1:3]],
37+
footnotes = [(:column_label, 1, 2) => "Footnote in column label", (:data, 2, 2) => "Footnote in data"],
38+
merge_column_label_cells = [MergeCells(1, 2, 2, "Merged Column", :c)],
39+
row_group_labels = [2 => "Row Group"],
40+
row_labels = ["Row $i" for i in 1:5],
41+
show_row_number_column = true,
42+
source_notes = "Source Notes",
43+
stubhead_label = "Rows",
44+
subtitle = "Table Subtitle",
45+
summary_rows = [(data, i) -> 10i, (data, i) -> 20i],
46+
table_format = MarkdownTableFormat(compact_table = true),
47+
title = "Table Title",
48+
)
49+
50+
@test result == expected
51+
52+
expected = """
53+
# Table Title
54+
55+
## Table Subtitle
56+
57+
| **Rows** | **Col. 1**<br>`1` | **Merged Column[^1]**<br>`2` | ─ |
58+
|--:|--:|--:|--:|
59+
| **Row 1** | (1, 1) | (1, 2) | (1, 3) |
60+
| **Row Group** | ─ | ─ | ─ |
61+
| **Row 2** | (2, 1) | (2, 2)[^2] | (2, 3) |
62+
| **Row 3** | (3, 1) | (3, 2) | (3, 3) |
63+
| ─ | ─ | ─ | ─ |
64+
| **Summary 1** | 10 | 20 | 30 |
65+
| **Summary 2** | 20 | 40 | 60 |
66+
67+
[^1]: Footnote in column label
68+
[^2]: Footnote in data
69+
70+
Source Notes
71+
"""
72+
73+
result = pretty_table(
74+
String,
75+
matrix;
76+
backend = :markdown,
77+
column_labels = [["Col. $i" for i in 1:3], ["$i" for i in 1:3]],
78+
footnotes = [(:column_label, 1, 2) => "Footnote in column label", (:data, 2, 2) => "Footnote in data"],
79+
merge_column_label_cells = [MergeCells(1, 2, 2, "Merged Column", :c)],
80+
row_group_labels = [2 => "Row Group"],
81+
row_labels = ["Row $i" for i in 1:5],
82+
show_row_number_column = false,
83+
source_notes = "Source Notes",
84+
stubhead_label = "Rows",
85+
subtitle = "Table Subtitle",
86+
summary_rows = [(data, i) -> 10i, (data, i) -> 20i],
87+
table_format = MarkdownTableFormat(compact_table = true),
88+
title = "Table Title",
89+
)
90+
91+
@test result == expected
92+
end
93+
94+
@testset "With Bottom Cropping" begin
95+
expected = """
96+
# Table Title
97+
98+
## Table Subtitle
99+
100+
| **Row** | **Rows** | **Col. 1** | **Merged Column[^1]** | ⋯ |
101+
|--:|--:|--:|--:|---|
102+
| 1 | **Row 1** | (1, 1) | (1, 2) | ⋯ |
103+
| **Row Group** | ─ | ─ | ─ | ⋯ |
104+
| 2 | **Row 2** | (2, 1) | (2, 2)[^2] | ⋯ |
105+
| ⋮ | ⋮ | ⋮ | ⋮ | ⋱ |
106+
| ─ | ─ | ─ | ─ | ─ |
107+
| | **Summary 1** | 10 | 20 | ⋯ |
108+
| | **Summary 2** | 20 | 40 | ⋯ |
109+
110+
*1 column and 1 row omitted*
111+
112+
[^1]: Footnote in column label
113+
[^2]: Footnote in data
114+
115+
Source Notes
116+
"""
117+
118+
result = pretty_table(
119+
String,
120+
matrix;
121+
backend = :markdown,
122+
footnotes = [(:column_label, 1, 2) => "Footnote in column label", (:data, 2, 2) => "Footnote in data"],
123+
maximum_number_of_columns = 2,
124+
maximum_number_of_rows = 2,
125+
merge_column_label_cells = [MergeCells(1, 2, 2, "Merged Column", :c)],
126+
row_group_labels = [2 => "Row Group"],
127+
row_labels = ["Row $i" for i in 1:5],
128+
show_row_number_column = true,
129+
source_notes = "Source Notes",
130+
stubhead_label = "Rows",
131+
subtitle = "Table Subtitle",
132+
summary_rows = [(data, i) -> 10i, (data, i) -> 20i],
133+
table_format = MarkdownTableFormat(compact_table = true),
134+
title = "Table Title",
135+
)
136+
137+
@test result == expected
138+
end
139+
140+
@testset "With Middle Cropping" begin
141+
expected = """
142+
# Table Title
143+
144+
## Table Subtitle
145+
146+
| **Row** | **Rows** | **Col. 1** | **Merged Column[^1]** | ⋯ |
147+
|--:|--:|--:|--:|---|
148+
| 1 | **Row 1** | (1, 1) | (1, 2) | ⋯ |
149+
| ⋮ | ⋮ | ⋮ | ⋮ | ⋱ |
150+
| 3 | **Row 3** | (3, 1) | (3, 2) | ⋯ |
151+
| ─ | ─ | ─ | ─ | ─ |
152+
| | **Summary 1** | 10 | 20 | ⋯ |
153+
| | **Summary 2** | 20 | 40 | ⋯ |
154+
155+
*1 column and 1 row omitted*
156+
157+
[^1]: Footnote in column label
158+
[^2]: Footnote in data
159+
160+
Source Notes
161+
"""
162+
163+
result = pretty_table(
164+
String,
165+
matrix;
166+
backend = :markdown,
167+
footnotes = [(:column_label, 1, 2) => "Footnote in column label", (:data, 2, 2) => "Footnote in data"],
168+
maximum_number_of_columns = 2,
169+
maximum_number_of_rows = 2,
170+
merge_column_label_cells = [MergeCells(1, 2, 2, "Merged Column", :c)],
171+
row_group_labels = [2 => "Row Group"],
172+
row_labels = ["Row $i" for i in 1:5],
173+
show_row_number_column = true,
174+
source_notes = "Source Notes",
175+
stubhead_label = "Rows",
176+
subtitle = "Table Subtitle",
177+
summary_rows = [(data, i) -> 10i, (data, i) -> 20i],
178+
table_format = MarkdownTableFormat(compact_table = true),
179+
title = "Table Title",
180+
vertical_crop_mode = :middle
181+
)
182+
183+
@test result == expected
184+
end
185+
end

test/runtests.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ end
5454
@testset "Markdown Back End Tests" verbose = true begin
5555
include("./backends/markdown/alignment.jl")
5656
include("./backends/markdown/circular_reference.jl")
57+
include("./backends/markdown/compact.jl")
5758
include("./backends/markdown/cropping.jl")
5859
include("./backends/markdown/default.jl")
5960
include("./backends/markdown/full.jl")

0 commit comments

Comments
 (0)