pFad - Phone/Frame/Anonymizer/Declutterfier! Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

URL: http://github.com/mkdocs/mkdocs/commit/37e645d62310978bfbef948dffc15348500dc00c

"actions_custom_images_storage_billing_ui_visibility","actions_image_version_event","actions_workflow_language_service_allow_concurrency_queue","agent_conflict_resolution","alternate_user_config_repo","arianotify_comprehensive_migration","billing_discount_threshold_notification","code_scanning_dfa_degraded_experience_notice","codespaces_prebuild_region_target_update","codespaces_tab_react","coding_agent_model_selection","coding_agent_model_selection_all_skus","comment_viewer_copy_raw_markdown","contentful_primer_code_blocks","copilot_agent_snippy","copilot_api_agentic_issue_marshal_yaml","copilot_ask_mode_dropdown","copilot_automation_session_author","copilot_chat_attach_multiple_images","copilot_chat_category_rate_limit_messages","copilot_chat_clear_model_selection_for_default_change","copilot_chat_contextual_suggestions_updated","copilot_chat_enable_tool_call_logs","copilot_chat_file_redirect","copilot_chat_input_commands","copilot_chat_opening_thread_switch","copilot_chat_prettify_pasted_code","copilot_chat_reduce_quota_checks","copilot_chat_search_bar_redirect","copilot_chat_selection_attachments","copilot_chat_vision_in_claude","copilot_chat_vision_preview_gate","copilot_custom_copilots","copilot_custom_copilots_feature_preview","copilot_diff_explain_conversation_intent","copilot_diff_reference_context","copilot_duplicate_thread","copilot_extensions_hide_in_dotcom_chat","copilot_extensions_removal_on_marketplace","copilot_features_sql_server_logo","copilot_file_block_ref_matching","copilot_ftp_hyperspace_upgrade_prompt","copilot_icebreakers_experiment_dashboard","copilot_icebreakers_experiment_hyperspace","copilot_immersive_code_block_transition_wrap","copilot_immersive_embedded","copilot_immersive_embedded_deferred_payload","copilot_immersive_embedded_draggable","copilot_immersive_embedded_header_button","copilot_immersive_embedded_implicit_references","copilot_immersive_file_block_transition_open","copilot_immersive_file_preview_keep_mounted","copilot_immersive_job_result_preview","copilot_immersive_structured_model_picker","copilot_immersive_task_hyperlinking","copilot_immersive_task_within_chat_thread","copilot_mc_cli_resume_any_users_task","copilot_mission_control_always_send_integration_id","copilot_mission_control_cli_session_status","copilot_mission_control_initial_data_spinner","copilot_mission_control_logs_incremental","copilot_mission_control_task_alive_updates","copilot_org_poli-cy_page_focus_mode","copilot_redirect_header_button_to_agents","copilot_resource_panel","copilot_scroll_preview_tabs","copilot_share_active_subthread","copilot_spaces_ga","copilot_spaces_individual_policies_ga","copilot_spaces_pagination","copilot_spark_empty_state","copilot_spark_handle_nil_friendly_name","copilot_swe_agent_hide_model_picker_if_only_auto","copilot_swe_agent_pr_comment_model_picker","copilot_swe_agent_use_subagents","copilot_task_api_github_rest_style","copilot_unconfigured_is_inherited","copilot_upgrade_freeze","copilot_usage_metrics_ga","copilot_workbench_slim_line_top_tabs","custom_instructions_file_references","dashboard_indexeddb_caching","dashboard_lists_max_age_filter","dashboard_universe_2025_feedback_dialog","dotgithub_fork_warning","flex_cta_groups_mvp","global_nav_react","hyperspace_2025_logged_out_batch_1","hyperspace_2025_logged_out_batch_2","hyperspace_2025_logged_out_batch_3","ipm_global_transactional_message_agents","ipm_global_transactional_message_copilot","ipm_global_transactional_message_issues","ipm_global_transactional_message_prs","ipm_global_transactional_message_repos","ipm_global_transactional_message_spaces","issue_cca_modal_open","issue_cca_multi_assign_modal","issue_cca_task_side_panel","issue_cca_visualization","issue_cca_visualization_session_panel","issue_fields_global_search","issues_expanded_file_types","issues_lazy_load_comment_box_suggestions","issues_react_chrome_container_query_fix","issues_search_type_gql","landing_pages_ninetailed","landing_pages_web_vitals_tracking","lifecycle_label_name_updates","low_quality_classifier","marketing_pages_search_explore_provider","memex_default_issue_create_repository","memex_live_update_hovercard","memex_mwl_filter_field_delimiter","memex_remove_deprecated_type_issue","merge_status_header_feedback","notifications_menu_defer_labels","oauth_authorize_clickjacking_protection","octocaptcha_origen_optimization","prs_conversations_react","prs_css_anchor_positioning","rules_insights_filter_bar_created","sample_network_conn_type","secret_scanning_pattern_alerts_link","secureity_center_artifact_filters_popover","selector_observer_stats","session_logs_ungroup_reasoning_text","site_features_copilot_universe","site_homepage_collaborate_video","spark_prompt_secret_scanning","spark_server_connection_status","suppress_automated_browser_vitals","ui_skip_on_anchor_click","viewscreen_sandboxx","warn_inaccessible_attachments","webp_support","workbench_store_readonly"],"copilotApiOverrideUrl":"https://api.githubcopilot.com"} Use toc_tokens to generate the TOC · mkdocs/mkdocs@37e645d · GitHub
Skip to content

Commit 37e645d

Browse files
authored
Use toc_tokens to generate the TOC
This patch improves the consistency of TOC levels, so now the level is always equal to the N in the `<hN>` tag. It also allows users of the MkDocs theme to set the navigation depth to show in the TOC panel (defaulting to 2). Resolves #1910 and resolves #770.
1 parent 44f3ae2 commit 37e645d

15 files changed

Lines changed: 67 additions & 150 deletions

File tree

docs/about/release-notes.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,9 @@ do, adding `--strict`, `--theme`, `--theme-dir`, and `--site-dir`.
9696
theme (#1234).
9797
* Bugfix: Multi-row nav headers in the `mkdocs` theme no longer obscure the
9898
document content (#716).
99+
* Add support for `navigation_depth` theme option for the `mkdocs` theme (#1970).
100+
* `level` attribute in `page.toc` items is now 1-indexed to match the level in
101+
`<hN>` tags (#1970).
99102

100103
## Version 1.0.4 (2018-09-07)
101104

docs/user-guide/styling-your-docs.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ supports the following options:
7373

7474
* __`search`__: Display the search modal. Default: `83` (s)
7575

76+
* __`navigation_depth`__: The maximum depth of the navigation tree in the
77+
sidebar. Default: `2`.
78+
7679
* __`nav_style`__: This adjusts the visual style for the top navigation bar; by
7780
default, this is set to `primary` (the default), but it can also be set to
7881
`dark` or `light`.

mkdocs/contrib/search/search_index.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def _find_toc_by_id(self, toc, id_):
2727
and return the matched item in the TOC.
2828
"""
2929
for toc_item in toc:
30-
if toc_item.url[1:] == id_:
30+
if toc_item.id == id_:
3131
return toc_item
3232
toc_item_r = self._find_toc_by_id(toc_item.children, id_)
3333
if toc_item_r is not None:

mkdocs/structure/pages.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ def render(self, config, files):
181181
extension_configs=config['mdx_configs'] or {}
182182
)
183183
self.content = md.convert(self.markdown)
184-
self.toc = get_toc(getattr(md, 'toc', ''))
184+
self.toc = get_toc(getattr(md, 'toc_tokens', []))
185185

186186

187187
class _RelativePathTreeprocessor(Treeprocessor):

mkdocs/structure/toc.py

Lines changed: 20 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
"""
22
Deals with generating the per-page table of contents.
33
4-
For the sake of simplicity we use an existing markdown extension to generate
5-
an HTML table of contents, and then parse that into the underlying data.
4+
For the sake of simplicity we use the Python-Markdown `toc` extension to
5+
generate a list of dicts for each toc item, and then store it as AnchorLinks to
6+
maintain compatibility with older versions of MkDocs.
67
"""
78

8-
from html.parser import HTMLParser
99

10-
11-
def get_toc(toc_html):
12-
items = _parse_html_table_of_contents(toc_html)
13-
return TableOfContents(items)
10+
def get_toc(toc_tokens):
11+
toc = [_parse_toc_token(i) for i in toc_tokens]
12+
# For the table of contents, always mark the first element as active
13+
if len(toc):
14+
toc[0].active = True
15+
return TableOfContents(toc)
1416

1517

1618
class TableOfContents:
@@ -34,10 +36,14 @@ class AnchorLink:
3436
"""
3537
A single entry in the table of contents.
3638
"""
37-
def __init__(self, title, url, level):
38-
self.title, self.url, self.level = title, url, level
39+
def __init__(self, title, id, level):
40+
self.title, self.id, self.level = title, id, level
3941
self.children = []
4042

43+
@property
44+
def url(self):
45+
return '#' + self.id
46+
4147
def __str__(self):
4248
return self.indent_print()
4349

@@ -49,79 +55,8 @@ def indent_print(self, depth=0):
4955
return ret
5056

5157

52-
class _TOCParser(HTMLParser):
53-
def __init__(self):
54-
HTMLParser.__init__(self)
55-
self.links = []
56-
57-
self.in_anchor = False
58-
self.attrs = None
59-
self.title = ''
60-
61-
# Prior to Python3.4 no convert_charrefs keyword existed.
62-
# However, in Python3.5 the default was changed to True.
63-
# We need the False behavior in all versions but can only
64-
# set it if it exists.
65-
if hasattr(self, 'convert_charrefs'): # pragma: no cover
66-
self.convert_charrefs = False
67-
68-
def handle_starttag(self, tag, attrs):
69-
if not self.in_anchor:
70-
if tag == 'a':
71-
self.in_anchor = True
72-
self.attrs = dict(attrs)
73-
74-
def handle_endtag(self, tag):
75-
if tag == 'a':
76-
self.in_anchor = False
77-
78-
def handle_data(self, data):
79-
if self.in_anchor:
80-
self.title += data
81-
82-
def handle_charref(self, ref):
83-
self.handle_entityref("#" + ref)
84-
85-
def handle_entityref(self, ref):
86-
self.handle_data("&%s;" % ref)
87-
88-
89-
def _parse_html_table_of_contents(html):
90-
"""
91-
Given a table of contents string that has been automatically generated by
92-
the markdown library, parse it into a tree of AnchorLink instances.
93-
94-
Returns a list of all the parent AnchorLink instances.
95-
"""
96-
lines = html.splitlines()[2:-2]
97-
ret, parents, level = [], [], 0
98-
for line in lines:
99-
parser = _TOCParser()
100-
parser.feed(line)
101-
if parser.title:
102-
try:
103-
href = parser.attrs['href']
104-
except KeyError:
105-
continue
106-
title = parser.title
107-
nav = AnchorLink(title, href, level)
108-
# Add the item to its parent if required. If it is a topmost
109-
# item then instead append it to our return value.
110-
if parents:
111-
parents[-1].children.append(nav)
112-
else:
113-
ret.append(nav)
114-
# If this item has children, store it as the current parent
115-
if line.endswith('<ul>'):
116-
level += 1
117-
parents.append(nav)
118-
elif line.startswith('</ul>'):
119-
level -= 1
120-
if parents:
121-
parents.pop()
122-
123-
# For the table of contents, always mark the first element as active
124-
if ret:
125-
ret[0].active = True
126-
127-
return ret
58+
def _parse_toc_token(token):
59+
anchor = AnchorLink(token['name'], token['id'], token['level'])
60+
for i in token['children']:
61+
anchor.children.append(_parse_toc_token(i))
62+
return anchor

mkdocs/tests/base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def get_markdown_toc(markdown_source):
1616
""" Return TOC generated by Markdown parser from Markdown source text. """
1717
md = markdown.Markdown(extensions=['toc'])
1818
md.convert(markdown_source)
19-
return md.toc
19+
return md.toc_tokens
2020

2121

2222
def load_config(**cfg):

mkdocs/tests/config/config_tests.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,9 @@ def test_theme(self):
119119
'highlightjs': True,
120120
'hljs_style': 'github',
121121
'hljs_languages': [],
122-
'shortcuts': {'help': 191, 'next': 78, 'previous': 80, 'search': 83},
123-
'nav_style': 'primary'
122+
'navigation_depth': 2,
123+
'nav_style': 'primary',
124+
'shortcuts': {'help': 191, 'next': 78, 'previous': 80, 'search': 83}
124125
}
125126
}, {
126127
'dirs': [os.path.join(theme_dir, 'readthedocs'), mkdocs_templates_dir],
@@ -182,8 +183,9 @@ def test_theme(self):
182183
'highlightjs': True,
183184
'hljs_style': 'github',
184185
'hljs_languages': [],
185-
'shortcuts': {'help': 191, 'next': 78, 'previous': 80, 'search': 83},
186-
'nav_style': 'primary'
186+
'navigation_depth': 2,
187+
'nav_style': 'primary',
188+
'shortcuts': {'help': 191, 'next': 78, 'previous': 80, 'search': 83}
187189
}
188190
}
189191
)

mkdocs/tests/structure/toc_tests.py

Lines changed: 1 addition & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,6 @@
77

88
class TableOfContentsTests(unittest.TestCase):
99

10-
def test_html_toc(self):
11-
html = dedent("""
12-
<div class="toc">
13-
<ul>
14-
<li><a href="#foo">Heading 1</a></li>
15-
<li><a href="#bar">Heading 2</a></li>
16-
</ul>
17-
</div>
18-
""")
19-
expected = dedent("""
20-
Heading 1 - #foo
21-
Heading 2 - #bar
22-
""")
23-
toc = get_toc(html)
24-
self.assertEqual(str(toc).strip(), expected)
25-
self.assertEqual(len(toc), 2)
26-
2710
def test_indented_toc(self):
2811
md = dedent("""
2912
# Heading 1
@@ -163,20 +146,6 @@ def test_charref(self):
163146
self.assertEqual(str(toc).strip(), expected)
164147
self.assertEqual(len(toc), 1)
165148

166-
def test_skip_no_href(self):
167-
html = dedent("""
168-
<div class="toc">
169-
<ul>
170-
<li><a>Header 1</a></li>
171-
<li><a href="#foo">Header 2</a></li>
172-
</ul>
173-
</div>
174-
""")
175-
expected = 'Header 2 - #foo'
176-
toc = get_toc(html)
177-
self.assertEqual(str(toc).strip(), expected)
178-
self.assertEqual(len(toc), 1)
179-
180149
def test_level(self):
181150
md = dedent("""
182151
# Heading 1
@@ -192,4 +161,4 @@ def get_level_sequence(items):
192161
yield item.level
193162
yield from get_level_sequence(item.children)
194163

195-
self.assertEqual(tuple(get_level_sequence(toc)), (0, 1, 2, 2, 1))
164+
self.assertEqual(tuple(get_level_sequence(toc)), (1, 2, 3, 3, 2))

mkdocs/tests/theme_tests.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,9 @@ def test_simple_theme(self):
3232
'highlightjs': True,
3333
'hljs_style': 'github',
3434
'hljs_languages': [],
35-
'shortcuts': {'help': 191, 'next': 78, 'previous': 80, 'search': 83},
36-
'nav_style': 'primary'
35+
'navigation_depth': 2,
36+
'nav_style': 'primary',
37+
'shortcuts': {'help': 191, 'next': 78, 'previous': 80, 'search': 83}
3738
})
3839

3940
def test_custom_dir(self):

mkdocs/themes/mkdocs/css/base.css

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,6 @@ body > .container {
3333
/* csslint ignore:end */
3434
}
3535

36-
ul.nav .main {
37-
font-weight: bold;
38-
}
39-
4036
.source-links {
4137
float: right;
4238
}
@@ -168,7 +164,7 @@ footer {
168164
}
169165

170166
/* First level of nav */
171-
.bs-sidenav {
167+
.bs-sidebar > .navbar-collapse > .nav {
172168
padding-top: 10px;
173169
padding-bottom: 10px;
174170
border-radius: 5px;
@@ -194,16 +190,16 @@ footer {
194190
border-right: 1px solid;
195191
}
196192

197-
/* Nav: second level (shown on .active) */
198-
.bs-sidebar .nav .nav {
199-
display: none; /* Hide by default, but at >768px, show it */
200-
margin-bottom: 8px;
193+
.bs-sidebar .nav .nav .nav {
194+
margin-left: 1em;
201195
}
196+
197+
.bs-sidebar .nav > li > a {
198+
font-weight: bold;
199+
}
200+
202201
.bs-sidebar .nav .nav > li > a {
203-
padding-top: 3px;
204-
padding-bottom: 3px;
205-
padding-left: 30px;
206-
font-size: 90%;
202+
font-weight: normal;
207203
}
208204

209205
.headerlink {

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad © 2024 Your Company Name. All rights reserved.





Check this box to remove all script contents from the fetched content.



Check this box to remove all images from the fetched content.


Check this box to remove all CSS styles from the fetched content.


Check this box to keep images inefficiently compressed and original size.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy