Skip to content

Commit

Permalink
Propagate language information to all <programlisting> XML elements.
Browse files Browse the repository at this point in the history
This is based on work done in 141dbfd
through ed9acb6 and makes a few
behavioral changes to it.

There's a new attribute called `filename` and the `language` was removed,
because it could provide misleading information. This allows for more
flexibility on the user side. In particular:

 * For historical reasons, `*.txt` files are marked by Doxygen as C++
   (see https://bugzilla.gnome.org/show_bug.cgi?id=760836 for details).
   In particular, code snippet included from a CMakeLists.txt file would
   be marked and highlighted as C++. So in this case, the language
   attribute would be very misleading.
 * Doxygen is aware only of a very small subset of languages and thus a
   lot of information can be lost when relying on its
   extension-to-language-name conversion -- in particular, all
   extensions that are not recognized are assumed to be C++. On the other
   hand, putting more effort into its language detection algorithms is
   not worth the time, as there will always be new languages that fail to
   detect. So let's leave that on the user of the XML output instead.
 * Using just file extension is not enough, it has to be a full filename.
   For example, `*.txt` can be either a plain text file or a
   `CMakeLists.txt`.
 * The path is not stripped from the filename, as it also may contain
   additional information that helps to detect the language better.

In addition to that, filenames of code snippets included via the \include
command and related are propagated to the <programlisting> element as
well.

With this change, (1) code snippets using simply

    \code
    some code
    \endcode

will not produce any `filename` attribute and it's up to the user what to
do -- assume C++, detect language from contents or not highlight
anything.

    <programlisting>
    some code
    </programlisting>

(2) Code snippets using

    \code{.cmake}
    some code
    \endcode

will produce the following:

    <programlisting filename=".cmake">
    some code
    </programlisting>

(3) And finally, \include, \dontinclude and related \skip, \skipline etc.
commands

    \include path/to/some-file.py

will produce

    <programlisting filename="path/to/some-file.py">
    some code
    </programlisting>

The tests were updated to check all three cases.

On the user side, when using Pygments for example, it's then just a
matter of calling pygments.lexers.find_lexer_class_for_filename() with
value of the `filename` attribute value and optionally also the code
snippet for additional language analysis.
  • Loading branch information
mosra committed Nov 19, 2017
1 parent ebf75c1 commit eaf8edb
Show file tree
Hide file tree
Showing 10 changed files with 33 additions and 13 deletions.
3 changes: 3 additions & 0 deletions src/docparser.cpp
Expand Up @@ -104,6 +104,7 @@ static QCString g_exampleName;
static SectionDict * g_sectionDict;
static QCString g_searchUrl;

static QCString g_includeFileName;
static QCString g_includeFileText;
static uint g_includeFileOffset;
static uint g_includeFileLength;
Expand Down Expand Up @@ -1917,6 +1918,7 @@ void DocInclude::parse()
// fall through
case DontInclude:
readTextFileByName(m_file,m_text);
g_includeFileName = m_file;
g_includeFileText = m_text;
g_includeFileOffset = 0;
g_includeFileLength = m_text.length();
Expand Down Expand Up @@ -1954,6 +1956,7 @@ void DocInclude::parse()

void DocIncOperator::parse()
{
m_includeFileName = g_includeFileName;
const char *p = g_includeFileText;
uint l = g_includeFileLength;
uint o = g_includeFileOffset;
Expand Down
2 changes: 2 additions & 0 deletions src/docparser.h
Expand Up @@ -541,6 +541,7 @@ class DocIncOperator : public DocNode
void markLast(bool v=TRUE) { m_isLast = v; }
bool isExample() const { return m_isExample; }
QCString exampleFile() const { return m_exampleFile; }
QCString includeFileName() const { return m_includeFileName; }
void parse();

private:
Expand All @@ -552,6 +553,7 @@ class DocIncOperator : public DocNode
bool m_isLast;
bool m_isExample;
QCString m_exampleFile;
QCString m_includeFileName;
};

/** Node representing an item of a cross-referenced list */
Expand Down
16 changes: 10 additions & 6 deletions src/xmldocvisitor.cpp
Expand Up @@ -211,7 +211,11 @@ void XmlDocVisitor::visit(DocVerbatim *s)
switch(s->type())
{
case DocVerbatim::Code: // fall though
m_t << "<programlisting language=\"" << langToString(langExt) << "\">";
m_t << "<programlisting";
if (!s->language().isEmpty())
m_t << " filename=\"" << lang << "\">";
else
m_t << ">";
Doxygen::parserManager->getParser(lang)
->parseCode(m_ci,s->context(),s->text(),langExt,
s->isExample(),s->exampleFile());
Expand Down Expand Up @@ -264,7 +268,7 @@ void XmlDocVisitor::visit(DocInclude *inc)
{
case DocInclude::IncWithLines:
{
m_t << "<programlisting>";
m_t << "<programlisting filename=\"" << inc->file() << "\">";
QFileInfo cfi( inc->file() );
FileDef fd( cfi.dirPath().utf8(), cfi.fileName().utf8() );
Doxygen::parserManager->getParser(inc->extension())
Expand All @@ -284,7 +288,7 @@ void XmlDocVisitor::visit(DocInclude *inc)
}
break;
case DocInclude::Include:
m_t << "<programlisting>";
m_t << "<programlisting filename=\"" << inc->file() << "\">";
Doxygen::parserManager->getParser(inc->extension())
->parseCode(m_ci,inc->context(),
inc->text(),
Expand Down Expand Up @@ -318,7 +322,7 @@ void XmlDocVisitor::visit(DocInclude *inc)
m_t << "</verbatim>";
break;
case DocInclude::Snippet:
m_t << "<programlisting>";
m_t << "<programlisting filename=\"" << inc->file() << "\">";
Doxygen::parserManager->getParser(inc->extension())
->parseCode(m_ci,
inc->context(),
Expand All @@ -331,7 +335,7 @@ void XmlDocVisitor::visit(DocInclude *inc)
break;
case DocInclude::SnipWithLines:
{
m_t << "<programlisting>";
m_t << "<programlisting filename=\"" << inc->file() << "\">";
QFileInfo cfi( inc->file() );
FileDef fd( cfi.dirPath().utf8(), cfi.fileName().utf8() );
Doxygen::parserManager->getParser(inc->extension())
Expand Down Expand Up @@ -367,7 +371,7 @@ void XmlDocVisitor::visit(DocIncOperator *op)
{
if (!m_hide)
{
m_t << "<programlisting>";
m_t << "<programlisting filename=\"" << op->includeFileName() << "\">";
}
pushEnabled();
m_hide = TRUE;
Expand Down
2 changes: 1 addition & 1 deletion templates/xml/compound.xsd
Expand Up @@ -264,7 +264,7 @@
<xsd:sequence>
<xsd:element name="codeline" type="codelineType" minOccurs="0" maxOccurs="unbounded" />
</xsd:sequence>
<xsd:attribute name="language" type="DoxLanguage" use="optional"/>
<xsd:attribute name="filename" type="xsd:string" use="optional"/>
</xsd:complexType>

<xsd:complexType name="codelineType">
Expand Down
11 changes: 9 additions & 2 deletions testing/014/indexpage.xml
Expand Up @@ -5,7 +5,7 @@
<title>My Project</title>
<detaileddescription>
<para>
<programlisting language="Python">
<programlisting filename=".py">
<codeline>
<highlight class="comment">#<sp/>comment<sp/>in<sp/>Python</highlight>
<highlight class="normal"/>
Expand All @@ -25,7 +25,7 @@
</programlisting>
</para>
<para>
<programlisting language="C++">
<programlisting filename=".cpp">
<codeline>
<highlight class="comment">//<sp/>comment<sp/>in<sp/>a<sp/>code<sp/>block</highlight>
<highlight class="normal"/>
Expand All @@ -37,6 +37,13 @@
</codeline>
</programlisting>
</para>
<para>
<programlisting>
<codeline>
<highlight class="normal">//<sp />implicit<sp />code<sp />language</highlight>
</codeline>
</programlisting>
</para>
</detaileddescription>
</compounddef>
</doxygen>
4 changes: 4 additions & 0 deletions testing/014_code.dox
Expand Up @@ -11,4 +11,8 @@
* // comment in a code block
* class Cpp {};
* \endcode
*
* \code
* // implicit code language
* \endcode
*/
2 changes: 1 addition & 1 deletion testing/021/indexpage.xml
Expand Up @@ -4,7 +4,7 @@
<compoundname>index</compoundname>
<title>My Project</title>
<detaileddescription>
<para> Our main function starts like this: <programlisting><codeline><highlight class="normal">void<sp/>main()</highlight></codeline><codeline><highlight class="normal">{</highlight></codeline></programlisting> First we create a object <computeroutput>t</computeroutput> of the <ref refid="class_test" kindref="compound">Test</ref> class. <programlisting><codeline><highlight class="normal"><sp/><sp/>Test<sp/>t;</highlight></codeline></programlisting> Then we call the example member function <programlisting><codeline><highlight class="normal"><sp/><sp/>t.example();</highlight></codeline></programlisting> After that our little test routine ends. <programlisting><codeline><highlight class="normal">}</highlight></codeline></programlisting> </para>
<para> Our main function starts like this: <programlisting filename="example_test.cpp"><codeline><highlight class="normal">void<sp/>main()</highlight></codeline><codeline><highlight class="normal">{</highlight></codeline></programlisting> First we create a object <computeroutput>t</computeroutput> of the <ref refid="class_test" kindref="compound">Test</ref> class. <programlisting filename="example_test.cpp"><codeline><highlight class="normal"><sp/><sp/>Test<sp/>t;</highlight></codeline></programlisting> Then we call the example member function <programlisting filename="example_test.cpp"><codeline><highlight class="normal"><sp/><sp/>t.example();</highlight></codeline></programlisting> After that our little test routine ends. <programlisting filename="example_test.cpp"><codeline><highlight class="normal">}</highlight></codeline></programlisting> </para>
</detaileddescription>
</compounddef>
</doxygen>
2 changes: 1 addition & 1 deletion testing/025/example_test_8cpp-example.xml
Expand Up @@ -4,7 +4,7 @@
<compoundname>example_test.cpp</compoundname>
<detaileddescription>
<para>This is an example of how to use the <ref refid="class_test" kindref="compound">Test</ref> class.</para>
<para>More details about this example. <programlisting><codeline><highlight class="keywordtype">void</highlight><highlight class="normal"><sp/>main()</highlight></codeline><codeline><highlight class="normal">{</highlight></codeline><codeline><highlight class="normal"><sp/><sp/><ref refid="class_test" kindref="compound">Test</ref><sp/>t;</highlight></codeline><codeline><highlight class="normal"><sp/><sp/>t.<ref refid="class_test_1a47b775f65718978f1ffcd96376f8ecfa" kindref="member">example</ref>();</highlight></codeline><codeline><highlight class="normal">}</highlight></codeline><codeline><highlight class="normal"/></codeline></programlisting> </para>
<para>More details about this example. <programlisting filename="example_test.cpp"><codeline><highlight class="keywordtype">void</highlight><highlight class="normal"><sp/>main()</highlight></codeline><codeline><highlight class="normal">{</highlight></codeline><codeline><highlight class="normal"><sp/><sp/><ref refid="class_test" kindref="compound">Test</ref><sp/>t;</highlight></codeline><codeline><highlight class="normal"><sp/><sp/>t.<ref refid="class_test_1a47b775f65718978f1ffcd96376f8ecfa" kindref="member">example</ref>();</highlight></codeline><codeline><highlight class="normal">}</highlight></codeline><codeline><highlight class="normal"/></codeline></programlisting> </para>
</detaileddescription>
</compounddef>
</doxygen>
2 changes: 1 addition & 1 deletion testing/032/indexpage.xml
Expand Up @@ -4,7 +4,7 @@
<compoundname>index</compoundname>
<title>My Project</title>
<detaileddescription>
<para>Some text. <programlisting><codeline><highlight class="keywordtype">void</highlight><highlight class="normal"><sp/>main()</highlight></codeline><codeline><highlight class="normal">{</highlight></codeline><codeline><highlight class="normal"><sp/><sp/>Test<sp/>t;</highlight></codeline><codeline><highlight class="normal"><sp/><sp/>t.example();</highlight></codeline><codeline><highlight class="normal">}</highlight></codeline><codeline><highlight class="normal"/></codeline></programlisting> More text. <programlisting><codeline lineno="1"><highlight class="keywordtype">void</highlight><highlight class="normal"><sp/>main()</highlight></codeline><codeline lineno="2"><highlight class="normal">{</highlight></codeline><codeline lineno="3"><highlight class="normal"><sp/><sp/>Test<sp/>t;</highlight></codeline><codeline lineno="4"><highlight class="normal"><sp/><sp/>t.example();</highlight></codeline><codeline lineno="5"><highlight class="normal">}</highlight></codeline><codeline lineno="6"><highlight class="normal"/></codeline></programlisting> End. </para>
<para>Some text. <programlisting filename="example_test.cpp"><codeline><highlight class="keywordtype">void</highlight><highlight class="normal"><sp/>main()</highlight></codeline><codeline><highlight class="normal">{</highlight></codeline><codeline><highlight class="normal"><sp/><sp/>Test<sp/>t;</highlight></codeline><codeline><highlight class="normal"><sp/><sp/>t.example();</highlight></codeline><codeline><highlight class="normal">}</highlight></codeline><codeline><highlight class="normal"/></codeline></programlisting> More text. <programlisting filename="example_test.cpp"><codeline lineno="1"><highlight class="keywordtype">void</highlight><highlight class="normal"><sp/>main()</highlight></codeline><codeline lineno="2"><highlight class="normal">{</highlight></codeline><codeline lineno="3"><highlight class="normal"><sp/><sp/>Test<sp/>t;</highlight></codeline><codeline lineno="4"><highlight class="normal"><sp/><sp/>t.example();</highlight></codeline><codeline lineno="5"><highlight class="normal">}</highlight></codeline><codeline lineno="6"><highlight class="normal"/></codeline></programlisting> End. </para>
</detaileddescription>
</compounddef>
</doxygen>
2 changes: 1 addition & 1 deletion testing/049/indexpage.xml
Expand Up @@ -4,7 +4,7 @@
<compoundname>index</compoundname>
<title>My Project</title>
<detaileddescription>
<para>A bubble sort algorithm First get the inputs <programlisting><codeline><highlight class="normal"><sp/><sp/></highlight><highlight class="keywordflow">for</highlight><highlight class="normal">(i=0<sp/>;<sp/>i&lt;n<sp/>;<sp/>i++)</highlight></codeline><codeline><highlight class="normal"><sp/><sp/>{</highlight></codeline><codeline><highlight class="normal"><sp/><sp/><sp/><sp/>printf(</highlight><highlight class="stringliteral">"<sp/>Array[%d]<sp/>=<sp/>"</highlight><highlight class="normal">,i);</highlight></codeline><codeline><highlight class="normal"><sp/><sp/><sp/><sp/>scanf(</highlight><highlight class="stringliteral">"%d"</highlight><highlight class="normal">,&amp;arr[i]);</highlight></codeline><codeline><highlight class="normal"><sp/><sp/>}</highlight></codeline></programlisting>Then do the bubbling <programlisting><codeline><highlight class="normal"><sp/><sp/></highlight><highlight class="keywordflow">for</highlight><highlight class="normal">(i=0<sp/>;<sp/>i&lt;n<sp/>;<sp/>i++)</highlight></codeline><codeline><highlight class="normal"><sp/><sp/>{</highlight></codeline><codeline><highlight class="normal"><sp/><sp/><sp/><sp/></highlight><highlight class="keywordflow">for</highlight><highlight class="normal">(j=0<sp/>;<sp/>j&lt;n-i-1<sp/>;<sp/>j++)</highlight></codeline><codeline><highlight class="normal"><sp/><sp/><sp/><sp/>{</highlight></codeline><codeline><highlight class="normal"><sp/><sp/><sp/><sp/><sp/><sp/></highlight><highlight class="keywordflow">if</highlight><highlight class="normal">(arr[j]&gt;arr[j+1])<sp/></highlight><highlight class="comment">//Swapping<sp/>Condition<sp/>is<sp/>Checked</highlight><highlight class="normal"/></codeline><codeline><highlight class="normal"><sp/><sp/><sp/><sp/><sp/><sp/>{</highlight></codeline><codeline><highlight class="normal"><sp/><sp/><sp/><sp/><sp/><sp/><sp/><sp/>temp=arr[j];</highlight></codeline><codeline><highlight class="normal"><sp/><sp/><sp/><sp/><sp/><sp/><sp/><sp/>arr[j]=arr[j+1];</highlight></codeline><codeline><highlight class="normal"><sp/><sp/><sp/><sp/><sp/><sp/><sp/><sp/>arr[j+1]=temp;</highlight></codeline><codeline><highlight class="normal"><sp/><sp/><sp/><sp/><sp/><sp/>}</highlight></codeline><codeline><highlight class="normal"><sp/><sp/><sp/><sp/>}</highlight></codeline><codeline><highlight class="normal"><sp/><sp/>}</highlight></codeline></programlisting>Then write the result <programlisting><codeline><highlight class="normal"><sp/><sp/></highlight><highlight class="keywordflow">for</highlight><highlight class="normal">(i=0<sp/>;<sp/>i&lt;n<sp/>;<sp/>i++)</highlight></codeline><codeline><highlight class="normal"><sp/><sp/>{</highlight></codeline><codeline><highlight class="normal"><sp/><sp/><sp/><sp/>printf(</highlight><highlight class="stringliteral">"<sp/>%4d"</highlight><highlight class="normal">,arr[i]);</highlight></codeline><codeline><highlight class="normal"><sp/><sp/>}</highlight></codeline></programlisting></para>
<para>A bubble sort algorithm First get the inputs <programlisting filename="snippet_test.cpp"><codeline><highlight class="normal"><sp/><sp/></highlight><highlight class="keywordflow">for</highlight><highlight class="normal">(i=0<sp/>;<sp/>i&lt;n<sp/>;<sp/>i++)</highlight></codeline><codeline><highlight class="normal"><sp/><sp/>{</highlight></codeline><codeline><highlight class="normal"><sp/><sp/><sp/><sp/>printf(</highlight><highlight class="stringliteral">"<sp/>Array[%d]<sp/>=<sp/>"</highlight><highlight class="normal">,i);</highlight></codeline><codeline><highlight class="normal"><sp/><sp/><sp/><sp/>scanf(</highlight><highlight class="stringliteral">"%d"</highlight><highlight class="normal">,&amp;arr[i]);</highlight></codeline><codeline><highlight class="normal"><sp/><sp/>}</highlight></codeline></programlisting>Then do the bubbling <programlisting filename="snippet_test.cpp"><codeline><highlight class="normal"><sp/><sp/></highlight><highlight class="keywordflow">for</highlight><highlight class="normal">(i=0<sp/>;<sp/>i&lt;n<sp/>;<sp/>i++)</highlight></codeline><codeline><highlight class="normal"><sp/><sp/>{</highlight></codeline><codeline><highlight class="normal"><sp/><sp/><sp/><sp/></highlight><highlight class="keywordflow">for</highlight><highlight class="normal">(j=0<sp/>;<sp/>j&lt;n-i-1<sp/>;<sp/>j++)</highlight></codeline><codeline><highlight class="normal"><sp/><sp/><sp/><sp/>{</highlight></codeline><codeline><highlight class="normal"><sp/><sp/><sp/><sp/><sp/><sp/></highlight><highlight class="keywordflow">if</highlight><highlight class="normal">(arr[j]&gt;arr[j+1])<sp/></highlight><highlight class="comment">//Swapping<sp/>Condition<sp/>is<sp/>Checked</highlight><highlight class="normal"/></codeline><codeline><highlight class="normal"><sp/><sp/><sp/><sp/><sp/><sp/>{</highlight></codeline><codeline><highlight class="normal"><sp/><sp/><sp/><sp/><sp/><sp/><sp/><sp/>temp=arr[j];</highlight></codeline><codeline><highlight class="normal"><sp/><sp/><sp/><sp/><sp/><sp/><sp/><sp/>arr[j]=arr[j+1];</highlight></codeline><codeline><highlight class="normal"><sp/><sp/><sp/><sp/><sp/><sp/><sp/><sp/>arr[j+1]=temp;</highlight></codeline><codeline><highlight class="normal"><sp/><sp/><sp/><sp/><sp/><sp/>}</highlight></codeline><codeline><highlight class="normal"><sp/><sp/><sp/><sp/>}</highlight></codeline><codeline><highlight class="normal"><sp/><sp/>}</highlight></codeline></programlisting>Then write the result <programlisting filename="snippet_test.cpp"><codeline><highlight class="normal"><sp/><sp/></highlight><highlight class="keywordflow">for</highlight><highlight class="normal">(i=0<sp/>;<sp/>i&lt;n<sp/>;<sp/>i++)</highlight></codeline><codeline><highlight class="normal"><sp/><sp/>{</highlight></codeline><codeline><highlight class="normal"><sp/><sp/><sp/><sp/>printf(</highlight><highlight class="stringliteral">"<sp/>%4d"</highlight><highlight class="normal">,arr[i]);</highlight></codeline><codeline><highlight class="normal"><sp/><sp/>}</highlight></codeline></programlisting></para>
</detaileddescription>
</compounddef>
</doxygen>

0 comments on commit eaf8edb

Please sign in to comment.