5-72

5-72.com helps novice musicians master sound engineering by analyzing the FX chains of world-famous artists
Log | Files | Refs

plugin.py (5148B)


      1 # Copyright (c) 2016-2022 Martin Donath <martin.donath@squidfunk.com>
      2 
      3 # Permission is hereby granted, free of charge, to any person obtaining a copy
      4 # of this software and associated documentation files (the "Software"), to
      5 # deal in the Software without restriction, including without limitation the
      6 # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
      7 # sell copies of the Software, and to permit persons to whom the Software is
      8 # furnished to do so, subject to the following conditions:
      9 
     10 # The above copyright notice and this permission notice shall be included in
     11 # all copies or substantial portions of the Software.
     12 
     13 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     14 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     15 # FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
     16 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     17 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     18 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     19 # IN THE SOFTWARE.
     20 
     21 import logging
     22 import os
     23 import sys
     24 
     25 from collections import defaultdict
     26 from markdown.extensions.toc import slugify
     27 from mkdocs import utils
     28 from mkdocs.commands.build import DuplicateFilter
     29 from mkdocs.config.config_options import Type
     30 from mkdocs.plugins import BasePlugin
     31 
     32 # -----------------------------------------------------------------------------
     33 # Class
     34 # -----------------------------------------------------------------------------
     35 
     36 # Tags plugin
     37 class TagsPlugin(BasePlugin):
     38 
     39     # Configuration scheme
     40     config_scheme = (
     41         ("tags_file", Type(str, required = False)),
     42     )
     43 
     44     # Initialize plugin
     45     def __init__(self):
     46         self.tags = defaultdict(list)
     47         self.tags_file = None
     48         self.slugify = None
     49 
     50     # Retrieve configuration for anchor generation
     51     def on_config(self, config):
     52         if "toc" in config["markdown_extensions"]:
     53             toc = { "slugify": slugify, "separator": "-" }
     54             if "toc" in config["mdx_configs"]:
     55                 toc = { **toc, **config["mdx_configs"]["toc"] }
     56 
     57             # Partially apply slugify function
     58             self.slugify = lambda value: (
     59                 toc["slugify"](str(value), toc["separator"])
     60             )
     61 
     62     # Hack: 2nd pass for tags index page
     63     def on_nav(self, nav, files, **kwargs):
     64         file = self.config.get("tags_file")
     65         if file:
     66             self.tags_file = files.get_file_from_path(file)
     67             if not self.tags_file:
     68                 log.error(f"Configuration error: {file} doesn't exist.")
     69                 sys.exit()
     70 
     71             # Add tags file to files
     72             files.append(self.tags_file)
     73 
     74     # Build and render tags index page
     75     def on_page_markdown(self, markdown, page, **kwargs):
     76         if page.file == self.tags_file:
     77             return self.__render_tag_index(markdown)
     78 
     79         # Add page to tags index
     80         for tag in page.meta.get("tags", []):
     81             self.tags[tag].append(page)
     82 
     83     # Inject tags into page (after search and before minification)
     84     def on_page_context(self, context, page, **kwargs):
     85         if "tags" in page.meta:
     86             context["tags"] = [
     87                 self.__render_tag(tag)
     88                     for tag in page.meta["tags"]
     89             ]
     90 
     91     # -------------------------------------------------------------------------
     92 
     93     # Render tags index
     94     def __render_tag_index(self, markdown):
     95         if not "[TAGS]" in markdown:
     96             markdown += "\n[TAGS]"
     97 
     98         # Replace placeholder in Markdown with rendered tags index
     99         return markdown.replace("[TAGS]", "\n".join([
    100             self.__render_tag_links(*args)
    101                 for args in sorted(self.tags.items())
    102         ]))
    103 
    104     # Render the given tag and links to all pages with occurrences
    105     def __render_tag_links(self, tag, pages):
    106         content = [f"## <span class=\"md-tag\">{tag}</span>", ""]
    107         for page in pages:
    108             url = utils.get_relative_url(
    109                 page.file.src_path.replace(os.path.sep, "/"),
    110                 self.tags_file.src_path.replace(os.path.sep, "/")
    111             )
    112 
    113             # Ensure forward slashes, as we have to use the path of the source
    114             # file which contains the operating system's path separator.
    115             content.append("- [{}]({})".format(
    116                 page.meta.get("title", page.title),
    117                 url
    118             ))
    119 
    120         # Return rendered tag links
    121         return "\n".join(content)
    122 
    123     # Render the given tag, linking to the tags index (if enabled)
    124     def __render_tag(self, tag):
    125         if not self.tags_file or not self.slugify:
    126             return dict(name = tag)
    127         else:
    128             url = self.tags_file.url
    129             url += f"#{self.slugify(tag)}"
    130             return dict(name = tag, url = url)
    131 
    132 # -----------------------------------------------------------------------------
    133 # Data
    134 # -----------------------------------------------------------------------------
    135 
    136 # Set up logging
    137 log = logging.getLogger("mkdocs")
    138 log.addFilter(DuplicateFilter())