Skip to content

Commit d02307e

Browse files
committed
✨ [Text] Shrinkable data column
1 parent 53f57be commit d02307e

File tree

5 files changed

+353
-6
lines changed

5 files changed

+353
-6
lines changed

docs/src/man/text/text_backend.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ the output.
6767
- `reserved_display_lines::Int`: Number of lines to be left at the beginning of the printing
6868
when vertically cropping the output.
6969
(**Default** = 0)
70+
- `shrinkable_data_column::Int`: If it is a positive integer, this column will be
71+
shrinkable. This means that if the table does not fit in the display, this column will be
72+
shrunk to fit the table in the display. If it is `0` or negative, no column will be
73+
shrinkable.
74+
(**Default** = 0)
7075
- `style::TextTableStyle`: Style of the table. For more information, see the section
7176
[Text Table Style](@ref).
7277
- `table_format::TextTableFormat`: Text table format used to render the table. For more

src/backends/text/documentation.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,11 @@ the output.
7474
- `reserved_display_lines::Int`: Number of lines to be left at the beginning of the printing
7575
when vertically cropping the output.
7676
(**Default** = 0)
77+
- `shrinkable_data_column::Int`: If it is a positive integer, this column will be
78+
shrinkable. This means that if the table does not fit in the display, this column will
79+
be shrunk to fit the table in the display. If it is `0` or negative, no column will be
80+
shrinkable.
81+
(**Default** = 0)
7782
- `style::TextTableStyle`: Style of the table. For more information, see the section
7883
**Text Table Style** in the **Extended Help**.
7984
- `table_format::TextTableFormat`: Text table format used to render the table. For more

src/backends/text/text_backend.jl

Lines changed: 79 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ function _text__print_table(
2727
maximum_data_column_widths::Union{Int, Vector{Int}} = 0,
2828
overwrite_display::Bool = false,
2929
reserved_display_lines::Int = 0,
30+
shrinkable_data_column::Int = 0,
3031
style::TextTableStyle = TextTableStyle(),
3132
table_format::TextTableFormat = TextTableFormat(),
3233
)
@@ -365,7 +366,7 @@ function _text__print_table(
365366
end
366367

367368
# If the user wants a fixed column width, we must reprocess all the data columns to crop
368-
# to the correct size if necesary.
369+
# to the correct size if necessary.
369370
has_fixed_data_column_widths && _text__fix_data_column_widths!(
370371
printed_data_column_widths,
371372
column_labels,
@@ -406,19 +407,23 @@ function _text__print_table(
406407
horizontally_limited_by_display = false
407408

408409
if fit_table_in_display_horizontally && (display.size[2] > 0)
409-
# Here we have three possibilities:
410+
# Here we have four possibilities:
410411
#
411-
# 1. We cannot show the table continuation column, meaning that the table is
412+
# 1. We can show the entire table. If not, we will have a continuation column.
413+
# 2. We cannot show the table continuation column, meaning that the table is
412414
# horizontally limited by the display.
413-
# 2. We can partially show the continuation column, meaning that the table is
415+
# 3. We can partially show the continuation column, meaning that the table is
414416
# horizontally limited by the display but there is a continuation column.
415-
# 3. We can show the continuation column, meaning that the table is horizontally
417+
# 4. We can show the continuation column, meaning that the table is horizontally
416418
# cropped by the user specification.
417419

418420
num_remaining_columns = display_size[2] - table_width_wo_cont_col
419421

420422
horizontally_limited_by_display =
421-
if (num_remaining_columns == 0) && (num_printed_data_columns == table_data.num_columns)
423+
if (
424+
(num_remaining_columns > 0) ||
425+
((num_remaining_columns == 0) && (num_printed_data_columns == table_data.num_columns))
426+
)
422427
false
423428
else
424429
num_remaining_columns < (3 + tf.vertical_line_after_continuation_column)
@@ -428,6 +433,74 @@ function _text__print_table(
428433
# If we are limited by the display, we need to update the number of printed columns and
429434
# rows.
430435
if horizontally_limited_by_display
436+
# Check if the user select one visible row to shrink to fit the table in the
437+
# display.
438+
if (1 <= shrinkable_data_column <= num_printed_data_columns)
439+
# Number of characters we should remove from the shrinkable data column to fit
440+
# the table in the display.
441+
Δc = table_width_wo_cont_col - display_size[2]
442+
443+
# Compute the new column width.
444+
cw = max(1, printed_data_column_widths[shrinkable_data_column] - Δc)
445+
446+
printed_data_column_widths[shrinkable_data_column] = cw
447+
448+
# Shrink the column labels.
449+
for i in 1:size(column_labels, 1)
450+
# Compute the column limits of this column label.
451+
j₀, j₁ = _column_label_limits(table_data, i, shrinkable_data_column)
452+
453+
# Compute the available width.
454+
cell_width = 0
455+
456+
# Make sure we are not accessing a column out of the bounds.
457+
j₁ = min(j₁, num_printed_data_columns)
458+
459+
for j in j₀:j₁
460+
cell_width += printed_data_column_widths[j] + 2
461+
462+
# We must add a space if we have a vertical line in the merged cells.
463+
if (j != j₁) && (j vertical_lines_at_data_columns)
464+
cell_width += 1
465+
end
466+
end
467+
468+
# We already take into account 2 characters for the margin below.
469+
cell_width -= 2
470+
471+
# We need to modify the first field of this column label to take into
472+
# account merged labels.
473+
column_labels[i, j₀] =
474+
_text__fit_cell_in_maximum_cell_width(
475+
column_labels[i, j₀],
476+
cell_width,
477+
line_breaks
478+
)
479+
end
480+
481+
# Shrink the data cells.
482+
for i in 1:num_printed_data_rows
483+
table_str[i, shrinkable_data_column] =
484+
_text__fit_cell_in_maximum_cell_width(
485+
table_str[i, shrinkable_data_column],
486+
printed_data_column_widths[shrinkable_data_column],
487+
line_breaks
488+
)
489+
end
490+
491+
# Shrink the summary rows.
492+
if !isnothing(summary_rows)
493+
for i in 1:size(summary_rows, 1)
494+
summary_rows[i, shrinkable_data_column] =
495+
_text__fit_cell_in_maximum_cell_width(
496+
summary_rows[i, shrinkable_data_column],
497+
printed_data_column_widths[shrinkable_data_column],
498+
line_breaks
499+
)
500+
end
501+
end
502+
end
503+
431504
num_printed_data_columns = _text__number_of_printed_data_columns(
432505
display.size[2],
433506
table_data,

src/printing_state/information.jl

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,28 @@
44
#
55
############################################################################################
66

7+
"""
8+
_column_label_limits(table_data::TableData, i::Int, j::Int) -> Tuple{Int, Int}
9+
10+
Return the limits of the column label cell at `(i, j)` in `table_data`. If the cell is not
11+
merged, the limits are just `(j, j)`. If the cell is merged, the limits are the start and
12+
end of the merged cell, which is defined by the `merge_column_label_cells` field of
13+
`table_data`.
14+
"""
15+
function _column_label_limits(table_data::TableData, i::Int, j::Int)
16+
isnothing(table_data.merge_column_label_cells) && return j, j
17+
18+
# Check if we are in a merged column.
19+
for mc in table_data.merge_column_label_cells
20+
if mc.i == i && (mc.j <= j <= mc.j + mc.column_span - 1)
21+
return mc.j, mc.j + mc.column_span - 1
22+
end
23+
end
24+
25+
# If we are not in a merged column, the limits are just the cell itself.
26+
return j, j
27+
end
28+
729
"""
830
_has_footnotes(table_data::TableData) -> Bool
931

0 commit comments

Comments
 (0)