Skip to content

Commit 14ed636

Browse files
committed
Unique labels for \include{doc}
With the `raise` option with the `\internal{doc}` command it was possible to raise the level of the used sections to the sub-sections specified. Problem would still be that the same `label_id` would have been used which would give warnings like: ``` warning: multiple use of section label 'cmd_1' while adding section ``` by creating also the `label` option this can be prevented, the specified value will be, recursively, appended to the given `label_id`. This would not only happen for section ids but also for anchor ids. - option handling in commentcnv - more flexibility in the order in which the options can be used (only a fixed order was possible so far). - add handling of the new option `label` - comentscan handling of the `label` with the `\iraise` command - updating documentation - for the new option - making `\includedoc` also have the possibility to use the `raise` and `label` options. - updating the internal documentation of `\iraise` to accommodate the `label_id`. (everything also applies the `\snippet` type of commands)
1 parent 0e74aa5 commit 14ed636

File tree

4 files changed

+118
-33
lines changed

4 files changed

+118
-33
lines changed

doc/commands.dox

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2771,13 +2771,18 @@ Commands for displaying examples
27712771
- The `option` `local` can be used make doxygen interpret the code as if it was in the
27722772
class or namespace in which the include command appears, rather than the global namespace.
27732773

2774-
When using option `doc`, there is an second option `raise` that can be specified to raise
2774+
When using option `doc`, there is also the option `raise` that can be specified to raise
27752775
all sections found in the referenced file by a certain amount. For example
27762776
\verbatim
27772777
\include{doc,raise=1} file.dox
27782778
\endverbatim will treat any level 1 \c \\section found in `file.dox` as a level 2 \c \\subsection, and any level 2 \c \\subsection
27792779
into a level 3 \c \\subsubsection, etc.
27802780
Similarly, for Markdown a \c \# section will be treated as a \c \#\# section.
2781+
Furtehermore there is the option `label` that can be used to change the labels of the included sections and anchors by appending
2782+
the given label_id to the given id. For example:
2783+
\verbatim
2784+
\include{doc,label=_append_id} file.dox
2785+
\endverbatim will treat e.g. `\section s1` found in `file.dox` as if it was specified as `\section s1_append_id`.
27812786

27822787
\note The included documentation should not have comment signs in it as they will appear
27832788
in the documentation as well.
@@ -2796,12 +2801,14 @@ Commands for displaying examples
27962801
\sa sections \ref cmdinclude "\\include{lineno}".
27972802

27982803
<hr>
2799-
\section cmdincludedoc \\includedoc <file-name>
2804+
\section cmdincludedoc \\includedoc['{'option'}'] <file-name>
28002805

28012806
\addindex \\includedoc
28022807
This command is obsolete and is still supported for backward compatibility reasons,
28032808
it works the same way as \ref cmdinclude "\\include{doc}"
28042809

2810+
The `option`s are the same `option`s that can be used with the `\include` when using there the option `doc`.
2811+
28052812
\sa section \ref cmdinclude "\\include{doc}".
28062813

28072814
<hr>
@@ -2911,14 +2918,19 @@ Commands for displaying examples
29112918
- The `option` `local` can be used make doxygen interpret the code as if it was in the
29122919
class or namespace in which the include command appears, rather than the global namespace.
29132920

2914-
When using option `doc`, there is an second option `raise` that can be specified to raise
2921+
When using option `doc`, there is also the option `raise` that can be specified to raise
29152922
all sections found in the referenced file by a certain amount. For example
29162923
\verbatim
29172924
\snippet{doc,raise=1} file.dox XXX
29182925
\endverbatim will
29192926
treat any level 1 \c \\section found the snippet as a level 2 \c \\subsection, and any level 2 \c \\subsection
29202927
into a level 3 \c \\subsubsection, etc.
29212928
Similarly, for Markdown a \c \# section will be treated as a \c \#\# section.
2929+
Furtehermore there is the option `label` that can be used to change the labels of the included sections and anchors by appending
2930+
the given label_id to the given id. For example:
2931+
\verbatim
2932+
\snippet{doc,label=_append_id} file.dox
2933+
\endverbatim will treat e.g. `\section s1` found in `file.dox` as if it was specified as `\section s1_append_id`.
29222934

29232935
\note The included documentation should not have comment signs in it as they will appear
29242936
in the documentation as well.
@@ -2936,12 +2948,14 @@ Commands for displaying examples
29362948
\sa sections \ref cmdsnippet "\\snippet{lineno}"
29372949

29382950
<hr>
2939-
\section cmdsnippetdoc \\snippetdoc <file-name> ( block_id )
2951+
\section cmdsnippetdoc \\snippetdoc['{'option'}'] <file-name> ( block_id )
29402952

29412953
\addindex \\snippetdoc
29422954
This command is obsolete and is still supported for backward compatibility reasons,
29432955
it works the same way as \ref cmdsnippet "\\snippet{doc}"
29442956

2957+
The `option`s are the same `option`s that can be used with the `\snippet` when using there the option `doc`.
2958+
29452959
\sa section \ref cmdsnippet "\\snippet{doc}" and \ref cmdinclude "\\include{doc}".
29462960

29472961
<hr>

doc_internal/commands_internal.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -130,12 +130,13 @@ and the version in which they were introduced.
130130
\since doxygen version 1.9.5
131131

132132
<hr>
133-
\section cmdiraise \\iraise \<amount\>
133+
\section cmdiraise \\iraise \<amount\> "<label>"
134134
\addindex \\iraise
135135

136-
Internal doxygen command to increase the section level by a given amount.
137-
After processing `\iraise 1` for instance, a `\section` will be treated as a `\subsection`.
138-
Inserted when processing `\include{doc}` with the `raise` option.
136+
Internal doxygen command to increase the section level by a given `amount` and append the
137+
`label` to the label of the `\section` type of commands and the the `\anchor` command.
138+
After processing `\iraise 1 "_lab"` for instance, a `\section s1` will be treated as a `\subsection s1_lab`.
139+
Inserted when processing `\include{doc}` with the `raise` or `label` option.
139140

140141
\since doxygen version 1.11.0
141142

src/commentcnv.l

Lines changed: 78 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ struct commentcnv_FileState
8181
int oldFileBufPos = 0;
8282
int oldIncludeCtx = 0;
8383
int oldRaiseLvl = 0;
84+
QCString oldRaiseLbl;
8485
};
8586

8687
struct commentcnvYY_state
@@ -96,7 +97,9 @@ struct commentcnvYY_state
9697
int readLineCtx = 0;
9798
int includeCtx = 0;
9899
int raiseLevel = 0;
100+
QCString raiseLabel;
99101
int raiseIncrement = 0;
102+
QCString incrementLabel;
100103
bool skip = FALSE;
101104
QCString fileName;
102105
int lineNr = 0;
@@ -144,7 +147,7 @@ static void replaceComment(yyscan_t yyscanner,int offset);
144147
static void clearCommentStack(yyscan_t yyscanner);
145148
static bool readIncludeFile(yyscan_t yyscanner,const QCString &inc,const QCString &blockId);
146149
static void insertCommentStart(yyscan_t yyscanner);
147-
static void parseIncludeOptions(yyscan_t yyscanner,std::string_view s);
150+
static bool parseIncludeOptions(yyscan_t yyscanner,std::string_view s);
148151

149152
#undef YY_INPUT
150153
#define YY_INPUT(buf,result,max_size) result=yyread(yyscanner,buf,max_size);
@@ -214,7 +217,7 @@ FILEMASK {VFILEMASK}|{HFILEMASK}
214217
B [ \t]
215218
ID [$a-z_A-Z\x80-\xFF][$a-z_A-Z0-9\x80-\xFF]*
216219
217-
OPTS (","{B}*{ID}{B}*("="{B}*({ID}|[0-9]*){B}*)?)*
220+
OPTS "{"[^}]*"}"{B}*
218221
219222
//- end: NUMBER ---------------------------------------------------------------------------
220223
@@ -1033,7 +1036,7 @@ SLASHopt [/]*
10331036
copyToOutput(yyscanner,yytext,yyleng);
10341037
}
10351038

1036-
<CComment,ReadLine,IncludeFile>{B}{B}{B}{B}[\\@]("include{"{B}*"doc"{B}*{OPTS}"}"|"includedoc") { // Markdown code section
1039+
<CComment,ReadLine,IncludeFile>{B}{B}{B}{B}[\\@]("include"{OPTS}|"includedoc"{OPTS}*) { // Markdown code section
10371040
if (Config_getBool(MARKDOWN_SUPPORT))
10381041
{
10391042
copyToOutput(yyscanner,yytext,yyleng);
@@ -1043,7 +1046,7 @@ SLASHopt [/]*
10431046
REJECT;
10441047
}
10451048
}
1046-
<CComment,ReadLine,IncludeFile>{B}{B}{B}{B}[\\@]("snippet{"{B}*"doc"{B}*{OPTS}"}"|"snippetdoc") { // Markdown code section
1049+
<CComment,ReadLine,IncludeFile>{B}{B}{B}{B}[\\@]("snippet"{OPTS}|"snippetdoc"{OPTS}*) { // Markdown code section
10471050
if (Config_getBool(MARKDOWN_SUPPORT))
10481051
{
10491052
copyToOutput(yyscanner,yytext,yyleng);
@@ -1053,10 +1056,10 @@ SLASHopt [/]*
10531056
REJECT;
10541057
}
10551058
}
1056-
<CComment,ReadLine,IncludeFile>[\\@]("include{"{B}*"doc"{B}*{OPTS}"}"|"includedoc") {
1059+
<CComment,ReadLine,IncludeFile>[\\@]("include"{OPTS}|"includedoc"{OPTS}*) {
1060+
if (!parseIncludeOptions(yyscanner,std::string_view{yytext,static_cast<size_t>(yyleng)})) REJECT;
10571061
yyextra->includeCtx = YY_START;
10581062
yyextra->firstIncludeLine = true;
1059-
parseIncludeOptions(yyscanner,std::string_view{yytext,static_cast<size_t>(yyleng)});
10601063
if (!yyextra->insertCppCommentMarker && (yyextra->includeCtx==ReadLine || yyextra->includeCtx==IncludeFile))
10611064
{
10621065
if (yyextra->includeCtx==ReadLine)
@@ -1067,10 +1070,10 @@ SLASHopt [/]*
10671070
}
10681071
BEGIN(IncludeDoc);
10691072
}
1070-
<CComment,ReadLine,IncludeFile>[\\@]("snippet{"{B}*"doc"{B}*{OPTS}"}"|"snippetdoc") {
1073+
<CComment,ReadLine,IncludeFile>[\\@]("snippet"{OPTS}|"snippetdoc"{OPTS}*) {
1074+
if (!parseIncludeOptions(yyscanner,std::string_view{yytext,static_cast<size_t>(yyleng)})) REJECT;
10711075
yyextra->includeCtx = YY_START;
10721076
yyextra->firstIncludeLine = true;
1073-
parseIncludeOptions(yyscanner,std::string_view{yytext,static_cast<size_t>(yyleng)});
10741077
if (!yyextra->insertCppCommentMarker && (yyextra->includeCtx==ReadLine || yyextra->includeCtx==IncludeFile))
10751078
{
10761079
if (yyextra->includeCtx==ReadLine)
@@ -1283,11 +1286,12 @@ SLASHopt [/]*
12831286
yyextra->inBufPos = fs->oldFileBufPos;
12841287
yyextra->includeCtx = fs->oldIncludeCtx;
12851288
QCString lineStr= " \\ilinebr \\ifile \""+yyextra->fileName+"\" \\iline "+QCString().setNum(yyextra->lineNr)+" ";
1286-
if (fs->oldRaiseLvl!=yyextra->raiseLevel)
1289+
if (fs->oldRaiseLvl!=yyextra->raiseLevel || fs->oldRaiseLbl!=yyextra->raiseLabel)
12871290
{
1288-
lineStr+=std::string(" \\iraise ") + std::to_string(fs->oldRaiseLvl);
1291+
lineStr+=" \\iraise " + std::to_string(fs->oldRaiseLvl) + " \"" + fs->oldRaiseLbl + "\"";
12891292
}
12901293
yyextra->raiseLevel = fs->oldRaiseLvl;
1294+
yyextra->raiseLabel = fs->oldRaiseLbl;
12911295
copyToOutput(yyscanner,lineStr.view());
12921296
yyextra->includeStack.pop_back();
12931297
//printf("<<EOF>> switch back to %s line %d inbufPos=%d outbufPos=%d\n",
@@ -1299,22 +1303,70 @@ SLASHopt [/]*
12991303
*/
13001304
%%
13011305

1302-
static void parseIncludeOptions(yyscan_t yyscanner,std::string_view s)
1306+
static bool parseIncludeOptions(yyscan_t yyscanner,std::string_view s)
13031307
{
13041308
struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1309+
1310+
QCString fullMatch = QCString(yytext);
13051311
//printf("parseIncludeOptions=%s\n",qPrint(QCString(s)));
1306-
static const reg::Ex re(R"(,\s*raise\s*=\s*(\d+))");
1307-
reg::Match match;
1308-
if (reg::search(s,match,re))
1312+
int idx = fullMatch.find('{');
1313+
int idxEnd = fullMatch.find("}",idx+1);
1314+
QCString cmdName;
1315+
StringVector optList;
1316+
if (idx == -1) // no options
1317+
{
1318+
cmdName = QCString(yytext).stripWhiteSpace().mid(1); // to remove {CMD}
1319+
}
1320+
else // options present
1321+
{
1322+
cmdName = fullMatch.left(idx).stripWhiteSpace().mid(1); // to remove {CMD}
1323+
QCString optStr = fullMatch.mid(idx+1,idxEnd-idx-1).stripWhiteSpace();
1324+
optList = split(optStr.str(),",");
1325+
}
1326+
bool isDoc = false;
1327+
if (cmdName=="includedoc" || cmdName=="snippetdoc") isDoc = true;
1328+
1329+
for (const auto &opt : optList)
13091330
{
1310-
yyextra->raiseIncrement = atoi(match[1].str().c_str());
1311-
if (yyextra->raiseLevel+yyextra->raiseIncrement>=Section::MaxLevel) // check range
1331+
QCString locOpt = QCString(opt);
1332+
locOpt = locOpt.stripWhiteSpace();
1333+
if (locOpt=="doc")
13121334
{
1313-
warn(yyextra->fileName,yyextra->lineNr,"Raising section level from %d to %d, exceeds allowed range [0-%d], adjusting",
1314-
yyextra->raiseLevel,yyextra->raiseLevel+yyextra->raiseIncrement,Section::MaxLevel-1);
1315-
yyextra->raiseIncrement = std::max(0,Section::MaxLevel-1-yyextra->raiseLevel);
1335+
isDoc = true;
1336+
}
1337+
else
1338+
{
1339+
int posEqual = locOpt.find('=');
1340+
if (posEqual == -1)
1341+
{
1342+
isDoc = false;
1343+
break;
1344+
}
1345+
QCString option = locOpt.left(posEqual);
1346+
QCString value = locOpt.mid(posEqual+1);
1347+
if (option == "raise")
1348+
{
1349+
yyextra->raiseIncrement = atoi(value.data());
1350+
if (yyextra->raiseLevel+yyextra->raiseIncrement>=Section::MaxLevel) // check range
1351+
{
1352+
warn(yyextra->fileName,yyextra->lineNr,"Raising section level from %d to %d, exceeds allowed range [0-%d], adjusting",
1353+
yyextra->raiseLevel,yyextra->raiseLevel+yyextra->raiseIncrement,Section::MaxLevel-1);
1354+
yyextra->raiseIncrement = std::max(0,Section::MaxLevel-1-yyextra->raiseLevel);
1355+
}
1356+
}
1357+
else if (option == "label")
1358+
{
1359+
yyextra->incrementLabel = value;
1360+
}
1361+
else
1362+
{
1363+
isDoc = false;
1364+
break;
1365+
}
13161366
}
13171367
}
1368+
1369+
return isDoc;
13181370
}
13191371
13201372
@@ -1633,11 +1685,13 @@ static bool readIncludeFile(yyscan_t yyscanner,const QCString &inc,const QCStrin
16331685
}
16341686
}
16351687
int oldRaiseLevel = yyextra->raiseLevel;
1688+
QCString oldRaiseLabel = yyextra->raiseLabel;
16361689
yyextra->raiseLevel+=yyextra->raiseIncrement;
1690+
yyextra->raiseLabel+=yyextra->incrementLabel;
16371691
QCString lineStr=" \\ilinebr \\ifile \""+absFileName+"\" \\iline " + std::to_string(lineNr);
1638-
if (yyextra->raiseLevel>0)
1692+
if (yyextra->raiseLevel>0 || !yyextra->raiseLabel.isEmpty())
16391693
{
1640-
lineStr+=" \\iraise " + std::to_string(yyextra->raiseLevel);
1694+
lineStr+=" \\iraise " + std::to_string(yyextra->raiseLevel) + " \"" + yyextra->raiseLabel + "\"";
16411695
}
16421696
lineStr+=" \\ilinebr ";
16431697
copyToOutput(yyscanner,lineStr.view());
@@ -1651,6 +1705,7 @@ static bool readIncludeFile(yyscan_t yyscanner,const QCString &inc,const QCStrin
16511705
fs->oldFileBufPos = yyextra->inBufPos;
16521706
fs->oldIncludeCtx = yyextra->includeCtx;
16531707
fs->oldRaiseLvl = oldRaiseLevel;
1708+
fs->oldRaiseLbl = oldRaiseLabel;
16541709
fs->blockId = blockId;
16551710
yy_switch_to_buffer(yy_create_buffer(0, YY_BUF_SIZE, yyscanner),yyscanner);
16561711
yyextra->fileName = absFileName;
@@ -1803,7 +1858,9 @@ void convertCppComments(const std::string &inBuf,std::string &outBuf,const std::
18031858
yyextra->pythonDocString = FALSE;
18041859
yyextra->lineNr = 1;
18051860
yyextra->raiseLevel = 0;
1861+
yyextra->raiseLabel = "";
18061862
yyextra->raiseIncrement = 0;
1863+
yyextra->incrementLabel = "";
18071864
yyextra->insertCppCommentMarker=false;
18081865
yyextra->expandedAliases.clear();
18091866
while (!yyextra->condStack.empty()) yyextra->condStack.pop();

src/commentscan.l

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,7 @@ struct commentscanYY_state
464464
QCString fileName; // file name that is read from
465465
int lineNr = 0; // line number in the input
466466
int raiseLevel = 0; // section level raise amount
467+
QCString raiseLabel; // section label to append
467468
bool inBody = FALSE; // was the comment found inside the body of a function?
468469
OutputContext inContext; // are we inside the brief, details or xref part
469470
bool briefEndsAtDot = FALSE; // does the brief description stop at a dot?
@@ -693,6 +694,7 @@ STopt [^\n@\\]*
693694
%x ILine
694695
%x ILineSection
695696
%x IRaise
697+
%x IRaiseLabel
696698

697699
%%
698700

@@ -1761,12 +1763,21 @@ STopt [^\n@\\]*
17611763
{
17621764
yyextra->raiseLevel = nr;
17631765
}
1764-
BEGIN(Comment);
1766+
BEGIN(IRaiseLabel);
17651767
}
17661768
<IRaise>. {
17671769
unput(yytext[0]);
17681770
BEGIN(Comment);
17691771
}
1772+
<IRaiseLabel>{B}*"\""({LABELID})?"\"" {
1773+
QCString text(yytext);
1774+
yyextra->raiseLabel = text.stripWhiteSpace().mid(1,text.length()-2);
1775+
BEGIN(Comment);
1776+
}
1777+
<IRaiseLabel>. {
1778+
unput(yytext[0]);
1779+
BEGIN(Comment);
1780+
}
17701781

17711782

17721783
/* ----- handle arguments of the ifile command ----- */
@@ -1838,7 +1849,8 @@ STopt [^\n@\\]*
18381849

18391850
<SectionLabel>{LABELID} { // first argument
18401851
yyextra->sectionLabel=yytext;
1841-
addOutput(yyscanner,yytext);
1852+
yyextra->sectionLabel+=yyextra->raiseLabel;
1853+
addOutput(yyscanner,yyextra->sectionLabel.data());
18421854
yyextra->sectionTitle.clear();
18431855
BEGIN(SectionTitle);
18441856
}
@@ -2099,8 +2111,9 @@ STopt [^\n@\\]*
20992111
/* ----- handle arguments of the anchor command ------- */
21002112

21012113
<AnchorLabel,AnchorLabelSection>{LABELID} { // found argument
2102-
addAnchor(yyscanner,QCString(yytext), yyextra->anchorTitle);
2103-
addOutput(yyscanner,yytext);
2114+
QCString lbl = QCString(yytext)+yyextra->raiseLabel;
2115+
addAnchor(yyscanner,lbl, yyextra->anchorTitle);
2116+
addOutput(yyscanner,lbl.data());
21042117
if (YY_START == AnchorLabel)
21052118
{
21062119
BEGIN(Comment);

0 commit comments

Comments
 (0)