manim_example_ext.py 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. from docutils import nodes
  2. from docutils.parsers.rst import directives, Directive
  3. import jinja2
  4. import os
  5. class skip_manim_node(nodes.Admonition, nodes.Element):
  6. pass
  7. def visit(self, node, name=""):
  8. self.visit_admonition(node, name)
  9. def depart(self, node):
  10. self.depart_admonition(node)
  11. class ManimExampleDirective(Directive):
  12. has_content = True
  13. required_arguments = 1
  14. optional_arguments = 0
  15. option_spec = {
  16. "hide_code": bool,
  17. "media": str,
  18. }
  19. final_argument_whitespace = True
  20. def run(self):
  21. hide_code = "hide_code" in self.options
  22. scene_name = self.arguments[0]
  23. media_file_name = self.options["media"]
  24. source_block = [
  25. ".. code-block:: python",
  26. "",
  27. *[" " + line for line in self.content],
  28. ]
  29. source_block = "\n".join(source_block)
  30. state_machine = self.state_machine
  31. document = state_machine.document
  32. if any(media_file_name.endswith(ext) for ext in [".png", ".jpg", ".gif"]):
  33. is_video = False
  34. else:
  35. is_video = True
  36. rendered_template = jinja2.Template(TEMPLATE).render(
  37. scene_name=scene_name,
  38. scene_name_lowercase=scene_name.lower(),
  39. hide_code=hide_code,
  40. is_video=is_video,
  41. media_file_name=media_file_name,
  42. source_block=source_block,
  43. )
  44. state_machine.insert_input(
  45. rendered_template.split("\n"), source=document.attributes["source"]
  46. )
  47. return []
  48. def setup(app):
  49. app.add_node(skip_manim_node, html=(visit, depart))
  50. setup.app = app
  51. setup.config = app.config
  52. setup.confdir = app.confdir
  53. app.add_directive("manim-example", ManimExampleDirective)
  54. metadata = {"parallel_read_safe": False, "parallel_write_safe": True}
  55. return metadata
  56. TEMPLATE = r"""
  57. {% if not hide_code %}
  58. .. raw:: html
  59. <div class="manim-example">
  60. {% endif %}
  61. {% if is_video %}
  62. .. raw:: html
  63. <video id="{{ scene_name_lowercase }}" class="manim-video" controls loop autoplay src="{{ media_file_name }}"></video>
  64. {% else %}
  65. .. image:: {{ media_file_name }}
  66. :align: center
  67. :name: {{ scene_name_lowercase }}
  68. {% endif %}
  69. {% if not hide_code %}
  70. .. raw:: html
  71. <h5 class="example-header">{{ scene_name }}<a class="headerlink" href="#{{ scene_name_lowercase }}">¶</a></h5>
  72. {{ source_block }}
  73. {% endif %}
  74. .. raw:: html
  75. </div>
  76. """