Skip to content

Commit 658e865

Browse files
committed
Add index_file config option
The option allows to use a different page for the section page instead of the first child.
1 parent 6e7b33e commit 658e865

File tree

3 files changed

+78
-21
lines changed

3 files changed

+78
-21
lines changed

README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,21 @@ To make writing this kind of `nav` more natural ([in YAML there's no better opti
6363

6464
[literate-nav]: https://oprypin.github.io/mkdocs-literate-nav/
6565

66+
### Specifying the page to use for the section
67+
68+
By default the first child is used as the section page, even if there is no
69+
`index.md`. If you want to change the page to use add the `index_file` config
70+
option:
71+
72+
```yaml
73+
plugins:
74+
- section-index:
75+
index_file: index.md
76+
```
77+
78+
The value is the name of the page to use, in this case `index.md`. If a child
79+
with that name does not exist no section page is generated.
80+
6681
## [Implementation](https://github.com/oprypin/mkdocs-section-index/blob/master/mkdocs_section_index/plugin.py)
6782

6883
### "Protocol"

mkdocs_section_index/plugin.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import collections
22
import logging
3+
import os
34

45
import mkdocs.utils
56
from jinja2 import Environment
@@ -16,6 +17,8 @@
1617

1718

1819
class SectionIndexPlugin(BasePlugin):
20+
config_scheme = (("index_file", mkdocs.config.config_options.Type(str, default=None)),)
21+
1922
def on_nav(self, nav: Navigation, config, files) -> Navigation:
2023
todo = collections.deque((nav.items,))
2124
while todo:
@@ -24,7 +27,17 @@ def on_nav(self, nav: Navigation, config, files) -> Navigation:
2427
if not isinstance(section, Section) or not section.children:
2528
continue
2629
todo.append(section.children)
27-
page = section.children[0]
30+
index_file = self.config["index_file"]
31+
if index_file is None:
32+
page_index = 0
33+
page = section.children[0]
34+
else:
35+
for page_index, child in enumerate(section.children):
36+
if os.path.basename(child.file.src_path) == index_file:
37+
page = child
38+
break
39+
else:
40+
continue
2841
if not isinstance(page, Page):
2942
continue
3043
assert not page.children
@@ -34,12 +47,14 @@ def on_nav(self, nav: Navigation, config, files) -> Navigation:
3447
page.is_section = page.is_page = True
3548
page.title = section.title
3649
# The page leaves the section but takes over children that used to be its peers.
37-
section.children.pop(0)
50+
section.children.pop(page_index)
3851
page.children = section.children
3952
for child in page.children:
4053
child.parent = page
4154
# The page replaces the section; the section will be garbage-collected.
4255
items[i] = page
56+
if i > 0:
57+
items[i - 1].next_page = items[i]
4358
self._nav = nav
4459
return nav
4560

tests/test_plugin.py

Lines changed: 46 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,39 +15,64 @@
1515

1616

1717
@pytest.mark.parametrize("directory_urls", ["use_directory_urls", "no_directory_urls"])
18-
@pytest.mark.parametrize("nav", ["explicit_nav", "derived_nav"])
19-
def test_real_example(tmpdir, directory_urls, nav):
18+
@pytest.mark.parametrize("nav_src", ["explicit_nav", "derived_nav"])
19+
@pytest.mark.parametrize("index_file", ["default_index_file", "index.md", "foo.md"])
20+
def test_real_example(tmpdir, directory_urls, nav_src, index_file):
2021
config = dict(
2122
docs_dir=str(example_dir / "docs"),
2223
site_dir=tmpdir,
2324
use_directory_urls=(directory_urls == "use_directory_urls"),
24-
nav=load_config(str(example_dir / "mkdocs.yml"))["nav"] if nav == "explicit_nav" else None,
25+
nav=load_config(str(example_dir / "mkdocs.yml"))["nav"]
26+
if nav_src == "explicit_nav"
27+
else None,
2528
)
29+
if nav_src == "derived_nav" and index_file != "default_index_file":
30+
# only test index_file for derived nav
31+
# if index_file is None we test the default value (which is first child)
32+
config["index_file"] = index_file
33+
else:
34+
index_file = None
2635
files = get_files(config)
2736
nav = get_navigation(files, config)
28-
nav = plugin.SectionIndexPlugin().on_nav(nav, config, files)
37+
instance = plugin.SectionIndexPlugin()
38+
instance.load_config(config)
39+
if index_file is None:
40+
assert instance.config["index_file"] is None
41+
nav = instance.on_nav(nav, instance.config, files)
2942

30-
assert len(nav.pages) == 5
31-
assert len(nav.items) == 3
43+
assert len(nav.pages) == (6 if nav_src == "derived_nav" else 5)
44+
assert len(nav.items) == (4 if nav_src == "derived_nav" else 3)
45+
46+
# items = index.md, baz.md, borgs/, z_noindex/
3247

3348
assert nav.items[1].is_page
3449
assert nav.items[1].file.name == "baz"
3550
assert not nav.items[1].is_section
3651

37-
sec = nav.items[2]
38-
assert isinstance(sec, SectionPage)
39-
assert sec.is_section
40-
assert sec.is_page
41-
assert sec.title == "Borgs"
42-
assert sec.url in ("borgs/", "borgs/index.html")
43-
assert sec.file.name == "index"
52+
assert nav.items[0].file.name == "index"
53+
assert not nav.items[0].is_section
54+
55+
borgs_sec = nav.items[2]
56+
assert isinstance(borgs_sec, SectionPage)
57+
assert borgs_sec.is_section
58+
assert borgs_sec.is_page
59+
assert borgs_sec.title == "Borgs"
60+
if index_file == "foo.md":
61+
assert borgs_sec.url in ("borgs/foo/", "borgs/foo.html")
62+
assert borgs_sec.file.name == "foo"
63+
else:
64+
assert borgs_sec.url in ("borgs/", "borgs/index.html")
65+
assert borgs_sec.file.name == "index"
4466

45-
assert len(sec.children) == 2
46-
assert sec.children[0].is_page
47-
assert sec.children[0].file.name == "bar"
67+
assert len(borgs_sec.children) == 2
68+
assert borgs_sec.children[0].is_page
69+
if index_file == "foo.md":
70+
assert borgs_sec.children[0].file.name == "index"
71+
else:
72+
assert borgs_sec.children[0].file.name == "bar"
4873

49-
assert nav.items[1].next_page == sec
50-
assert sec.children[1].parent == sec
74+
assert nav.items[1].next_page == borgs_sec
75+
assert borgs_sec.children[1].parent == borgs_sec
5176

5277

5378
@dataclasses.dataclass
@@ -74,7 +99,9 @@ def test_nav_repr(golden, tmpdir):
7499
config = dict(nav=golden["input"], use_directory_urls=use_directory_urls)
75100
files = FakeFiles(config)
76101
nav = get_navigation(files, config)
77-
nav = plugin.SectionIndexPlugin().on_nav(nav, config, files)
102+
instance = plugin.SectionIndexPlugin()
103+
instance.load_config(config)
104+
nav = instance.on_nav(nav, instance.config, files)
78105
assert str(nav) == golden.out[use_directory_urls]
79106

80107

0 commit comments

Comments
 (0)