blob: b4956b9d99d6e0cfbf0af74e0026b75ec430d4cd [file] [log] [blame]
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
import re
import os
import os.path as path
from util import debug
cleanup_on_finish_files = []
def setup(app):
app.add_event("create_index_softlink")
app.connect("create_index_softlink", index_softlink)
app.add_event("toc_from_markdown")
app.connect("toc_from_markdown", auto_generate_toc)
app.connect("build-finished", after_build_cleanup)
return {"version": "1.0", "parallel_read_safe": True}
def after_build_cleanup(app, exception):
for f in cleanup_on_finish_files:
os.remove(path.join(app.srcdir, f))
debug(f"[TOC] Deleted {f}.")
def extract_markdown_links(file):
"""Extracts list of local markdown links from markdown file"""
# two formats for local markdown file links
linknameexp1 = r"\[[\/\.\w]*\]"
linktargetexp1 = r"\(\.[\/\.\w]*{fileext}\)"
linkexp1 = linknameexp1 + linktargetexp1.format(fileext=r"\.md")
# case 2 [tag] link
linknameexp2 = r"\[[0-9]*\]\:\s*"
linktargetexp2 = r"\.[\/\.\w]*{fileext}\s*\n"
linkexp2 = linknameexp2 + linktargetexp2.format(fileext=r"\.md")
links = []
try:
with open(file, "r") as f:
block = f.read()
for m in re.finditer(linkexp1, block):
link = m.group(0).partition("(")[2].rpartition(")")[0].strip()
links.append(link)
for m in re.finditer(linkexp2, block):
link = m.group(0).rpartition(":")[2].strip()
links.append(link)
except Exception:
debug(f"[TOC] Warning: Failed to process {file}.")
return links
def auto_generate_toc(app, master, tocname, cleanup=False, hidden=True, maxdepth=3):
"""
Automaticaly generate rst file with hidden toc'
"""
global cleanup_on_finish_files
if cleanup:
cleanup_on_finish_files.append(tocname)
master = path.join(app.srcdir, master)
tocname = path.join(app.srcdir, path.basename(tocname))
links = [master]
while maxdepth:
newlinks = []
for file in links:
fromfile = extract_markdown_links(file)
newlinks += [
path.normpath(path.join(os.path.dirname(file), file_link))
for file_link in fromfile
]
newlinks = [newlink for newlink in set(newlinks) if newlink not in links]
if not len(newlinks):
break
links += newlinks
maxdepth -= 1
links = [os.path.relpath(abslink, os.path.dirname(tocname)) for abslink in links]
links.sort()
with open(tocname, "w") as f:
indent = " "
f.write(":orphan:\n\n")
f.write(".. toctree::\n")
if hidden:
f.write(indent + ":hidden:\n")
f.write("\n")
for link in links:
f.write(indent + link + "\n")
def index_softlink(app, master, cleanup=False):
global cleanup_on_finish_files
softlink = "index." + master.rpartition(".")[2]
if cleanup:
cleanup_on_finish_files.append(softlink)
master = path.join(app.srcdir, master)
softlink = path.join(app.srcdir, softlink)
try:
os.symlink(master, softlink)
except FileExistsError:
os.remove(softlink)
os.symlink(master, softlink)