From dff9dd2683790fd0648a7be40ef80e0c39d3a8ba Mon Sep 17 00:00:00 2001 From: LoaD Accumulator Date: Tue, 13 Jun 2023 16:36:36 +0200 Subject: [PATCH] [ADD] Add basic support for custom styles in LaTeX I still need to fix that syncing issue. --- callbacks.py | 27 +++++++++++++++++++++------ latex.py | 25 +++++++++++++++++++------ main.py | 7 ++++--- utils.py | 29 +++++++++++++++++++++++++++++ 4 files changed, 73 insertions(+), 15 deletions(-) diff --git a/callbacks.py b/callbacks.py index 8c138bb..aa037ff 100644 --- a/callbacks.py +++ b/callbacks.py @@ -1,21 +1,21 @@ from nio import * -import utils +latex_regex = r'((?:\$[^\$]+\$)|(?:\$\$[^\$]+\$\$)|(?:\\\[[^\]]+\\\]))' # Our message callback. It should be passed through a router. async def msg_cb(room: MatrixRoom, event: RoomMessageText) -> None: - import re import latex + import utils + import re + client = utils.get_client() if event.sender == client.user_id: return - print("ae", client) - for tex in re.findall(r'((?:\$[^\$]+\$)|(?:\$\$[^\$]+\$\$)|(?:\\\[[^\]]+\\\]))', event.body, re.M): - print("Text:", tex) + for tex in re.findall(latex_regex, event.body, re.M): try: - filename = latex.render("", tex) + filename = latex.render(event.sender, tex) await utils.send_png(room, filename) except FileNotFoundError as e: content = { @@ -35,5 +35,20 @@ async def msg_cb(room: MatrixRoom, event: RoomMessageText) -> None: # Our file callback. async def file_cb(room: MatrixRoom, event: RoomMessageFile) -> None: + import utils + import os + url = event.url filename = event.body + + if filename.endswith(".sty"): + # Download file and save it for user. + client = utils.get_client() + directory = utils.create_user_dir(event.sender) + response = await client.download(url, filename) + + if not isinstance(response, DownloadResponse): + return + + with open(os.path.join(directory, filename), 'wb') as f: + f.write(response.body) diff --git a/latex.py b/latex.py index c4d24f1..2f5f71c 100644 --- a/latex.py +++ b/latex.py @@ -1,10 +1,12 @@ # Converts a TeX file into a PNG/SVG file. template = r""" -\documentclass[utf8,preview]{{standalone}} +\documentclass[utf8,preview,varwidth]{{standalone}} \usepackage{{amsmath}} - \usepackage[active,tightpage]{{preview}} + \usepackage[active]{{preview}} \usepackage[utf8]{{inputenc}} + \usepackage{{tikz}} % TODO: Add user packages here. + {packages} \begin{{document}} % The user content goes here. {content} @@ -16,13 +18,25 @@ template = r""" def render(user: str, source: str, png: bool = True) -> str: import tempfile import subprocess + import utils + import os + + # Put the user's packages in the format too. + directory = utils.create_user_dir(user) + pkgs = "" - fmt = template.format(content=source) + for f in os.listdir(directory): + if f.endswith(".sty"): + base = os.path.join(directory, f[:-4]) + pkgs += "\\usepackage{{{base}}}\n ".format(base=base) + print(pkgs) + + fmt = template.format(content=source, packages=pkgs) tmp = tempfile.NamedTemporaryFile(delete=False) tmp.write(bytes(fmt, encoding="utf8")) tmp.close() - print(tmp.name) + # Parse our templated file thru' LaTeX and dvipng. # TODO: Allow arbitrary DPI and foreground color. ret = subprocess.run(["latex", "-halt-on-error", tmp.name], cwd="/tmp", capture_output=True) @@ -30,8 +44,7 @@ def render(user: str, source: str, png: bool = True) -> str: raise FileNotFoundError(ret.stdout.decode()) if png: - print("PNG") - subprocess.run(["dvipng", "-D", "2000", tmp.name + ".dvi", "-bg", "Transparent", + subprocess.run(["dvipng", "-D", "5000", tmp.name + ".dvi", "-bg", "Transparent", "-fg", "rgb 1 1 1", "-o", tmp.name + ".png"], cwd="/tmp") return tmp.name + ".png" diff --git a/main.py b/main.py index 1f03594..be4cdff 100644 --- a/main.py +++ b/main.py @@ -18,7 +18,8 @@ async def main() -> None: homeserver = str(config["homeserver"]) user = str(config["user"]) token = str(config["token"]) - # path = str(config["path"]) # not used + path = str(config["data"]) # Unused there, required. + utils.set_config(config) # if config file does not exist, quit except FileNotFoundError: print("No config file found.") @@ -32,8 +33,8 @@ async def main() -> None: client.access_token = token client.user_id = user - # Bad kludge! - await client.sync(timeout=3000) + # TODO: Fix this hot mess before merging onto main. + client.sync(timeout=10000) # Register all of the callbacks utils.set_client(client) diff --git a/utils.py b/utils.py index 086e7ac..dc1cddb 100644 --- a/utils.py +++ b/utils.py @@ -1,12 +1,41 @@ from nio import * + def set_client(c: AsyncClient) -> None: global client client = c + def get_client() -> AsyncClient: return client + +def set_config(c: dict) -> None: + global config + config = c + + +def get_config() -> dict: + return config + +def create_user_dir(user: str) -> str: + import hashlib + import os + + # NOTE: I would have used the user directly, but the Spec allows MXIDs + # with '/' and UNIX-based OSes will **not** like that. + sha = hashlib.sha256(bytes(user, 'ascii')).hexdigest() + + path = os.path.join(get_config()["data"], sha) + if not os.path.exists(path): + os.makedirs(path) + + return os.path.abspath(path) + + + + + async def send_png(room: MatrixRoom, filename: str) -> None: import imagesize import os