tabular 0.3.1
Improvements
as_grid()andemit()are 11-24% faster on long tables across every backend: cell inline-markup ASTs are parsed once per distinct string, style layers extract their overrides once per layer instead of per cell, subgroup splitting / decimal alignment / pagination keys are single-pass, XML/HTML escaping is vectorised, and body rows are assembled without quadratic append.
New features
-
preset(font_family = )generic chains ("mono"/"serif"/"sans") gained the URW/Nimbus Core-35 clone (Nimbus Mono PS / Nimbus Roman / Nimbus Sans) between the PostScript name and the Liberation face, so the default still renders as Courier / Times / Helvetica on Linux images that ship only the ghostscript fonts (and whose Type 1 Courier the Typst compiler cannot read); all links are metric-compatible, so layout is unchanged wherever the chain resolves. -
emit()to.tex,.typ, and PDF now re-expresses plain group-separator blank rows as discardable space (a white tabularray hline band on LaTeX, arow-gutterentry on Typst), so a page never ends on a stray blank line above the repeated closing rule when the native page break lands at a group boundary, matching how Word renders the RTF/DOCX output; mid-page the gap keeps the blank row's exact height, and styled or ruled tables (rowrules, side frames, striped separators) keep the real blank row. -
preset(decimal_metrics = "afm")now measures afont_familywith no bundled metric table (e.g. a system-installed face such as Courier 10 Pitch) through a temporary graphics device, so decimal alignment and width measurement stay exact whenever the host can resolve the font; the Times-fallback fidelity warning now fires only when that device probe also fails, and the probe can be disabled withoptions(tabular.device_metrics = FALSE). -
check_typst()is a new diagnostic that audits the Typst PDF toolchain: which typst binary is discoverable (standalonetypst, or the copy bundled inside Quarto), whether its version meets the 0.11 floor, and which families of the configured font chain the compiler can see; the chain is a fallback chain, so the check reports ready as soon as any family resolves and names the face PDFs render in.emit()warns after a Typst compile only when a family the user explicitly named cannot be found — missing members of the built-in cross-OS fallback chains substitute silently, matching the other backends. -
emit()gained a Typst backend:emit(spec, "out.typ")writes a standalone Typst document (native#tablewith repeatingtable.header/table.footer, page chrome via#set page()counters, native per-cell borders), andemit(spec, "out.pdf", format = "typst")compiles it through the standalone typst binary or Quarto's bundled copy, so PDF output no longer requires any TeX installation. The table centres on the page, the running header and footer anchor to the body edges (the header grows upward into the top margin, the footer downward, tracking the configured margins), andpaginate()'s keep-with-next mask is enforced through unbreakable rowspans in a hidden zero-width column. -
emit()on a bare.pdftarget now selects its compile engine by probing the machine, LaTeX first: a usable TeX (resolved the way the compile resolves it, and not frozen on a pre-2023 TeX Live kernel) keeps the historical LaTeX path byte-stable, a discoverable typst binary takes over otherwise, and with neither engine the call aborts up front naming both remedies;format = "latex"/format = "typst"pick the engine explicitly. -
check_latex()now reports the TeX Live release year of the activexelatexand fails the check when it predates 2023, the first release whose LaTeX kernel (2022-11-01) can load the bundled tabularray; the report and theemit()PDF compile error both explain the update / user-space TinyTeX remedy for images frozen on an old TeX Live. -
check_latex()and the PDF pre-compile staging now resolve TeX the same way the compile does, preferring a TinyTeX at the standard root (installed by eithertinytex::install_tinytex()orquarto install tinytex) over thePATH, so the diagnostic can no longer describe a different TeX than the oneemit()actually runs; remediation hints name thequarto install tinytexroute, which downloads from GitHub and therefore works behind proxies that block CTAN. -
cols()accepts a bare string as label shorthand (soc = "SOC / PT"issoc = col_spec(label = "SOC / PT"), including glue interpolation and the deferred{.name}token) and a.hideargument that hides the named columns in one flat vector. -
paginate()keep-together protection on the natively-paginating backends (RTF, DOCX) now emits edge-only row glue instead of gluing a whole fitting block, so a block that fits a fresh page but not the space left on the current one no longer bumps wholesale and strands a near-empty page; widow/orphan floors count content rows only, with trailing blank spacer rows still riding with their block. -
paginate(keep_together = )now accepts any column ofdata(including hidden block-key columns), not onlyusage = "group"columns.
Breaking changes
-
col_spec()no longer hasusage,group_display, orgroup_skiparguments; row grouping is a table-level fact and is now declared once with the newgroup_rows()verb. The inert-knob warning forgroup_display/group_skipon non-group columns is gone with them. -
group_rows()is the new structural verb:group_rows(by, display, skip)names only the structural grouping keys outer to inner (the section headers and any hidden break keys, not the visible label column, which stays an ordinarycols()column and is auto-indented).displayis a single value applied to every key ("section","collapse", or"repeat"); a hidden break-only key is expressed withcol_spec(visible = FALSE)rather than a display mode.skipfollows thereadr::read_csv(col_names = )pattern:TRUE(the default) derives the blank spacers fromdisplayand key visibility,FALSEinserts none, and a character subset ofbybreaks on exactly those keys (e.g.skip = "param"). Nesting is just listing the header keys (by = c("param", "visit")). It replaces a prior declaration wholesale, and its keys may not overlapsubgroup(by = ). -
paginate()gainedrepeat_cols, replacing theusage = "id"role: the horizontal-panel stub defaults to the visiblegroup_rows()keys, and an explicitrepeat_colsvector replaces that default.
Minor improvements and bug fixes
-
DESCRIPTION's SystemRequirements no longer contains the bare word "LaTeX", which pak's system-requirements scraper matched and answered by force-installing the
texliveOS package (a sudo failure on locked-down hosts such as Domino); the TeX distribution remains optional for PDF output. -
Fidelity warnings now render their feature string as inline code instead of a quoted value, so a feature that itself contains quotes (
decimal_metrics = "afm") no longer prints with escaped quotes. -
check_latex()now probes package availability throughkpsewhich(the resolver xelatex itself uses) instead of the tlmgr package database, fixing all-missing false negatives on apt-installed TeX Live and frozen TinyTeX images, no longer requires the tinytex R package, and reports a newbundledcolumn. -
emit()to DOCX now stamps the body's left/right cell margins on section-header, blank-spacer, column-header, and subgroup-banner cells, so their text aligns with body text exactly as in RTF (section headers previously sat one cell margin further left, making nested indents read one character too wide in Word). -
emit()to Typst now folds 2+ space runs in body cells underpreset(whitespace = "collapse"); the no-wrap hardening previously rewrote the run to non-breaking spaces first, so the knob was a silent no-op on Typst while every other backend honoured it. -
emit()to Typst now stamps the header surface background and padding on the column-label cells, sopreset(colors = list(header = ...)),preset(padding = list(header = ...)), and the equivalentstyle()atcells_headers()render as they do on RTF, HTML, LaTeX, and DOCX. -
emit()to LaTeX/PDF and Typst now places the running header band so its bottom edge sits exactly on the top-margin line, growing upward into the margin, and keeps the body at exactly the configured top margin — matching the RTF and DOCX placement; the LaTeX head lengths moved onto thegeometryoption list (a post-load\setlength{\headsep}shifted the body off the margin instead of moving the header) and every band row now carries a\strutso the band's bottom edge no longer depends on descenders in its content. -
emit()to HTML and Markdown no longer drops agroup_rows()blank spacer when a group transition coincides with a page boundary; the continuous flow keeps every spacer and only the very first row of the table suppresses one. -
emit()to Markdown now renders the indent of nested section headers as before the bold markers instead of spaces inside them, which CommonMark refused to parse as bold (literal**showed in the render). -
emit()to PDF now writes to a relativefilepath correctly; the path was previously resolved after switching into the temporary compile directory, so the output landed there and was deleted with it. -
emit()to RTF now resolves the row cell gap of header-band, column-label, blank-spacer, section-header, banner, and title rows frompreset(cell_padding = )like body rows do (previously hardcoded, so a non-default padding skewed header text relative to body text). -
figure()output no longer spills onto a blank trailing page in Word: the RTF closing paragraph after the full-page image row now carries the body font size (a bare paragraph rendered at RTF's 12pt default, taller than the reserved row), and the page-size model now budgets thepreset(pagefoot = )slot rows (and anypageheadrows that overflow the top margin), which intrude into the body exactly like footnote lines. The same budget applies to table pagination. -
emit()PDF output now works on TeX installations that lacktabularray/ninecolorsand cannot runtlmgr install(locked-down Domino / Posit Workbench images): tabular ships verbatim CTAN copies of both single-file packages ininst/tex/and stages them next to the generated.texat compile time whenever the local TeX cannot resolve them.