Skip to content

Commit 7d0436d

Browse files
committed
fix(HTMLParser): fix ghCodeBlocks being parsed inside code tags
When using html pre/code tags to wrap github's fenced code block syntax, showdown would parsed them instead of treating them like plain code. Closes #229
1 parent e8852a8 commit 7d0436d

14 files changed

+174
-45
lines changed

dist/showdown.js

Lines changed: 41 additions & 16 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/showdown.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/showdown.min.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/showdown.min.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/converter.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,8 @@ showdown.Converter = function (converterOptions) {
242242
hashLinkCounts: {},
243243
langExtensions: langExtensions,
244244
outputModifiers: outputModifiers,
245-
converter: this
245+
converter: this,
246+
ghCodeBlocks: []
246247
};
247248

248249
// attacklab: Replace ~ with ~T

src/subParsers/githubCodeBlocks.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,20 +23,24 @@ showdown.subParser('githubCodeBlocks', function (text, options, globals) {
2323
text = text.replace(/(?:^|\n)```(.*)\n([\s\S]*?)\n```/g, function (wholeMatch, language, codeblock) {
2424
var end = (options.omitExtraWLInCodeBlocks) ? '' : '\n';
2525

26+
// First parse the github code block
2627
codeblock = showdown.subParser('encodeCode')(codeblock);
2728
codeblock = showdown.subParser('detab')(codeblock);
2829
codeblock = codeblock.replace(/^\n+/g, ''); // trim leading newlines
2930
codeblock = codeblock.replace(/\n+$/g, ''); // trim trailing whitespace
3031

3132
codeblock = '<pre><code' + (language ? ' class="' + language + ' language-' + language + '"' : '') + '>' + codeblock + end + '</code></pre>';
3233

33-
return showdown.subParser('hashBlock')(codeblock, options, globals);
34+
codeblock = showdown.subParser('hashBlock')(codeblock, options, globals);
35+
36+
// Since GHCodeblocks can be false positives, we need to
37+
// store the primitive text and the parsed text in a global var,
38+
// and then return a token
39+
return '\n\n~G' + (globals.ghCodeBlocks.push({text: wholeMatch, codeblock: codeblock}) - 1) + 'G\n\n';
3440
});
3541

3642
// attacklab: strip sentinel
3743
text = text.replace(/~0/, '');
3844

39-
text = globals.converter._dispatch('githubCodeBlocks.after', text, options);
40-
41-
return text;
45+
return globals.converter._dispatch('githubCodeBlocks.after', text, options);
4246
});

src/subParsers/paragraphs.js

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,10 @@ showdown.subParser('paragraphs', function (text, options, globals) {
1515

1616
for (var i = 0; i < end; i++) {
1717
var str = grafs[i];
18-
1918
// if this is an HTML marker, copy it
20-
if (str.search(/~K(\d+)K/g) >= 0) {
19+
if (str.search(/~(K|G)(\d+)\1/g) >= 0) {
2120
grafsOut.push(str);
22-
} else if (str.search(/\S/) >= 0) {
21+
} else {
2322
str = showdown.subParser('spanGamut')(str, options, globals);
2423
str = str.replace(/^([ \t]*)/g, '<p>');
2524
str += '</p>';
@@ -29,16 +28,37 @@ showdown.subParser('paragraphs', function (text, options, globals) {
2928

3029
/** Unhashify HTML blocks */
3130
end = grafsOut.length;
31+
console.log(text);
3232
for (i = 0; i < end; i++) {
33-
var blockText = '';
33+
var blockText = '',
34+
grafsOutIt = grafsOut[i],
35+
child = false,
36+
codeFlag = false;
3437
// if this is a marker for an html block...
35-
while (grafsOut[i].search(/~K(\d+)K/) >= 0) {
36-
blockText = globals.gHtmlBlocks[RegExp.$1];
38+
while (grafsOutIt.search(/~(K|G)(\d+)\1/) >= 0) {
39+
var delim = RegExp.$1,
40+
num = RegExp.$2;
41+
42+
if (delim === 'K') {
43+
blockText = globals.gHtmlBlocks[num];
44+
} else {
45+
// we need to check if ghBlock is a false positive
46+
blockText = (codeFlag) ? globals.ghCodeBlocks[num].text : globals.ghCodeBlocks[num].codeblock;
47+
}
3748
blockText = blockText.replace(/\$/g, '$$$$'); // Escape any dollar signs
38-
grafsOut[i] = grafsOut[i].replace(/~K\d+K/, blockText);
49+
50+
grafsOutIt = grafsOutIt.replace(/(\n\n)?~(K|G)\d+\2(\n\n)?/, blockText);
51+
// Check if grafsOutIt is a pre->code
52+
if (/^<pre\b[^>]*>\s*<code\b[^>]*>/.test(grafsOutIt)) {
53+
codeFlag = true;
54+
}
55+
child = true;
3956
}
57+
grafsOut[i] = grafsOutIt;
4058
}
41-
42-
text = globals.converter._dispatch('paragraphs.after', text, options);
43-
return grafsOut.join('\n\n');
59+
text = grafsOut.join('\n\n');
60+
// Strip leading and trailing lines:
61+
text = text.replace(/^\n+/g, '');
62+
text = text.replace(/\n+$/g, '');
63+
return globals.converter._dispatch('paragraphs.after', text, options);
4464
});

test/cases/list-with-code.html

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,5 @@
22
<li><p>A list item with code:</p>
33

44
<pre><code>alert('Hello world!');
5-
</code></pre>
6-
</li>
5+
</code></pre></li>
76
</ul>

test/issues/#183.gh-code-blocks-within-lists-do-not-render-properly.html

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,12 @@
55
<pre><code class="sh language-sh">$ git clone thing.git
66

77
dfgdfg
8-
</code></pre>
9-
</li>
8+
</code></pre></li>
109
<li>
1110
<p>I am another thing!</p>
1211

1312
<pre><code class="sh language-sh">$ git clone other-thing.git
1413

1514
foobar
16-
</code></pre>
17-
</li>
15+
</code></pre></li>
1816
</ol>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<pre lang="no-highlight"><code>
2+
foo
3+
4+
```javascript
5+
var s = "JavaScript syntax highlighting";
6+
alert(s);
7+
```
8+
9+
bar
10+
</code></pre>
11+
12+
<p>this is a long paragraph</p>
13+
14+
<p>this is another long paragraph</p>
15+
16+
<pre lang="no-highlight"><code>```javascript
17+
var s = "JavaScript syntax highlighting";
18+
alert(s);
19+
```
20+
21+
```python
22+
s = "Python syntax highlighting"
23+
print s
24+
```
25+
</code></pre>

0 commit comments

Comments
 (0)