Replies: 1 comment 1 reply
|
Confirmed reproduction in the current source, and one constraint worth flagging before anyone lands a fix: a blanket "remove single-dollar math" would break an intended feature. Where the bug lives
// parse.ts:39-43 (settled arm)
return fromMarkdown(text, {
extensions: [gfm(), cjkFriendlyStrong(), mathCompatibility(), math()],
mdastExtensions: [gfmFromMarkdown(), mathFromMarkdown()],
})The project does not pass The constraint: single-dollar math is a tested featureThe existing test suite explicitly asserts single-dollar inline math renders, e.g. const source = ['Einstein wrote $E = mc^2$.', '', '$$', '\\frac{\\partial \\mathbf{u}}{\\partial t} ...', '$$', '', '$\\href{javascript:alert(1)}{unsafe}$'].join('\\n')
expect(container.querySelectorAll('.katex')).toHaveLength(3)
What that means for the fix shapeYour suggested kramdown/Obsidian-style edge guards are the right direction, applied only to single-
The key subtlety: guard #1 (the opener) and guard #2 (no whitespace/word-tight content) together — a lone Note: this is a renderer fix in — argszero |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Summary
In the web UI, when a rendered message contains a currency dollar sign (e.g.
US$ 500) and, later in the same paragraph, a legitimate inline math span ($n$), the renderer pairs the two$and parses everything between them as one inline KaTeX math token. All whitespace inside collapses (KaTeX math mode) and accented characters get converted to TeX accent commands, producing garbled text like500pelaresolu\c c\~ao.Taoaclassificou....This happens whenever a paragraph has two or more
$where the first one isn't intended as math — very common with currency in technical answers.Minimal reproduction
$inUS$ 50up to the$of$n$is parsed as a single inline-math token (italic glyph soup or a KaTeX error), and$n$does not render as math.US$ 50stays literal text;$n$renders as math.With accented text (e.g. Portuguese
resolução) the swallowed span renders asresolu\c c\~ao, which makes the corruption obvious.Root cause
dsh-web-frontendbundlesmicromark-extension-mathwith the defaultsingleDollarTextMath: trueand no edge/flanking rules. In the bundledmathTexttokenizer (dist/assets/vendor-*.js, hash varies per build):previous(code)only rejects a$immediately preceded by another$— a$preceded by a letter/digit (as inUS$,R$) still opens math.$run is accepted whenever its length matches the opener — even if the character right before it is a space, or the content starts with whitespace.So any two stray
$in one paragraph pair up across sentences.Suggested fix
kramdown/Obsidian-style guards, applied to single-
$math only ($$…$$flow/display untouched):previous(code): refuse to open whencodeis a letter or digit (ASCII0-9 A-Z a-z, plus non-ASCII letters) → fixesUS$/R$.$run is a space or line ending; refuse when the content began with whitespace; refuse when the character right after the closing run is a digit (Obsidian rule, avoids closing into$100).On rejection, call
nokso micromark falls back to literal text. That rollback is safe: micromark already supports text constructs that consume and then fail (the extension itself relies on this for unclosed$…), and after the rollback a later$can still open a legitimate span.Verified behavior after patching the bundled tokenizer locally:
US$ 500 … quase todo $n$→US$ 500literal,$n$renders as math ✅price $50 and $60→ literal ✅$x^2$,$y$,$$E=mc^2$$, multi-line$x\ny$,(see $x$), code spans → unchanged ✅$ x $→ literal (same as kramdown/Pandoc) ✅Happy to share the patch if useful.
Environment
@deepseek-ai/dsh/@deepseek-ai/dsh-web-frontend0.1.1-rc.2, web UI served bydsh --profile webAll reactions