mirror of
https://git.freetards.xyz/array.in.a.matrix/TexLiLy.git
synced 2025-04-02 13:21:42 -04:00
[ADD] Allow more complex expressions in code tags.
Now you can put long LilyPond stuff! And text-mode LaTeX! Signed-off-by: LoaD Accumulator <lda@freetards.xyz>
This commit is contained in:
parent
3ebc41fddb
commit
4d4aa7d5ab
5 changed files with 89 additions and 7 deletions
24
callbacks.py
24
callbacks.py
|
@ -31,12 +31,34 @@ async def msg_cb(room: MatrixRoom, event: RoomMessageText) -> None:
|
||||||
args = shlex.split(event.body[4:])
|
args = shlex.split(event.body[4:])
|
||||||
if len(args) >= 1:
|
if len(args) >= 1:
|
||||||
await tex_router.handle_command(args[0], room.room_id, event, args[1:])
|
await tex_router.handle_command(args[0], room.room_id, event, args[1:])
|
||||||
|
|
||||||
|
return
|
||||||
if event.body.startswith("lily!"):
|
if event.body.startswith("lily!"):
|
||||||
import router
|
import router
|
||||||
args = shlex.split(event.body[5:])
|
args = shlex.split(event.body[5:])
|
||||||
if len(args) >= 1:
|
if len(args) >= 1:
|
||||||
await lily_router.handle_command(args[0], room.room_id, event, args[1:])
|
await lily_router.handle_command(args[0], room.room_id, event, args[1:])
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
if event.formatted_body is not None:
|
||||||
|
import lilypond
|
||||||
|
import parser
|
||||||
|
|
||||||
|
code = parser.CodeParser()
|
||||||
|
code.feed(event.formatted_body)
|
||||||
|
code.close()
|
||||||
|
|
||||||
|
for block in code.blocks:
|
||||||
|
content = block['content']
|
||||||
|
if block['lang'] == 'tex':
|
||||||
|
filename = latex.render(event.sender, content)
|
||||||
|
await utils.send_png(room.room_id, filename)
|
||||||
|
if block['lang'] == 'ly':
|
||||||
|
filename = lilypond.render(event.sender, content, template=False)
|
||||||
|
await utils.send_png(room.room_id, filename)
|
||||||
|
|
||||||
|
|
||||||
for tex in re.findall(latex_regex, event.body, re.M):
|
for tex in re.findall(latex_regex, event.body, re.M):
|
||||||
try:
|
try:
|
||||||
filename = latex.render(event.sender, tex)
|
filename = latex.render(event.sender, tex)
|
||||||
|
|
5
latex.py
5
latex.py
|
@ -20,7 +20,7 @@ def render(user: str, source: str, png: bool = True) -> str:
|
||||||
import subprocess
|
import subprocess
|
||||||
import utils
|
import utils
|
||||||
import os
|
import os
|
||||||
|
|
||||||
# Put the user's packages in the format too.
|
# Put the user's packages in the format too.
|
||||||
directory = utils.create_user_dir(user)
|
directory = utils.create_user_dir(user)
|
||||||
pkgs = ""
|
pkgs = ""
|
||||||
|
@ -38,7 +38,8 @@ def render(user: str, source: str, png: bool = True) -> str:
|
||||||
|
|
||||||
# Parse our templated file thru' LaTeX and dvipng.
|
# Parse our templated file thru' LaTeX and dvipng.
|
||||||
# TODO: Allow arbitrary DPI and foreground color.
|
# TODO: Allow arbitrary DPI and foreground color.
|
||||||
ret = subprocess.run(["latex", "-halt-on-error", tmp.name], cwd="/tmp", capture_output=True)
|
ret = subprocess.run(["latex", "-halt-on-error", tmp.name],
|
||||||
|
cwd="/tmp", capture_output=True)
|
||||||
if ret.returncode != 0:
|
if ret.returncode != 0:
|
||||||
raise FileNotFoundError(ret.stdout.decode())
|
raise FileNotFoundError(ret.stdout.decode())
|
||||||
|
|
||||||
|
|
11
lilypond.py
11
lilypond.py
|
@ -5,23 +5,26 @@ template = r"""
|
||||||
{content}
|
{content}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def render(user: str, source: str, png: bool = True) -> str:
|
|
||||||
|
def render(user: str, source: str, png: bool = True, template: bool = False) -> str:
|
||||||
import tempfile
|
import tempfile
|
||||||
import subprocess
|
import subprocess
|
||||||
import utils
|
import utils
|
||||||
import os
|
import os
|
||||||
|
|
||||||
fmt = template.format(content=source)
|
fmt = template.format(content=source) if template else source
|
||||||
|
|
||||||
tmp = tempfile.NamedTemporaryFile(delete=False)
|
tmp = tempfile.NamedTemporaryFile(delete=False)
|
||||||
tmp.write(bytes(fmt, encoding="utf8"))
|
tmp.write(bytes(fmt, encoding="utf8"))
|
||||||
tmp.close()
|
tmp.close()
|
||||||
if png:
|
if png:
|
||||||
ret = subprocess.run(["lilypond", "-d", "preview", "--png", "-dresolution=500", tmp.name], cwd="/tmp", capture_output=True)
|
ret = subprocess.run(["lilypond", "-d", "preview", "--png",
|
||||||
|
"-dresolution=500", tmp.name], cwd="/tmp", capture_output=True)
|
||||||
if ret.returncode != 0:
|
if ret.returncode != 0:
|
||||||
raise FileNotFoundError(ret.stderr.decode())
|
raise FileNotFoundError(ret.stderr.decode())
|
||||||
|
|
||||||
return tmp.name + ".preview.png"
|
return tmp.name + ".preview.png"
|
||||||
|
|
||||||
subprocess.run(["lilypond", "-d", "preview", "--svg", tmp.name], cwd="/tmp")
|
subprocess.run(["lilypond", "-d", "preview",
|
||||||
|
"--svg", tmp.name], cwd="/tmp")
|
||||||
return tmp.name + "preview.svg"
|
return tmp.name + "preview.svg"
|
||||||
|
|
53
parser.py
Normal file
53
parser.py
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
from html.parser import HTMLParser
|
||||||
|
|
||||||
|
STATE_NONE = 0
|
||||||
|
STATE_PRE = 1
|
||||||
|
STATE_CODE = 2
|
||||||
|
|
||||||
|
class CodeParser(HTMLParser):
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
# This shall be a list of dictionnaries, which
|
||||||
|
# look like this:
|
||||||
|
# [
|
||||||
|
# {'lang': 'ly', 'content': '...'},
|
||||||
|
# {'lang': 'ly', 'content': '...'},
|
||||||
|
# {'lang': 'tex', 'content': '...'},
|
||||||
|
# ...
|
||||||
|
# ]
|
||||||
|
self.blocks = []
|
||||||
|
|
||||||
|
# Yes, this thing acts kinda like a state machine.
|
||||||
|
self.state = STATE_NONE
|
||||||
|
self.language = ''
|
||||||
|
self.data = ''
|
||||||
|
|
||||||
|
def handle_starttag(self, tag, attrs):
|
||||||
|
if self.state == STATE_NONE and tag == "pre":
|
||||||
|
self.state = STATE_PRE
|
||||||
|
elif self.state == STATE_PRE and tag == "code":
|
||||||
|
self.state = STATE_CODE
|
||||||
|
for val in attrs:
|
||||||
|
v = val[1]
|
||||||
|
if val[0] == "class":
|
||||||
|
if v == "language-lilypond":
|
||||||
|
self.language = 'ly'
|
||||||
|
if v == "language-tex" or v == "language-latex":
|
||||||
|
self.language = 'tex'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def handle_endtag(self, tag):
|
||||||
|
if self.state == STATE_CODE and tag == "pre":
|
||||||
|
self.blocks.append({'lang': self.language, 'content': self.data})
|
||||||
|
|
||||||
|
self.state = STATE_NONE
|
||||||
|
self.data = ''
|
||||||
|
self.language = ''
|
||||||
|
|
||||||
|
def handle_data(self, data):
|
||||||
|
if self.state == STATE_CODE:
|
||||||
|
self.data += data
|
||||||
|
|
||||||
|
|
|
@ -45,3 +45,6 @@ async def route_lshow(router: Router, client: Client, room: str, event: RoomMess
|
||||||
"formatted_body": f"Couldn't parse LilyPond correctly.<br><code><pre>{e.args[0]}</pre></code>",
|
"formatted_body": f"Couldn't parse LilyPond correctly.<br><code><pre>{e.args[0]}</pre></code>",
|
||||||
}
|
}
|
||||||
await client.room_send(room, message_type="m.room.message", content=content)
|
await client.room_send(room, message_type="m.room.message", content=content)
|
||||||
|
except Exception:
|
||||||
|
# ???
|
||||||
|
pass
|
||||||
|
|
Loading…
Add table
Reference in a new issue