chiark / gitweb /
doxygen: proper <hX> hierarchy for headings in non-top-level description.
authorVladimír Vondruš <mosra@centrum.cz>
Sat, 19 May 2018 08:29:16 +0000 (10:29 +0200)
committerVladimír Vondruš <mosra@centrum.cz>
Sat, 19 May 2018 08:50:03 +0000 (10:50 +0200)
Also don't emit the \section warning for these, it does not make sense.

doxygen/dox2html5.py
doxygen/test/contents_section_in_function/Doxyfile [new file with mode: 0644]
doxygen/test/contents_section_in_function/File.h [new file with mode: 0644]
doxygen/test/contents_section_in_function/File_8h.html [new file with mode: 0644]
doxygen/test/test_contents.py

index 5c3b78a9d414ee0322ada895b3485b85f6cfefd7..5a03f8f1449173a70b4122f82371c0b947e3423c 100755 (executable)
@@ -356,6 +356,7 @@ class State:
         self.current = ''
         self.current_prefix = []
         self.current_compound = None
+        self.parsing_toplevel_desc = False
 
 def slugify(text: str) -> str:
     # Maybe some Unicode normalization would be nice here?
@@ -692,17 +693,36 @@ def parse_desc_internal(state: State, element: ET.Element, immediate_parent: ET.
             assert element.tag == 'para' # is inside a paragraph :/
             has_block_elements = True
 
-            if i.attrib['level'] == '1':
-                tag = 'h2'
-            elif i.attrib['level'] == '2':
-                tag = 'h3'
-            elif i.attrib['level'] == '3':
-                tag = 'h4'
-            elif i.attrib['level'] == '4':
-                tag = 'h5'
-            else: # pragma: no cover
-                assert False
-            logging.warning("{}: prefer @section over Markdown heading for properly generated TOC".format(state.current))
+            # Top-level description
+            if state.parsing_toplevel_desc:
+                if i.attrib['level'] == '1':
+                    tag = 'h2'
+                elif i.attrib['level'] == '2':
+                    tag = 'h3'
+                elif i.attrib['level'] == '3':
+                    tag = 'h4'
+                elif i.attrib['level'] == '4':
+                    tag = 'h5'
+                else: # pragma: no cover
+                    assert False
+
+                # Emit this warning only in top-level desc, TOC is not
+                # generated for function/enum/... descriptions
+                logging.warning("{}: prefer @section over Markdown heading for properly generated TOC".format(state.current))
+
+            # Function/enum/... descriptions are inside <h3> for function
+            # header, which is inside <h2> for detailed definition section, so
+            # it needs to be <h4> and below
+            else:
+                if i.attrib['level'] == '1':
+                    tag = 'h4'
+                elif i.attrib['level'] == '2':
+                    tag = 'h5'
+                elif i.attrib['level'] in ['3', '4']:
+                    tag = 'h6' # there is no <h7>
+                else: # pragma: no cover
+                    assert False
+
             out.parsed += '<{0}>{1}</{0}>'.format(tag, html.escape(i.text))
 
         elif i.tag == 'para':
@@ -1344,8 +1364,10 @@ def parse_var_desc(state: State, element: ET.Element) -> str:
     return (parsed.parsed, parsed.search_keywords, parsed.is_deprecated)
 
 def parse_toplevel_desc(state: State, element: ET.Element):
-    # Verify that we didn't ignore any important info by accident
+    state.parsing_toplevel_desc = True
     parsed = parse_desc_internal(state, element)
+    state.parsing_toplevel_desc = False
+    # Verify that we didn't ignore any important info by accident
     assert not parsed.return_value and not parsed.return_values and not parsed.exceptions
     if parsed.params:
         logging.warning("{}: use @tparam instead of @param for documenting class templates, @param is ignored".format(state.current))
diff --git a/doxygen/test/contents_section_in_function/Doxyfile b/doxygen/test/contents_section_in_function/Doxyfile
new file mode 100644 (file)
index 0000000..471f68b
--- /dev/null
@@ -0,0 +1,13 @@
+INPUT                   = File.h
+QUIET                   = YES
+GENERATE_HTML           = NO
+GENERATE_LATEX          = NO
+GENERATE_XML            = YES
+XML_PROGRAMLISTING      = NO
+
+M_PAGE_FINE_PRINT       =
+M_THEME_COLOR           =
+M_FAVICON               =
+M_LINKS_NAVBAR1         =
+M_LINKS_NAVBAR2         =
+M_SEARCH_DISABLED       = YES
diff --git a/doxygen/test/contents_section_in_function/File.h b/doxygen/test/contents_section_in_function/File.h
new file mode 100644 (file)
index 0000000..1fb1712
--- /dev/null
@@ -0,0 +1,16 @@
+/** @file
+ * @brief A file
+ */
+
+/**
+@brief A function
+
+# A top-level header
+
+## A second-level header
+
+### A third-level header
+
+#### A fourth-level header
+*/
+void foo();
diff --git a/doxygen/test/contents_section_in_function/File_8h.html b/doxygen/test/contents_section_in_function/File_8h.html
new file mode 100644 (file)
index 0000000..92a9f75
--- /dev/null
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8" />
+  <title>File.h file | My Project</title>
+  <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400i,600,600i%7CSource+Code+Pro:400,400i,600" />
+  <link rel="stylesheet" href="m-dark+doxygen.compiled.css" />
+  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+</head>
+<body>
+<header><nav id="navigation">
+  <div class="m-container">
+    <div class="m-row">
+      <a href="index.html" id="m-navbar-brand" class="m-col-t-8 m-col-m-none m-left-m">My Project</a>
+    </div>
+  </div>
+</nav></header>
+<main><article>
+  <div class="m-container m-container-inflatable">
+    <div class="m-row">
+      <div class="m-col-l-10 m-push-l-1">
+        <h1>
+          File.h <span class="m-thin">file</span>
+        </h1>
+        <p>A file.</p>
+        <div class="m-block m-default">
+          <h3>Contents</h3>
+          <ul>
+            <li>
+              Reference
+              <ul>
+                <li><a href="#func-members">Functions</a></li>
+              </ul>
+            </li>
+          </ul>
+        </div>
+        <section id="func-members">
+          <h2><a href="#func-members">Functions</a></h2>
+          <dl class="m-dox">
+            <dt>
+              <span class="m-dox-wrap-bumper">void <a href="#ac07863d69ae41a4e395b31f73b35fbcd" class="m-dox">foo</a>(</span><span class="m-dox-wrap">)</span>
+            </dt>
+            <dd>A function.</dd>
+          </dl>
+        </section>
+        <section>
+          <h2>Function documentation</h2>
+          <section class="m-dox-details" id="ac07863d69ae41a4e395b31f73b35fbcd"><div>
+            <h3>
+              <span class="m-dox-wrap-bumper">void </span><span class="m-dox-wrap"><span class="m-dox-wrap-bumper"><a href="#ac07863d69ae41a4e395b31f73b35fbcd" class="m-dox-self">foo</a>(</span><span class="m-dox-wrap">)</span></span>
+            </h3>
+            <p>A function.</p>
+<h4>A top-level header</h4><h5>A second-level header</h5><h6>A third-level header</h6><h6>A fourth-level header</h6>
+          </div></section>
+        </section>
+      </div>
+    </div>
+  </div>
+</article></main>
+</body>
+</html>
index ac5b1d04d6e8844807ec5ca1c876db8a02193509..be1090e95ea4211f8f2cf4ed662f4718c697d933 100644 (file)
@@ -184,3 +184,11 @@ class SectionUnderscoreOne(IntegrationTestCase):
     def test(self):
         self.run_dox2html5(wildcard='indexpage.xml')
         self.assertEqual(*self.actual_expected_contents('index.html'))
+
+class SectionInFunction(IntegrationTestCase):
+    def __init__(self, *args, **kwargs):
+        super().__init__(__file__, 'section_in_function', *args, **kwargs)
+
+    def test(self):
+        self.run_dox2html5(wildcard='File_8h.xml')
+        self.assertEqual(*self.actual_expected_contents('File_8h.html'))