Skip to content

💡 Verbatim escape passthrough on text #66

Description

@natemoo-re

Is your feature request related to a problem?

A text run can't carry pre-formatted terminal output. Every non-printable byte in the content is mapped to U+FFFD before it reaches the screen, so any embedded escape sequence is destroyed. Rendering text(ESC + "[32mgreen" + ESC + "[0m") produces �[32mgreen�[0m—the structural ESC bytes become replacement glyphs and the rest leaks through as literal characters, so the terminal never interprets the color. Captured subprocess output, a pre-styled string, or any text that already contains escapes can't pass through intact.

Describe the solution you'd like

An opt-in passthrough flag that emits the run's bytes verbatim—no U+FFFD substitution and no per-run SGR wrapper—so embedded escapes reach the terminal unchanged:

text(preStyled, { passthrough: true });

Width accounting should still count only the printable cells (ignoring the zero-width escape bytes) so layout stays correct.

Describe alternatives you've considered

Stripping escapes in JS and re-expressing them via text({ color }) loses anything we don't model (cursor moves, OSC, mixed styling) and re-implements an ANSI parser on the JS side. The point of passthrough is to hand the renderer bytes it shouldn't touch.

Additional context

Failing test case on nm/repro/text-passthrough (test · diff).

Today emit_ch maps non-printables to U+FFFD (src/clayterm.c:155) and render_text wraps each run in its own SGR; passthrough needs a flag on the text op (ops.ts) that the text decode in reduce (src/clayterm.c:562) threads to a verbatim-copy path.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions