diff --git a/sphinx/environment.py b/sphinx/environment.py index 6c3a2cc98..743021e0f 100644 --- a/sphinx/environment.py +++ b/sphinx/environment.py @@ -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): diff --git a/tests/roots/test-toctree-glob/bar/bar_4/index.rst b/tests/roots/test-toctree-glob/bar/bar_4/index.rst new file mode 100644 index 000000000..4fae623ce --- /dev/null +++ b/tests/roots/test-toctree-glob/bar/bar_4/index.rst @@ -0,0 +1,4 @@ +Bar-4 +===== + +bar diff --git a/tests/roots/test-toctree-glob/bar/index.rst b/tests/roots/test-toctree-glob/bar/index.rst index 290bd2b75..74a9ba942 100644 --- a/tests/roots/test-toctree-glob/bar/index.rst +++ b/tests/roots/test-toctree-glob/bar/index.rst @@ -5,3 +5,4 @@ Bar :glob: * + bar_4/index diff --git a/tests/roots/test-toctree-glob/index.rst b/tests/roots/test-toctree-glob/index.rst index 4a8acecbc..079cd6027 100644 --- a/tests/roots/test-toctree-glob/index.rst +++ b/tests/roots/test-toctree-glob/index.rst @@ -8,3 +8,4 @@ test-toctree-glob bar/index bar/* baz + qux/index diff --git a/tests/roots/test-toctree-glob/quux.rst b/tests/roots/test-toctree-glob/quux.rst new file mode 100644 index 000000000..340389d0a --- /dev/null +++ b/tests/roots/test-toctree-glob/quux.rst @@ -0,0 +1,4 @@ +Quux +==== + +quux diff --git a/tests/roots/test-toctree-glob/qux/index.rst b/tests/roots/test-toctree-glob/qux/index.rst new file mode 100644 index 000000000..ad0bee51f --- /dev/null +++ b/tests/roots/test-toctree-glob/qux/index.rst @@ -0,0 +1,8 @@ +Qux +=== + +.. toctree:: + :glob: + :hidden: + + * diff --git a/tests/roots/test-toctree-glob/qux/qux_1.rst b/tests/roots/test-toctree-glob/qux/qux_1.rst new file mode 100644 index 000000000..bac227b42 --- /dev/null +++ b/tests/roots/test-toctree-glob/qux/qux_1.rst @@ -0,0 +1,4 @@ +Qux-1 +===== + +qux diff --git a/tests/roots/test-toctree-glob/qux/qux_2.rst b/tests/roots/test-toctree-glob/qux/qux_2.rst new file mode 100644 index 000000000..bac227b42 --- /dev/null +++ b/tests/roots/test-toctree-glob/qux/qux_2.rst @@ -0,0 +1,4 @@ +Qux-1 +===== + +qux diff --git a/tests/test_toctree.py b/tests/test_toctree.py index 17e1a780d..d91d92389 100644 --- a/tests/test_toctree.py +++ b/tests/test_toctree.py @@ -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