From: Vladimír Vondruš Date: Sun, 4 Feb 2018 22:54:59 +0000 (+0100) Subject: doxygen: support for aliases in search. X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~cjwatson/git?a=commitdiff_plain;h=c7e7f7e1e9987ca8360fd7d9a66f3faf41dcbce3;p=blog.git doxygen: support for aliases in search. Not yet wired to the complete doxygen extraction, though. --- diff --git a/doxygen/dox2html5.py b/doxygen/dox2html5.py index ab9a7b32..5165d5ff 100755 --- a/doxygen/dox2html5.py +++ b/doxygen/dox2html5.py @@ -132,6 +132,7 @@ class ResultFlag(Flag): DELETED = 1 << 2 _TYPE = 0xf << 4 + ALIAS = 0 << 4 NAMESPACE = 1 << 4 CLASS = 2 << 4 STRUCT = 3 << 4 @@ -176,21 +177,31 @@ class ResultMap: # id + len | length | suffix | | # 16b + 8b | 8b | | 8b | # + # alias item (flags & 0xf0 == 0x00): + # + # alias | | alias + # id | ... | name + # 16b | | + # offset_struct = struct.Struct(' int: + def add(self, name, url, alias=None, suffix_length=0, flags=ResultFlag(0)) -> int: if suffix_length: flags |= ResultFlag.HAS_SUFFIX + if alias is not None: + assert flags & ResultFlag._TYPE == ResultFlag.ALIAS entry = Empty() entry.name = name entry.url = url entry.flags = flags + entry.alias = alias entry.prefix = 0 entry.prefix_length = 0 entry.suffix_length = suffix_length @@ -260,6 +271,7 @@ class ResultMap: entry.name = e.name[len(self.entries[longest_prefix.results[0]].name):] entry.url = e.url[max_prefix[1]:] entry.flags = e.flags|ResultFlag.HAS_PREFIX + entry.alias = e.alias entry.prefix = max_prefix[0] entry.prefix_length = max_prefix[1] entry.suffix_length = e.suffix_length @@ -279,6 +291,10 @@ class ResultMap: output += self.offset_struct.pack(offset) self.flags_struct.pack_into(output, len(output) - 1, e.flags.value) + # The entry is an alias, extra field for alias index + if e.flags & ResultFlag._TYPE == ResultFlag.ALIAS: + offset += 2 + # Extra field for prefix index and length if e.flags & ResultFlag.HAS_PREFIX: offset += 3 @@ -300,6 +316,10 @@ class ResultMap: # Write the entries themselves for e in self.entries: + if e.flags & ResultFlag._TYPE == ResultFlag.ALIAS: + assert not e.alias is None + assert not e.url + output += self.alias_struct.pack(e.alias) if e.flags & ResultFlag.HAS_PREFIX: output += self.prefix_struct.pack(e.prefix, e.prefix_length) if e.flags & ResultFlag.HAS_SUFFIX: diff --git a/doxygen/search.js b/doxygen/search.js index 8186ade3..35060dd6 100644 --- a/doxygen/search.js +++ b/doxygen/search.js @@ -264,6 +264,13 @@ var Search = { let flags = this.map.getUint8(index*4 + 3); let resultOffset = this.map.getUint32(index*4, true) & 0x00ffffff; + /* The result is an alias, parse the aliased prefix */ + let aliasedIndex = null; + if((flags & 0xf0) == 0x00) { + aliasedIndex = this.map.getUint16(resultOffset, true); + resultOffset += 2; + } + /* The result has a prefix, parse that first, recursively */ let name = ''; let url = ''; @@ -301,10 +308,25 @@ var Search = { name += String.fromCharCode(c); /* eheh. IS THIS FAST?! */ } - /* Extract URL */ - let max = Math.min(j + maxUrlPrefix, nextResultOffset); - for(; j != max; ++j) { - url += String.fromCharCode(this.map.getUint8(j)); + /* The result is an alias and we're not deep inside resolving a prefix, + extract the aliased name and URL */ + /* TODO: this abuses 0xffffff to guess how the call stack is deep and + that's just wrong, fix! */ + if(aliasedIndex != null && maxUrlPrefix == 0xffffff) { + let alias = this.gatherResult(aliasedIndex, 0 /* ignored */, 0xffffff); /* should be enough haha */ + name += ': ' + alias.name; + url = alias.url; + flags = alias.flags; + + /* Result suffix length: add the whole aliased name + the `: ` */ + resultSuffixLength += 2 + alias.name.length; + + /* Otherwise extract URL from here */ + } else { + let max = Math.min(j + maxUrlPrefix, nextResultOffset); + for(; j != max; ++j) { + url += String.fromCharCode(this.map.getUint8(j)); + } } /* Keeping in UTF-8, as we need that for proper slicing (and concatenating) */ diff --git a/doxygen/test/js-test-data/searchdata.b85 b/doxygen/test/js-test-data/searchdata.b85 index 773bb0ea..7353fb94 100644 --- a/doxygen/test/js-test-data/searchdata.b85 +++ b/doxygen/test/js-test-data/searchdata.b85 @@ -1 +1 @@ -O+!-vL;(N*Dggih0RRC2009I504V?g2mk;m009mF0B!&Q6aWBe0RRI400AHX04V?gBme*?00Alh0B!&QFaQ8)00A}t0BryPJOBVX0RaL4LI8j|00Bq<0CE5UPyhgL00CA20CWHWTmS%L00CkE0A&FH1poj6ZU6u&00D9U04M+fcmM!y00Djg0BHaLga80-00D{s06GBy1OSi#fI0vHmH+@{00Eu=0A~OJqyPYJ00F810AT;M3600P(m0Aca~0BHdL1^@s70s#PJ009O80A~OJ3;_UP009yK0B`^S7y$rc00ABW0CfNa_y7QHXaE3qumAvZBmn?(AOHXmHvj->PXGWaa{vHoi2wj7s{jCP!2kfj-2eapO<{Cs0B&JzWpi+0V`WWYbZ9PUbZu+^01^l~I&EogC~0nVEFfuabSVHMZE0=*0025VR%K&!Z*l-*Y+-YAO<{CsUol@XR%K&!Z*neZbZu+`02l^3I&EogC@COgZ*FsR03&T_ZU6uPIyzEeZf9ixV{Bn_b4_7%XkRg3F;Zb}XJsyEbZu+|02c;2I&EogC@COgZ*FsR03&T_Zct%oWgx=4AX9Z>aA9X<0CRO>aA9X;M3600P(m0Aca~0BHdL2LJ#80s#PJ009O80BisO3;_UV009yK0B!*Q2mk;99svL;00I~R0AV5l04M+fC;VQpn|aA9L*O<{CsE@*UZYybcf2s%1#X>KTKZgealX>N2W03&T_ZU6uPIyzQmV{~tF0Ap-nb8}5$bZB2OUolo?V{~tFE@*UZYyton20A)zX>KSfAY*TCb94YBZE0=*0025VQekdqWdLJrVRLg$VRUF;F<&uKVQyz-E@*UZYyKSfAY*TCb94YBZE0>$VP|C^!n+_-bz*Q~XJr6$bz*Q~XJsyEbZu+|08(XRbYX61Y-I!h2LJ#9IyzEiV{|Af \ No newline at end of file diff --git a/doxygen/test/js-test-data/searchdata.bin b/doxygen/test/js-test-data/searchdata.bin index 6ab162d5..f1bed626 100644 Binary files a/doxygen/test/js-test-data/searchdata.bin and b/doxygen/test/js-test-data/searchdata.bin differ diff --git a/doxygen/test/populate-js-test-data.py b/doxygen/test/populate-js-test-data.py index fb848414..06280371 100755 --- a/doxygen/test/populate-js-test-data.py +++ b/doxygen/test/populate-js-test-data.py @@ -57,15 +57,18 @@ index = map.add("Math::Vector::min() const", "classMath_1_1Vector.html#min", suf 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", flags=ResultFlag.CLASS) -trie.insert("math::range", index) -trie.insert("range", index) +range_index = map.add("Math::Range", "classMath_1_1Range.html", flags=ResultFlag.CLASS) +trie.insert("math::range", range_index) +trie.insert("range", range_index) index = map.add("Math::Range::min() const", "classMath_1_1Range.html#min", suffix_length=6, flags=ResultFlag.FUNC|ResultFlag.DELETED) 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", flags=ResultFlag.PAGE)) +trie.insert("rectangle", map.add("Rectangle", "", alias=range_index)) +trie.insert("rect()", map.add("Rectangle::Rect()", "", suffix_length=2, alias=range_index)) + with open(basedir/'searchdata.bin', 'wb') as f: f.write(serialize_search_data(trie, map)) with open(basedir/'searchdata.b85', 'wb') as f: diff --git a/doxygen/test/test-search.js b/doxygen/test/test-search.js index 427b9f47..56b0c47b 100644 --- a/doxygen/test/test-search.js +++ b/doxygen/test/test-search.js @@ -70,7 +70,7 @@ const { StringDecoder } = require('string_decoder'); /* Verify that base85-decoded file is equivalent to the binary */ { let binary = fs.readFileSync(path.join(__dirname, "js-test-data/searchdata.bin")); - assert.equal(binary.byteLength, 545); + assert.equal(binary.byteLength, 648); let b85 = fs.readFileSync(path.join(__dirname, "js-test-data/searchdata.b85"), {encoding: 'utf-8'}); assert.deepEqual(new DataView(binary.buffer.slice(binary.byteOffset, binary.byteOffset + binary.byteLength)), new DataView(Search.base85decode(b85), 0, binary.byteLength)); } @@ -105,8 +105,8 @@ const { StringDecoder } = require('string_decoder'); { let buffer = fs.readFileSync(path.join(__dirname, "js-test-data/searchdata.bin")); assert.ok(Search.init(buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength))); - assert.equal(Search.dataSize, 545); - assert.equal(Search.symbolCount, 7); + assert.equal(Search.dataSize, 648); + assert.equal(Search.symbolCount, 9); assert.equal(Search.maxResults, 100); /* Blow up */ @@ -167,14 +167,29 @@ const { StringDecoder } = require('string_decoder'); url: 'subpage.html', flags: 192, suffixLength: 5 }]); + + /* Alias */ + assert.deepEqual(Search.search('r'), [ + { name: 'Math::Range', + url: 'classMath_1_1Range.html', + flags: 40, + suffixLength: 4 }, + { name: 'Rectangle::Rect(): Math::Range', + url: 'classMath_1_1Range.html', + flags: 40, + suffixLength: 20 }, + { name: 'Rectangle: Math::Range', + url: 'classMath_1_1Range.html', + flags: 40, + suffixLength: 21 }]); } /* Search, limiting the results to 3 */ { let buffer = fs.readFileSync(path.join(__dirname, "js-test-data/searchdata.bin")); assert.ok(Search.init(buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength), 3)); - assert.equal(Search.dataSize, 545); - assert.equal(Search.symbolCount, 7); + assert.equal(Search.dataSize, 648); + assert.equal(Search.symbolCount, 9); assert.equal(Search.maxResults, 3); assert.deepEqual(Search.search('m'), [ { name: 'Math', @@ -195,8 +210,8 @@ const { StringDecoder } = require('string_decoder'); { let b85 = fs.readFileSync(path.join(__dirname, "js-test-data/searchdata.b85"), {encoding: 'utf-8'}); assert.ok(Search.load(b85)); - assert.equal(Search.dataSize, 548); /* some padding on the end, that's okay */ - assert.equal(Search.symbolCount, 7); + assert.equal(Search.dataSize, 648); /* some padding on the end, that's okay */ + assert.equal(Search.symbolCount, 9); assert.equal(Search.maxResults, 100); assert.deepEqual(Search.search('min'), [ { name: 'Math::min(int, int)', diff --git a/doxygen/test/test_search.py b/doxygen/test/test_search.py index 7a43c346..9b0b0ca3 100755 --- a/doxygen/test/test_search.py +++ b/doxygen/test/test_search.py @@ -132,6 +132,9 @@ def pretty_print_map(serialized: bytes, colors=False): if i: out += '\n' flags = ResultFlag(ResultMap.flags_struct.unpack_from(serialized, i*4 + 3)[0]) extra = [] + if flags & ResultFlag._TYPE == ResultFlag.ALIAS: + extra += ['alias={}'.format(ResultMap.alias_struct.unpack_from(serialized, offset)[0])] + offset += ResultMap.alias_struct.size if flags & ResultFlag.HAS_PREFIX: extra += ['prefix={}[:{}]'.format(*ResultMap.prefix_struct.unpack_from(serialized, offset))] offset += ResultMap.prefix_struct.size @@ -310,6 +313,8 @@ class MapSerialization(unittest.TestCase): 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#abcdef1234", suffix_length=8, flags=ResultFlag.FUNC|ResultFlag.DEPRECATED|ResultFlag.DELETED), 4) + self.assertEqual(map.add("Rectangle", "", alias=2), 5) + self.assertEqual(map.add("Rectangle::Rect()", "", suffix_length=2, alias=2), 6) serialized = map.serialize() self.compare(serialized, """ @@ -318,8 +323,10 @@ class MapSerialization(unittest.TestCase): 2: ::Range [prefix=0[:0], type=CLASS] -> classMath_1_1Range.html 3: ::min() [prefix=0[:18], type=FUNC] -> #abcdef2875 4: ::max(int, int) [prefix=0[:18], suffix_length=8, deprecated, deleted, type=FUNC] -> #abcdef1234 +5: Rectangle [alias=2] -> +6: ::Rect() [alias=2, prefix=5[:0], suffix_length=2] -> """) - self.assertEqual(len(serialized), 170) + self.assertEqual(len(serialized), 203) class Serialization(unittest.TestCase): def __init__(self, *args, **kwargs):