Skip to content
20 changes: 18 additions & 2 deletions modules/markup/markdown/markdown_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -511,17 +511,33 @@ func TestMathBlock(t *testing.T) {
`\(a\) \(b\)`,
`<p><code class="language-math is-loading">a</code> <code class="language-math is-loading">b</code></p>` + nl,
},
{
`$a$.`,
`<p><code class="language-math is-loading">a</code>.</p>` + nl,
},
{
`.$a$`,
`<p>.$a$</p>` + nl,
},
{
`$a a$b b$`,
`<p><code class="language-math is-loading">a a$b b</code></p>` + nl,
`<p>$a a$b b$</p>` + nl,
Copy link
Contributor

@wxiaoguang wxiaoguang Apr 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could there be a case for something like:

  • $a a\\$b b$ => $a a\$b b$

?

In case the users would like to escape and use $

I have this question because I guess the old code might work with $a a\\$b b$ (although it reports errors for $a a$b b$, it is still acceptable)

So I'd like to confirm the new code's behavior.

Copy link
Contributor Author

@jmlt2002 jmlt2002 Apr 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The old code does what you described with $a a\$b b$, with only one backslash. With two, or any even number of backslashes it would generate an error.

With the current code, the expression $a a\\$b b$ generates the expression below.
image

If the user wanted to get the output that you described he would need to use the following expression
$a a \$ b b$
image

},
{
`a a$b b`,
`<p>a a$b b</p>` + nl,
},
{
`a$b $a a$b b$`,
`<p>a$b <code class="language-math is-loading">a a$b b</code></p>` + nl,
`<p>a$b $a a$b b$</p>` + nl,
},
{
"a$x$",
`<p>a$x$</p>` + nl,
},
{
"$x$a",
`<p>$x$a</p>` + nl,
},
{
"$$a$$",
Expand Down
18 changes: 13 additions & 5 deletions modules/markup/markdown/math/inline_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,12 @@ func (parser *inlineParser) Trigger() []byte {
return parser.start[0:1]
}

func isPunctuation(b byte) bool {
return b == '.' || b == '!' || b == '?' || b == ',' || b == ';' || b == ':'
}

func isAlphanumeric(b byte) bool {
// Github only cares about 0-9A-Za-z
return (b >= '0' && b <= '9') || (b >= 'A' && b <= 'Z') || (b >= 'a' && b <= 'z')
return (b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || (b >= '0' && b <= '9')
}

// Parse parses the current line and returns a result of parsing.
Expand All @@ -56,7 +59,7 @@ func (parser *inlineParser) Parse(parent ast.Node, block text.Reader, pc parser.
}

precedingCharacter := block.PrecendingCharacter()
if precedingCharacter < 256 && isAlphanumeric(byte(precedingCharacter)) {
if precedingCharacter < 256 && (isAlphanumeric(byte(precedingCharacter)) || isPunctuation(byte(precedingCharacter))) {
// need to exclude things like `a$` from being considered a start
return nil
}
Expand All @@ -75,14 +78,19 @@ func (parser *inlineParser) Parse(parent ast.Node, block text.Reader, pc parser.
ender += pos

// Now we want to check the character at the end of our parser section
// that is ender + len(parser.end)
// that is ender + len(parser.end) and check if char before ender is '\'
pos = ender + len(parser.end)
if len(line) <= pos {
break
}
if !isAlphanumeric(line[pos]) {
suceedingCharacter := line[pos]
if !isPunctuation(suceedingCharacter) && !(suceedingCharacter == ' ') {
return nil
}
if line[ender-1] != '\\' {
break
}

// move the pointer onwards
ender += len(parser.end)
}
Expand Down