Added asc sorted headings

This commit is contained in:
Kevin Veen-Birkenbach 2025-03-15 14:32:15 +01:00
parent cd21645148
commit b446fb5476
No known key found for this signature in database
GPG Key ID: 44D8F11FD62F878E

View File

@ -7,6 +7,13 @@ logger = logging.getLogger(__name__)
# Set the maximum heading level to include (e.g., include headings up to H3)
MAX_HEADING_LEVEL = 3
def natural_sort_key(text):
"""
Generate a key for natural (human-friendly) sorting,
where numbers in the text are taken into account by their numeric value.
"""
return [int(c) if c.isdigit() else c.lower() for c in re.split('(\d+)', text)]
def extract_headings_from_file(filepath, max_level=MAX_HEADING_LEVEL):
"""
Extract Markdown headings (up to max_level) from the file at filepath.
@ -17,7 +24,7 @@ def extract_headings_from_file(filepath, max_level=MAX_HEADING_LEVEL):
with open(filepath, 'r', encoding='utf-8') as f:
in_code_block = False
for line in f:
# Toggle fenced code block state if a line starts with ```
# Toggle code block state if a line starts with ```
if line.strip().startswith("```"):
in_code_block = not in_code_block
continue
@ -29,10 +36,10 @@ def extract_headings_from_file(filepath, max_level=MAX_HEADING_LEVEL):
level = len(match.group(1))
if level <= max_level:
heading_text = match.group(2).strip()
# Create a simple slug for the anchor by:
# - converting to lowercase
# - replacing spaces with hyphens
# - removing non-alphanumeric characters (except hyphens)
# Create a simple slug for the anchor:
# - convert to lowercase
# - replace spaces with hyphens
# - remove non-alphanumeric characters (except hyphens)
anchor = re.sub(r'\s+', '-', heading_text.lower())
anchor = re.sub(r'[^a-z0-9\-]', '', anchor)
headings.append({'level': level, 'text': heading_text, 'anchor': anchor})
@ -43,10 +50,11 @@ def extract_headings_from_file(filepath, max_level=MAX_HEADING_LEVEL):
def add_local_md_headings(app, pagename, templatename, context, doctree):
"""
For every Markdown file in the same directory as the current page,
extract its headings and add them to the context.
extract its headings, sort them in natural ascending order, and add them
to the context.
"""
srcdir = app.srcdir
# Determine the directory of the current page (e.g., "directory/file" "directory")
# Determine the directory of the current page (e.g., "directory/file" -> "directory")
directory = os.path.dirname(pagename)
abs_dir = os.path.join(srcdir, directory)
if not os.path.isdir(abs_dir):
@ -57,13 +65,9 @@ def add_local_md_headings(app, pagename, templatename, context, doctree):
local_md_headings = []
for file in os.listdir(abs_dir):
if file.endswith('.md'):
# Optionally, you may choose to skip the current file:
# if file == os.path.basename(pagename):
# continue
filepath = os.path.join(abs_dir, file)
headings = extract_headings_from_file(filepath)
for heading in headings:
# Build a full link: if there is a directory, include it in the path.
file_link = os.path.join(directory, file) if directory else file
full_link = file_link + '#' + heading['anchor']
local_md_headings.append({
@ -71,9 +75,10 @@ def add_local_md_headings(app, pagename, templatename, context, doctree):
'text': heading['text'],
'link': full_link
})
# Sort headings in natural ascending order using natural_sort_key.
local_md_headings.sort(key=lambda x: natural_sort_key(x['text']))
context['local_md_headings'] = local_md_headings
def setup(app):
# Connect our handler to the "html-page-context" event.
app.connect('html-page-context', add_local_md_headings)
return {'version': '0.1', 'parallel_read_safe': True}