Skip to content

Ansi highlighter has incorrect block offsets and code string #19

@folke

Description

@folke

Environment

md4x 0.0.25, Bun 1.3.11, CachyOS

Reproduction

import { renderToAnsi } from "md4x"

const md = `# Test

Text before.

\`\`\`lua
local a = 1
\`\`\`

Text between.

\`\`\`lua
local a = 2
\`\`\`

More text.

\`\`\`lua
local a = 3
\`\`\`

Final text.

\`\`\`lua
local a = 4
\`\`\`
`

const blocks = []
renderToAnsi(md, {
  highlighter: (code, block) => {
    blocks.push({ code, lang: block.lang, start: block.start, end: block.end
})
  },
})
console.log(blocks)

This gives the following output:

     [
       {
         "code":
     "local a = 1
     \x1B[22m
     S"
     ,
         "end": 86,
         "lang": "lua",
         "start": 61,
       },
       {
         "code":
     "2m  local a = 2
     \x1B[22m
     Mor"
     ,
         "end": 139,
         "lang": "lua",
         "start": 114,
       },
       {
         "code":
     "local a = 3
     \x1B[22m
     And s"
     ,
         "end": 182,
         "lang": "lua",
         "start": 157,
       },
       {
         "code": "local a = 4",
         "end": 222,
         "lang": "lua",
         "start": 205,
       },
     ]

Describe the bug

Code content includes leaked (partial) ANSI sequences and surrounding text:

  • Block 0: "local a = 1\x1b[22m\nS" — DIM_OFF + next text leaks in
  • Block 1: "2m local a = 2\x1b[22m\nMor" — starts with tail of DIM, ends with
    next text
  • Block 2: "local a = 3\x1b[22m\nAnd s" — DIM_OFF + next text
  • Block 3: "local a = 4" — correct (last block, nothing after it)

The error accumulates: each block's end drifts further by ~2 chars. The issue
is probably that meta->start is captured before ANSI_DIM is rendered and meta->end is
captured after ANSI_DIM_OFF, so the offsets include the DIM/DIM_OFF escape
sequences rather than pointing to the actual code content.

From my testing it also seems that only the second block in the markdown starts with a partial
DIM and includes the prefix. All other blocks typically don't have the prefix included.

Additional context

No response

Logs

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions