Skip to content

paragraph/heading/list word-wrap never breaks unbroken CJK text #595

Description

Description

Note: I'm not confident in my written English, so this issue was translated with the help of an AI assistant. Please excuse any unnatural phrasing.

Symptom

Even when a width is specified via WordWrap, paragraphs, headings, and list items written in a language without ASCII spaces (such as Japanese) are never wrapped at all. The output ignores the specified width and renders everything on a single line.

Steps to reproduce

r, _ := glamour.NewTermRenderer(
      glamour.WithStandardStyle("dark"),
      glamour.WithWordWrap(40),
)
out, _ := r.Render("これは日本語のように単語間にスペースを含まない言語で書かれた非常に長い段落です。")

out is not wrapped despite WordWrap: 40, and stays on a single line:

これは日本語のように単語間にスペースを含まない言語で書かれた非常に長い段落です。

Root cause

ansi/paragraph.go and ansi/heading.go use github.com/muesli/reflow/wordwrap. ansi/blockelement.go (which margin-bearing blocks such as lists and blockquotes go through) uses charmbracelet/x/ansi.Wordwrap.

Both are designed to only break at word boundaries, with no hard-wrap fallback for a "word" that itself exceeds the given width. In languages like Japanese that don't separate words with spaces, an entire block of text is treated as a single "word," so no line break ever occurs regardless of the configured width.

By contrast, ansi/table.go delegates table rendering to lipgloss/table, which internally uses ansi.Wrap — a function that does have a hard-wrap fallback for oversized words — so tables are not affected. I verified this behavioral difference between ansi.Wrap and ansi.Wordwrap directly against real Japanese text:

  • ansi.Wrap: correctly wraps within the specified width
  • ansi.Wordwrap / muesli/reflow/wordwrap: neither wraps at all, and both produce lines far exceeding the specified width (in one real-world example, a width of 100 was requested but lines of width 314–372 were produced)

Note: already fixed on the v2 line

On the master branch (the v2 line), paragraph.go has already moved to lipgloss.Wrap (refactor(ansi): drop reflow and use cellbuf.Wrap), so this issue does not occur there. However, it has not been backported to the currently tagged release line (v0.10.x — the version fetched via go get, and also the version charmbracelet/glow currently depends on).

Environment

  • glamour v0.10.0
  • Example of a downstream consumer affected: glow v2.1.1 (rendering Markdown containing CJK text, e.g. some-command | glow -, breaks paragraphs, headings, and list items)

Fix

I plan to submit a separate PR that switches paragraph.go, heading.go, and blockelement.go to use ansi.Wrap.

Version

v0.10.0

Environment

Ubuntu 24.04.4 LTS (WSL2, Linux 6.6.114.1-microsoft-standard-WSL2, x86_64), go1.26.3, glamour v0.10.0, glow v2.1.1

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions