mkdocs-nav-numbering-plugin 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,3 @@
1
+ from .nav_numbering import NavNumberingPlugin
2
+
3
+ __all__ = ["NavNumberingPlugin"]
@@ -0,0 +1,169 @@
1
+ import re
2
+ from typing import Dict, List
3
+
4
+ from mkdocs.config import config_options
5
+ from mkdocs.plugins import BasePlugin
6
+ from mkdocs.structure.nav import Navigation, Section, Page, Link
7
+
8
+
9
+ class NavNumberingPlugin(BasePlugin):
10
+ """
11
+ MkDocs plugin to add hierarchical numbering to navigation items and page headings.
12
+
13
+ Configuration options:
14
+ enabled: Enable/disable the plugin (default: true)
15
+ nav_depth: Maximum depth for nav numbering, 0 = unlimited (default: 0)
16
+ heading_depth: Maximum depth for heading numbering within pages, 0 = unlimited (default: 0)
17
+ number_nav: Add numbers to navigation items (default: true)
18
+ number_headings: Add numbers to headings within pages (default: true)
19
+ number_h1: Add number to the first h1 (page title) (default: true)
20
+ separator: Separator between number parts (default: ".")
21
+ exclude: List of page paths to exclude from numbering (default: [])
22
+ """
23
+
24
+ config_scheme = (
25
+ ("enabled", config_options.Type(bool, default=True)),
26
+ ("nav_depth", config_options.Type(int, default=0)),
27
+ ("heading_depth", config_options.Type(int, default=0)),
28
+ ("number_nav", config_options.Type(bool, default=True)),
29
+ ("number_headings", config_options.Type(bool, default=True)),
30
+ ("number_h1", config_options.Type(bool, default=True)),
31
+ ("separator", config_options.Type(str, default=".")),
32
+ ("exclude", config_options.Type(list, default=[])),
33
+ )
34
+
35
+ def __init__(self):
36
+ # Maps page src_uri -> nav number, e.g. "Manual/Model/Model_Intro.md" -> "1.2.1"
37
+ self.page_numbers: Dict[str, str] = {}
38
+
39
+ def on_nav(self, nav: Navigation, config, files) -> Navigation:
40
+ """
41
+ Assign numbers to all nav items based on their position, including groups.
42
+ """
43
+ if not self.config["enabled"] or not self.config["number_nav"]:
44
+ return nav
45
+
46
+ nav_depth = self.config["nav_depth"]
47
+ separator = self.config["separator"]
48
+ exclude = self.config["exclude"]
49
+
50
+ def walk(items, prefix: List[int]) -> None:
51
+ for idx, item in enumerate(items, start=1):
52
+ number_parts = prefix + [idx]
53
+ current_depth = len(number_parts)
54
+
55
+ # Check if we should number at this depth
56
+ should_number = nav_depth == 0 or current_depth <= nav_depth
57
+ number_str = separator.join(map(str, number_parts))
58
+
59
+ # Section (group) – e.g. "Manual", "Model Environment"
60
+ if isinstance(item, Section):
61
+ if should_number:
62
+ item.title = f"{number_str} {item.title}"
63
+ # For sections, prefix continues for children
64
+ walk(item.children, number_parts)
65
+
66
+ # Page – actual Markdown file
67
+ elif isinstance(item, Page):
68
+ # Check if page is excluded
69
+ src_uri = item.file.src_uri if item.file else None
70
+ is_excluded = src_uri and any(
71
+ src_uri.endswith(exc) or exc in src_uri for exc in exclude
72
+ )
73
+
74
+ if should_number and not is_excluded:
75
+ item.title = f"{number_str} {item.title}"
76
+ # Map src_uri -> number so we can use it in on_page_markdown
77
+ if src_uri and not is_excluded:
78
+ self.page_numbers[src_uri] = number_str
79
+
80
+ # Link or other types – optionally number them or skip
81
+ elif isinstance(item, Link):
82
+ if should_number:
83
+ item.title = f"{number_str} {item.title}"
84
+ else:
85
+ # Unknown / custom nav item – just recurse if it has children
86
+ children = getattr(item, "children", None)
87
+ if children:
88
+ walk(children, number_parts)
89
+
90
+ # Start top-level at 1,2,3,... (tabs like Introduction, Manual, Tutorials)
91
+ walk(nav.items, [])
92
+
93
+ return nav
94
+
95
+ def on_page_markdown(self, markdown: str, page: Page, config, files) -> str:
96
+ """
97
+ Prepend the nav number to headings inside each page.
98
+ - The first h1 (page title) gets the base_number (e.g., 3.1.1)
99
+ - Subsequent h2, h3, etc. get sub-numbers (e.g., 3.1.1.1, 3.1.1.2)
100
+ """
101
+ if not self.config["enabled"] or not self.config["number_headings"]:
102
+ return markdown
103
+
104
+ src_uri = page.file.src_uri if page and page.file else None
105
+ base_number = self.page_numbers.get(src_uri)
106
+ if not base_number:
107
+ return markdown
108
+
109
+ heading_depth = self.config["heading_depth"]
110
+ number_h1 = self.config["number_h1"]
111
+ separator = self.config["separator"]
112
+ base_depth = len(base_number.split(separator))
113
+
114
+ # Track whether we've seen the first h1 (page title)
115
+ first_h1_seen = [False] # Use list to allow mutation in nested function
116
+
117
+ # Track heading counters for h2+ (sub-sections within the page)
118
+ # h2 -> counter[0], h3 -> counter[1], etc.
119
+ counters: List[int] = []
120
+
121
+ def repl(match: re.Match) -> str:
122
+ hashes = match.group("hashes")
123
+ title = match.group("title").strip()
124
+ level = len(hashes) # "#"=1, "##"=2, etc.
125
+
126
+ # Avoid double-numbering if already numbered
127
+ if re.match(r"^\d+(\.\d+)*\s+", title):
128
+ return match.group(0)
129
+
130
+ # First h1 is the page title - use base_number directly
131
+ if level == 1:
132
+ if not first_h1_seen[0]:
133
+ first_h1_seen[0] = True
134
+ if number_h1:
135
+ return f"{hashes} {base_number} {title}"
136
+ return match.group(0)
137
+ else:
138
+ # Additional h1s in the same page - handle gracefully
139
+ counters.clear()
140
+ if number_h1:
141
+ return f"{hashes} {base_number} {title}"
142
+ return match.group(0)
143
+
144
+ # For h2 and below, add sub-numbering relative to base_number
145
+ # Adjust level: h2 -> index 0, h3 -> index 1, etc.
146
+ adjusted_level = level - 1 # h2=1, h3=2, etc.
147
+
148
+ # Check depth limit (total depth = base_depth + adjusted_level)
149
+ total_depth = base_depth + adjusted_level
150
+ if heading_depth > 0 and total_depth > heading_depth:
151
+ return match.group(0)
152
+
153
+ # Resize counters to current adjusted level
154
+ while len(counters) < adjusted_level:
155
+ counters.append(0)
156
+ while len(counters) > adjusted_level:
157
+ counters.pop()
158
+
159
+ counters[adjusted_level - 1] += 1
160
+
161
+ # Build full number: base_number + sub-counters
162
+ rel = separator.join(str(c) for c in counters[:adjusted_level])
163
+ full_number = f"{base_number}{separator}{rel}"
164
+
165
+ return f"{hashes} {full_number} {title}"
166
+
167
+ heading_pattern = re.compile(r"^(?P<hashes>#{1,6})\s+(?P<title>.+)$", re.MULTILINE)
168
+ markdown = heading_pattern.sub(repl, markdown)
169
+ return markdown
@@ -0,0 +1,68 @@
1
+ Metadata-Version: 2.4
2
+ Name: mkdocs-nav-numbering-plugin
3
+ Version: 0.1.0
4
+ Summary: MkDocs plugin to add hierarchical numbering to nav and page headings
5
+ Author: ZMT Zurich MedTech AG
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/your-org/mkdocs-nav-numbering-plugin
8
+ Project-URL: Repository, https://github.com/your-org/mkdocs-nav-numbering-plugin
9
+ Project-URL: Issues, https://github.com/your-org/mkdocs-nav-numbering-plugin/issues
10
+ Keywords: mkdocs,plugin,navigation,numbering,documentation
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Environment :: Plugins
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: Topic :: Documentation
19
+ Classifier: Topic :: Software Development :: Documentation
20
+ Requires-Python: >=3.8
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Requires-Dist: mkdocs>=1.4
24
+ Dynamic: license-file
25
+
26
+ # mkdocs-nav-numbering-plugin
27
+
28
+ MkDocs plugin that adds hierarchical numbering to navigation items and page headings.
29
+
30
+ ## Features
31
+
32
+ - Number nav sections, pages, and links (optional)
33
+ - Number page headings based on nav position
34
+ - Configurable depth limits for nav and headings
35
+ - Configurable separator
36
+ - Exclude specific pages
37
+
38
+ ## Installation
39
+
40
+ ```bash
41
+ pip install mkdocs-nav-numbering-plugin
42
+ ```
43
+
44
+ ## Usage
45
+
46
+ ```yaml
47
+ plugins:
48
+ - nav-numbering:
49
+ nav_depth: 4
50
+ heading_depth: 5
51
+ number_h1: true
52
+ number_nav: true
53
+ number_headings: true
54
+ separator: "."
55
+ exclude:
56
+ - index.md
57
+ ```
58
+
59
+ ## Options
60
+
61
+ - `enabled` (bool, default: true)
62
+ - `nav_depth` (int, default: 0) — 0 means unlimited
63
+ - `heading_depth` (int, default: 0) — 0 means unlimited
64
+ - `number_nav` (bool, default: true)
65
+ - `number_headings` (bool, default: true)
66
+ - `number_h1` (bool, default: true)
67
+ - `separator` (str, default: ".")
68
+ - `exclude` (list, default: [])
@@ -0,0 +1,8 @@
1
+ mkdocs_nav_numbering_plugin/__init__.py,sha256=McZEZwPtatKF0PvPVKMD7_nBeaOjdHNME6tQNwNIt8M,80
2
+ mkdocs_nav_numbering_plugin/nav_numbering.py,sha256=zRiG9_AZdLKe21pnb_b_vQSw8LkWpL8HK6UdY14WoPc,7263
3
+ mkdocs_nav_numbering_plugin-0.1.0.dist-info/licenses/LICENSE,sha256=o8hK_UrJ1kd51VuQ5ZP4d8gwK5WPlt6Zg5vO-T42eoo,1078
4
+ mkdocs_nav_numbering_plugin-0.1.0.dist-info/METADATA,sha256=Erwhh43scMWp4QOY-uGORxkA-5TPRs88iZfNoqqoDew,2005
5
+ mkdocs_nav_numbering_plugin-0.1.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
6
+ mkdocs_nav_numbering_plugin-0.1.0.dist-info/entry_points.txt,sha256=NnO7O_09mMyAHFIspg2zmsfri_m7nt8Km8xZK0tgvtQ,80
7
+ mkdocs_nav_numbering_plugin-0.1.0.dist-info/top_level.txt,sha256=UcRwMarClerK-Iuj0RooOAq7IVhn_oRmQRiCZgSCfN4,28
8
+ mkdocs_nav_numbering_plugin-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.10.2)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [mkdocs.plugins]
2
+ nav-numbering = mkdocs_nav_numbering_plugin:NavNumberingPlugin
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ZMT Zurich MedTech AG
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ mkdocs_nav_numbering_plugin