As mentioned, the issue here is catastrophic backtracking on that huge data
string. I think addressing this in the general case may be a bit difficult (with the obvious solution being not to shove that much code into a single block), since unfortunately we're playing with fire here.
That said, in this particular scenario Markdown shoots itself in the foot a bit by rendering 4-space indented code blocks as
<pre><code>(code)
</code></pre>
which causes the subsequent recalling of HashHTMLBlocks
to use the far less efficient "\n<tag>
to </tag>\n
" block matching regular expression.
If instead DoCodeBlocks
performed the replacement as
codeblock = "<pre><code>" + codeblock + "</code>\n</pre>";
// ^------^ shift newline
then HashHTMLBlocks
would be able to make use of the first, more strict block matching expression, which, while still involving a lot of iterations, is significantly more efficient for cases like this.
Of course, unlike Chrome/Firefox/Opera, IE opts to display
<pre><code>(code)</code>
</pre>
incorrectly, preserving the newline between </code>
and </pre>
, so this may not be a viable solution.
There are some other, more complex changes that might be able to address this as well, but I'm not sure it makes sense to make drastic modifications for such an irrational edge case. Of course, the fact that this inconvenienced you as an editor going in to attempt to fix the problem(s) does make it seem a little more worthwhile from my perspective.
As a side note, I believe that the stricter expression can be modified to match in significantly fewer steps as well, by transforming
^(<(...)\b[^\r]*?\n<\/\2>[ \t]*(?=\n+))
into
^(<(...)\b([^\r\n]*\n)+?\n<\/\2>[ \t]*(?=\n+))
unless I'm mistaken and there's a reason they aren't functionally equivalent.
And actually, I think similar treatment can be applied to the looser expression as well (which would solve the general case reasonably) where
^(<(...)\b[^\r]*?.*<\/\2>[ \t]*(?=\n+)\n)
becomes
^(<(...)\b([^\r\n]*\n)*?[^\n]*<\/\2>[ \t]*(?=\n+)\n)
and completes against the generated <pre>
element as-is in ~84,000 steps, versus the multiple millions currently required.