Skip to content

Commit

Permalink
Add option 'ignore_top_header' to exclude h1 headers from the table o…
Browse files Browse the repository at this point in the history
…f content and numbering
  • Loading branch information
oliora committed Oct 23, 2024
1 parent c115328 commit 55d96a0
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 12 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ plugins:
#excludes_children:
# - 'release-notes/:upgrading'
# - 'release-notes/:changelog'
#ignore_top_header: false
#
#exclude_pages:
# - 'bugs/'
Expand Down Expand Up @@ -194,6 +195,12 @@ plugins:
Set the page `id` of `nav` url. If the `id` matches in this list, it will be excluded from the heading number addition and table of contents.
**default**: `[]`
* `ignore_top_header`
Set this value to `true` to skip `h1` headers from being numbered (`ordered_chapter_level`) and
included into _Table of Content_ (`toc_level`).
**default**: `false`
##### for Page
* `exclude_pages`
Expand Down
2 changes: 2 additions & 0 deletions mkdocs_with_pdf/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class Options(object):
('toc_level', config_options.Type(int, default=2)),
('ordered_chapter_level', config_options.Type(int, default=3)),
('excludes_children', config_options.Type(list, default=[])),
('ignore_top_header', config_options.Type(bool, default=False)),

('exclude_pages', config_options.Type(list, default=[])),
('convert_iframe', config_options.Type(list, default=[])),
Expand Down Expand Up @@ -81,6 +82,7 @@ def __init__(self, local_config, config, logger: logging):
self.toc_level = local_config['toc_level']
self.ordered_chapter_level = local_config['ordered_chapter_level']
self.excludes_children = local_config['excludes_children']
self.ignore_top_header = local_config['ignore_top_header']

# Page
self.exclude_pages = local_config['exclude_pages']
Expand Down
26 changes: 14 additions & 12 deletions mkdocs_with_pdf/toc.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@ def make_indexes(soup: BeautifulSoup, options: Options) -> None:
_inject_heading_order(soup, options)

# Step 2: generate toc page
start_level = 1 if options.ignore_top_header else 0
stop_level = options.toc_level
if stop_level <= 0:
if stop_level <= start_level:
return
if stop_level > _MAX_HEADER_LEVEL:
options.logger.warning(f'Ignore `toc_level` value {stop_level}. Use max possible {_MAX_HEADER_LEVEL} instead')
stop_level = _MAX_HEADER_LEVEL

options.logger.info(
f'Generate a table of contents up to heading level {stop_level}.')
options.logger.info(f'Generate a table of contents from h{start_level + 1} to h{stop_level + 1}')

def make_link(h: Tag) -> Tag:
li = soup.new_tag('li')
Expand Down Expand Up @@ -64,7 +64,7 @@ def create_toc(headers: List[_HeaderTree], parent: Tag):
if len(header.subheaders) > 0:
create_toc(header.subheaders, link_tag)

headers = _collect_headers(soup, options, stop_level)
headers = _collect_headers(soup, options, start_level, stop_level)

toc = soup.new_tag('article', id='doc-toc')
title = soup.new_tag('h1')
Expand All @@ -80,19 +80,20 @@ def _set_list_elements(l: List[Any], value: Any, start: int, end: int | None = N
l[i] = value


def _collect_headers(soup: BeautifulSoup, options: Options, stop_level: int) -> List[_HeaderTree]:
def _collect_headers(soup: BeautifulSoup, options: Options, start_level: int, stop_level: int) -> List[_HeaderTree]:
"""Collect document headers.
Retuns a list of h1 headers with their subheaders
Retuns a list of top headers with their subheaders
Levels are counted from zero i.e. zero level corresponds to h1
"""
assert 0 <= start_level < stop_level
assert 0 < stop_level <= _MAX_HEADER_LEVEL

top_headers: List[_HeaderTree] = []

header_levels: List[_HeaderTree | None] = [None] * stop_level
exclude_levels: List[bool] = [False] * stop_level

headings = soup.find_all([f'h{i + 1}' for i in range(stop_level)])
headings = soup.find_all([f'h{i + 1}' for i in range(start_level, stop_level)])
for h in headings:
level = int(h.name[1:]) - 1

Expand All @@ -103,7 +104,7 @@ def _collect_headers(soup: BeautifulSoup, options: Options, stop_level: int) ->
header_levels[level] = header
_set_list_elements(header_levels, None, level + 1)

if level == 0:
if level == start_level:
top_headers.append(header)
else:
parent_header = header_levels[level - 1]
Expand All @@ -114,7 +115,7 @@ def _collect_headers(soup: BeautifulSoup, options: Options, stop_level: int) ->
header_levels[i] = header

parent_header = header_levels[i - 1]
if i == 0:
if i == start_level:
top_headers.append(header)
else:
parent_header = header_levels[i - 1]
Expand All @@ -130,14 +131,15 @@ def _collect_headers(soup: BeautifulSoup, options: Options, stop_level: int) ->


def _inject_heading_order(soup: BeautifulSoup, options: Options) -> None:
start_level = 1 if options.ignore_top_header else 0
stop_level = options.ordered_chapter_level
if stop_level <= 0:
if stop_level <= start_level:
return
if stop_level > _MAX_HEADER_LEVEL:
options.logger.warning(f'Ignore `ordered_chapter_level` value {stop_level}. Use max possible {_MAX_HEADER_LEVEL} instead')
stop_level = _MAX_HEADER_LEVEL

options.logger.info(f'Number headings up to level {stop_level}.')
options.logger.info(f'Number headers from h{start_level + 1} to h{stop_level + 1}')

def inject_order(headers: List[_HeaderTree], numbers_prefix: List[int] = []):
for i, header in enumerate(headers):
Expand All @@ -152,7 +154,7 @@ def inject_order(headers: List[_HeaderTree], numbers_prefix: List[int] = []):
options.logger.warning(f'Assigning number for a missed header {prefix_str}')
inject_order(header.subheaders, prefix)

headers = _collect_headers(soup, options, stop_level)
headers = _collect_headers(soup, options, start_level, stop_level)
inject_order(headers)


Expand Down

0 comments on commit 55d96a0

Please sign in to comment.