diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7a90113b..351664f3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -114,9 +114,6 @@ jobs: - name: Run repository checks if: always() run: pre-commit run --all-files --show-diff-on-failure - - name: Check with mypy - if: always() - run: hatch run types:check package: runs-on: ubuntu-latest diff --git a/mkdocs/commands/build.py b/mkdocs/commands/build.py index 0df8e90e..1c93c498 100644 --- a/mkdocs/commands/build.py +++ b/mkdocs/commands/build.py @@ -20,7 +20,11 @@ get_files, set_exclusions, ) -from mkdocs.structure.nav import Navigation, get_navigation +from mkdocs.structure.nav import ( + Navigation, + _set_section_titles_from_index_pages, + get_navigation, +) from mkdocs.structure.pages import Page from mkdocs.utils import DuplicateFilter # noqa: F401 - legacy re-export from mkdocs.utils import templates @@ -351,6 +355,9 @@ def build( + "\n - ".join(excluded) ) + # Update auto-generated section titles from index page titles. + _set_section_titles_from_index_pages(nav.items) + # Run `env` plugin events. env = config.plugins.on_env(env, config=config, files=files) diff --git a/mkdocs/structure/nav.py b/mkdocs/structure/nav.py index 3ebe0f47..a10b8b3b 100644 --- a/mkdocs/structure/nav.py +++ b/mkdocs/structure/nav.py @@ -254,7 +254,7 @@ def _get_by_type(nav, t: type[T]) -> list[T]: def _add_parent_links(nav) -> None: for item in nav: - if item.is_section: + if isinstance(item, Section): for child in item.children: child.parent = item _add_parent_links(item.children) @@ -265,3 +265,26 @@ def _add_previous_and_next_links(pages: list[Page]) -> None: zipped = zip(bookended[:-2], pages, bookended[2:]) for page0, page1, page2 in zipped: page1.previous_page, page1.next_page = page0, page2 + + +def _set_section_titles_from_index_pages(items: list[StructureItem]) -> None: + """ + For auto-generated navigation, update section titles to use the index + page's title instead of the directory name. + + When `nav` is not explicitly configured, MkDocs generates section names + from directory names (e.g. "about" for an "about/" directory). If the + section contains an index page (e.g. "about/index.md"), this function + uses that page's title as the section title instead. + + This only applies when `page.title` is not None (i.e. the page has + been read/rendered, so its title is known from metadata or headings). + """ + for item in items: + if not isinstance(item, Section): + continue + for child in item.children: + if isinstance(child, Page) and child.is_index and child.title is not None: + item.title = child.title + break + _set_section_titles_from_index_pages(item.children) diff --git a/mkdocs/tests/structure/nav_tests.py b/mkdocs/tests/structure/nav_tests.py index 4f020ded..6b4530c5 100644 --- a/mkdocs/tests/structure/nav_tests.py +++ b/mkdocs/tests/structure/nav_tests.py @@ -4,7 +4,12 @@ import unittest from mkdocs.structure.files import File, Files, set_exclusions -from mkdocs.structure.nav import Section, _get_by_type, get_navigation +from mkdocs.structure.nav import ( + Section, + _get_by_type, + _set_section_titles_from_index_pages, + get_navigation, +) from mkdocs.structure.pages import Page from mkdocs.tests.base import dedent, load_config @@ -608,3 +613,33 @@ def test_get_by_type_nested_sections(self): files = Files(fs) site_navigation = get_navigation(files, cfg) self.assertEqual(len(_get_by_type(site_navigation, Section)), 2) + + def test_smart_section_titles_from_index_pages(self): + """Section titles use index page titles instead of directory names.""" + cfg = load_config(site_url="http://example.com/") + fs = [ + "index.md", + "about/index.md", + "about/license.md", + "api-guide/index.md", + "api-guide/running.md", + ] + files = Files( + [File(s, cfg.docs_dir, cfg.site_dir, cfg.use_directory_urls) for s in fs] + ) + site_navigation = get_navigation(files, cfg) + + # Before update: sections use directory names + about_section = site_navigation.items[1] + api_section = site_navigation.items[2] + self.assertEqual(about_section.title, "About") + self.assertEqual(api_section.title, "Api guide") + + # Set titles on index pages (as if they were read/rendered) + about_section.children[0].title = "About This Project" + api_section.children[0].title = "API Reference" + + _set_section_titles_from_index_pages(site_navigation.items) + + self.assertEqual(about_section.title, "About This Project") + self.assertEqual(api_section.title, "API Reference")