Fix #2189: previous sibling link has broken if previous doc is under nested toctree

This commit is contained in:
Takeshi KOMIYA 2015-12-26 23:57:09 +09:00
parent 222a51e0cf
commit 8a763feb6b
9 changed files with 55 additions and 56 deletions

View File

@ -1950,63 +1950,31 @@ class BuildEnvironment:
for (key_, group) in groupby(newlist, keyfunc2)]
def collect_relations(self):
traversed = set()
def traverse_toctree(parent, docname):
# traverse toctree by pre-order
yield parent, docname
traversed.add(docname)
for child in (self.toctree_includes.get(docname) or []):
for subparent, subdocname in traverse_toctree(docname, child):
if subdocname not in traversed:
yield subparent, subdocname
traversed.add(subdocname)
relations = {}
getinc = self.toctree_includes.get
docnames = traverse_toctree(None, self.config.master_doc)
prevdoc = None
parent, docname = docnames.next()
for nextparent, nextdoc in docnames:
relations[docname] = [parent, prevdoc, nextdoc]
prevdoc = docname
docname = nextdoc
parent = nextparent
def collect(parents, parents_set, docname, previous, next):
# circular relationship?
if docname in parents_set:
# we will warn about this in resolve_toctree()
return
if docname in relations:
return
includes = getinc(docname)
# previous
if not previous:
# if no previous sibling, go to parent
previous = parents[0][0]
else:
# else, go to previous sibling, or if it has children, to
# the last of its children, or if that has children, to the
# last of those, and so forth
while 1:
previncs = getinc(previous)
if previncs:
previous = previncs[-1]
else:
break
# next
if includes:
# if it has children, go to first of them
next = includes[0]
elif next:
# else, if next sibling, go to it
pass
else:
# else, go to the next sibling of the parent, if present,
# else the grandparent's sibling, if present, and so forth
for parname, parindex in parents:
parincs = getinc(parname)
if parincs:
for parinc in parincs[parindex + 1:]:
if parinc in relations or parinc == docname:
pass
else:
next = parinc
break
relations[docname] = [parent, prevdoc, None]
if next:
break
# else it will stay None
# same for children
if includes:
for subindex, args in enumerate(zip(includes,
[None] + includes,
includes[1:] + [None])):
collect([(docname, subindex)] + parents,
parents_set.union([docname]), *args)
relations[docname] = [parents[0][0], previous, next]
collect([(None, 0)], set(), self.config.master_doc, None, None)
return relations
def check_consistency(self):

View File

@ -0,0 +1,4 @@
Bar-4
=====
bar

View File

@ -5,3 +5,4 @@ Bar
:glob:
*
bar_4/index

View File

@ -8,3 +8,4 @@ test-toctree-glob
bar/index
bar/*
baz
qux/index

View File

@ -0,0 +1,4 @@
Quux
====
quux

View File

@ -0,0 +1,8 @@
Qux
===
.. toctree::
:glob:
:hidden:
*

View File

@ -0,0 +1,4 @@
Qux-1
=====
qux

View File

@ -0,0 +1,4 @@
Qux-1
=====
qux

View File

@ -20,5 +20,10 @@ def test_relations(app, status, warning):
assert app.builder.relations['bar/index'] == ['index', 'foo', 'bar/bar_1']
assert app.builder.relations['bar/bar_1'] == ['bar/index', 'bar/index', 'bar/bar_2']
assert app.builder.relations['bar/bar_2'] == ['bar/index', 'bar/bar_1', 'bar/bar_3']
assert app.builder.relations['bar/bar_3'] == ['bar/index', 'bar/bar_2', 'baz']
assert app.builder.relations['baz'] == ['index', 'bar/bar_3', None]
assert app.builder.relations['bar/bar_3'] == ['bar/index', 'bar/bar_2', 'bar/bar_4/index']
assert app.builder.relations['bar/bar_4/index'] == ['bar/index', 'bar/bar_3', 'baz']
assert app.builder.relations['baz'] == ['index', 'bar/bar_4/index', 'qux/index']
assert app.builder.relations['qux/index'] == ['index', 'baz', 'qux/qux_1']
assert app.builder.relations['qux/qux_1'] == ['qux/index', 'qux/index', 'qux/qux_2']
assert app.builder.relations['qux/qux_2'] == ['qux/index', 'qux/qux_1', None]
assert 'quux' not in app.builder.relations