diff --git a/tbl.typ b/tbl.typ index 60bf97c..1a6bc05 100644 --- a/tbl.typ +++ b/tbl.typ @@ -186,7 +186,7 @@ (body: body, ..options) } -#let tbl-cell-ctx(spec, it) = { +#let tbl-cell-ctx(spec, it) = context { set text( baseline: if spec.stagger { -1em } @@ -199,28 +199,84 @@ ) set par(leading: spec.leading) - let funcs = () + let it = it if spec.macro != none { - funcs.push(spec.macro) + it = (spec.macro)(it) } if spec.bold { - funcs.push(strong) + it = strong(it) } if spec.italic { - funcs.push(emph) + it = emph(it) } if spec.fg != auto { - funcs.push(it => text(fill: spec.fg, it)) + it = text(fill: spec.fg, it) + } + it +} + +#let tbl-cell-numeric(options, spec, cell-widths, col, txt-left, sep, txt-right, lay: false) = tbl-cell-ctx(spec, { + let sep = sep + // Hacky as it gets... but necessary to preserve some + // spacing across the decimalpoint. + let sp = { + let w = measure("x .").width + w -= measure("x.").width + h(w) + } + + let cell-left = eval( + txt-left.trim(), + mode: options.mode, + scope: options.scope, + ) + let cell-right = eval( + txt-right.trim(), + mode: options.mode, + scope: options.scope, + ) + + // Spacing adjustments + let ladj = 0pt + let radj = 0pt + if txt-left.ends-with(regex-raw(`[^ \t][ \t]`)) { + cell-left = cell-left + sp + box[] + ladj = measure(sp).width + } + if txt-right.trim() == "" { + sep = hide(options.decimalpoint) + } else if txt-right.starts-with(regex-raw(`[ \t][^ \t]`)) { + cell-right = box[] + sp + cell-right + radj = measure(sp).width + // WHY DO I NEED TO ADD LADJ AND RADJ? + // THIS STILL DOESN'T WORK QUITE RIGHT + // README ALSO LOOKS DIFFERENT } - context { - let it = it() - for func in funcs { - it = (func)(it) + if type(cell-widths) == dictionary { + stack( + dir: ltr, + box(width: cell-widths.num-l, align(right, cell-left)), + sep, + box(width: cell-widths.num-r, align(left, cell-right)), + ) + } else { + let cell-left-width = measure(cell-left).width + ladj + let cell-right-width = measure(cell-right).width + radj + cell-widths.update(d => { + let (wcol, curr) = cell-width-at(d, col, spec: spec) + + curr.num-l = calc.max(curr.num-l, cell-left-width) + curr.num-r = calc.max(curr.num-r, cell-right-width) + + d.insert(wcol, curr) + d + }) + if lay { + stack(dir: ltr, cell-left, sep, cell-right) } - return it } -} +}) #let tbl-vline(..options) = options.named() @@ -481,7 +537,7 @@ } if min-width-given != none { - realize += tbl-cell-ctx(spec, () => { + realize += tbl-cell-ctx(spec, { let width = min-width-given.to-absolute() let width-p = width + (spec.pad.left + spec.pad.right).to-absolute() @@ -747,123 +803,76 @@ let spec = rowdef.at(col) - cell = tbl-cell-ctx(spec, () => { - let align-pos = none - let sep = [] - let sep-len = 0 + let align-pos = none + let sep = [] + let sep-len = 0 - if (spec.class == "N" - and cell != "" // Do nothing if special entry - and not txt-block - ) { - // one position AFTER \& - align-pos = txt-cell.position("\\&") - sep-len = "\\&".len() - - if align-pos == none { - // OR rightmost decimalpoint "ADJACENT TO DIGIT" - // (so "26.4. 12" aligns on "26.4", but - // "26.4 .12" aligns on ".12") - let all-pos = txt-cell.matches(options.decimalpoint) - - if all-pos != () { - sep = options.decimalpoint - sep-len = sep.len() - - for prev-pos in all-pos.rev() { - if prev-pos.start + sep-len >= txt-cell.len() { - continue - } - let next-char = txt-cell.slice(prev-pos.start + sep-len, count: 1) - if next-char.match(regex-raw(`[0-9]`)) != none { - align-pos = prev-pos.start - break - } + if (spec.class == "N" + and cell != "" // Do nothing if special entry + and not txt-block + ) { + // one position AFTER \& + align-pos = txt-cell.position("\\&") + sep-len = "\\&".len() + + if align-pos == none { + // OR rightmost decimalpoint "ADJACENT TO DIGIT" + // (so "26.4. 12" aligns on "26.4", but + // "26.4 .12" aligns on ".12") + let all-pos = txt-cell.matches(options.decimalpoint) + + if all-pos != () { + sep = options.decimalpoint + sep-len = sep.len() + + for prev-pos in all-pos.rev() { + if prev-pos.start + sep-len >= txt-cell.len() { + continue } - } - - if align-pos == none { - align-pos = txt-cell.matches(regex-raw(`[0-9]`)) - if align-pos != () { - // OR rightmost digit - align-pos = align-pos.last().end - sep = [] - sep-len = 0 - } else { - // OR centered (no digits) - align-pos = none - sep = [] - sep-len = 0 + let next-char = txt-cell.slice(prev-pos.start + sep-len, count: 1) + if next-char.match(regex-raw(`[0-9]`)) != none { + align-pos = prev-pos.start + break } } } - } - - if align-pos != none { - let txt-left = txt-cell.slice(0, align-pos) - let txt-right = txt-cell.slice(align-pos + sep-len) - - // Hacky as it gets... but necessary to preserve some - // spacing across the decimalpoint. - let sp = context { - let w = measure("x .").width - w -= measure("x.").width - h(w) - } - - let cell-left = eval( - txt-left.trim(), - mode: options.mode, - scope: options.scope, - ) - let cell-right = eval( - txt-right.trim(), - mode: options.mode, - scope: options.scope, - ) - // Spacing adjustments - if txt-left.ends-with(regex-raw(`[^ \t][ \t]`)) { - cell-left = cell-left + sp + box[] - } - if txt-right.trim() == "" { - sep = hide(options.decimalpoint) - } else if txt-right.starts-with(regex-raw(`[ \t][^ \t]`)) { - cell-right = box[] + sp + cell-right + if align-pos == none { + align-pos = txt-cell.matches(regex-raw(`[0-9]`)) + if align-pos != () { + // OR rightmost digit + align-pos = align-pos.last().end + sep = [] + sep-len = 0 + } else { + // OR centered (no digits) + align-pos = none + sep = [] + sep-len = 0 + } } - - let cell-left-width = measure(cell-left).width - let cell-right-width = measure(cell-right).width - cell-widths.update(d => { - let (wcol, curr) = cell-width-at(d, col, spec: spec) - - curr.num-l = calc.max(curr.num-l, cell-left-width) - curr.num-r = calc.max(curr.num-r, cell-right-width) - - d.insert(wcol, curr) - d - }) - let (_, curr) = cell-width-at(cell-widths.final(), col, spec: spec) - stack( - dir: ltr, - box(width: curr.num-l, align(right, cell-left)), - sep, - box(width: curr.num-r, align(left, cell-right)), - ) - - } else { + } + } + let tbl-n = none + if align-pos != none { + let txt-left = txt-cell.slice(0, align-pos) + let txt-right = txt-cell.slice(align-pos + sep-len) + tbl-n = (txt-left, sep, txt-right) + cell = tbl-cell-numeric(options, spec, cell-widths, col, txt-left, sep, txt-right, lay: true) + tbl-cell-numeric(options, spec, cell-widths, col, txt-left, sep, txt-right) + } else { + cell = tbl-cell-ctx(spec, { eval( cell, mode: options.mode, scope: options.scope, ) - } - }) + }) + } if txt-block and cols.at(col) != 1fr { cell = context { - let (_, curr) = cell-width-at(cell-widths.get(), col, spec: - spec) + let (_, curr) = cell-width-at(cell-widths.get(), col, spec: spec) if curr.min != 0pt { box(width: curr.min, cell) } else { @@ -945,7 +954,7 @@ } else if spec.class in ("L", "C", "R", "N", "A") { if spec.ignore { // Preserve height, but ignore width. - cell = tbl-cell-ctx(spec, () => { + cell = tbl-cell-ctx(spec, { box( width: 0pt, height: measure(cell).height, @@ -953,7 +962,7 @@ ) }) } else { - tbl-cell-ctx(spec, () => { + tbl-cell-ctx(spec, { let width = measure(cell).width let width-p = width + (spec.pad.left + spec.pad.right).to-absolute() if spec.colspan == 1 and cols.at(col) == "equalize" { @@ -982,6 +991,9 @@ if spec.class == "A" { cell } else { pad(..spec.pad, cell) }, ) + if tbl-n != none { + cell.tbl-n = tbl-n + } } new-row.push(cell) @@ -1031,9 +1043,13 @@ let (col, cell) = cell let spec = rowdef.at(col) let (_, curr) = cell-width-at(cell-widths, col, spec: spec) - if spec.class == "A" { + if spec.class == "N" and cell.at("tbl-n", default: none) != none { + let tbl-n = cell.remove("tbl-n") + cell.body = pad(..spec.pad, tbl-cell-numeric(options, spec, curr, col, ..tbl-n)) + + } else if spec.class == "A" { // Align smaller class "A" cells in this column - cell.body = tbl-cell-ctx(spec, () => { + cell.body = tbl-cell-ctx(spec, { pad( ..spec.pad, box(width: curr.alpha, align(left, cell.body)),