Skip to content

Commit

Permalink
Unique labels for \include{doc}
Browse files Browse the repository at this point in the history
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)
  • Loading branch information
albert-github committed Mar 17, 2024
1 parent 0e74aa5 commit 14ed636
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 33 deletions.
22 changes: 18 additions & 4 deletions doc/commands.dox
Original file line number Diff line number Diff line change
Expand Up @@ -2771,13 +2771,18 @@ Commands for displaying examples
- The `option` `local` can be used make doxygen interpret the code as if it was in the
class or namespace in which the include command appears, rather than the global namespace.

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

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

<hr>
\section cmdincludedoc \\includedoc <file-name>
\section cmdincludedoc \\includedoc['{'option'}'] <file-name>

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

The `option`s are the same `option`s that can be used with the `\include` when using there the option `doc`.

\sa section \ref cmdinclude "\\include{doc}".

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

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

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

<hr>
\section cmdsnippetdoc \\snippetdoc <file-name> ( block_id )
\section cmdsnippetdoc \\snippetdoc['{'option'}'] <file-name> ( block_id )

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

The `option`s are the same `option`s that can be used with the `\snippet` when using there the option `doc`.

\sa section \ref cmdsnippet "\\snippet{doc}" and \ref cmdinclude "\\include{doc}".

<hr>
Expand Down
9 changes: 5 additions & 4 deletions doc_internal/commands_internal.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,12 +130,13 @@ and the version in which they were introduced.
\since doxygen version 1.9.5

<hr>
\section cmdiraise \\iraise \<amount\>
\section cmdiraise \\iraise \<amount\> "<label>"
\addindex \\iraise

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

\since doxygen version 1.11.0

Expand Down
99 changes: 78 additions & 21 deletions src/commentcnv.l
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ struct commentcnv_FileState
int oldFileBufPos = 0;
int oldIncludeCtx = 0;
int oldRaiseLvl = 0;
QCString oldRaiseLbl;
};

struct commentcnvYY_state
Expand All @@ -96,7 +97,9 @@ struct commentcnvYY_state
int readLineCtx = 0;
int includeCtx = 0;
int raiseLevel = 0;
QCString raiseLabel;
int raiseIncrement = 0;
QCString incrementLabel;
bool skip = FALSE;
QCString fileName;
int lineNr = 0;
Expand Down Expand Up @@ -144,7 +147,7 @@ static void replaceComment(yyscan_t yyscanner,int offset);
static void clearCommentStack(yyscan_t yyscanner);
static bool readIncludeFile(yyscan_t yyscanner,const QCString &inc,const QCString &blockId);
static void insertCommentStart(yyscan_t yyscanner);
static void parseIncludeOptions(yyscan_t yyscanner,std::string_view s);
static bool parseIncludeOptions(yyscan_t yyscanner,std::string_view s);

#undef YY_INPUT
#define YY_INPUT(buf,result,max_size) result=yyread(yyscanner,buf,max_size);
Expand Down Expand Up @@ -214,7 +217,7 @@ FILEMASK {VFILEMASK}|{HFILEMASK}
B [ \t]
ID [$a-z_A-Z\x80-\xFF][$a-z_A-Z0-9\x80-\xFF]*
OPTS (","{B}*{ID}{B}*("="{B}*({ID}|[0-9]*){B}*)?)*
OPTS "{"[^}]*"}"{B}*
//- end: NUMBER ---------------------------------------------------------------------------
Expand Down Expand Up @@ -1033,7 +1036,7 @@ SLASHopt [/]*
copyToOutput(yyscanner,yytext,yyleng);
}

<CComment,ReadLine,IncludeFile>{B}{B}{B}{B}[\\@]("include{"{B}*"doc"{B}*{OPTS}"}"|"includedoc") { // Markdown code section
<CComment,ReadLine,IncludeFile>{B}{B}{B}{B}[\\@]("include"{OPTS}|"includedoc"{OPTS}*) { // Markdown code section
if (Config_getBool(MARKDOWN_SUPPORT))
{
copyToOutput(yyscanner,yytext,yyleng);
Expand All @@ -1043,7 +1046,7 @@ SLASHopt [/]*
REJECT;
}
}
<CComment,ReadLine,IncludeFile>{B}{B}{B}{B}[\\@]("snippet{"{B}*"doc"{B}*{OPTS}"}"|"snippetdoc") { // Markdown code section
<CComment,ReadLine,IncludeFile>{B}{B}{B}{B}[\\@]("snippet"{OPTS}|"snippetdoc"{OPTS}*) { // Markdown code section
if (Config_getBool(MARKDOWN_SUPPORT))
{
copyToOutput(yyscanner,yytext,yyleng);
Expand All @@ -1053,10 +1056,10 @@ SLASHopt [/]*
REJECT;
}
}
<CComment,ReadLine,IncludeFile>[\\@]("include{"{B}*"doc"{B}*{OPTS}"}"|"includedoc") {
<CComment,ReadLine,IncludeFile>[\\@]("include"{OPTS}|"includedoc"{OPTS}*) {
if (!parseIncludeOptions(yyscanner,std::string_view{yytext,static_cast<size_t>(yyleng)})) REJECT;
yyextra->includeCtx = YY_START;
yyextra->firstIncludeLine = true;
parseIncludeOptions(yyscanner,std::string_view{yytext,static_cast<size_t>(yyleng)});
if (!yyextra->insertCppCommentMarker && (yyextra->includeCtx==ReadLine || yyextra->includeCtx==IncludeFile))
{
if (yyextra->includeCtx==ReadLine)
Expand All @@ -1067,10 +1070,10 @@ SLASHopt [/]*
}
BEGIN(IncludeDoc);
}
<CComment,ReadLine,IncludeFile>[\\@]("snippet{"{B}*"doc"{B}*{OPTS}"}"|"snippetdoc") {
<CComment,ReadLine,IncludeFile>[\\@]("snippet"{OPTS}|"snippetdoc"{OPTS}*) {
if (!parseIncludeOptions(yyscanner,std::string_view{yytext,static_cast<size_t>(yyleng)})) REJECT;
yyextra->includeCtx = YY_START;
yyextra->firstIncludeLine = true;
parseIncludeOptions(yyscanner,std::string_view{yytext,static_cast<size_t>(yyleng)});
if (!yyextra->insertCppCommentMarker && (yyextra->includeCtx==ReadLine || yyextra->includeCtx==IncludeFile))
{
if (yyextra->includeCtx==ReadLine)
Expand Down Expand Up @@ -1283,11 +1286,12 @@ SLASHopt [/]*
yyextra->inBufPos = fs->oldFileBufPos;
yyextra->includeCtx = fs->oldIncludeCtx;
QCString lineStr= " \\ilinebr \\ifile \""+yyextra->fileName+"\" \\iline "+QCString().setNum(yyextra->lineNr)+" ";
if (fs->oldRaiseLvl!=yyextra->raiseLevel)
if (fs->oldRaiseLvl!=yyextra->raiseLevel || fs->oldRaiseLbl!=yyextra->raiseLabel)
{
lineStr+=std::string(" \\iraise ") + std::to_string(fs->oldRaiseLvl);
lineStr+=" \\iraise " + std::to_string(fs->oldRaiseLvl) + " \"" + fs->oldRaiseLbl + "\"";
}
yyextra->raiseLevel = fs->oldRaiseLvl;
yyextra->raiseLabel = fs->oldRaiseLbl;
copyToOutput(yyscanner,lineStr.view());
yyextra->includeStack.pop_back();
//printf("<<EOF>> switch back to %s line %d inbufPos=%d outbufPos=%d\n",
Expand All @@ -1299,22 +1303,70 @@ SLASHopt [/]*
*/
%%

static void parseIncludeOptions(yyscan_t yyscanner,std::string_view s)
static bool parseIncludeOptions(yyscan_t yyscanner,std::string_view s)
{
struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;

QCString fullMatch = QCString(yytext);
//printf("parseIncludeOptions=%s\n",qPrint(QCString(s)));
static const reg::Ex re(R"(,\s*raise\s*=\s*(\d+))");
reg::Match match;
if (reg::search(s,match,re))
int idx = fullMatch.find('{');
int idxEnd = fullMatch.find("}",idx+1);
QCString cmdName;
StringVector optList;
if (idx == -1) // no options
{
cmdName = QCString(yytext).stripWhiteSpace().mid(1); // to remove {CMD}
}
else // options present
{
cmdName = fullMatch.left(idx).stripWhiteSpace().mid(1); // to remove {CMD}
QCString optStr = fullMatch.mid(idx+1,idxEnd-idx-1).stripWhiteSpace();
optList = split(optStr.str(),",");
}
bool isDoc = false;
if (cmdName=="includedoc" || cmdName=="snippetdoc") isDoc = true;
for (const auto &opt : optList)
{
yyextra->raiseIncrement = atoi(match[1].str().c_str());
if (yyextra->raiseLevel+yyextra->raiseIncrement>=Section::MaxLevel) // check range
QCString locOpt = QCString(opt);
locOpt = locOpt.stripWhiteSpace();
if (locOpt=="doc")
{
warn(yyextra->fileName,yyextra->lineNr,"Raising section level from %d to %d, exceeds allowed range [0-%d], adjusting",
yyextra->raiseLevel,yyextra->raiseLevel+yyextra->raiseIncrement,Section::MaxLevel-1);
yyextra->raiseIncrement = std::max(0,Section::MaxLevel-1-yyextra->raiseLevel);
isDoc = true;
}
else
{
int posEqual = locOpt.find('=');
if (posEqual == -1)
{
isDoc = false;
break;
}
QCString option = locOpt.left(posEqual);
QCString value = locOpt.mid(posEqual+1);
if (option == "raise")
{
yyextra->raiseIncrement = atoi(value.data());
if (yyextra->raiseLevel+yyextra->raiseIncrement>=Section::MaxLevel) // check range
{
warn(yyextra->fileName,yyextra->lineNr,"Raising section level from %d to %d, exceeds allowed range [0-%d], adjusting",
yyextra->raiseLevel,yyextra->raiseLevel+yyextra->raiseIncrement,Section::MaxLevel-1);
yyextra->raiseIncrement = std::max(0,Section::MaxLevel-1-yyextra->raiseLevel);
}
}
else if (option == "label")
{
yyextra->incrementLabel = value;
}
else
{
isDoc = false;
break;
}
}
}
return isDoc;
}
Expand Down Expand Up @@ -1633,11 +1685,13 @@ static bool readIncludeFile(yyscan_t yyscanner,const QCString &inc,const QCStrin
}
}
int oldRaiseLevel = yyextra->raiseLevel;
QCString oldRaiseLabel = yyextra->raiseLabel;
yyextra->raiseLevel+=yyextra->raiseIncrement;
yyextra->raiseLabel+=yyextra->incrementLabel;
QCString lineStr=" \\ilinebr \\ifile \""+absFileName+"\" \\iline " + std::to_string(lineNr);
if (yyextra->raiseLevel>0)
if (yyextra->raiseLevel>0 || !yyextra->raiseLabel.isEmpty())
{
lineStr+=" \\iraise " + std::to_string(yyextra->raiseLevel);
lineStr+=" \\iraise " + std::to_string(yyextra->raiseLevel) + " \"" + yyextra->raiseLabel + "\"";
}
lineStr+=" \\ilinebr ";
copyToOutput(yyscanner,lineStr.view());
Expand All @@ -1651,6 +1705,7 @@ static bool readIncludeFile(yyscan_t yyscanner,const QCString &inc,const QCStrin
fs->oldFileBufPos = yyextra->inBufPos;
fs->oldIncludeCtx = yyextra->includeCtx;
fs->oldRaiseLvl = oldRaiseLevel;
fs->oldRaiseLbl = oldRaiseLabel;
fs->blockId = blockId;
yy_switch_to_buffer(yy_create_buffer(0, YY_BUF_SIZE, yyscanner),yyscanner);
yyextra->fileName = absFileName;
Expand Down Expand Up @@ -1803,7 +1858,9 @@ void convertCppComments(const std::string &inBuf,std::string &outBuf,const std::
yyextra->pythonDocString = FALSE;
yyextra->lineNr = 1;
yyextra->raiseLevel = 0;
yyextra->raiseLabel = "";
yyextra->raiseIncrement = 0;
yyextra->incrementLabel = "";
yyextra->insertCppCommentMarker=false;
yyextra->expandedAliases.clear();
while (!yyextra->condStack.empty()) yyextra->condStack.pop();
Expand Down
21 changes: 17 additions & 4 deletions src/commentscan.l
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,7 @@ struct commentscanYY_state
QCString fileName; // file name that is read from
int lineNr = 0; // line number in the input
int raiseLevel = 0; // section level raise amount
QCString raiseLabel; // section label to append
bool inBody = FALSE; // was the comment found inside the body of a function?
OutputContext inContext; // are we inside the brief, details or xref part
bool briefEndsAtDot = FALSE; // does the brief description stop at a dot?
Expand Down Expand Up @@ -693,6 +694,7 @@ STopt [^\n@\\]*
%x ILine
%x ILineSection
%x IRaise
%x IRaiseLabel

%%

Expand Down Expand Up @@ -1761,12 +1763,21 @@ STopt [^\n@\\]*
{
yyextra->raiseLevel = nr;
}
BEGIN(Comment);
BEGIN(IRaiseLabel);
}
<IRaise>. {
unput(yytext[0]);
BEGIN(Comment);
}
<IRaiseLabel>{B}*"\""({LABELID})?"\"" {
QCString text(yytext);
yyextra->raiseLabel = text.stripWhiteSpace().mid(1,text.length()-2);
BEGIN(Comment);
}
<IRaiseLabel>. {
unput(yytext[0]);
BEGIN(Comment);
}


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

<SectionLabel>{LABELID} { // first argument
yyextra->sectionLabel=yytext;
addOutput(yyscanner,yytext);
yyextra->sectionLabel+=yyextra->raiseLabel;
addOutput(yyscanner,yyextra->sectionLabel.data());
yyextra->sectionTitle.clear();
BEGIN(SectionTitle);
}
Expand Down Expand Up @@ -2099,8 +2111,9 @@ STopt [^\n@\\]*
/* ----- handle arguments of the anchor command ------- */

<AnchorLabel,AnchorLabelSection>{LABELID} { // found argument
addAnchor(yyscanner,QCString(yytext), yyextra->anchorTitle);
addOutput(yyscanner,yytext);
QCString lbl = QCString(yytext)+yyextra->raiseLabel;
addAnchor(yyscanner,lbl, yyextra->anchorTitle);
addOutput(yyscanner,lbl.data());
if (YY_START == AnchorLabel)
{
BEGIN(Comment);
Expand Down

0 comments on commit 14ed636

Please sign in to comment.