Skip to content

Markdown tables: preserve sizing hints and support richer grid-table layout #5738

Open

Description

@harder

Problem

The Markdig audit in #5737 found table features that parse correctly upstream but cannot be represented faithfully by Terminal.Gui's current TableData / MarkdownTable layout model.

  • Markdig's PipeTableOptions.InferColumnWidthsFromSeparator (available since 0.41.0) computes percentage widths in TableColumnDefinition.Width. Terminal.Gui drops those hints and chooses widths from content alone.
  • Grid tables can have no header, multiple header rows, column spans, row spans, and block content inside a cell. Terminal.Gui currently promotes the first row to a header and represents each cell as inline text.
  • The current height, border, hit-testing, and selection calculations assume one header row and one independent rectangular cell per column.

The changes in #5737 address inline fidelity and alert labels. They deliberately leave sizing policy and richer table geometry for this issue.

Goal

Render Markdig table structure faithfully while keeping ordinary pipe tables and standalone MarkdownTable use compatible. Define predictable behavior when requested proportions or cell contents cannot fit a narrow terminal.

Examples

Optional inferred widths

MarkdownPipeline pipeline = new MarkdownPipelineBuilder ()
    .UsePipeTables (new PipeTableOptions { InferColumnWidthsFromSeparator = true })
    .Build ();
| Short | Description |
| ----- | -------------------- |
| A     | B                    |

The separator expresses a 1:4 width preference. Currently those hints never reach table layout. Decide how preferences interact with available content width, cell padding, borders, minimum widths, rounding, and overflow. Keep the existing content-driven behavior when no widths are specified.

Grid table with an explicit header and multiline cells

+-----------+-------------------+
| Name      | Description       |
+===========+===================+
| Markdig   | A fast, powerful  |
|           | Markdown parser.  |
+-----------+-------------------+

Grid table with a spanning cell

+-------+-------+
| A     | B     |
+=======+=======+
| Cell spanning |
+-------+-------+

Headerless grid table

+-------+-------+
| A     | B     |
+-------+-------+
| C     | D     |
+-------+-------+

Markdig identifies the header status; the first row must not automatically become a styled header.

Scope

  1. Preserve optional column width hints, row header status, cell coordinates, ColumnSpan, RowSpan, and cell block content when lowering the Markdig AST.
  2. Design the table data model. Preserve existing TableData constructors and standalone MarkdownTable behavior where practical. Avoid exposing Markdig-specific AST types in Terminal.Gui's public API without an explicit compatibility decision.
  3. Specify natural widths, preferred proportions, minimum/maximum widths, border/padding accounting, deterministic rounding, narrow-terminal overflow, and resizing behavior.
  4. Lay out headerless and multiple-header-row tables, row/column spans, and multiline cells containing paragraphs, hard breaks, lists, and code blocks.
  5. Draw borders without internal separators through spanning cells; preserve correct intersections at mixed spans and header boundaries.
  6. Keep link navigation, keyboard activation, mouse hit testing, selection, scrolling, clipboard output, and ANSI rendering aligned with the actual cell rectangles.
  7. Apply the same geometry and width calculations during measurement, rendering, and hit testing. Support Unicode graphemes, combining sequences, CJK, and emoji display widths.

Acceptance criteria

  • With inferred widths enabled, a 1:4 separator preference affects rendered column widths according to a documented allocation rule, within deterministic integer-cell rounding.
  • Without width hints, existing ordinary pipe-table layout tests continue to pass.
  • Zero/unspecified width hints, partial hints, widths that cannot satisfy minimums, and terminal widths below the normal minimum have documented, tested outcomes without negative sizes, exceptions, or infinite loops.
  • Resizing narrow → wide → narrow recomputes widths, row heights, borders, content size, and link regions consistently.
  • Headerless grid tables retain every data row without synthetic header styling or a synthetic header separator.
  • Explicit header boundaries and multiple header rows follow the AST rather than row position assumptions.
  • Representative row spans, column spans, and mixed spans render correct borders and preserve every cell's content.
  • Paragraphs, explicit line breaks, lists, and code inside grid cells retain their structure and have correct row heights.
  • Links in wrapped, aligned, and spanning cells activate the original URL with both keyboard and mouse input.
  • Selection/copy over partial cells, spans, headers, and complete tables has a documented representation and does not duplicate or drop content.
  • ANSI output and on-screen rendering agree on cell positions and text. Grapheme-aware width tests cover CJK, combining sequences, and ZWJ emoji.
  • Existing constructors and standalone table use remain covered; intentional compatibility changes are documented.
  • Native AOT smoke coverage exercises representative proportional, headerless, and spanning tables without new unsuppressed trim/AOT warnings.
  • Add UICatalog examples plus a tuirec recording; inspect the cast and rendered output at more than one terminal width.

Implementation pointers

  • Terminal.Gui/Views/Markdown/MarkdownView.Parsing.cs: HandleTableBlock, AST lowering and header/row classification.
  • Terminal.Gui/Views/Markdown/TableData.cs: current public table model.
  • Terminal.Gui/Views/Markdown/MarkdownTable.cs: ComputeColumnWidths, Recalculate, row heights, DrawBorders, DrawWrappedRow, HitTestLinkRegion, and BuildLinkRegions.
  • Terminal.Gui/Views/Markdown/MarkdownView.Layout.cs: table SubView placement and placeholder rows.
  • Terminal.Gui/Views/Markdown/MarkdownView.Selection.cs: table reconstruction and selection mapping.
  • Existing Markdown table, selection, ANSI rendering, and dependency regression tests; Tests/NativeAotSmoke/MarkdownSmokeTests.cs.

Reuse the structured inline-cell lowering added by #5737. Preserve parsed display content through measurement and rendering rather than serializing and reparsing it.

References and dependencies

Deferred decisions

Choose the public representation and exact sizing/overflow policy before implementing the larger geometry change. Source-to-preview navigation, general Markdown editing, default pipeline changes, and HTML/KaTeX/Mermaid rendering are outside this issue.

This is follow-up work; #5737 can land without it.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions