chiark / gitweb /
doxygen: implement \m_keyword, \m_keywords and \m_enum_values_as_keywords.
authorVladimír Vondruš <mosra@centrum.cz>
Mon, 5 Feb 2018 00:10:47 +0000 (01:10 +0100)
committerVladimír Vondruš <mosra@centrum.cz>
Mon, 5 Feb 2018 00:50:28 +0000 (01:50 +0100)
doc/doxygen.rst
doxygen/dox2html5.py
doxygen/test/search/Dir/File.h
doxygen/test/search/Doxyfile
doxygen/test/test_search.py

index 9e285926d85523b18b252fdbc1dd663bca67f03d..1fe1e1c7064a18fb8c3f02359a96ebd8a33be40e 100644 (file)
@@ -687,7 +687,10 @@ following to your ``Doxyfile-mcss``:
         "m_endspan=@xmlonly</mcss:span>@endxmlonly" \
         "m_class{1}=@xmlonly<mcss:class xmlns:mcss=\"http://mcss.mosra.cz/doxygen/\" mcss:class=\"\1\" />@endxmlonly" \
         "m_footernavigation=@xmlonly<mcss:footernavigation xmlns:mcss=\"http://mcss.mosra.cz/doxygen/\" />@endxmlonly" \
-        "m_examplenavigation{2}=@xmlonly<mcss:examplenavigation xmlns:mcss=\"http://mcss.mosra.cz/doxygen/\" mcss:page=\"\1\" mcss:prefix=\"\2\" />@endxmlonly"
+        "m_examplenavigation{2}=@xmlonly<mcss:examplenavigation xmlns:mcss=\"http://mcss.mosra.cz/doxygen/\" mcss:page=\"\1\" mcss:prefix=\"\2\" />@endxmlonly" \
+        "m_keywords{1}=@xmlonly<mcss:search xmlns:mcss=\"http://mcss.mosra.cz/doxygen/\" mcss:keywords=\"\1\" />@endxmlonly" \
+        "m_keyword{3}=@xmlonly<mcss:search xmlns:mcss=\"http://mcss.mosra.cz/doxygen/\" mcss:keyword=\"\1\" mcss:title=\"\2\" mcss:suffix-length=\"\3\" />@endxmlonly" \
+        "m_enum_values_as_keywords=@xmlonly<mcss:search xmlns:mcss=\"http://mcss.mosra.cz/doxygen/\" mcss:enum-values-as-keywords=\"true\" />@endxmlonly"
 
 If you need backwards compatibility with stock Doxygen HTML output, just make
 the aliases empty in your original ``Doxyfile``. Note that you can rename the
@@ -702,7 +705,10 @@ aliases however you want to fit your naming scheme.
         "m_endspan=" \
         "m_class{1}=" \
         "m_footernavigation=" \
-        "m_examplenavigation{2}"
+        "m_examplenavigation{2}" \
+        "m_keywords{1}=" \
+        "m_keyword{3}=" \
+        "m_enum_values_as_keywords="
 
 With ``@m_div`` and ``@m_span`` it's possible to wrap individual paragraphs or
 inline text in :html:`<div>` / :html:`<span>` and add CSS classes to them.
@@ -771,15 +777,45 @@ to discover which example files belong together). Example usage --- the
 ``@m_examplenavigation`` and ``@m_footernavigation`` commands are simply
 appended the an existing ``@example`` command.
 
-.. code-figure::
+.. code:: c++
 
-    .. code:: c++
+    /**
+    @example helloworld/CMakeLists.txt @m_examplenavigation{example,helloworld/} @m_footernavigation
+    @example helloworld/configure.h.cmake @m_examplenavigation{example,helloworld/} @m_footernavigation
+    @example helloworld/main.cpp @m_examplenavigation{example,helloworld/} @m_footernavigation
+    */
 
-        /**
-        @example helloworld/CMakeLists.txt @m_examplenavigation{example,helloworld/} @m_footernavigation
-        @example helloworld/configure.h.cmake @m_examplenavigation{example,helloworld/} @m_footernavigation
-        @example helloworld/main.cpp @m_examplenavigation{example,helloworld/} @m_footernavigation
-        */
+The purpose of ``@m_keywords``, ``@m_keyword`` and ``@m_enum_values_as_keywords``
+command is to add further search keywords to given documented symbols. Use
+``@m_keywords`` to enter whitespace-separated list of keywords. Use ``@m_keyword``
+if you need to enter a keyword containing spaces, the optional second and third
+parameter allow you to specify a different title and suffix length. The
+``@m_enum_values_as_keywords`` command will add initializers of given enum
+values as keywords for each corresponding value, it's ignored when not used in
+enum description block. In the following example, an OpenGL wrapper API adds GL
+API names as keywords for easier discoverability, so e.g. the
+:cpp:`Texture2D::setStorage()` function is also found when typing
+``glTexStorage2D()`` into the search field, or the :cpp:`Renderer::Feature::DepthTest`
+enum value is found when entering :cpp:`GL_DEPTH_TEST`:
+
+.. code:: c++
+
+    /**
+     * @brief Set texture storage
+     *
+     * @m_keywords{glTexStorage2D() glTextureStorage2D()}
+     */
+    Texture2D& Texture2D::setStorage(...);
+
+    /**
+     * @brief Renderer feature
+     *
+     * @m_enum_values_as_keywords
+     */
+    enum class RendererFeature: GLenum {
+        /** Depth test */
+        DepthTest = GL_DEPTH_TEST
+    };
 
 `Customizing the template`_
 ===========================
index 5165d5ff1c3b1c9f2495dbdbdb434646d2b1b3c1..c87df8337cec028d316fd0a17026e9a7b123a633 100755 (executable)
@@ -443,6 +443,8 @@ def parse_desc_internal(state: State, element: ET.Element, immediate_parent: ET.
     out.add_css_class = None
     out.footer_navigation = False
     out.example_navigation = None
+    out.search_keywords = []
+    out.search_enum_values_as_keywords = False
     out.is_deprecated = False
 
     # DOXYGEN <PARA> PATCHING 1/4
@@ -714,9 +716,12 @@ def parse_desc_internal(state: State, element: ET.Element, immediate_parent: ET.
             # resetting here explicitly.
             add_css_class = parsed.add_css_class
 
-            # Bubble up also footer / example navigation, deprecation flag
+            # Bubble up also footer / example navigation, search keywords,
+            # deprecation flag
             if parsed.footer_navigation: out.footer_navigation = True
             if parsed.example_navigation: out.example_navigation = parsed.example_navigation
+            out.search_keywords += parsed.search_keywords
+            if parsed.search_enum_values_as_keywords: out.search_enum_values_as_keywords = True
             if parsed.is_deprecated: out.is_deprecated = True
 
             # Assert we didn't miss anything important
@@ -938,6 +943,26 @@ def parse_desc_internal(state: State, element: ET.Element, immediate_parent: ET.
             out.example_navigation = (i.attrib['{http://mcss.mosra.cz/doxygen/}page'],
                                       i.attrib['{http://mcss.mosra.cz/doxygen/}prefix'])
 
+        # Search-related stuff
+        elif i.tag == '{http://mcss.mosra.cz/doxygen/}search':
+            # Space-separated keyword list
+            if '{http://mcss.mosra.cz/doxygen/}keywords' in i.attrib:
+                out.search_keywords += [(keyword, '', 0) for keyword in i.attrib['{http://mcss.mosra.cz/doxygen/}keywords'].split(' ')]
+
+            # Keyword with custom result title
+            elif '{http://mcss.mosra.cz/doxygen/}keyword' in i.attrib:
+                out.search_keywords += [(
+                    i.attrib['{http://mcss.mosra.cz/doxygen/}keyword'],
+                    i.attrib['{http://mcss.mosra.cz/doxygen/}title'],
+                    int(i.attrib['{http://mcss.mosra.cz/doxygen/}suffix-length'] or '0'))]
+
+            # Add values of this enum as search keywords
+            elif '{http://mcss.mosra.cz/doxygen/}enum-values-as-keywords' in i.attrib:
+                out.search_enum_values_as_keywords = True
+
+            # Nothing else at the moment
+            else: assert False
+
         # Either block or inline
         elif i.tag == 'programlisting':
             assert element.tag == 'para' # is inside a paragraph :/
@@ -1193,14 +1218,14 @@ def parse_enum_desc(state: State, element: ET.Element) -> str:
     parsed.parsed += parse_desc(state, element.find('inbodydescription'))
     assert not parsed.templates and not parsed.params and not parsed.return_value
     assert not parsed.section # might be problematic
-    return (parsed.parsed, parsed.is_deprecated)
+    return (parsed.parsed, parsed.search_keywords, parsed.search_enum_values_as_keywords, parsed.is_deprecated)
 
 def parse_enum_value_desc(state: State, element: ET.Element) -> str:
     # Verify that we didn't ignore any important info by accident
     parsed = parse_desc_internal(state, element.find('detaileddescription'))
     assert not parsed.templates and not parsed.params and not parsed.return_value
     assert not parsed.section # might be problematic
-    return (parsed.parsed, parsed.is_deprecated)
+    return (parsed.parsed, parsed.search_keywords, parsed.is_deprecated)
 
 def parse_var_desc(state: State, element: ET.Element) -> str:
     # Verify that we didn't ignore any important info by accident
@@ -1208,7 +1233,7 @@ def parse_var_desc(state: State, element: ET.Element) -> str:
     parsed.parsed += parse_desc(state, element.find('inbodydescription'))
     assert not parsed.templates and not parsed.params and not parsed.return_value
     assert not parsed.section # might be problematic
-    return (parsed.parsed, parsed.is_deprecated)
+    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
@@ -1216,7 +1241,7 @@ def parse_toplevel_desc(state: State, element: ET.Element):
     assert not parsed.return_value
     if parsed.params:
         logging.warning("{}: use @tparam instead of @param for documenting class templates, @param is ignored".format(state.current))
-    return (parsed.parsed, parsed.templates, parsed.section[2] if parsed.section else '', parsed.footer_navigation, parsed.example_navigation, parsed.is_deprecated)
+    return (parsed.parsed, parsed.templates, parsed.section[2] if parsed.section else '', parsed.footer_navigation, parsed.example_navigation, parsed.search_keywords, parsed.is_deprecated)
 
 def parse_typedef_desc(state: State, element: ET.Element):
     # Verify that we didn't ignore any important info by accident
@@ -1224,14 +1249,14 @@ def parse_typedef_desc(state: State, element: ET.Element):
     parsed.parsed += parse_desc(state, element.find('inbodydescription'))
     assert not parsed.params and not parsed.return_value
     assert not parsed.section # might be problematic
-    return (parsed.parsed, parsed.templates, parsed.is_deprecated)
+    return (parsed.parsed, parsed.templates, parsed.search_keywords, parsed.is_deprecated)
 
 def parse_func_desc(state: State, element: ET.Element):
     # Verify that we didn't ignore any important info by accident
     parsed = parse_desc_internal(state, element.find('detaileddescription'))
     parsed.parsed += parse_desc(state, element.find('inbodydescription'))
     assert not parsed.section # might be problematic
-    return (parsed.parsed, parsed.templates, parsed.params, parsed.return_value, parsed.is_deprecated)
+    return (parsed.parsed, parsed.templates, parsed.params, parsed.return_value, parsed.search_keywords, parsed.is_deprecated)
 
 def parse_define_desc(state: State, element: ET.Element):
     # Verify that we didn't ignore any important info by accident
@@ -1239,7 +1264,7 @@ def parse_define_desc(state: State, element: ET.Element):
     parsed.parsed += parse_desc(state, element.find('inbodydescription'))
     assert not parsed.templates
     assert not parsed.section # might be problematic
-    return (parsed.parsed, parsed.params, parsed.return_value, parsed.is_deprecated)
+    return (parsed.parsed, parsed.params, parsed.return_value, parsed.search_keywords, parsed.is_deprecated)
 
 def parse_inline_desc(state: State, element: ET.Element) -> str:
     if element is None: return ''
@@ -1259,7 +1284,7 @@ def parse_enum(state: State, element: ET.Element):
     enum.name = element.find('name').text
     if enum.name.startswith('@'): enum.name = '(anonymous)'
     enum.brief = parse_desc(state, element.find('briefdescription'))
-    enum.description, enum.is_deprecated = parse_enum_desc(state, element)
+    enum.description, search_keywords, search_enum_values_as_keywords, enum.is_deprecated = parse_enum_desc(state, element)
     enum.is_protected = element.attrib['prot'] == 'protected'
     enum.is_strong = False
     if 'strong' in element.attrib:
@@ -1276,7 +1301,7 @@ def parse_enum(state: State, element: ET.Element):
         value.initializer = html.escape(enumvalue.findtext('initializer', ''))
         if ''.join(enumvalue.find('briefdescription').itertext()).strip():
             logging.warning("{}: ignoring brief description of enum value {}::{}".format(state.current, enum.name, value.name))
-        value.description, value.is_deprecated = parse_enum_value_desc(state, enumvalue)
+        value.description, value_search_keywords, value.is_deprecated = parse_enum_value_desc(state, enumvalue)
         if value.description:
             enum.has_value_details = True
             if not state.doxyfile['M_SEARCH_DISABLED']:
@@ -1285,6 +1310,9 @@ def parse_enum(state: State, element: ET.Element):
                 result.url = state.current_url + '#' + value.id
                 result.prefix = state.current_prefix + [enum.name]
                 result.name = value.name
+                result.keywords = value_search_keywords
+                if search_enum_values_as_keywords and value.initializer.startswith('='):
+                    result.keywords += [(value.initializer[1:].lstrip(), '', 0)]
                 state.search += [result]
         enum.values += [value]
 
@@ -1296,6 +1324,7 @@ def parse_enum(state: State, element: ET.Element):
             result.url = state.current_url + '#' + enum.id
             result.prefix = state.current_prefix
             result.name = enum.name
+            result.keywords = search_keywords
             state.search += [result]
         return enum
     return None
@@ -1347,7 +1376,7 @@ def parse_typedef(state: State, element: ET.Element):
     typedef.args = parse_type(state, element.find('argsstring'))
     typedef.name = element.find('name').text
     typedef.brief = parse_desc(state, element.find('briefdescription'))
-    typedef.description, templates, typedef.is_deprecated = parse_typedef_desc(state, element)
+    typedef.description, templates, search_keywords, typedef.is_deprecated = parse_typedef_desc(state, element)
     typedef.is_protected = element.attrib['prot'] == 'protected'
     typedef.has_template_details, typedef.templates = parse_template_params(state, element.find('templateparamlist'), templates)
 
@@ -1358,6 +1387,7 @@ def parse_typedef(state: State, element: ET.Element):
         result.url = state.current_url + '#' + typedef.id
         result.prefix = state.current_prefix
         result.name = typedef.name
+        result.keywords = search_keywords
         state.search += [result]
         return typedef
     return None
@@ -1370,7 +1400,7 @@ def parse_func(state: State, element: ET.Element):
     func.type = parse_type(state, element.find('type'))
     func.name = fix_type_spacing(html.escape(element.find('name').text))
     func.brief = parse_desc(state, element.find('briefdescription'))
-    func.description, templates, params, func.return_value, func.is_deprecated = parse_func_desc(state, element)
+    func.description, templates, params, func.return_value, search_keywords, func.is_deprecated = parse_func_desc(state, element)
 
     # Extract function signature to prefix, suffix and various flags. Important
     # things affecting caller such as static or const (and rvalue overloads)
@@ -1461,6 +1491,7 @@ def parse_func(state: State, element: ET.Element):
             result.url = state.current_url + '#' + func.id
             result.prefix = state.current_prefix
             result.name = func.name
+            result.keywords = search_keywords
             result.params = [param.type for param in func.params]
             result.suffix = func.suffix
             state.search += [result]
@@ -1483,7 +1514,7 @@ def parse_var(state: State, element: ET.Element):
     var.is_private = element.attrib['prot'] == 'private'
     var.name = element.find('name').text
     var.brief = parse_desc(state, element.find('briefdescription'))
-    var.description, var.is_deprecated = parse_var_desc(state, element)
+    var.description, search_keywords, var.is_deprecated = parse_var_desc(state, element)
 
     var.has_details = not not var.description
     if var.brief or var.has_details:
@@ -1493,6 +1524,7 @@ def parse_var(state: State, element: ET.Element):
             result.url = state.current_url + '#' + var.id
             result.prefix = state.current_prefix
             result.name = var.name
+            result.keywords = search_keywords
             state.search += [result]
         return var
     return None
@@ -1504,8 +1536,7 @@ def parse_define(state: State, element: ET.Element):
     define.id = extract_id(element)
     define.name = element.find('name').text
     define.brief = parse_desc(state, element.find('briefdescription'))
-    define.description, params, define.return_value, define.is_deprecated = parse_define_desc(state, element)
-
+    define.description, params, define.return_value, search_keywords, define.is_deprecated = parse_define_desc(state, element)
     define.has_param_details = False
     define.params = None
     for p in element.findall('param'):
@@ -1531,6 +1562,7 @@ def parse_define(state: State, element: ET.Element):
             result.url = state.current_url + '#' + define.id
             result.prefix = []
             result.name = define.name
+            result.keywords = search_keywords
             result.params = None if define.params is None else [param[0] for param in define.params]
             state.search += [result]
         return define
@@ -1758,6 +1790,12 @@ def build_search_data(state: State, merge_subtrees=True, add_lookahead_barriers=
                 if hasattr(result, 'params') and result.params is not None:
                     trie.insert(name.lower() + '()', index_args, lookahead_barriers=lookahead_barriers + [len(name)] if add_lookahead_barriers else [])
 
+        # Add keyword aliases for this symbol
+        for search, title, suffix_length in result.keywords:
+            if not title: title = search
+            keyword_index = map.add(title, '', alias=index, suffix_length=suffix_length)
+            trie.insert(search.lower(), keyword_index)
+
     return serialize_search_data(trie, map, merge_subtrees=merge_subtrees, merge_prefixes=merge_prefixes)
 
 def base85encode_search_data(data: bytearray) -> bytearray:
@@ -1807,7 +1845,7 @@ def parse_xml(state: State, xml: str):
     compound.has_template_details = False
     compound.templates = None
     compound.brief = parse_desc(state, compounddef.find('briefdescription'))
-    compound.description, templates, compound.sections, footer_navigation, example_navigation, compound.is_deprecated = parse_toplevel_desc(state, compounddef.find('detaileddescription'))
+    compound.description, templates, compound.sections, footer_navigation, example_navigation, search_keywords, compound.is_deprecated = parse_toplevel_desc(state, compounddef.find('detaileddescription'))
     compound.example_navigation = None
     compound.footer_navigation = None
     compound.modules = []
@@ -2350,6 +2388,7 @@ def parse_xml(state: State, xml: str):
         result.url = compound.url
         result.prefix = state.current_prefix[:-1]
         result.name = state.current_prefix[-1]
+        result.keywords = search_keywords
         state.search += [result]
 
     parsed = Empty()
index 48eb54afd5760d92ba5cbda8403009d6309f22ed..176292fd14493d91e35c99a4c3570c570b2dff5f 100644 (file)
@@ -1,18 +1,34 @@
 /** @dir /Dir
  * @brief A directory
+ *
+ * @m_keywords{glDirectory() glDir() GL_DIR}
  */
 
 /** @file
  * @brief A file
+ *
+ * @m_keywords{glFile()}
  */
 
-/** @brief A namespace */
+/**
+ * @brief A namespace
+ *
+ * @m_keywords{glNamespace()}
+ */
 namespace Namespace {
 
-/** @brief A class */
+/**
+ * @brief A class
+ *
+ * @m_keywords{glClass()}
+ */
 class Class {
     public:
-        /** @brief Function without arguments */
+        /**
+         * @brief Function without arguments
+         *
+         * @m_keywords{glFoo()}
+         */
         void foo();
 
         void foo() const; /**< @overload */
@@ -23,32 +39,64 @@ class Class {
         void foo(const Enum& first, Typedef second);
 };
 
-/** @brief A variable */
+/**
+ * @brief A variable
+ *
+ * @m_keyword{min(),GLSL: min(),2}
+ */
 constexpr int Variable = 5;
 
-/** @brief A typedef */
+/**
+ * @brief A typedef
+ *
+ * @m_keywords{GL_TYPEDEF}
+ */
 typedef int Typedef;
 
-/** @brief An enum */
+/**
+ * @brief An enum
+ *
+ * @m_keywords{GL_ENUM}
+ * @m_enum_values_as_keywords
+ */
 enum class Enum {
-    Value = 15  /**< Enum value */
+    /**
+     * Enum value
+     *
+     * @m_keywords{GL_ENUM_VALUE_EXT}
+     */
+    Value = GL_ENUM_VALUE
 };
 
 /** @defgroup group A group
+ *
+ * @m_keywords{GL_GROUP}
  * @{
  */
 
-/** @brief An union */
+/**
+ * @brief An union
+ *
+ * @m_keywords{glUnion()}
+ */
 union Union {};
 
-/** @brief A struct */
+/**
+ * @brief A struct
+ *
+ * @m_keywords{glStruct()}
+ */
 struct Struct {};
 
 /*@}*/
 
 }
 
-/** @brief A macro */
+/**
+ * @brief A macro
+ *
+ * @m_keyword{glMacro(),,}
+ */
 #define MACRO
 
 /** @brief Macro function */
index f25fc022438f6d746d4b7195c4f5aaa296aed7d6..0e77c509fafe0b478abe057914c5052bbc5daa09 100644 (file)
@@ -5,6 +5,10 @@ GENERATE_LATEX          = NO
 GENERATE_XML            = YES
 XML_PROGRAMLISTING      = NO
 EXAMPLE_PATH            = .
+ALIASES                 = \
+    "m_keywords{1}=@xmlonly<mcss:search xmlns:mcss=\"http://mcss.mosra.cz/doxygen/\" mcss:keywords=\"\1\" />@endxmlonly" \
+    "m_keyword{3}=@xmlonly<mcss:search xmlns:mcss=\"http://mcss.mosra.cz/doxygen/\" mcss:keyword=\"\1\" mcss:title=\"\2\" mcss:suffix-length=\"\3\" />@endxmlonly" \
+    "m_enum_values_as_keywords=@xmlonly<mcss:search xmlns:mcss=\"http://mcss.mosra.cz/doxygen/\" mcss:enum-values-as-keywords=\"true\" />@endxmlonly"
 
 M_PAGE_FINE_PRINT       =
 M_THEME_COLOR           =
index 9b0b0ca31afd2f5ed2134fc6218ff900ea7116ed..6c7cd2bb3fac17d1237db7ae78fc2477d8e5775c 100755 (executable)
@@ -374,133 +374,165 @@ class Search(IntegrationTestCase):
             serialized = f.read()
             search_data_pretty = pretty_print(serialized)[0]
         #print(search_data_pretty)
-        self.assertEqual(len(serialized), 3704)
+        self.assertEqual(len(serialized), 4570)
         self.assertEqual(search_data_pretty, """
 deprecated_macro [0]
 ||        |     ($
 ||        |      ) [1]
-||        dir [19]
+||        dir [23]
 ||        |  /$
 ||        |   deprecatedfile.h [2]
 ||        file.h [2]
-||        |oo [29]
+||        |oo [37]
 ||        || ($
-||        ||  ) [30]
-||         list [18]
-||        namespace [31]
+||        ||  ) [38]
+||         list [22]
+||        namespace [39]
 ||        |        :$
-||        |         :deprecatedenum [24]
+||        |         :deprecatedenum [32]
 ||        |          |         |   :$
-||        |          |         |    :value [23]
-||        |          |         typedef [27]
-||        |          |         variable [28]
-||        |          |         foo [29]
+||        |          |         |    :value [31]
+||        |          |         typedef [35]
+||        |          |         variable [36]
+||        |          |         foo [37]
 ||        |          |         |  ($
-||        |          |         |   ) [30]
-||        |          |         class [38]
-||        |          |         struct [39]
-||        |          |         union [42]
-||        |          enum [26]
+||        |          |         |   ) [38]
+||        |          |         class [52]
+||        |          |         struct [53]
+||        |          |         union [57]
+||        |          enum [34]
 ||        |          |   :$
-||        |          |    :deprecatedvalue [25]
-||        enum [24]
+||        |          |    :deprecatedvalue [33]
+||        enum [32]
 ||        |   :$
-||        |    :value [23]
-||        value [25]
-||        | riable [28]
-||        typedef [27]
-||        class [38]
-||        struct [39]
-||        union [42]
-|ir [20]
+||        |    :value [31]
+||        value [33]
+||        | riable [36]
+||        typedef [35]
+||        class [52]
+||        struct [53]
+||        union [57]
+|ir [24]
 || /$
-||  file.h [8]
+||  file.h [9]
 macro [3]
-|    _function [4]
-|             ($
-|              ) [5]
-|             _with_params [6]
-|             |           ($
-|             |            ) [7]
-file.h [8]
-|oo [9, 11, 13, 15]
+||   _function [5]
+||            ($
+||             ) [6]
+||            _with_params [7]
+||            |           ($
+||            |            ) [8]
+|in() [48]
+glmacro() [4]
+| file() [10]
+| |oo() [13]
+| class() [21]
+| directory() [25]
+| |  () [26]
+| _dir [27]
+| |group [30]
+| |enum [44]
+| ||   _value [42]
+| ||         _ext [41]
+| |typedef [46]
+| namespace() [50]
+| struct() [55]
+| union() [59]
+file.h [9]
+|oo [11, 14, 16, 18]
 || ($
-||  ) [10, 12, 14, 16]
-namespace [36]
+||  ) [12, 15, 17, 19]
+namespace [49]
 |        :$
-|         :class [17]
+|         :class [20]
 |          |    :$
-|          |     :foo [9, 11, 13, 15]
+|          |     :foo [11, 14, 16, 18]
 |          |         ($
-|          |          ) [10, 12, 14, 16]
-|          enum [33]
+|          |          ) [12, 15, 17, 19]
+|          enum [43]
 |          |   :$
-|          |    :value [32]
-|          typedef [34]
-|          variable [35]
-|          struct [40]
-|          union [43]
-class [17]
+|          |    :value [40]
+|          typedef [45]
+|          variable [47]
+|          struct [54]
+|          union [58]
+class [20]
 |    :$
-|     :foo [9, 11, 13, 15]
+|     :foo [11, 14, 16, 18]
 |         ($
-|          ) [10, 12, 14, 16]
-a group [21, 22]
-| page [37]
-value [23, 32]
-| riable [35]
-enum [26, 33]
+|          ) [12, 15, 17, 19]
+a group [28, 29]
+| page [51]
+value [31, 40]
+| riable [47]
+enum [34, 43]
 |   :$
-|    :deprecatedvalue [25]
-|     value [32]
-typedef [34]
-struct [40]
-|ubpage [41]
-union [43]
+|    :deprecatedvalue [33]
+|     value [40]
+typedef [45]
+struct [54]
+|ubpage [56]
+union [58]
 0: DEPRECATED_MACRO(a, b, c) [suffix_length=9, deprecated, type=DEFINE] -> DeprecatedFile_8h.html#a7f8376730349fef9ff7d103b0245a13e
 1:  [prefix=0[:56], suffix_length=7, deprecated, type=DEFINE] ->
-2: /DeprecatedFile.h [prefix=19[:0], deprecated, type=FILE] -> DeprecatedFile_8h.html
+2: /DeprecatedFile.h [prefix=23[:0], deprecated, type=FILE] -> DeprecatedFile_8h.html
 3: MACRO [type=DEFINE] -> File_8h.html#a824c99cb152a3c2e9111a2cb9c34891e
-4: _FUNCTION() [prefix=3[:14], suffix_length=2, type=DEFINE] -> 025158d6007b306645a8eb7c7a9237c1
-5:  [prefix=4[:46], type=DEFINE] ->
-6: _FUNCTION_WITH_PARAMS(params) [prefix=3[:15], suffix_length=8, type=DEFINE] -> 8602bba5a72becb4f2dc544ce12c420
-7:  [prefix=6[:46], suffix_length=6, type=DEFINE] ->
-8: /File.h [prefix=20[:0], type=FILE] -> File_8h.html
-9: ::foo() [prefix=17[:28], suffix_length=2, type=FUNC] -> #aaeba4096356215868370d6ea476bf5d9
-10:  [prefix=9[:62], type=FUNC] ->
-11:  const [prefix=9[:30], suffix_length=8, type=FUNC] -> c03c5b93907dda16763eabd26b25500a
-12:  [prefix=11[:62], suffix_length=6, type=FUNC] ->
-13:  && [prefix=9[:30], suffix_length=5, deleted, type=FUNC] -> 77803233441965cad057a6619e9a75fd
-14:  [prefix=13[:62], suffix_length=3, deleted, type=FUNC] ->
-15: ::foo(const Enum&, Typedef) [prefix=17[:28], suffix_length=22, type=FUNC] -> #aba8d57a830d4d79f86d58d92298677fa
-16:  [prefix=15[:62], suffix_length=20, type=FUNC] ->
-17: ::Class [prefix=36[:0], type=CLASS] -> classNamespace_1_1Class.html
-18: Deprecated List [type=PAGE] -> deprecated.html
-19: DeprecatedDir [deprecated, type=DIR] -> dir_c6c97faf5a6cbd0f62c27843ce3af4d0.html
-20: Dir [type=DIR] -> dir_da5033def2d0db76e9883b31b76b3d0c.html
-21: A group [deprecated, type=GROUP] -> group__deprecated-group.html
-22: A group [type=GROUP] -> group__group.html
-23: ::Value [prefix=24[:67], type=ENUM_VALUE] -> a689202409e48743b914713f96d93947c
-24: ::DeprecatedEnum [prefix=31[:33], deprecated, type=ENUM] -> #ab1e37ddc1d65765f2a48485df4af7b47
-25: ::DeprecatedValue [prefix=26[:67], deprecated, type=ENUM_VALUE] -> a4b5b0e9709902228c33df7e5e377e596
-26: ::Enum [prefix=31[:33], type=ENUM] -> #ac59010e983270c330b8625b5433961b9
-27: ::DeprecatedTypedef [prefix=31[:33], deprecated, type=TYPEDEF] -> #af503ad3ff194a4c2512aff16df771164
-28: ::DeprecatedVariable [prefix=31[:33], deprecated, type=VAR] -> #ae934297fc39624409333eefbfeabf5e5
-29: ::deprecatedFoo(int, bool, double) [prefix=31[:33], suffix_length=19, deprecated, type=FUNC] -> #a9a1b3fc71d294b548095985acc0d5092
-30:  [prefix=29[:67], suffix_length=17, deprecated, type=FUNC] ->
-31: DeprecatedNamespace [deprecated, type=NAMESPACE] -> namespaceDeprecatedNamespace.html
-32: ::Value [prefix=33[:57], type=ENUM_VALUE] -> a689202409e48743b914713f96d93947c
-33: ::Enum [prefix=36[:23], type=ENUM] -> #add172b93283b1ab7612c3ca6cc5dcfea
-34: ::Typedef [prefix=36[:23], type=TYPEDEF] -> #abe2a245304bc2234927ef33175646e08
-35: ::Variable [prefix=36[:23], type=VAR] -> #ad3121960d8665ab045ca1bfa1480a86d
-36: Namespace [type=NAMESPACE] -> namespaceNamespace.html
-37: A page [type=PAGE] -> page.html
-38: ::DeprecatedClass [prefix=31[:0], deprecated, type=STRUCT] -> structDeprecatedNamespace_1_1DeprecatedClass.html
-39: ::DeprecatedStruct [prefix=31[:0], deprecated, type=STRUCT] -> structDeprecatedNamespace_1_1DeprecatedStruct.html
-40: ::Struct [prefix=36[:0], type=STRUCT] -> structNamespace_1_1Struct.html
-41:  » Subpage [prefix=37[:0], type=PAGE] -> subpage.html
-42: ::DeprecatedUnion [prefix=31[:0], deprecated, type=UNION] -> unionDeprecatedNamespace_1_1DeprecatedUnion.html
-43: ::Union [prefix=36[:0], type=UNION] -> unionNamespace_1_1Union.html
+4: glMacro() [alias=3] ->
+5: _FUNCTION() [prefix=3[:14], suffix_length=2, type=DEFINE] -> 025158d6007b306645a8eb7c7a9237c1
+6:  [prefix=5[:46], type=DEFINE] ->
+7: _FUNCTION_WITH_PARAMS(params) [prefix=3[:15], suffix_length=8, type=DEFINE] -> 8602bba5a72becb4f2dc544ce12c420
+8:  [prefix=7[:46], suffix_length=6, type=DEFINE] ->
+9: /File.h [prefix=24[:0], type=FILE] -> File_8h.html
+10: glFile() [alias=9] ->
+11: ::foo() [prefix=20[:28], suffix_length=2, type=FUNC] -> #aaeba4096356215868370d6ea476bf5d9
+12:  [prefix=11[:62], type=FUNC] ->
+13: glFoo() [alias=11] ->
+14:  const [prefix=11[:30], suffix_length=8, type=FUNC] -> c03c5b93907dda16763eabd26b25500a
+15:  [prefix=14[:62], suffix_length=6, type=FUNC] ->
+16:  && [prefix=11[:30], suffix_length=5, deleted, type=FUNC] -> 77803233441965cad057a6619e9a75fd
+17:  [prefix=16[:62], suffix_length=3, deleted, type=FUNC] ->
+18: ::foo(const Enum&, Typedef) [prefix=20[:28], suffix_length=22, type=FUNC] -> #aba8d57a830d4d79f86d58d92298677fa
+19:  [prefix=18[:62], suffix_length=20, type=FUNC] ->
+20: ::Class [prefix=49[:0], type=CLASS] -> classNamespace_1_1Class.html
+21: glClass() [alias=20] ->
+22: Deprecated List [type=PAGE] -> deprecated.html
+23: DeprecatedDir [deprecated, type=DIR] -> dir_c6c97faf5a6cbd0f62c27843ce3af4d0.html
+24: Dir [type=DIR] -> dir_da5033def2d0db76e9883b31b76b3d0c.html
+25: glDirectory() [alias=24] ->
+26: glDir() [alias=24] ->
+27: GL_DIR [alias=24] ->
+28: A group [deprecated, type=GROUP] -> group__deprecated-group.html
+29: A group [type=GROUP] -> group__group.html
+30: GL_GROUP [alias=29] ->
+31: ::Value [prefix=32[:67], type=ENUM_VALUE] -> a689202409e48743b914713f96d93947c
+32: ::DeprecatedEnum [prefix=39[:33], deprecated, type=ENUM] -> #ab1e37ddc1d65765f2a48485df4af7b47
+33: ::DeprecatedValue [prefix=34[:67], deprecated, type=ENUM_VALUE] -> a4b5b0e9709902228c33df7e5e377e596
+34: ::Enum [prefix=39[:33], type=ENUM] -> #ac59010e983270c330b8625b5433961b9
+35: ::DeprecatedTypedef [prefix=39[:33], deprecated, type=TYPEDEF] -> #af503ad3ff194a4c2512aff16df771164
+36: ::DeprecatedVariable [prefix=39[:33], deprecated, type=VAR] -> #ae934297fc39624409333eefbfeabf5e5
+37: ::deprecatedFoo(int, bool, double) [prefix=39[:33], suffix_length=19, deprecated, type=FUNC] -> #a9a1b3fc71d294b548095985acc0d5092
+38:  [prefix=37[:67], suffix_length=17, deprecated, type=FUNC] ->
+39: DeprecatedNamespace [deprecated, type=NAMESPACE] -> namespaceDeprecatedNamespace.html
+40: ::Value [prefix=43[:57], type=ENUM_VALUE] -> a689202409e48743b914713f96d93947c
+41: _EXT [alias=40, prefix=42[:0]] ->
+42: _VALUE [alias=40, prefix=44[:0]] ->
+43: ::Enum [prefix=49[:23], type=ENUM] -> #add172b93283b1ab7612c3ca6cc5dcfea
+44: GL_ENUM [alias=43] ->
+45: ::Typedef [prefix=49[:23], type=TYPEDEF] -> #abe2a245304bc2234927ef33175646e08
+46: GL_TYPEDEF [alias=45] ->
+47: ::Variable [prefix=49[:23], type=VAR] -> #ad3121960d8665ab045ca1bfa1480a86d
+48: GLSL: min() [alias=47, suffix_length=2] ->
+49: Namespace [type=NAMESPACE] -> namespaceNamespace.html
+50: glNamespace() [alias=49] ->
+51: A page [type=PAGE] -> page.html
+52: ::DeprecatedClass [prefix=39[:0], deprecated, type=STRUCT] -> structDeprecatedNamespace_1_1DeprecatedClass.html
+53: ::DeprecatedStruct [prefix=39[:0], deprecated, type=STRUCT] -> structDeprecatedNamespace_1_1DeprecatedStruct.html
+54: ::Struct [prefix=49[:0], type=STRUCT] -> structNamespace_1_1Struct.html
+55: glStruct() [alias=54] ->
+56:  » Subpage [prefix=51[:0], type=PAGE] -> subpage.html
+57: ::DeprecatedUnion [prefix=39[:0], deprecated, type=UNION] -> unionDeprecatedNamespace_1_1DeprecatedUnion.html
+58: ::Union [prefix=49[:0], type=UNION] -> unionNamespace_1_1Union.html
+59: glUnion() [alias=58] ->
 """.strip())
 
 if __name__ == '__main__': # pragma: no cover