πŸ“¦ 3b1b / manim

πŸ“„ manim_example_ext.py Β· 108 lines
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108from docutils import nodes
from docutils.parsers.rst import directives, Directive

import jinja2
import os


class skip_manim_node(nodes.Admonition, nodes.Element):
    pass


def visit(self, node, name=""):
    self.visit_admonition(node, name)


def depart(self, node):
    self.depart_admonition(node)


class ManimExampleDirective(Directive):
    has_content = True
    required_arguments = 1
    optional_arguments = 0
    option_spec = {
        "hide_code": bool,
        "media": str,
    }
    final_argument_whitespace = True

    def run(self):
        hide_code = "hide_code" in self.options
        scene_name = self.arguments[0]
        media_file_name = self.options["media"]

        source_block = [
            ".. code-block:: python",
            "",
            *["    " + line for line in self.content],
        ]
        source_block = "\n".join(source_block)

        state_machine = self.state_machine
        document = state_machine.document

        if any(media_file_name.endswith(ext) for ext in [".png", ".jpg", ".gif"]):
            is_video = False
        else:
            is_video = True

        rendered_template = jinja2.Template(TEMPLATE).render(
            scene_name=scene_name,
            scene_name_lowercase=scene_name.lower(),
            hide_code=hide_code,
            is_video=is_video,
            media_file_name=media_file_name,
            source_block=source_block,
        )
        state_machine.insert_input(
            rendered_template.split("\n"), source=document.attributes["source"]
        )

        return []


def setup(app):
    app.add_node(skip_manim_node, html=(visit, depart))

    setup.app = app
    setup.config = app.config
    setup.confdir = app.confdir

    app.add_directive("manim-example", ManimExampleDirective)

    metadata = {"parallel_read_safe": False, "parallel_write_safe": True}
    return metadata


TEMPLATE = r"""
{% if not hide_code %}

.. raw:: html

    <div class="manim-example">

{% endif %}

{% if is_video %}
.. raw:: html

    <video id="{{ scene_name_lowercase }}" class="manim-video" controls loop autoplay src="{{ media_file_name }}"></video>
{% else %}
.. image:: {{ media_file_name }}
    :align: center
    :name: {{ scene_name_lowercase }}
{% endif %}

{% if not hide_code %}
.. raw:: html

    <h5 class="example-header">{{ scene_name }}<a class="headerlink" href="#{{ scene_name_lowercase }}">ΒΆ</a></h5>

{{ source_block }}
{% endif %}

.. raw:: html

    </div>
"""