3b1b-manim/manimlib/utils/tex_file_writing.py

103 lines
3.2 KiB
Python
Raw Normal View History

from __future__ import annotations
2022-04-12 19:19:59 +08:00
import os
import re
from manimlib.config import get_custom_config
from manimlib.constants import PRESET_PREAMBLE
2021-10-07 17:37:10 +08:00
from manimlib.logger import log
2022-04-12 19:19:59 +08:00
from manimlib.utils.directories import get_tex_dir
from manimlib.utils.simple_functions import hash_string
2018-05-09 14:10:04 -07:00
class LatexError(Exception):
pass
class TexTemplate:
def __init__(self, preamble_type: str | None = None):
tex_config = get_custom_config()["tex"]
self.executable = tex_config["executable"]
self.dvi_ext = tex_config["intermediate_filetype"]
if preamble_type is None:
preamble_type = tex_config["preamble"]
self.preamble = list(PRESET_PREAMBLE.get(
preamble_type, PRESET_PREAMBLE["default"]
))
def __hash__(self) -> int:
return hash(self.get_tex_file_content(""))
def get_tex_file_content(self, content: str) -> str:
return "\n\n".join((
"\\documentclass[preview]{standalone}",
"\n".join(self.preamble),
"\\begin{document}",
content,
"\\end{document}"
)) + "\n"
def get_svg_file_path(self, content: str) -> str:
full_tex = self.get_tex_file_content(content)
hash_code = hash_string(full_tex)
tex_dir = get_tex_dir()
root = os.path.join(tex_dir, hash_code)
svg_file_path = root + ".svg"
if os.path.exists(svg_file_path):
return svg_file_path
# If svg doesn't exist, create it
replaced_content = content.replace("\n", " ")
displayed_msg = f"Writing \"{replaced_content}\""
max_characters = os.get_terminal_size().columns - 1
if len(displayed_msg) > max_characters:
displayed_msg = displayed_msg[:max_characters - 3] + "..."
print(displayed_msg, end="\r")
with open(root + ".tex", "w", encoding="utf-8") as tex_file:
tex_file.write(full_tex)
# tex to dvi
if os.system(" ".join((
self.executable,
2018-09-26 21:09:04 +08:00
"-interaction=batchmode",
"-halt-on-error",
f"-output-directory=\"{tex_dir}\"",
f"\"{root}.tex\"",
2018-09-26 21:09:04 +08:00
">",
os.devnull
))):
2021-10-07 17:37:10 +08:00
log.error("LaTeX Error! Not a worry, it happens to the best of us.")
with open(root + ".log", "r", encoding="utf-8") as log_file:
error_match_obj = re.search(r"(?<=\n! ).*", log_file.read())
if error_match_obj:
log.debug("The error could be: `%s`", error_match_obj.group())
raise LatexError()
# dvi to svg
os.system(" ".join((
2018-05-09 14:10:04 -07:00
"dvisvgm",
f"\"{root}{self.dvi_ext}\"",
2018-05-09 14:10:04 -07:00
"-n",
"-v",
"0",
"-o",
f"\"{svg_file_path}\"",
2018-05-09 14:10:04 -07:00
">",
os.devnull
)))
# Cleanup superfluous documents
for ext in (".tex", self.dvi_ext, ".log", ".aux"):
try:
os.remove(root + ext)
except FileNotFoundError:
pass
print(" " * len(displayed_msg), end="\r")
return svg_file_path
def add_preamble(self, *preamble_strs: str):
self.preamble.extend(preamble_strs)
return self