Browse Source

Create Sphinx extension to generate HTML meta description tags

Max Hilbrunner 5 years ago
parent
commit
2927a912a5
2 changed files with 118 additions and 0 deletions
  1. 117 0
      _extensions/godot_descriptions.py
  2. 1 0
      conf.py

+ 117 - 0
_extensions/godot_descriptions.py

@@ -0,0 +1,117 @@
+# -*- coding: utf-8 -*-
+"""
+    godot_descriptions
+    ~~~~~~~~~~~~~~~~~~
+
+    Sphinx extension to automatically generate HTML meta description tags
+    for all pages. Also comes with some special support for Godot class docs.
+
+    :copyright: Copyright 2020 by The Godot Engine Community
+    :license: MIT.
+
+    based on the work of Takayuki Shimizukawa on OpenGraph support for Sphinx,
+    see: https://github.com/sphinx-contrib/ogp
+"""
+
+import re
+from docutils import nodes
+from sphinx import addnodes
+
+
+class DescriptionGenerator:
+    def __init__(self, document, pagename="", n_sections_max=3, max_length=220):
+        self.document = document
+        self.text_list = []
+        self.max_length = max_length
+        self.current_length = 0
+        self.n_sections = 0
+        self.n_sections_max = n_sections_max
+        self.pagename = pagename
+        self.is_class = pagename.startswith("classes/")
+        self.stop_word_reached = False
+
+    def dispatch_visit(self, node):
+        if (
+            self.stop_word_reached
+            or self.current_length > self.max_length
+            or self.n_sections > self.n_sections_max
+        ):
+            return
+
+        if isinstance(node, addnodes.compact_paragraph) and node.get("toctree"):
+            raise nodes.SkipChildren
+
+        add = True
+
+        if isinstance(node, nodes.paragraph):
+            text = node.astext()
+
+            if self.is_class:
+                # Skip OOP hierarchy info for description
+                if (
+                    text.startswith("Inherits:")
+                    or text.startswith("Inherited By:")
+                    or text.strip() == "Example:"
+                ):
+                    add = False
+
+                # If we're in a class doc and reached the first table,
+                # stop adding to the description
+                if text.strip() == "Properties":
+                    self.stop_word_reached = True
+                    add = False
+
+            if add:
+                self.text_list.append(text)
+                self.current_length = self.current_length + len(text)
+
+        if add and isinstance(node, nodes.section):
+            self.n_sections += 1
+
+    def dispatch_departure(self, node):
+        pass
+
+    def format_description(self, desc):
+        # Replace newlines with spaces
+        desc = re.sub("\r|\n", " ", desc)
+
+        # Replace multiple spaces with single spaces
+        desc = re.sub("\\s+", " ", desc)
+
+        return desc
+
+    def create_description(self, cutoff_suffix="..."):
+        text = " ".join(self.text_list)
+
+        text = self.format_description(text)
+
+        # Cut to self.max_length, add cutoff_suffix at end
+        if len(text) > self.max_length:
+            text = text[: self.max_length - len(cutoff_suffix)].strip() + cutoff_suffix
+
+        return text
+
+
+def generate_description(app, pagename, templatename, context, doctree):
+    if not doctree:
+        return
+
+    generator = DescriptionGenerator(doctree, pagename)
+    doctree.walkabout(generator)
+
+    description = (
+        '<meta name="description" content="' + generator.create_description() + '">\n'
+    )
+
+    context["metatags"] += description
+
+
+def setup(app):
+    # Hook into Sphinx for all pages to
+    # generate meta description tag and add to meta tag list
+    app.connect("html-page-context", generate_description)
+
+    return {
+        "parallel_read_safe": True,
+        "parallel_write_safe": True,
+    }

+ 1 - 0
conf.py

@@ -14,6 +14,7 @@ needs_sphinx = "1.3"
 sys.path.append(os.path.abspath("_extensions"))
 sys.path.append(os.path.abspath("_extensions"))
 extensions = [
 extensions = [
     "gdscript",
     "gdscript",
+    "godot_descriptions",
     "sphinx_search.extension",
     "sphinx_search.extension",
     "sphinx_tabs.tabs",
     "sphinx_tabs.tabs",
     "sphinx.ext.imgmath",
     "sphinx.ext.imgmath",