Skip to content

Markdown tables (and other GFM extensions) render as raw text in PR detail view #23

Description

@mayfieldiv

Problem

Markdown tables in PR descriptions render as a blob of plain text with pipe characters instead of a formatted table. This is because mdast-util-from-markdown only supports CommonMark by default — GFM (GitHub Flavored Markdown) features like tables require additional extensions.

Example input:

| File | Change |
|------|--------|
| `cli/Cargo.toml` | Explicit tokio features |
| `cli/Cargo.lock` | Removed unused `parking_lot` dep |

Current rendering: a single paragraph containing the raw | File | Change | ... text, pipes and all.

Expected: a nicely formatted table with aligned columns and borders.

Root Cause

  1. No GFM parser extensions — the project only has mdast-util-from-markdown (CommonMark). Tables, task lists, strikethrough, and autolinks all require micromark-extension-gfm + mdast-util-gfm to parse into proper AST nodes.
  2. No table renderersrc/lib/markdown.tsx has no Match case for type === "table" / tableRow / tableCell, so even if parsed, tables would hit the FallbackBlock and render nothing.

Other GFM features affected

These are also commonly used in GitHub PR bodies and are similarly broken:

Feature Syntax Current behavior
Task lists - [x] done Renders as [x] done text
Strikethrough ~~deleted~~ Renders as ~~deleted~~ text
Autolinks https://example.com Plain text (no link)

Proposed Fix

1. Add GFM parsing extensions

bun add micromark-extension-gfm mdast-util-gfm

Then in src/lib/markdown.tsx:

import { gfm } from "micromark-extension-gfm";
import { gfmFromMarkdown } from "mdast-util-gfm";

// in MarkdownBody:
const tree = () => fromMarkdown(props.source, {
  extensions: [gfm()],
  mdastExtensions: [gfmFromMarkdown()],
});

2. Add table renderer component

Render tabletableRowtableCell AST nodes as a TUI table. Key considerations:

  • Column width calculation — measure the text content of each column across all rows, then pad to the max width per column
  • Box-drawing borders — use , , , , , etc. for clean TUI table borders
  • Alignment — the Table node has an align array ("left" | "center" | "right" | null) per column
  • Header row — first tableRow is the header; render bold or with a separator line beneath
  • Inline content in cells — cells contain PhrasingContent[], so reuse InlineNodes for rendering

3. (Bonus) Task lists, strikethrough

  • Task lists: check listItem.checked (boolean | null) and render [✓] / [ ] prefix
  • Strikethrough: wrap in ~~ style (dim or strikethrough if terminal supports it)

Files to Modify

  • package.json — add micromark-extension-gfm + mdast-util-gfm
  • src/lib/markdown.tsx — wire up GFM extensions, add MdTable/MdTableRow/MdTableCell components, add task list + strikethrough support

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

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions