Skip to content

Markdown underscore emphasis has no opening-delimiter guard, so math subscripts italicize arbitrary spans #6042

Description

@Hmbown

Symptom

In a maths research session the transcript rendered as visually shredded prose — italic runs starting and stopping mid-expression, unrelated to any emphasis the model wrote. Founder: "this log in transformatics just bugged out big time."

The content is dense LaTeX-ish notation: τ_p^{-h}, L_p, b_p, C₁L_i^{3/2}, [t_, b_p].

Cause

inline_tokens in crates/tui/src/tui/markdown_render.rs:1750:

// _italic_
if rest.starts_with('_')
    && !rest.starts_with("__")
    && let Some(end) = rest[1..].find('_')
{
    let inner = &rest[1..1 + end];
    let after = &rest[1 + end + 1..];
    // Closing delimiter must not be immediately followed by a
    // letter, digit, or underscore.
    if !after.starts_with(|c: char| c.is_alphanumeric() || c == '_') {
        out.push(InlineToken::new(inner.to_string(), italic_style, None));
        rest = after;
        continue;
    }
}

The guard applies only to the closing delimiter. Nothing checks the character preceding the opening _. CommonMark requires an opening _ to be left-flanking and forbids intraword _ emphasis on both sides; this implements one half.

PR #1455 added the closing-side check for identifiers like codewhale_tui, and the regression test underscores_inside_identifiers_render_as_literal_text covers exactly that shape — every one of its cases (foo_bar_baz, codewhale_tui) has the closing _ followed by a letter. Math subscripts are the shape it does not cover: the closing _ lands before punctuation or a space, so the guard passes and emphasis fires across an arbitrary span.

Reproduction

Faithful reproduction of that arm against the founder's on-screen text:

SRC   : windows tile [t_, b_p]. Actually - hold on, do we even tile all the way from t_?
  ITALIC -> 'p]. Actually - hold on, do we even tile all the way from t'

SRC   : see foo_bar_baz for details
  (no italic — existing test still passes)

The predicted italic run matches the screenshot exactly. The _ in b_p opens emphasis and the _ in t_? closes it — 60 characters of ordinary prose italicized because ? is not alphanumeric.

Note this was reproduced from the algorithm, not by running the compiled renderer: crates/tui currently does not build in the working tree (unrelated in-flight McpConnectRefresh edits in core/engine.rs). Confirm with a real test before landing.

Suggested fix

Add the opening-side guard symmetric to the existing closing-side one: an _ may open emphasis only when the preceding character is not alphanumeric or _. That leaves _italic_ at a word boundary working, keeps foo_bar_baz literal, and stops b_p … t_ from pairing.

Worth considering alongside it: crates/tui/src/tui/history/latex_render.rs already recognises maths and converts it to Unicode (Σ, , all render correctly in the same screenshot). If a span is known maths, inline markdown emphasis should not run over it at all — the ordering between the two renderers is the deeper fix.

Evidence

crates/tui/src/tui/markdown_render.rs:1750-1763 (the _italic_ arm), :2546 (the PR #1455 regression test), founder screenshot 2026-09-10 00:14.

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

    • Status
      Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions