chiark / gitweb /
doxygen: include symbol type in the search data.
authorVladimír Vondruš <mosra@centrum.cz>
Fri, 2 Feb 2018 10:29:53 +0000 (11:29 +0100)
committerVladimír Vondruš <mosra@centrum.cz>
Sat, 3 Feb 2018 09:51:55 +0000 (10:51 +0100)
doxygen/dox2html5.py
doxygen/search.js
doxygen/test/js-test-data/searchdata.b85
doxygen/test/js-test-data/searchdata.bin
doxygen/test/populate-js-test-data.py
doxygen/test/search/Dir/File.h
doxygen/test/test-search.js
doxygen/test/test_search.py

index 2e2272126e88e5afa9aa452bd22dfcd2641d0102..5e3ef581300c12aac63e97ef7ecec7c70c8825bb 100755 (executable)
@@ -130,7 +130,23 @@ class Trie:
         return output
 
 class ResultFlag(Flag):
-    HAS_SUFFIX = 1
+    HAS_SUFFIX = 1 << 0
+
+    _TYPE = 0xf << 4
+    NAMESPACE = 1 << 4
+    CLASS = 2 << 4
+    STRUCT = 3 << 4
+    UNION = 4 << 4
+    TYPEDEF = 5 << 4
+    FUNC = 6 << 4
+    VAR = 7 << 4
+    ENUM = 8 << 4
+    ENUM_VALUE = 9 << 4
+    DEFINE = 10 << 4
+    GROUP = 11 << 4
+    PAGE = 12 << 4
+    DIR = 13 << 4
+    FILE = 14 << 4
 
 class ResultMap:
     # item 1 flags | item 2 flags |     | item N flags | file | item 1 |
@@ -1132,6 +1148,7 @@ def parse_enum(state: State, element: ET.Element):
             enum.has_value_details = True
             if not state.doxyfile['M_SEARCH_DISABLED']:
                 result = Empty()
+                result.flags = ResultFlag.ENUM_VALUE
                 result.url = state.current_url + '#' + value.id
                 result.prefix = state.current_prefix + [enum.name]
                 result.name = value.name
@@ -1142,6 +1159,7 @@ def parse_enum(state: State, element: ET.Element):
     if enum.brief or enum.has_details or enum.has_value_details:
         if not state.doxyfile['M_SEARCH_DISABLED']:
             result = Empty()
+            result.flags = ResultFlag.ENUM
             result.url = state.current_url + '#' + enum.id
             result.prefix = state.current_prefix
             result.name = enum.name
@@ -1203,6 +1221,7 @@ def parse_typedef(state: State, element: ET.Element):
     typedef.has_details = typedef.description or typedef.has_template_details
     if typedef.brief or typedef.has_details:
         result = Empty()
+        result.flags = ResultFlag.TYPEDEF
         result.url = state.current_url + '#' + typedef.id
         result.prefix = state.current_prefix
         result.name = typedef.name
@@ -1305,6 +1324,7 @@ def parse_func(state: State, element: ET.Element):
     if func.brief or func.has_details:
         if not state.doxyfile['M_SEARCH_DISABLED']:
             result = Empty()
+            result.flags = ResultFlag.FUNC
             result.url = state.current_url + '#' + func.id
             result.prefix = state.current_prefix
             result.name = func.name
@@ -1336,6 +1356,7 @@ def parse_var(state: State, element: ET.Element):
     if var.brief or var.has_details:
         if not state.doxyfile['M_SEARCH_DISABLED']:
             result = Empty()
+            result.flags = ResultFlag.VAR
             result.url = state.current_url + '#' + var.id
             result.prefix = state.current_prefix
             result.name = var.name
@@ -1373,6 +1394,7 @@ def parse_define(state: State, element: ET.Element):
     if define.brief or define.has_details:
         if not state.doxyfile['M_SEARCH_DISABLED']:
             result = Empty()
+            result.flags = ResultFlag.DEFINE
             result.url = state.current_url + '#' + define.id
             result.prefix = []
             result.name = define.name
@@ -1528,6 +1550,24 @@ def _build_search_data(state: State, prefix, id: str, trie: Trie, map: ResultMap
     prefixed_result_name = prefix + [compound.leaf_name]
     suffix_length = 0
 
+    if compound.kind == 'namespace':
+        kind = ResultFlag.NAMESPACE
+    elif compound.kind == 'struct':
+        kind = ResultFlag.STRUCT
+    elif compound.kind == 'class':
+        kind = ResultFlag.CLASS
+    elif compound.kind == 'union':
+        kind = ResultFlag.UNION
+    elif compound.kind == 'dir':
+        kind = ResultFlag.DIR
+    elif compound.kind == 'file':
+        kind = ResultFlag.FILE
+    elif compound.kind == 'page':
+        kind = ResultFlag.PAGE
+    elif compound.kind == 'group':
+        kind = ResultFlag.GROUP
+    else: assert False # pragma: no cover
+
     # Calculate fully-qualified name
     if compound.kind in ['namespace', 'struct', 'class', 'union']:
         joiner = result_joiner = '::'
@@ -1548,13 +1588,13 @@ def _build_search_data(state: State, prefix, id: str, trie: Trie, map: ResultMap
         result_name = result_joiner.join(prefixed_result_name)
 
         # TODO: escape elsewhere so i don't have to unescape here
-        index = map.add(html.unescape(result_name), compound.url)
+        index = map.add(html.unescape(result_name), compound.url, flags=kind)
         trie.insert(html.unescape(compound.leaf_name).lower(), index)
 
     # Otherwise add it multiple times with all possible prefixes
     else:
         # TODO: escape elsewhere so i don't have to unescape here
-        index = map.add(html.unescape(result_joiner.join(prefixed_result_name)), compound.url, suffix_length=suffix_length)
+        index = map.add(html.unescape(result_joiner.join(prefixed_result_name)), compound.url, suffix_length=suffix_length, flags=kind)
         for i in range(len(prefixed_name)):
             lookahead_barriers = []
             name = ''
@@ -1598,7 +1638,7 @@ def build_search_data(state: State, merge_subtrees=True, add_lookahead_barriers=
             suffix_length += len(html.unescape(result.suffix))
 
         # TODO: escape elsewhere so i don't have to unescape here
-        index = map.add(html.unescape('::'.join(result.prefix + [name_with_args])), result.url, suffix_length=suffix_length)
+        index = map.add(html.unescape('::'.join(result.prefix + [name_with_args])), result.url, suffix_length=suffix_length, flags=result.flags)
 
         prefixed_name = result.prefix + [name]
         for i in range(len(prefixed_name)):
index 74d050f719306275e2b70939177299419f52a008..e0b6dac15fa4a8b8fb2b89ece60c78af155ebeed 100644 (file)
@@ -269,6 +269,7 @@ var Search = {
             /* Keeping in UTF-8, as we need that for proper slicing */
             results.push({name: name,
                           url: url,
+                          flags: flags,
                           suffixLength: suffixLength + resultSuffixLength});
 
             /* 'nuff said. */
@@ -327,9 +328,70 @@ var Search = {
             document.getElementById('search-results').style.display = 'block';
             document.getElementById('search-notfound').style.display = 'none';
 
-            var list = '';
+            let list = '';
             for(let i = 0; i != results.length; ++i) {
-                list += this.fromUtf8('<li' + (i ? '' : ' id="search-current"') + '><a href="' + results[i].url + '" onmouseover="selectResult(event)"><div><span class="m-text m-dim">' + this.escapeForRtl(results[i].name.substr(0, results[i].name.length - value.length - results[i].suffixLength)) + '</span><span class="m-dox-search-typed">' + this.escapeForRtl(results[i].name.substr(results[i].name.length - value.length - results[i].suffixLength, value.length)) + '</span>' + this.escapeForRtl(results[i].name.substr(results[i].name.length - results[i].suffixLength)) + '</div></a></li>');
+                let type = '';
+                let color = '';
+                switch(results[i].flags >> 4) {
+                    case 1:
+                        type = 'namespace';
+                        color = 'm-primary';
+                        break;
+                    case 2:
+                        type = 'class';
+                        color = 'm-primary';
+                        break;
+                    case 3:
+                        type = 'struct';
+                        color = 'm-primary';
+                        break;
+                    case 4:
+                        type = 'union';
+                        color = 'm-primary';
+                        break;
+                    case 5:
+                        type = 'typedef';
+                        color = 'm-primary';
+                        break;
+                    case 6:
+                        type = 'func';
+                        color = 'm-info';
+                        break;
+                    case 7:
+                        type = 'var';
+                        color = 'm-default';
+                        break;
+                    case 8:
+                        type = 'enum';
+                        color = 'm-primary';
+                        break;
+                    case 9:
+                        type = 'enum val';
+                        color = 'm-default';
+                        break;
+                    case 10:
+                        type = 'define';
+                        color = 'm-info';
+                        break;
+                    case 11:
+                        type = 'group';
+                        color = 'm-success';
+                        break;
+                    case 12:
+                        type = 'page';
+                        color = 'm-success';
+                        break;
+                    case 13:
+                        type = 'dir';
+                        color = 'm-warning';
+                        break;
+                    case 14:
+                        type = 'file';
+                        color = 'm-warning';
+                        break;
+                }
+
+                list += this.fromUtf8('<li' + (i ? '' : ' id="search-current"') + '><a href="' + results[i].url + '" onmouseover="selectResult(event)"><div class="m-label m-flat ' + color + '">' + type + '</div><div><span class="m-text m-dim">' + this.escapeForRtl(results[i].name.substr(0, results[i].name.length - value.length - results[i].suffixLength)) + '</span><span class="m-dox-search-typed">' + this.escapeForRtl(results[i].name.substr(results[i].name.length - value.length - results[i].suffixLength, value.length)) + '</span>' + this.escapeForRtl(results[i].name.substr(results[i].name.length - results[i].suffixLength)) + '</div></a></li>');
             }
             document.getElementById('search-results').innerHTML = list;
             document.getElementById('search-current').scrollIntoView(true);
index ba9751d5f611bb54e14753bb5491735f9e391e1d..d218b3914e2847bc9c34d0368729393ff5cfe0c5 100644 (file)
@@ -1 +1 @@
-O+!-vL;(N*Dggih0s#R40{{d704W0i2mk;m0{{*H0B!>S6aWBe0s#X60{|cZ04W0iBme*?0{|)j0B!>SFaQ8)0{}Jv0Br*RJOBVX1OWm7LI8j|0{}<>0CEEWPyhgL0{~V40CWQYTmS%L0{~(G0A&IJ1pos8ZU6u&0|0UW04M_hcmM!y0|0&i0BHjNga80-0|1Hu06GK#1OSi#fI0&JmH+@{0|1@?0A~XLqyPYJ0|2T30AU9J8UO%oXaE3qumAvZ0|2%F06GK#006`QfI0&J$^Zap0|3$h0CWTc0RRI41pos8-T(k80|4d#04M_h>;M361pwFp0Aca~0BHgN1^@#90s#PJ0{{jA0A~XL3;_UP0{{{M0B{2U7y$rc0{|WY0Cfof_y7QHXaE3qumAvZBmn?(AOHXWHvj+uVgLXDhX4Qpz5oCK;Q#;u76AYNG64VpO<{Cs0B&JzWpi+0V`WWYbZ9PUbZu-1O<{CsIy!A>ZYXJPbSxlgZgeRCZeeX@b8ul}WldppXf9}UZEPcLX>LtnbZ9y{R%K&!Z*l-*Y+-YAO<{CsUol@XR%K&!Z*neZbZu+~O<{CsIyzQmV{~tFIy!A>ZYU`rV{dMAbO2*)VRLg$VRUF;F<&uOWn*-2axQ3eZEPcLX>LtnbZ9y{QekdqWdLJrVRLg$VRUF;F<&uKVQyz-E@*UZYz9qXbZ9y{QekdqWjZ=-X>KSfAY*TCb94Y>Y+-YAO<{CsUol@XQekdqWiDuRZEPcLX>L$qXJsJ5yC73_VsK$+WdL(^VsK$+WiDuRZEOGl
\ No newline at end of file
+O+!-vL;(N*Dggih0s#R40{{d704W0i2mk;m0{{*H0B!>S6aWBe0s#X60{|cZ04W0iBme*?0{|)j0B!>SFaQ8)0{}Jv0Br*RJOBVX1OWm7LI8j|0{}<>0CEEWPyhgL0{~V40CWQYTmS%L0{~(G0A&IJ1pos8ZU6u&0|0UW04M_hcmM!y0|0&i0BHjNga80-0|1Hu06GK#1OSi#fI0&JmH+@{0|1@?0A~XLqyPYJ0|2T30AU9J8UO%oXaE3qumAvZ0|2%F06GK#006`QfI0&J$^Zap0|3$h0CWTc0RRI41pos8-T(k80|4d#04M_h>;M361pwFp0Aca~0BHgN1^@#90s#PJ0{{jA0A~XL3;_UP0{{{M0B{2U7y$rc0{|WY0Cfof_y7QHXaE3qumAvZBmn?(AOHXmHvj-(VgLXjhX4R!z5oCq;Q#<(76AajG64VpO<{Cs0B&JzWpi+0V`WWYbZ9PUbZu-1O<{CsIy!A>ZYXJPbSxlgZgeRCZeeX@b8ul}WldppXf9}UZEPcLX>LtnbZ9y{R%K&!Z*l-*Y+-YAO<{CsUol@XR%K&!Z*neZbZu+~O<{CsIyzQmV{~tFIy!A>ZYU`rV{dMAbO2*)VRLg$VRUF;F<&uOWn*-2axQ3eZEPcLX>LtnbZ9y{QekdqWdLJrVRLg$VRUF;F<&uKVQyz-E@*UZYz9qXbZ9y{QekdqWjZ=-X>KSfAY*TCb94Y>Y+-YAO<{CsUol@XQekdqWiDuRZEPcLX>L$qXJsJ5yC73_VsK$+WdL(^VsK$+WiDuRZEOGl
\ No newline at end of file
index 3af09be4e79c36db8c1f664602c790b0cd7f065d..017346703b27fd7522763d88a66c7a54070bacb5 100644 (file)
Binary files a/doxygen/test/js-test-data/searchdata.bin and b/doxygen/test/js-test-data/searchdata.bin differ
index 13a77f4f983d823f2ddaf78a78aaf4e3b7d884b6..35e182c123bc080e50e4f41644213a0944b3359d 100755 (executable)
@@ -30,7 +30,7 @@ import sys
 import pathlib
 sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), '..'))
 
-from dox2html5 import Trie, ResultMap, serialize_search_data
+from dox2html5 import Trie, ResultMap, ResultFlag, serialize_search_data
 
 basedir = pathlib.Path(os.path.dirname(os.path.realpath(__file__)))/'js-test-data'
 
@@ -46,25 +46,25 @@ with open(basedir/'empty.bin', 'wb') as f:
 trie = Trie()
 map = ResultMap()
 
-trie.insert("math", map.add("Math", "namespaceMath.html"))
-index = map.add("Math::min(int, int)", "namespaceMath.html#min", suffix_length=8)
+trie.insert("math", map.add("Math", "namespaceMath.html", flags=ResultFlag.NAMESPACE))
+index = map.add("Math::min(int, int)", "namespaceMath.html#min", suffix_length=8, flags=ResultFlag.FUNC)
 trie.insert("math::min()", index, lookahead_barriers=[4])
 trie.insert("min()", index)
-index = map.add("Math::Vector", "classMath_1_1Vector.html")
+index = map.add("Math::Vector", "classMath_1_1Vector.html", flags=ResultFlag.CLASS)
 trie.insert("math::vector", index)
 trie.insert("vector", index)
-index = map.add("Math::Vector::min() const", "classMath_1_1Vector.html#min", suffix_length=6)
+index = map.add("Math::Vector::min() const", "classMath_1_1Vector.html#min", suffix_length=6, flags=ResultFlag.FUNC)
 trie.insert("math::vector::min()", index, lookahead_barriers=[4, 12])
 trie.insert("vector::min()", index, lookahead_barriers=[6])
 trie.insert("min()", index)
-index = map.add("Math::Range", "classMath_1_1Range.html")
+index = map.add("Math::Range", "classMath_1_1Range.html", flags=ResultFlag.CLASS)
 trie.insert("math::range", index)
 trie.insert("range", index)
-index = map.add("Math::Range::min() const", "classMath_1_1Range.html#min", suffix_length=6)
+index = map.add("Math::Range::min() const", "classMath_1_1Range.html#min", suffix_length=6, flags=ResultFlag.FUNC)
 trie.insert("math::range::min()", index, lookahead_barriers=[4, 11])
 trie.insert("range::min()", index, lookahead_barriers=[5])
 trie.insert("min()", index)
-trie.insert("subpage", map.add("Page » Subpage", "subpage.html"))
+trie.insert("subpage", map.add("Page » Subpage", "subpage.html", flags=ResultFlag.PAGE))
 
 with open(basedir/'searchdata.bin', 'wb') as f:
     f.write(serialize_search_data(trie, map))
index 459d447e5dee29588688439fa03e53132ef0a6f7..81b883459f313f6b2ddc9b2b60a408008a4630e2 100644 (file)
@@ -34,6 +34,18 @@ enum class Enum {
     Value = 15  /**< Enum value */
 };
 
+/** @defgroup group A group
+ * @{
+ */
+
+/** @brief An union */
+union Union {};
+
+/** @brief A struct */
+struct Struct {};
+
+/*@}*/
+
 }
 
 /** @brief A macro */
index ec8637c791057d00ceaa3f6d5234d7eda6d76154..d1af900cbb4c42756fe18d3677dede5dcca922cc 100644 (file)
@@ -113,15 +113,19 @@ const { StringDecoder } = require('string_decoder');
     let resultsForM = [
         { name: 'Math',
           url: 'namespaceMath.html',
+          flags: 16,
           suffixLength: 3 },
         { name: 'Math::min(int, int)',
           url: 'namespaceMath.html#min',
+          flags: 97,
           suffixLength: 12 },
         { name: 'Math::Vector::min() const',
           url: 'classMath_1_1Vector.html#min',
+          flags: 97,
           suffixLength: 10 },
         { name: 'Math::Range::min() const',
           url: 'classMath_1_1Range.html#min',
+          flags: 97,
           suffixLength: 10 }];
     assert.deepEqual(Search.search('m'), resultsForM);
 
@@ -129,12 +133,15 @@ const { StringDecoder } = require('string_decoder');
     assert.deepEqual(Search.search('min'), [
         { name: 'Math::min(int, int)',
           url: 'namespaceMath.html#min',
+          flags: 97,
           suffixLength: 10 },
         { name: 'Math::Vector::min() const',
           url: 'classMath_1_1Vector.html#min',
+          flags: 97,
           suffixLength: 8 },
         { name: 'Math::Range::min() const',
           url: 'classMath_1_1Range.html#min',
+          flags: 97,
           suffixLength: 8 }]);
 
     /* Go back, get the same thing */
@@ -144,6 +151,7 @@ const { StringDecoder } = require('string_decoder');
     let resultsForVec = [
         { name: 'Math::Vector',
           url: 'classMath_1_1Vector.html',
+          flags: 32,
           suffixLength: 3 }];
     assert.deepEqual(Search.search('vec'), resultsForVec);
 
@@ -157,6 +165,7 @@ const { StringDecoder } = require('string_decoder');
     assert.deepEqual(Search.search('su'), [
         { name: Search.toUtf8('Page » Subpage'),
           url: 'subpage.html',
+          flags: 192,
           suffixLength: 5 }]);
 }
 
@@ -170,12 +179,15 @@ const { StringDecoder } = require('string_decoder');
     assert.deepEqual(Search.search('m'), [
         { name: 'Math',
           url: 'namespaceMath.html',
+          flags: 16,
           suffixLength: 3 },
         { name: 'Math::min(int, int)',
           url: 'namespaceMath.html#min',
+          flags: 97,
           suffixLength: 12 },
         { name: 'Math::Vector::min() const',
           url: 'classMath_1_1Vector.html#min',
+          flags: 97,
           suffixLength: 10 }]);
 }
 
@@ -189,12 +201,15 @@ const { StringDecoder } = require('string_decoder');
     assert.deepEqual(Search.search('min'), [
         { name: 'Math::min(int, int)',
           url: 'namespaceMath.html#min',
+          flags: 97,
           suffixLength: 10 },
         { name: 'Math::Vector::min() const',
           url: 'classMath_1_1Vector.html#min',
+          flags: 97,
           suffixLength: 8 },
         { name: 'Math::Range::min() const',
           url: 'classMath_1_1Range.html#min',
+          flags: 97,
           suffixLength: 8 }]);
 }
 
@@ -207,17 +222,21 @@ const { StringDecoder } = require('string_decoder');
     assert.deepEqual(Search.search('h'), [
         { name: Search.toUtf8('Hýždě'),
           url: '#a',
+          flags: 0,
           suffixLength: 7 },
         { name: Search.toUtf8('Hárá'),
           url: '#b',
+          flags: 0,
           suffixLength: 5 }]);
     assert.deepEqual(Search.search('hý'), [
         { name: Search.toUtf8('Hýždě'),
           url: '#a',
+          flags: 0,
           suffixLength: 5 }]);
     assert.deepEqual(Search.search('há'), [
         { name: Search.toUtf8('Hárá'),
           url: '#b',
+          flags: 0,
           suffixLength: 3 }]);
 }
 
index 4aacd6291a82a0d70bdcabf4ca4b9a18c0fecd15..ad83dde395baba812e880c79b7dd64355308db90 100755 (executable)
@@ -137,10 +137,12 @@ def pretty_print_map(serialized: bytes, colors=False):
     for i in range(size):
         if i: out += '\n'
         flags = ResultFlag(ResultMap.flags_struct.unpack_from(serialized, i*4 + 3)[0])
-        extra = [str(int(flags.value))]
+        extra = []
         if flags & ResultFlag.HAS_SUFFIX:
             extra += ['suffix_length={}'.format(ResultMap.suffix_length_struct.unpack_from(serialized, offset)[0])]
             offset += 1
+        if flags & ResultFlag._TYPE:
+            extra += ['type={}'.format((flags & ResultFlag._TYPE).name)]
         next_offset = ResultMap.offset_struct.unpack_from(serialized, (i + 1)*4)[0] & 0x00ffffff
         name, _, url = serialized[offset:next_offset].partition(b'\0')
         out += color_map['cyan'] + str(i) + color_map['blue'] + ': ' + color_map['white'] + name.decode('utf-8') + color_map['blue'] + ' [' + color_map['yellow'] + (color_map['blue'] + ', ' + color_map['yellow']).join(extra) + color_map['blue'] + '] -> ' + color_map['reset'] + url.decode('utf-8')
@@ -291,30 +293,30 @@ class MapSerialization(unittest.TestCase):
 
     def test_single(self):
         map = ResultMap()
-        self.assertEqual(map.add("Magnum", "namespaceMagnum.html", suffix_length=11), 0)
+        self.assertEqual(map.add("Magnum", "namespaceMagnum.html", suffix_length=11, flags=ResultFlag.NAMESPACE), 0)
 
         serialized = map.serialize()
         self.compare(serialized, """
-0: Magnum [1, suffix_length=11] -> namespaceMagnum.html
+0: Magnum [suffix_length=11, type=NAMESPACE] -> namespaceMagnum.html
 """)
         self.assertEqual(len(serialized), 36)
 
     def test_multiple(self):
         map = ResultMap()
 
-        self.assertEqual(map.add("Math", "namespaceMath.html"), 0)
-        self.assertEqual(map.add("Math::Vector", "classMath_1_1Vector.html"), 1)
-        self.assertEqual(map.add("Math::Range", "classMath_1_1Range.html"), 2)
-        self.assertEqual(map.add("Math::min()", "namespaceMath.html#abcdef2875"), 3)
-        self.assertEqual(map.add("Math::max(int, int)", "namespaceMath.html#abcdef2875", suffix_length=8), 4)
+        self.assertEqual(map.add("Math", "namespaceMath.html", flags=ResultFlag.NAMESPACE), 0)
+        self.assertEqual(map.add("Math::Vector", "classMath_1_1Vector.html", flags=ResultFlag.CLASS), 1)
+        self.assertEqual(map.add("Math::Range", "classMath_1_1Range.html", flags=ResultFlag.CLASS), 2)
+        self.assertEqual(map.add("Math::min()", "namespaceMath.html#abcdef2875", flags=ResultFlag.FUNC), 3)
+        self.assertEqual(map.add("Math::max(int, int)", "namespaceMath.html#abcdef2875", suffix_length=8, flags=ResultFlag.FUNC), 4)
 
         serialized = map.serialize()
         self.compare(serialized, """
-0: Math [0] -> namespaceMath.html
-1: Math::Vector [0] -> classMath_1_1Vector.html
-2: Math::Range [0] -> classMath_1_1Range.html
-3: Math::min() [0] -> namespaceMath.html#abcdef2875
-4: Math::max(int, int) [1, suffix_length=8] -> namespaceMath.html#abcdef2875
+0: Math [type=NAMESPACE] -> namespaceMath.html
+1: Math::Vector [type=CLASS] -> classMath_1_1Vector.html
+2: Math::Range [type=CLASS] -> classMath_1_1Range.html
+3: Math::min() [type=FUNC] -> namespaceMath.html#abcdef2875
+4: Math::max(int, int) [suffix_length=8, type=FUNC] -> namespaceMath.html#abcdef2875
 """)
         self.assertEqual(len(serialized), 210)
 
@@ -332,11 +334,11 @@ class Serialization(unittest.TestCase):
         trie = Trie()
         map = ResultMap()
 
-        trie.insert("math", map.add("Math", "namespaceMath.html"))
-        index = map.add("Math::Vector", "classMath_1_1Vector.html")
+        trie.insert("math", map.add("Math", "namespaceMath.html", flags=ResultFlag.NAMESPACE))
+        index = map.add("Math::Vector", "classMath_1_1Vector.html", flags=ResultFlag.CLASS)
         trie.insert("math::vector", index)
         trie.insert("vector", index)
-        index = map.add("Math::Range", "classMath_1_1Range.html")
+        index = map.add("Math::Range", "classMath_1_1Range.html", flags=ResultFlag.CLASS)
         trie.insert("math::range", index)
         trie.insert("range", index)
 
@@ -347,9 +349,9 @@ math [0]
 |     range [2]
 vector [1]
 range [2]
-0: Math [0] -> namespaceMath.html
-1: Math::Vector [0] -> classMath_1_1Vector.html
-2: Math::Range [0] -> classMath_1_1Range.html
+0: Math [type=NAMESPACE] -> namespaceMath.html
+1: Math::Vector [type=CLASS] -> classMath_1_1Vector.html
+2: Math::Range [type=CLASS] -> classMath_1_1Range.html
 """)
         self.assertEqual(len(serialized), 241)
 
@@ -364,52 +366,60 @@ class Search(IntegrationTestCase):
             search_data_pretty = pretty_print(f.read())[0]
         #print(search_data_pretty)
         self.assertEqual(search_data_pretty, """
-namespace [0]
+a group [0]
+| page [5]
+namespace [1]
 |        :$
-|         :class [1]
+|         :class [2]
 |          |    :$
-|          |     :foo() [6, 7, 8, 9]
-|          enum [11]
+|          |     :foo() [9, 10, 11, 12]
+|          struct [3]
+|          union [4]
+|          enum [14]
 |          |   :$
-|          |    :value [10]
-|          typedef [12]
-|          variable [13]
-class [1]
+|          |    :value [13]
+|          typedef [15]
+|          variable [16]
+class [2]
 |    :$
-|     :foo() [6, 7, 8, 9]
-a page [2]
-subpage [3]
-dir [4]
+|     :foo() [9, 10, 11, 12]
+struct [3]
+|ubpage [6]
+union [4]
+dir [7]
 |  /$
-|   file.h [5]
-file.h [5]
-|oo() [6, 7, 8, 9]
-enum [11]
+|   file.h [8]
+file.h [8]
+|oo() [9, 10, 11, 12]
+enum [14]
 |   :$
-|    :value [10]
-value [10]
-| riable [13]
-typedef [12]
-macro [14]
-|    _function() [15]
-|             _with_params() [16]
-0: Namespace [0] -> namespaceNamespace.html
-1: Namespace::Class [0] -> classNamespace_1_1Class.html
-2: A page [0] -> page.html
-3: A page » Subpage [0] -> subpage.html
-4: Dir/ [1, suffix_length=1] -> dir_da5033def2d0db76e9883b31b76b3d0c.html
-5: Dir/File.h [0] -> File_8h.html
-6: Namespace::Class::foo() [0] -> classNamespace_1_1Class.html#aaeba4096356215868370d6ea476bf5d9
-7: Namespace::Class::foo() const [1, suffix_length=6] -> classNamespace_1_1Class.html#ac03c5b93907dda16763eabd26b25500a
-8: Namespace::Class::foo() && [1, suffix_length=3] -> classNamespace_1_1Class.html#ac9e7e80d06281e30cfcc13171d117ade
-9: Namespace::Class::foo(const Enum&, Typedef) [1, suffix_length=20] -> classNamespace_1_1Class.html#aba8d57a830d4d79f86d58d92298677fa
-10: Namespace::Enum::Value [0] -> namespaceNamespace.html#add172b93283b1ab7612c3ca6cc5dcfeaa689202409e48743b914713f96d93947c
-11: Namespace::Enum [0] -> namespaceNamespace.html#add172b93283b1ab7612c3ca6cc5dcfea
-12: Namespace::Typedef [0] -> namespaceNamespace.html#abe2a245304bc2234927ef33175646e08
-13: Namespace::Variable [0] -> namespaceNamespace.html#ad3121960d8665ab045ca1bfa1480a86d
-14: MACRO [0] -> File_8h.html#a824c99cb152a3c2e9111a2cb9c34891e
-15: MACRO_FUNCTION() [0] -> File_8h.html#a025158d6007b306645a8eb7c7a9237c1
-16: MACRO_FUNCTION_WITH_PARAMS(params) [1, suffix_length=6] -> File_8h.html#a88602bba5a72becb4f2dc544ce12c420
+|    :value [13]
+value [13]
+| riable [16]
+typedef [15]
+macro [17]
+|    _function() [18]
+|             _with_params() [19]
+0: A group [type=GROUP] -> group__group.html
+1: Namespace [type=NAMESPACE] -> namespaceNamespace.html
+2: Namespace::Class [type=CLASS] -> classNamespace_1_1Class.html
+3: Namespace::Struct [type=STRUCT] -> structNamespace_1_1Struct.html
+4: Namespace::Union [type=UNION] -> unionNamespace_1_1Union.html
+5: A page [type=PAGE] -> page.html
+6: A page » Subpage [type=PAGE] -> subpage.html
+7: Dir/ [suffix_length=1, type=DIR] -> dir_da5033def2d0db76e9883b31b76b3d0c.html
+8: Dir/File.h [type=FILE] -> File_8h.html
+9: Namespace::Class::foo() [type=FUNC] -> classNamespace_1_1Class.html#aaeba4096356215868370d6ea476bf5d9
+10: Namespace::Class::foo() const [suffix_length=6, type=FUNC] -> classNamespace_1_1Class.html#ac03c5b93907dda16763eabd26b25500a
+11: Namespace::Class::foo() && [suffix_length=3, type=FUNC] -> classNamespace_1_1Class.html#ac9e7e80d06281e30cfcc13171d117ade
+12: Namespace::Class::foo(const Enum&, Typedef) [suffix_length=20, type=FUNC] -> classNamespace_1_1Class.html#aba8d57a830d4d79f86d58d92298677fa
+13: Namespace::Enum::Value [type=ENUM_VALUE] -> namespaceNamespace.html#add172b93283b1ab7612c3ca6cc5dcfeaa689202409e48743b914713f96d93947c
+14: Namespace::Enum [type=ENUM] -> namespaceNamespace.html#add172b93283b1ab7612c3ca6cc5dcfea
+15: Namespace::Typedef [type=TYPEDEF] -> namespaceNamespace.html#abe2a245304bc2234927ef33175646e08
+16: Namespace::Variable [type=VAR] -> namespaceNamespace.html#ad3121960d8665ab045ca1bfa1480a86d
+17: MACRO [type=DEFINE] -> File_8h.html#a824c99cb152a3c2e9111a2cb9c34891e
+18: MACRO_FUNCTION() [type=DEFINE] -> File_8h.html#a025158d6007b306645a8eb7c7a9237c1
+19: MACRO_FUNCTION_WITH_PARAMS(params) [suffix_length=6, type=DEFINE] -> File_8h.html#a88602bba5a72becb4f2dc544ce12c420
 """.strip())
 
 if __name__ == '__main__': # pragma: no cover