Table format - #554
Draft
teunbrand wants to merge 7 commits into
Draft
Table format#554teunbrand wants to merge 7 commits into
teunbrand wants to merge 7 commits into
Conversation
…rule
SPAN's columns, PARTITION BY's columns, and FACET's row/column vars were
four identical `identifier, (',' identifier)*` grammar rules with matching
duplicate extraction logic in builder.rs. Collapse them into one
column_list rule and one parse_column_list() function. project_aesthetics
stays separate since it names aesthetics, not columns, despite the
identical shape.
Also correct two CLAUDE.md files that claimed the generated tree-sitter
parser files are committed to git — they're gitignored and regenerated by
the Rust build script instead.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
FORMAT configures cell formatting for a group of columns: FORMAT col, ... [SETTING ...] [RENAMING ...], repeatable like SPAN. SETTING's semantics are deferred — parsed and stored but not yet validated or applied. RENAMING reuses SCALE's exact clause (scale_renaming_clause renamed to the generic renaming_clause) so FORMAT gets identical explicit-value and wildcard-template renaming behavior for free. Table gains a `formats: Vec<Format>` field. Format stores value_mapping/ value_template rather than reusing Scale's label_mapping/label_template names, since Table::labels already claims "label" for column headers. Both fields share one default_template() helper in format.rs instead of each struct defining its own serde default function. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Wires Format.value_mapping/value_template into actual cell display: a new table_format module replaces each FORMAT-covered column in the resolved DataFrame with its resolved display text before column/cell layout runs, so create_body's ordinary value_to_string rendering already reflects any RENAMING and never needs to know FORMAT exists. A later FORMAT clause wins over an earlier one naming the same column; an unknown column errors. format.rs gains resolve_column_values, which works directly off a column's typed Arrow values rather than boxing each row into an ArrayElement first (the path apply_label_template uses for Scale's much smaller break lists) — avoiding that allocation for what can be a much larger number of table rows. compute_numeric_precision now takes plain f64s so both call sites can share it without going through ArrayElement, and the string/numeric column conversion in format_dataframe_column is factored out into column_to_strings for both to reuse. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Validates FORMAT's SETTING against a real FORMAT_PARAMS list (previously accepted-and-ignored): hjust takes "left"/"right"/"center"/"centre" or a 0-1 number, via a new ParamConstraint::string_option_or_number shared with any future param needing the same keyword-or-continuous shape. TableColumn and TableCell gain a `properties: Parameters` field. resolve_column_properties resolves each column's hjust exactly once, standardised to a number (left/center/right = 0.0/0.5/1.0; an explicit number passes through; an absent setting defaults from the column's Arrow dtype, numeric right, else left) so every writer buckets one representation instead of re-implementing keyword handling. Column-label cells inherit their column's properties, matching gt's own convention. HtmlWriter reads a cell's resolved hjust and renders it as an inline `style` attribute (text-align, plus font-variant-numeric: tabular-nums when right-aligned) through one translation function, so a future property is one more mapper rather than a change to render_cell itself. The numeric bucketing (0.25/0.75 thresholds) matches VegaLiteWriter's own convert_hjust, so hjust means the same alignment in every writer. Since dtype-derived defaults apply to every TABULATE output regardless of FORMAT, several pre-existing HtmlWriter/CLI/Jupyter tests asserting bare `<th>`/`<td>` strings needed updating; loosened them (and the new cell tests) to check tag content and alignment keywords rather than exact attribute strings, so future properties don't compound into unreadable literals. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds a FORMAT section to doc/syntax/clause/tabulate.qmd (clause syntax, SETTING's hjust, RENAMING linked to SCALE's own RENAMING/break-formatting docs rather than duplicated) plus a runnable example combining hjust alignment with null/template RENAMING against ggsql:penguins. doc/ggsql.xml gains a FORMAT keyword and FormatClause highlighting context, mirroring SpanClause, so the doc site's ```ggsql fences highlight it correctly; verified with a full quarto render of the page (after rebuilding and reinstalling the ggsql-jupyter kernel, since the previously-installed one predated the FORMAT grammar). CHANGELOG.md's existing TABULATE bullet list gains a FORMAT entry at the same one-line-per-clause detail level as LABEL/SPAN. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Table writers now receive resolved TableColumn/TableRow slices alongside cells, so a future whole-column setting like FORMAT's width can be read once per column instead of duplicated across every cell. Also drops ResolvedTable's vestigial table: Table field, made dead once cells/columns absorbed everything it used to carry. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds a numeric-with-unit ParamConstraint (px/%) for FORMAT's width SETTING, and has HtmlWriter emit a <colgroup> with a per-column width style, mirroring gt's own colgroup output (checked directly against gt's source: width is the only thing it ever puts there). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
teunbrand
added this pull request to stack #552
September 21, 2026 11:37
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR stacks on top of #553.
The user-facing change It implements is the
FORMATclause for plain columns in tabulate.The important internal change is that table cells now have a
propertiesparameter list that the writer can read.Currently, is only threads horizontal justification through
properties, but eventually this will also be used for other style attributes and classes.It also adds
TableColumnandTableRowarguments to the writer. TheTableColumnis the only place where column-wide properties can be set that can't be handed off to cell levels, such as thewidthattribute.The
TableRowis a stub to be expanded upon in the future, once we have to deal with group labels/summaries and such.