Skip to content

Commit b37955d

Browse files
committed
Fix blockquote parsing to match GFM behavior
Two changes to the BlockQuoteRaw rule in the PEG grammar: 1. Stop lazy continuation from consuming block-level elements by adding negative lookaheads for headings, list markers, and code fences. 2. End blockquotes at unquoted blank lines. Previously, all blank lines were consumed and the parser continued matching subsequent > lines as part of the same blockquote. Now only blank lines prefixed with > continue the blockquote, matching GFM where an unquoted blank line separates two distinct blockquotes.
1 parent c59a7a8 commit b37955d

File tree

2 files changed

+102
-28
lines changed

2 files changed

+102
-28
lines changed

lib/rdoc/markdown.kpeg

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -617,8 +617,8 @@ BlockQuote = BlockQuoteRaw:a
617617

618618
BlockQuoteRaw = @StartList:a
619619
(( ">" " "? Line:l { a << l } )
620-
( !">" !@BlankLine Line:c { a << c } )*
621-
( @BlankLine:n { a << n } )*
620+
( !">" !@BlankLine !AtxStart !Bullet !Enumerator !Ticks3 Line:c { a << c } )*
621+
( ">" @BlankLine:n { a << n } )*
622622
)+
623623
{ inner_parse a.join }
624624

lib/rdoc/markdown.rb

Lines changed: 100 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1656,7 +1656,7 @@ def _BlockQuote
16561656
return _tmp
16571657
end
16581658

1659-
# BlockQuoteRaw = @StartList:a (">" " "? Line:l { a << l } (!">" !@BlankLine Line:c { a << c })* (@BlankLine:n { a << n })*)+ { inner_parse a.join }
1659+
# BlockQuoteRaw = @StartList:a (">" " "? Line:l { a << l } (!">" !@BlankLine !AtxStart !Bullet !Enumerator !Ticks3 Line:c { a << c })* (">" @BlankLine:n { a << n })*)+ { inner_parse a.join }
16601660
def _BlockQuoteRaw
16611661

16621662
_save = self.pos
@@ -1718,6 +1718,38 @@ def _BlockQuoteRaw
17181718
self.pos = _save5
17191719
break
17201720
end
1721+
_save8 = self.pos
1722+
_tmp = apply(:_AtxStart)
1723+
_tmp = _tmp ? nil : true
1724+
self.pos = _save8
1725+
unless _tmp
1726+
self.pos = _save5
1727+
break
1728+
end
1729+
_save9 = self.pos
1730+
_tmp = apply(:_Bullet)
1731+
_tmp = _tmp ? nil : true
1732+
self.pos = _save9
1733+
unless _tmp
1734+
self.pos = _save5
1735+
break
1736+
end
1737+
_save10 = self.pos
1738+
_tmp = apply(:_Enumerator)
1739+
_tmp = _tmp ? nil : true
1740+
self.pos = _save10
1741+
unless _tmp
1742+
self.pos = _save5
1743+
break
1744+
end
1745+
_save11 = self.pos
1746+
_tmp = apply(:_Ticks3)
1747+
_tmp = _tmp ? nil : true
1748+
self.pos = _save11
1749+
unless _tmp
1750+
self.pos = _save5
1751+
break
1752+
end
17211753
_tmp = apply(:_Line)
17221754
c = @result
17231755
unless _tmp
@@ -1741,18 +1773,23 @@ def _BlockQuoteRaw
17411773
end
17421774
while true
17431775

1744-
_save9 = self.pos
1776+
_save13 = self.pos
17451777
while true # sequence
1778+
_tmp = match_string(">")
1779+
unless _tmp
1780+
self.pos = _save13
1781+
break
1782+
end
17461783
_tmp = _BlankLine()
17471784
n = @result
17481785
unless _tmp
1749-
self.pos = _save9
1786+
self.pos = _save13
17501787
break
17511788
end
17521789
@result = begin; a << n ; end
17531790
_tmp = true
17541791
unless _tmp
1755-
self.pos = _save9
1792+
self.pos = _save13
17561793
end
17571794
break
17581795
end # end sequence
@@ -1769,65 +1806,97 @@ def _BlockQuoteRaw
17691806
if _tmp
17701807
while true
17711808

1772-
_save10 = self.pos
1809+
_save14 = self.pos
17731810
while true # sequence
17741811
_tmp = match_string(">")
17751812
unless _tmp
1776-
self.pos = _save10
1813+
self.pos = _save14
17771814
break
17781815
end
1779-
_save11 = self.pos
1816+
_save15 = self.pos
17801817
_tmp = match_string(" ")
17811818
unless _tmp
17821819
_tmp = true
1783-
self.pos = _save11
1820+
self.pos = _save15
17841821
end
17851822
unless _tmp
1786-
self.pos = _save10
1823+
self.pos = _save14
17871824
break
17881825
end
17891826
_tmp = apply(:_Line)
17901827
l = @result
17911828
unless _tmp
1792-
self.pos = _save10
1829+
self.pos = _save14
17931830
break
17941831
end
17951832
@result = begin; a << l ; end
17961833
_tmp = true
17971834
unless _tmp
1798-
self.pos = _save10
1835+
self.pos = _save14
17991836
break
18001837
end
18011838
while true
18021839

1803-
_save13 = self.pos
1840+
_save17 = self.pos
18041841
while true # sequence
1805-
_save14 = self.pos
1842+
_save18 = self.pos
18061843
_tmp = match_string(">")
18071844
_tmp = _tmp ? nil : true
1808-
self.pos = _save14
1845+
self.pos = _save18
18091846
unless _tmp
1810-
self.pos = _save13
1847+
self.pos = _save17
18111848
break
18121849
end
1813-
_save15 = self.pos
1850+
_save19 = self.pos
18141851
_tmp = _BlankLine()
18151852
_tmp = _tmp ? nil : true
1816-
self.pos = _save15
1853+
self.pos = _save19
1854+
unless _tmp
1855+
self.pos = _save17
1856+
break
1857+
end
1858+
_save20 = self.pos
1859+
_tmp = apply(:_AtxStart)
1860+
_tmp = _tmp ? nil : true
1861+
self.pos = _save20
1862+
unless _tmp
1863+
self.pos = _save17
1864+
break
1865+
end
1866+
_save21 = self.pos
1867+
_tmp = apply(:_Bullet)
1868+
_tmp = _tmp ? nil : true
1869+
self.pos = _save21
1870+
unless _tmp
1871+
self.pos = _save17
1872+
break
1873+
end
1874+
_save22 = self.pos
1875+
_tmp = apply(:_Enumerator)
1876+
_tmp = _tmp ? nil : true
1877+
self.pos = _save22
1878+
unless _tmp
1879+
self.pos = _save17
1880+
break
1881+
end
1882+
_save23 = self.pos
1883+
_tmp = apply(:_Ticks3)
1884+
_tmp = _tmp ? nil : true
1885+
self.pos = _save23
18171886
unless _tmp
1818-
self.pos = _save13
1887+
self.pos = _save17
18191888
break
18201889
end
18211890
_tmp = apply(:_Line)
18221891
c = @result
18231892
unless _tmp
1824-
self.pos = _save13
1893+
self.pos = _save17
18251894
break
18261895
end
18271896
@result = begin; a << c ; end
18281897
_tmp = true
18291898
unless _tmp
1830-
self.pos = _save13
1899+
self.pos = _save17
18311900
end
18321901
break
18331902
end # end sequence
@@ -1836,23 +1905,28 @@ def _BlockQuoteRaw
18361905
end
18371906
_tmp = true
18381907
unless _tmp
1839-
self.pos = _save10
1908+
self.pos = _save14
18401909
break
18411910
end
18421911
while true
18431912

1844-
_save17 = self.pos
1913+
_save25 = self.pos
18451914
while true # sequence
1915+
_tmp = match_string(">")
1916+
unless _tmp
1917+
self.pos = _save25
1918+
break
1919+
end
18461920
_tmp = _BlankLine()
18471921
n = @result
18481922
unless _tmp
1849-
self.pos = _save17
1923+
self.pos = _save25
18501924
break
18511925
end
18521926
@result = begin; a << n ; end
18531927
_tmp = true
18541928
unless _tmp
1855-
self.pos = _save17
1929+
self.pos = _save25
18561930
end
18571931
break
18581932
end # end sequence
@@ -1861,7 +1935,7 @@ def _BlockQuoteRaw
18611935
end
18621936
_tmp = true
18631937
unless _tmp
1864-
self.pos = _save10
1938+
self.pos = _save14
18651939
end
18661940
break
18671941
end # end sequence
@@ -16457,7 +16531,7 @@ def _DefinitionListDefinition
1645716531
Rules[:_SetextHeading2] = rule_info("SetextHeading2", "&(@RawLine SetextBottom2) @StartList:a (!@Endline Inline:b { a << b })+ @Sp @Newline SetextBottom2 { RDoc::Markup::Heading.new(2, a.join) }")
1645816532
Rules[:_Heading] = rule_info("Heading", "(SetextHeading | AtxHeading)")
1645916533
Rules[:_BlockQuote] = rule_info("BlockQuote", "BlockQuoteRaw:a { RDoc::Markup::BlockQuote.new(*a) }")
16460-
Rules[:_BlockQuoteRaw] = rule_info("BlockQuoteRaw", "@StartList:a (\">\" \" \"? Line:l { a << l } (!\">\" !@BlankLine Line:c { a << c })* (@BlankLine:n { a << n })*)+ { inner_parse a.join }")
16534+
Rules[:_BlockQuoteRaw] = rule_info("BlockQuoteRaw", "@StartList:a (\">\" \" \"? Line:l { a << l } (!\">\" !@BlankLine !AtxStart !Bullet !Enumerator !Ticks3 Line:c { a << c })* (\">\" @BlankLine:n { a << n })*)+ { inner_parse a.join }")
1646116535
Rules[:_NonblankIndentedLine] = rule_info("NonblankIndentedLine", "!@BlankLine IndentedLine")
1646216536
Rules[:_VerbatimChunk] = rule_info("VerbatimChunk", "@BlankLine*:a NonblankIndentedLine+:b { a.concat b }")
1646316537
Rules[:_Verbatim] = rule_info("Verbatim", "VerbatimChunk+:a { RDoc::Markup::Verbatim.new(*a.flatten) }")

0 commit comments

Comments
 (0)