Skip to content

Commit

Permalink
Switch to native tables' fit auto columns algorithm (#109)
Browse files Browse the repository at this point in the history
* change to native tables' fit auto cols algorithm

Ensures maximum fairness by calculating the maximum fair share to shrink
the smallest amount of columns possible.

* don't use infinity on fit-auto-cols algo

* add cell overflow tests
  • Loading branch information
PgBiel authored Jan 1, 2024
1 parent 4639f59 commit 8a76b6c
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 21 deletions.
75 changes: 54 additions & 21 deletions src/col-row-size.typ
Original file line number Diff line number Diff line change
Expand Up @@ -291,40 +291,73 @@
(total: total-auto-size, sizes: auto-sizes, columns: new-columns)
}

// Try to reduce the width of auto columns so that the table fits within the
// page width.
// Fair version of the algorithm, tries to shrink the minimum amount of columns
// possible. The same algorithm used by native tables.
// Auto columns that are too wide will receive equal amounts of the remaining
// width (the "fair-share").
#let fit-auto-columns(available: 0pt, auto-cols: none, columns: none) = {
if is-infinite-len(available) {
// infinite space available => don't modify columns
return columns
}

// Remaining space to share between auto columns.
// Starts as all of the available space (excluding fixed-width columns).
// Will reduce as we exclude auto columns from being resized.
let remaining = available
let auto-cols-remaining = auto-cols.len()
let auto-cols-to-resize = auto-cols.len()

if auto-cols-remaining <= 0 {
if auto-cols-to-resize <= 0 {
return columns
}

let fair-share = remaining / auto-cols-remaining

for i-col in auto-cols {
let i = i-col.at(0)
let col = i-col.at(1)

if auto-cols-remaining <= 0 {
return columns // no more to share
// The fair-share must be the largest possible (to ensure maximum fairness)
// such that we can shrink the minimum amount of columns possible and, at the
// same time, ensure that the table won't cross the page width.
// To do this, we will try to divide the space evenly between each auto column
// to be resized.
// If one or more auto columns are smaller than that, then they don't need to be
// resized, so we will increase the fair share and check other columns, until
// either none needs to be resized (all are smaller than the fair share)
// or all columns to be resized are larger than the fair share.
let last-share
let fair-share = none
let fair-share-should-change = true

// 1. Rule out auto columns from resizing, and determine the final fair share
// (the largest possible such that no columns are smaller than it).
// One iteration of this 'while' runs for each attempt at a value for the fair
// share. Once no non-excluded columns are smaller than the fair share
// (which would otherwise lead to them being excluded from being resized, and the
// fair share would increase), the loop stops, and we can resize down all columns
// larger than the fair share.
// The loop also stops if all auto columns would be smaller than the fair share,
// and thus there is nothing to resize.
while fair-share-should-change and auto-cols-to-resize > 0 {
last-share = fair-share
fair-share = remaining / auto-cols-to-resize
fair-share-should-change = false

for (_, col) in auto-cols {
// 1. If it is smaller than the fair share,
// then it can keep its size, and we should
// update the fair share.
// 2. If it is larger than the last fair share,
// then it wasn't already excluded in any previous
// iterations.
if col <= fair-share and (last-share == none or col > last-share) {
remaining -= col
auto-cols-to-resize -= 1
fair-share-should-change = true
}
}
}

// subtract AFTER the check!!! (Avoid off-by-one error)
auto-cols-remaining -= 1

if col < fair-share { // ok, keep your size, it's less than the limit
remaining -= col

if auto-cols-remaining > 0 {
fair-share = remaining / auto-cols-remaining
}
} else { // you surpassed the limit!!!
remaining -= fair-share
// 2. Resize any columns larger than the calculated fair share to the fair share.
for (i, col) in auto-cols {
if col > fair-share {
columns.at(i) = fair-share
}
}
Expand Down
13 changes: 13 additions & 0 deletions tablex-test.typ
Original file line number Diff line number Diff line change
Expand Up @@ -1153,3 +1153,16 @@ Combining em and pt (with a stroke object):
colspanx(2)[], ..range(3),
)
]

#set page("a4")

*Overflowing cells (Issues \#48 and \#75)*

#tablex(
columns: 3,
[a: #lorem(7)], [b: $T h i s I s A L o n g A n d R a n d o m M a t h E p r e s s i o n$], [c]
)

#tablex(columns: (auto, auto, auto, auto),
[lorem_ipsum_dolor_sit_amet], [lorem], [lorem_ipsum_dolor_sit_amet_consectetur_adipisici], [lorem],
)

0 comments on commit 8a76b6c

Please sign in to comment.