chiark / gitweb /
documentation/doxygen: parse inline namespaces.
authorVladimír Vondruš <mosra@centrum.cz>
Mon, 8 Jun 2020 22:15:10 +0000 (00:15 +0200)
committerVladimír Vondruš <mosra@centrum.cz>
Mon, 8 Jun 2020 22:27:47 +0000 (00:27 +0200)
12 files changed:
doc/documentation/doxygen.rst
documentation/doxygen.py
documentation/templates/doxygen/annotated.html
documentation/templates/doxygen/entry-namespace.html
documentation/templates/doxygen/namespace.html
documentation/templates/doxygen/namespaces.html
documentation/test_doxygen/compound_inline_namespace/Doxyfile [new file with mode: 0644]
documentation/test_doxygen/compound_inline_namespace/File.h [new file with mode: 0644]
documentation/test_doxygen/compound_inline_namespace/annotated.html [new file with mode: 0644]
documentation/test_doxygen/compound_inline_namespace/namespaceFoo_1_1Bar.html [new file with mode: 0644]
documentation/test_doxygen/compound_inline_namespace/namespaces.html [new file with mode: 0644]
documentation/test_doxygen/test_compound.py

index 9181f38bc5649ef8d5d09dfb211b278d2ac0dfde..7329c8760a82013c361f257a4a0b969aac8d5118 100644 (file)
@@ -867,6 +867,18 @@ and you have to enable the :ini:`EXTRACT_PRIV_VIRTUAL` Doxyfile option:
     with :gh:`doxygen/doxygen#6729` integrated, the 1.8.15 release does not
     have this option yet.
 
+`Inline namespaces`_
+--------------------
+
+:cpp:`inline namespace`\ s are marked as such in class/namespace index pages,
+namespace documentation pages and nested namespace lists. Doxygen additionally
+flattens those, so their contents appear in the parent namespace as well.
+
+.. note-warning:: Doxygen patches
+
+    This feature requires :gh:`doxygen/doxygen#7828` to work (not merged to
+    Doxygen master yet).
+
 `Include files`_
 ----------------
 
@@ -1669,6 +1681,8 @@ Property                                Description
 :py:`compound.footer_navigation`        Footer navigation of a page. See
                                         `Navigation properties`_ for details.
 :py:`compound.brief`                    Brief description. Can be empty. [1]_
+:py:`compound.is_inline`                Whether the namespace is :cpp:`inline`.
+                                        Set only for namespaces.
 :py:`compound.is_final`                 Whether the class is :cpp:`final`. Set
                                         only for classes.
 :py:`compound.deprecated`               Deprecation status [7]_
@@ -1894,6 +1908,7 @@ Property                        Description
 :py:`namespace.deprecated`      Deprecation status [7]_
 :py:`namespace.since`           Since which version the namespace is available
                                 [8]_
+:py:`namespace.is_inline`       Whether this is an :cpp:`inline` namespace
 =============================== ===============================================
 
 `Class properties`_
@@ -2327,6 +2342,8 @@ Property                        Description
 :py:`i.brief`                   Brief documentation
 :py:`i.deprecated`              Deprecation status [7]_
 :py:`i.since`                   Since which version the entry is available [8]_
+:py:`i.is_inline`               Whether this is an :cpp:`inline` namespace. Set
+                                only for namespaces.
 :py:`i.is_final`                Whether the class is :cpp:`final`. Set only for
                                 classes.
 :py:`i.has_nestable_children`   If the list has nestable children (i.e., dirs
index 21b8ee32d9839a18850dd6032f378d50f10cb6ab..464758375a99b058283704c47b5e0ca725dd1242 100755 (executable)
@@ -2227,6 +2227,10 @@ def extract_metadata(state: State, xml):
                 compound.deprecated = 'deprecated'
             break
 
+    # Inline namespaces
+    if compound.kind == 'namespace':
+        compound.is_inline = compounddef.attrib.get('inline') == 'yes'
+
     # Final classes
     if compound.kind in ['struct', 'class', 'union']:
         compound.is_final = compounddef.attrib.get('final') == 'yes'
@@ -2539,6 +2543,10 @@ def parse_xml(state: State, xml: str):
     else:
         state.current_prefix = []
 
+    # Inline namespaces
+    if compound.kind == 'namespace':
+        compound.is_inline = compounddef.attrib.get('inline') == 'yes'
+
     # Final classes
     if compound.kind in ['struct', 'class', 'union']:
         compound.is_final = compounddef.attrib.get('final') == 'yes'
@@ -2659,6 +2667,7 @@ def parse_xml(state: State, xml: str):
                     namespace.brief = symbol.brief
                     namespace.deprecated = symbol.deprecated
                     namespace.since = symbol.since
+                    namespace.is_inline = compounddef_child.attrib.get('inline') == 'yes'
                     compound.namespaces += [namespace]
 
                 else:
@@ -3253,6 +3262,8 @@ def parse_index_xml(state: State, xml):
         entry.deprecated = compound.deprecated
         entry.since = compound.since
         entry.has_nestable_children = False
+        if compound.kind == 'namespace':
+            entry.is_inline = compound.is_inline
         if compound.kind in ['class', 'struct', 'union']:
             entry.is_final = compound.is_final
 
index c8ed0a78dd45f7f9565a3bd3bd5673525c152643..50fa77b9f8e29740e2d4a32fb9d299fa4b28fc19 100644 (file)
@@ -7,13 +7,13 @@
           {% for i in index.symbols recursive %}
           {% if i.children %}
           <li class="m-doc-collapsible{% if loop.depth > CLASS_INDEX_EXPAND_LEVELS or (i.kind != 'namespace' and not CLASS_INDEX_EXPAND_INNER) %} collapsed{% endif %}">
-            <a href="#" onclick="return toggle(this)">{{ i.kind }}</a> <a href="{{ i.url }}" class="m-doc">{{ i.name }}</a>{% if i.is_final %} <span class="m-label m-flat m-warning">final</span>{% endif %}{% if i.deprecated %} <span class="m-label m-danger">{{ i.deprecated }}</span>{% endif %}{% if i.since %} {{ i.since }}{% endif %} <span class="m-doc">{{ i.brief }}</span>
+            <a href="#" onclick="return toggle(this)">{{ i.kind }}</a> <a href="{{ i.url }}" class="m-doc">{{ i.name }}</a>{% if i.is_inline %} <span class="m-label m-flat m-info">inline</span>{% endif %}{% if i.is_final %} <span class="m-label m-flat m-warning">final</span>{% endif %}{% if i.deprecated %} <span class="m-label m-danger">{{ i.deprecated }}</span>{% endif %}{% if i.since %} {{ i.since }}{% endif %} <span class="m-doc">{{ i.brief }}</span>
             <ul class="m-doc">
 {{ loop(i.children)|rtrim|indent(4, true) }}
             </ul>
           </li>
           {% else %}
-          <li>{{ i.kind }} <a href="{{ i.url }}" class="m-doc">{{ i.name }}</a>{% if i.is_final %} <span class="m-label m-flat m-warning">final</span>{% endif %}{% if i.deprecated %} <span class="m-label m-danger">{{ i.deprecated }}</span>{% endif %}{% if i.since %} {{ i.since }}{% endif %} <span class="m-doc">{{ i.brief }}</span></li>
+          <li>{{ i.kind }} <a href="{{ i.url }}" class="m-doc">{{ i.name }}</a>{% if i.is_inline %} <span class="m-label m-flat m-info">inline</span>{% endif %}{% if i.is_final %} <span class="m-label m-flat m-warning">final</span>{% endif %}{% if i.deprecated %} <span class="m-label m-danger">{{ i.deprecated }}</span>{% endif %}{% if i.since %} {{ i.since }}{% endif %} <span class="m-doc">{{ i.brief }}</span></li>
           {% endif %}
           {% endfor %}
         </ul>
index 9e90087bafc1e5a124a0a8817be0984b09565b3d..e0fb9ee70d9e6b791562f03f3b444f2d5296b87f 100644 (file)
@@ -1,2 +1,2 @@
-            <dt>namespace <a href="{{ namespace.url }}" class="m-doc">{{ namespace.name }}</a>{% if namespace.deprecated %} <span class="m-label m-danger">{{ namespace.deprecated }}</span>{% endif %}{% if namespace.since %} {{ namespace.since }}{% endif %}</dt>
+            <dt>namespace <a href="{{ namespace.url }}" class="m-doc">{{ namespace.name }}</a>{% if namespace.is_inline %} <span class="m-label m-flat m-info">inline</span>{% endif %}{% if namespace.deprecated %} <span class="m-label m-danger">{{ namespace.deprecated }}</span>{% endif %}{% if namespace.since %} {{ namespace.since }}{% endif %}</dt>
             <dd>{{ namespace.brief }}</dd>
index 9cab47fccad1f2edd80ad584751e9f7fc61aba4d..267d439962fded723b9db25ec7e0088642bb6494 100644 (file)
@@ -4,7 +4,7 @@
 
 {% block header %}
         <h1>
-          {%+ for name, target in compound.breadcrumb[:-1] %}<span class="m-breadcrumb"><a href="{{ target }}">{{ name }}</a>::<wbr/></span>{% endfor %}{{ compound.breadcrumb[-1][0] }} <span class="m-thin">namespace</span>{% if compound.since %} {{ compound.since }}{% endif %}
+          {%+ for name, target in compound.breadcrumb[:-1] %}<span class="m-breadcrumb"><a href="{{ target }}">{{ name }}</a>::<wbr/></span>{% endfor %}{{ compound.breadcrumb[-1][0] }} <span class="m-thin">namespace</span>{% if compound.is_inline %} <span class="m-label m-flat m-info">inline</span>{% endif %}{% if compound.since %} {{ compound.since }}{% endif %}
           {# need an explicit space here otherwise the newline gets removed #}
 
           {% if compound.include %}
index 5ff416bff5e7895f083afd2e03536883861faa7d..ca8748239b643e2aa7c33ef0e839ee5eef3354d3 100644 (file)
@@ -7,13 +7,13 @@
           {% for i in index.symbols|selectattr('kind', 'equalto', 'namespace') recursive %}
           {% if i.has_nestable_children %}
           <li class="m-doc-collapsible">
-            <a href="#" onclick="return toggle(this)">{{ i.kind }}</a> <a href="{{ i.url }}" class="m-doc">{{ i.name }}</a>{% if i.deprecated %} <span class="m-label m-danger">{{ i.deprecated }}</span>{% endif %}{% if i.since %} {{ i.since }}{% endif %} <span class="m-doc">{{ i.brief }}</span>
+            <a href="#" onclick="return toggle(this)">{{ i.kind }}</a> <a href="{{ i.url }}" class="m-doc">{{ i.name }}</a>{% if i.is_inline %} <span class="m-label m-flat m-info">inline</span>{% endif %}{% if i.deprecated %} <span class="m-label m-danger">{{ i.deprecated }}</span>{% endif %}{% if i.since %} {{ i.since }}{% endif %} <span class="m-doc">{{ i.brief }}</span>
             <ul class="m-doc">
 {{ loop(i.children|selectattr('kind', 'equalto', 'namespace'))|rtrim|indent(4, true) }}
             </ul>
           </li>
           {% else %}
-          <li>{{ i.kind }} <a href="{{ i.url }}" class="m-doc">{{ i.name }}</a>{% if i.deprecated %} <span class="m-label m-danger">{{ i.deprecated }}</span>{% endif %}{% if i.since %} {{ i.since }}{% endif %} <span class="m-doc">{{ i.brief }}</span></li>
+          <li>{{ i.kind }} <a href="{{ i.url }}" class="m-doc">{{ i.name }}</a>{% if i.is_inline %} <span class="m-label m-flat m-info">inline</span>{% endif %}{% if i.deprecated %} <span class="m-label m-danger">{{ i.deprecated }}</span>{% endif %}{% if i.since %} {{ i.since }}{% endif %} <span class="m-doc">{{ i.brief }}</span></li>
           {% endif %}
           {% endfor %}
         </ul>
diff --git a/documentation/test_doxygen/compound_inline_namespace/Doxyfile b/documentation/test_doxygen/compound_inline_namespace/Doxyfile
new file mode 100644 (file)
index 0000000..9752e60
--- /dev/null
@@ -0,0 +1,15 @@
+INPUT                   = File.h
+QUIET                   = YES
+GENERATE_HTML           = NO
+GENERATE_LATEX          = NO
+GENERATE_XML            = YES
+XML_PROGRAMLISTING      = NO
+CASE_SENSE_NAMES        = YES
+
+##! M_PAGE_FINE_PRINT   =
+##! M_THEME_COLOR       =
+##! M_FAVICON           =
+##! M_LINKS_NAVBAR1     =
+##! M_LINKS_NAVBAR2     =
+##! M_SEARCH_DISABLED   = YES
+##! M_CLASS_TREE_EXPAND_LEVELS = 3
diff --git a/documentation/test_doxygen/compound_inline_namespace/File.h b/documentation/test_doxygen/compound_inline_namespace/File.h
new file mode 100644 (file)
index 0000000..258dbce
--- /dev/null
@@ -0,0 +1,15 @@
+/** @brief A namespace */
+namespace Foo {
+
+/** @brief An inline nested namespace */
+inline namespace Bar {
+
+/** @brief Another inline namespace */
+inline namespace Baz {}
+
+}
+
+/** @brief A thing */
+struct Thing {};
+
+}
diff --git a/documentation/test_doxygen/compound_inline_namespace/annotated.html b/documentation/test_doxygen/compound_inline_namespace/annotated.html
new file mode 100644 (file)
index 0000000..dbf61da
--- /dev/null
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8" />
+  <title>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+documentation.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>Classes</h2>
+        <ul class="m-doc">
+          <li class="m-doc-collapsible">
+            <a href="#" onclick="return toggle(this)">namespace</a> <a href="namespaceFoo.html" class="m-doc">Foo</a> <span class="m-doc">A namespace.</span>
+            <ul class="m-doc">
+              <li class="m-doc-collapsible">
+                <a href="#" onclick="return toggle(this)">namespace</a> <a href="namespaceFoo_1_1Bar.html" class="m-doc">Bar</a> <span class="m-label m-flat m-info">inline</span> <span class="m-doc">An inline nested namespace.</span>
+                <ul class="m-doc">
+                  <li>namespace <a href="namespaceFoo_1_1Bar_1_1Baz.html" class="m-doc">Baz</a> <span class="m-label m-flat m-info">inline</span> <span class="m-doc">Another inline namespace.</span></li>
+                </ul>
+              </li>
+              <li>struct <a href="structFoo_1_1Thing.html" class="m-doc">Thing</a> <span class="m-doc">A thing.</span></li>
+            </ul>
+          </li>
+        </ul>
+        <script>
+        function toggle(e) {
+            e.parentElement.className = e.parentElement.className == 'm-doc-collapsible' ?
+                'm-doc-expansible' : 'm-doc-collapsible';
+            return false;
+        }
+        /* Collapse all nodes marked as such. Doing it via JS instead of
+           directly in markup so disabling it doesn't harm usability. The list
+           is somehow regenerated on every iteration and shrinks as I change
+           the classes. It's not documented anywhere and I'm not sure if this
+           is the same across browsers, so I am going backwards in that list to
+           be sure. */
+        var collapsed = document.getElementsByClassName("collapsed");
+        for(var i = collapsed.length - 1; i >= 0; --i)
+            collapsed[i].className = 'm-doc-expansible';
+        </script>
+      </div>
+    </div>
+  </div>
+</article></main>
+</body>
+</html>
diff --git a/documentation/test_doxygen/compound_inline_namespace/namespaceFoo_1_1Bar.html b/documentation/test_doxygen/compound_inline_namespace/namespaceFoo_1_1Bar.html
new file mode 100644 (file)
index 0000000..977f05f
--- /dev/null
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8" />
+  <title>Foo::Bar namespace | 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+documentation.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>
+          <span class="m-breadcrumb"><a href="namespaceFoo.html">Foo</a>::<wbr/></span>Bar <span class="m-thin">namespace</span> <span class="m-label m-flat m-info">inline</span>
+        </h1>
+        <p>An inline nested namespace.</p>
+        <div class="m-block m-default">
+          <h3>Contents</h3>
+          <ul>
+            <li>
+              Reference
+              <ul>
+                <li><a href="#namespaces">Namespaces</a></li>
+              </ul>
+            </li>
+          </ul>
+        </div>
+        <section id="namespaces">
+          <h2><a href="#namespaces">Namespaces</a></h2>
+          <dl class="m-doc">
+            <dt>namespace <a href="namespaceFoo_1_1Bar_1_1Baz.html" class="m-doc">Baz</a> <span class="m-label m-flat m-info">inline</span></dt>
+            <dd>Another inline namespace.</dd>
+          </dl>
+        </section>
+      </div>
+    </div>
+  </div>
+</article></main>
+</body>
+</html>
diff --git a/documentation/test_doxygen/compound_inline_namespace/namespaces.html b/documentation/test_doxygen/compound_inline_namespace/namespaces.html
new file mode 100644 (file)
index 0000000..85a848a
--- /dev/null
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8" />
+  <title>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+documentation.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>Namespaces</h2>
+        <ul class="m-doc">
+          <li class="m-doc-collapsible">
+            <a href="#" onclick="return toggle(this)">namespace</a> <a href="namespaceFoo.html" class="m-doc">Foo</a> <span class="m-doc">A namespace.</span>
+            <ul class="m-doc">
+              <li class="m-doc-collapsible">
+                <a href="#" onclick="return toggle(this)">namespace</a> <a href="namespaceFoo_1_1Bar.html" class="m-doc">Bar</a> <span class="m-label m-flat m-info">inline</span> <span class="m-doc">An inline nested namespace.</span>
+                <ul class="m-doc">
+                  <li>namespace <a href="namespaceFoo_1_1Bar_1_1Baz.html" class="m-doc">Baz</a> <span class="m-label m-flat m-info">inline</span> <span class="m-doc">Another inline namespace.</span></li>
+                </ul>
+              </li>
+            </ul>
+          </li>
+        </ul>
+        <script>
+        function toggle(e) {
+            e.parentElement.className = e.parentElement.className == 'm-doc-collapsible' ?
+                'm-doc-expansible' : 'm-doc-collapsible';
+            return false;
+        }
+        /* Collapse all nodes marked as such. Doing it via JS instead of
+           directly in markup so disabling it doesn't harm usability. The list
+           is somehow regenerated on every iteration and shrinks as I change
+           the classes. It's not documented anywhere and I'm not sure if this
+           is the same across browsers, so I am going backwards in that list to
+           be sure. */
+        var collapsed = document.getElementsByClassName("collapsed");
+        for(var i = collapsed.length - 1; i >= 0; --i)
+            collapsed[i].className = 'm-doc-expansible';
+        </script>
+      </div>
+    </div>
+  </div>
+</article></main>
+</body>
+</html>
index efcd7d1b110001629d5aa261244739cf3a97dff6..97421bd63fd7acb51995ac85bcd518d0117a47d1 100644 (file)
@@ -319,3 +319,15 @@ class BaseTemplateClasses(IntegrationTestCase):
     def test(self):
         self.run_doxygen(wildcard='*.xml')
         self.assertEqual(*self.actual_expected_contents('structNamespace_1_1MyClass.html'))
+
+class InlineNamespace(IntegrationTestCase):
+    def test(self):
+        self.run_doxygen(wildcard='*.xml')
+
+        with open(os.path.join(self.path, 'xml/namespaceFoo_1_1Bar.xml')) as f:
+            if 'kind="namespace" inline="yes"' not in f.read():
+                self.skipTest("Doxygen doesn't support inline namespaces here")
+
+        self.assertEqual(*self.actual_expected_contents('namespaceFoo_1_1Bar.html'))
+        self.assertEqual(*self.actual_expected_contents('annotated.html'))
+        self.assertEqual(*self.actual_expected_contents('namespaces.html'))