Skip to content

Commit 5d19e4b

Browse files
committed
issue doxygen#11621 Markdown code handling ` gets confused by unterminated ` within (introduced by 1.11)
Fixed for escaped backtick
1 parent 0aa2496 commit 5d19e4b

File tree

7 files changed

+94
-13
lines changed

7 files changed

+94
-13
lines changed

doc/autolink.dox

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
\tableofcontents{html,latex}
2020

21-
Most documentation systems have special 'see also' sections where links
21+
Most documentation systems have special `see also' sections where links
2222
to other pieces of documentation can be inserted.
2323
Although Doxygen also has a command to start such a section (See section
2424
\ref cmdsa "\\sa"), it does allow you to put these kind of links anywhere in the

doc/features.dox

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ Although Doxygen can now be used in any project written in a language that is
101101
supported by Doxygen, initially it was specifically designed to be used for projects
102102
that make use of Qt Software's
103103
<A HREF="https://doc.qt.io">Qt toolkit</A>. I have tried to
104-
make Doxygen 'Qt-compatible'. That is: Doxygen can read the documentation contained in
104+
make Doxygen `Qt-compatible'. That is: Doxygen can read the documentation contained in
105105
the Qt source code and create a class browser that looks quite similar to the
106106
one that is generated by Qt Software. Doxygen understands the C++ extensions
107107
used by Qt such as signals and slots and many of the markup commands used in the Qt sources.

src/commentcnv.l

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,9 @@ SLASHopt [/]*
616616
yyextra->verbatimLine=yyextra->lineNr;
617617
BEGIN(VerbatimCode);
618618
}
619+
<CComment,ReadLine,IncludeFile>"\\`" {
620+
copyToOutput(yyscanner,yytext,yyleng);
621+
}
619622
<CComment,ReadLine,IncludeFile>"```" { // skip ``` if not at the start of the line
620623
copyToOutput(yyscanner,yytext,yyleng);
621624
}
@@ -740,7 +743,7 @@ SLASHopt [/]*
740743
}
741744
}
742745
<VerbatimCode>("```"[`]*|"~~~"[~]*) { /* end of markdown code block */
743-
if (yyextra->blockName=="`" || yyextra->blockName=="``") // ``` inside single quote block
746+
if (yytext[0]=='`' && (yyextra->blockName=="`" || yyextra->blockName=="``")) // ``` inside single quote block
744747
{
745748
// copy the end block marker
746749
copyToOutput(yyscanner,yytext,yyleng);
@@ -757,6 +760,14 @@ SLASHopt [/]*
757760
}
758761
}
759762
}
763+
<VerbatimCode>"'" {
764+
copyToOutput(yyscanner,yytext,yyleng);
765+
if (yyextra->blockName=="`") // support for `text'
766+
{
767+
yyextra->inVerbatim=false;
768+
BEGIN(yyextra->lastCommentContext);
769+
}
770+
}
760771
<VerbatimCode>"`"{1,2} {
761772
copyToOutput(yyscanner,yytext,yyleng);
762773
if (yytext==yyextra->blockName)
@@ -765,7 +776,7 @@ SLASHopt [/]*
765776
BEGIN(yyextra->lastCommentContext);
766777
}
767778
}
768-
<VerbatimCode>{CMD}("enddot"|"endcode"|"endmsc"|"enduml")/("{")? { /* end of verbatim block */
779+
<VerbatimCode>{CMD}("enddot"|"endcode"|"endmsc"|"enduml")/("{")? { // end of verbatim block
769780
copyToOutput(yyscanner,yytext,yyleng);
770781
if (&yytext[1]==yyextra->blockName)
771782
{
@@ -796,10 +807,10 @@ SLASHopt [/]*
796807
}
797808
}
798809
}
799-
<Verbatim,VerbatimCode>[^`~@\/\-\\\n{}]* { /* any character not a backslash or new line or } */
810+
<Verbatim,VerbatimCode>[^`'~@\/\-\\\n{}]* { /* any character not a backslash or new line or } */
800811
copyToOutput(yyscanner,yytext,yyleng);
801812
}
802-
<Verbatim,VerbatimCode>[^`~@\/\-\\\n{}]+/\n { /* premature end of comment block */
813+
<Verbatim,VerbatimCode>[^`'~@\/\-\\\n{}]+/\n { /* premature end of comment block */
803814
if (yyextra->lastCommentContext==ReadLine)
804815
{
805816
yyextra->inVerbatim=false;

src/markdown.cpp

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1626,9 +1626,9 @@ int Markdown::Private::processLink(const std::string_view data,size_t offset)
16261626
}
16271627

16281628
/** `` ` `` parsing a code span (assuming codespan != 0) */
1629-
int Markdown::Private::processCodeSpan(std::string_view data,size_t)
1629+
int Markdown::Private::processCodeSpan(std::string_view data,size_t offset)
16301630
{
1631-
AUTO_TRACE("data='{}'",Trace::trunc(data));
1631+
AUTO_TRACE("data='{}' offset={}",Trace::trunc(data),offset);
16321632
const size_t size = data.size();
16331633

16341634
/* counting the number of backticks in the delimiter */
@@ -1650,7 +1650,11 @@ int Markdown::Private::processCodeSpan(std::string_view data,size_t)
16501650
else if (data[end]=='\n')
16511651
{
16521652
// consecutive newlines
1653-
if (pc == '\n') return 0;
1653+
if (pc == '\n')
1654+
{
1655+
AUTO_TRACE_EXIT("new paragraph");
1656+
return 0;
1657+
}
16541658
pc = '\n';
16551659
i = 0;
16561660
}
@@ -1659,6 +1663,7 @@ int Markdown::Private::processCodeSpan(std::string_view data,size_t)
16591663
out+="&lsquo;";
16601664
out+=data.substr(nb,end-nb);
16611665
out+="&rsquo;";
1666+
AUTO_TRACE_EXIT("quoted end={}",end+1);
16621667
return static_cast<int>(end+1);
16631668
}
16641669
else
@@ -1669,8 +1674,18 @@ int Markdown::Private::processCodeSpan(std::string_view data,size_t)
16691674
}
16701675
if (i < nb && end >= size)
16711676
{
1677+
AUTO_TRACE_EXIT("no matching delimiter nb={} i={}",nb,i);
1678+
if (nb>=3) // found ``` that is not at the start of the line, keep it as-is.
1679+
{
1680+
out+=data.substr(0,nb);
1681+
return nb;
1682+
}
16721683
return 0; // no matching delimiter
16731684
}
1685+
while (end<size && data[end]=='`') // do greedy match in case we have more end backticks.
1686+
{
1687+
end++;
1688+
}
16741689

16751690
//printf("found code span '%s'\n",qPrint(QCString(data+f_begin).left(f_end-f_begin)));
16761691

@@ -1682,7 +1697,7 @@ int Markdown::Private::processCodeSpan(std::string_view data,size_t)
16821697
out+=escapeSpecialChars(codeFragment);
16831698
out+="</tt>";
16841699
}
1685-
AUTO_TRACE_EXIT("result={}",end);
1700+
AUTO_TRACE_EXIT("result={} nb={}",end,nb);
16861701
return static_cast<int>(end);
16871702
}
16881703

src/scanner.l

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7190,6 +7190,9 @@ NONLopt [^\n]*
71907190
BEGIN(DocCopyBlock);
71917191
}
71927192
<DocBlock>"```" { // skip ``` if not at the start of a line
7193+
yyextra->docBlock << "```";
7194+
}
7195+
<DocBlock>"\\`" { // skip escaped backtick
71937196
yyextra->docBlock << yytext;
71947197
}
71957198
<DocBlock>"`"{1,2} {
@@ -7209,7 +7212,7 @@ NONLopt [^\n]*
72097212
REJECT;
72107213
}
72117214
}
7212-
<DocBlock>[^@*~`\/\\\n]+ { // any character that isn't special
7215+
<DocBlock>[^@*~`'\/\\\n]+ { // any character that isn't special
72137216
yyextra->docBlock << yytext;
72147217
}
72157218
<DocBlock>\n { // newline
@@ -7323,7 +7326,20 @@ NONLopt [^\n]*
73237326
yyextra->docBlock << pat;
73247327
}
73257328
<DocCopyBlock>"```" { // backtick + end marker
7326-
if (yyextra->docBlockName=="``" && endVerbatimBlock(yyscanner,"``",2))
7329+
if (yyextra->docBlockName=="``")
7330+
{
7331+
yyextra->docBlock << "`";
7332+
endVerbatimBlock(yyscanner,"``",2);
7333+
yyextra->docBlock << "``";
7334+
BEGIN(DocBlock);
7335+
}
7336+
else
7337+
{
7338+
yyextra->docBlock << yytext;
7339+
}
7340+
}
7341+
<DocCopyBlock>"'"/[^a-z_A-Z0-9-] {
7342+
if (endVerbatimBlock(yyscanner,"`",1))
73277343
{
73287344
BEGIN(DocBlock);
73297345
}
@@ -7336,7 +7352,7 @@ NONLopt [^\n]*
73367352
}
73377353
yyextra->docBlock << yytext;
73387354
}
7339-
<DocCopyBlock>[^\<@/\*\]`~"\$\\\n]+ { // any character that is not special
7355+
<DocCopyBlock>[^\<@/\*\]`'~"\$\\\n]+ { // any character that is not special
73407356
yyextra->docBlock << yytext;
73417357
}
73427358
<DocCopyBlock>\" {

testing/110/indexpage.xml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2+
<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="" xml:lang="en-US">
3+
<compounddef id="indexpage" kind="page">
4+
<compoundname>index</compoundname>
5+
<title>My Project</title>
6+
<briefdescription>
7+
</briefdescription>
8+
<detaileddescription>
9+
<para>Text with <computeroutput>single</computeroutput> backtick. <linebreak/>
10+
Text with <lsquo/>mixed<rsquo/> backtick. <linebreak/>
11+
Text <computeroutput>it's cool</computeroutput>. with embedded ' <linebreak/>
12+
Text with <computeroutput>double</computeroutput> backtick. <linebreak/>
13+
Text with <computeroutput>double and `single` form</computeroutput> of backticks. <linebreak/>
14+
Text with <computeroutput>double backtick `ending`</computeroutput> in triple backtick. <linebreak/>
15+
Text with `escaped` backticks. <linebreak/>
16+
Text with triple ``` backtick not at the start of the line. <linebreak/>
17+
<programlisting><codeline><highlight class="normal">Text<sp/>inside<sp/>triple<sp/>backticks</highlight></codeline><codeline><highlight class="normal">Nested<sp/>`single`<sp/>backtick</highlight></codeline><codeline><highlight class="normal">Nested<sp/>``</highlight><highlight class="keywordtype">double</highlight><highlight class="normal">``<sp/>backtick</highlight></codeline></programlisting> More text after triple backtick section. </para>
18+
</detaileddescription>
19+
<location file="110_backticks.dox"/>
20+
</compounddef>
21+
</doxygen>

testing/110_backticks.dox

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// objective: test various forms of backtick handling
2+
// check: indexpage.xml
3+
/** @mainpage
4+
Text with `single` backtick.
5+
Text with `mixed' backtick.
6+
Text `it's cool`. with embedded '
7+
Text with ``double`` backtick.
8+
Text with ``double and `single` form`` of backticks.
9+
Text with ``double backtick `ending``` in triple backtick.
10+
Text with \`escaped\` backticks.
11+
Text with triple ``` backtick not at the start of the line.
12+
```
13+
Text inside triple backticks
14+
Nested `single` backtick
15+
Nested ``double`` backtick
16+
```
17+
More text after triple backtick section.
18+
*/

0 commit comments

Comments
 (0)