fix(math): $…$ inside a backtick code span stays literal (#194 P4-4)

Verifying the KaTeX checklist: `$x^2$` in inline code was turned into
math and the backticks were left as literal text, because the math split
runs before markdown. The splitter now skips backtick code spans (N ticks
close with N), so markdown's inline code wins: wire is
<code>$y^2$</code>. Fenced blocks were already fine.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
This commit is contained in:
2026-09-20 15:35:54 -04:00
co-authored by Claude Opus 5
parent e3883e0fce
commit eb4b88a028
2 changed files with 32 additions and 0 deletions
+15
View File
@@ -81,3 +81,18 @@ test('block and inline mixed with text', () => {
{ type: 'text', value: ' ok' },
]);
});
test('math inside a backtick code span stays literal text (#194 P4-4)', () => {
assert.deepEqual(splitMathSegments('inline `$y^2$` here'), [
{ type: 'text', value: 'inline `$y^2$` here' },
]);
assert.deepEqual(splitMathSegments('``$a$`` and $b$'), [
{ type: 'text', value: '``$a$`` and ' },
{ type: 'inline', value: 'b' },
]);
// An unclosed backtick is just a character.
assert.deepEqual(splitMathSegments('tick ` then $c$'), [
{ type: 'text', value: 'tick ` then ' },
{ type: 'inline', value: 'c' },
]);
});
+17
View File
@@ -88,6 +88,23 @@ export const splitMathSegments = (text: string): MathSegment[] => {
};
while (i < text.length) {
// Backtick code spans are literal: `$x$` inside them must stay text so
// markdown's inline code wins (a run of N backticks closes with N).
if (text[i] === '`') {
let ticks = 0;
while (text[i + ticks] === '`') ticks += 1;
const fence = '`'.repeat(ticks);
const close = text.indexOf(fence, i + ticks);
if (close !== -1) {
buffer += text.slice(i, close + ticks);
i = close + ticks;
continue;
}
buffer += fence;
i += ticks;
continue;
}
// Escaped dollar: consume `\$` and emit a literal `$` as text.
if (text[i] === '\\' && text[i + 1] === '$') {
buffer += '$';