diff --git a/formatitko.py b/formatitko.py
index 4293929..2bf4fe9 100755
--- a/formatitko.py
+++ b/formatitko.py
@@ -23,7 +23,5 @@ doc = doc.walk(transform, context)
print("---------------------")
#print(show(doc))
#print(convert_text(doc, input_format="panflute", output_format="markdown"))
-#open("output.html", "w").write("
" + html(doc))
-k = KatexClient()
-input()
-print(k)
+katexClient = KatexClient()
+open("output.html", "w").write(" " + html(doc, katexClient))
diff --git a/html.py b/html.py
index 207619d..b3f4f42 100644
--- a/html.py
+++ b/html.py
@@ -1,11 +1,12 @@
from panflute import *
from whitespace import NBSP
from transform import FQuoted
+from katex import KatexClient
-def html(e: Element, indent_level: int=0, indent_str: str="\t") -> str:
+def html(e: Element, k: KatexClient, indent_level: int=0, indent_str: str="\t") -> str:
if isinstance(e, ListContainer):
- return ''.join([html(child, indent_level, indent_str) for child in e])
+ return ''.join([html(child, k, indent_level, indent_str) for child in e])
tag = e.tag.lower()
attributes = ""
@@ -67,14 +68,14 @@ def html(e: Element, indent_level: int=0, indent_str: str="\t") -> str:
tag = "pre"
if isinstance(e, Figure):
- content_foot = html(e.caption, indent_level+1, indent_str)
+ content_foot = html(e.caption, k, indent_level+1, indent_str)
if isinstance(e, Caption):
tag = "figcaption"
if isinstance(e, Image):
# TODO: Image processing
- return f''
+ return f''
if isinstance(e, Header):
tag = "h"+str(e.level)
@@ -86,13 +87,13 @@ def html(e: Element, indent_level: int=0, indent_str: str="\t") -> str:
attributes += f' title="{e.title}"'
if isinstance(e, LineItem):
- return indent_level*indent_str + html(e.content) + "
\n"
+ return indent_level*indent_str + html(e.content, k) + "
\n"
if isinstance(e, Note):
content_head = "("
content_foot = ")"
if len(e.content) == 1 and isinstance(e.content[0], Para):
- return f' ({html(e.content[0].content, 0, "")})'
+ return f' ({html(e.content[0].content, k, 0, "")})'
if isinstance(e, OrderedList):
tag = "ol"
@@ -110,8 +111,8 @@ def html(e: Element, indent_level: int=0, indent_str: str="\t") -> str:
# FIXME: Delimeter styles
if isinstance(e, Table):
- content_head = html(e.head, indent_level+1, indent_str)
- content_foot = html(e.foot, indent_level+1, indent_str)
+ content_head = html(e.head, k, indent_level+1, indent_str)
+ content_foot = html(e.foot, k, indent_level+1, indent_str)
# FIXME: Fancy pandoc tables, using colspec
if isinstance(e, TableCell):
@@ -131,28 +132,34 @@ def html(e: Element, indent_level: int=0, indent_str: str="\t") -> str:
if isinstance(e, FQuoted):
if e.style == "cs":
if e.quote_type == "SingleQuote":
- return f'‚{html(e.content, 0, "")}‘'
+ return f'‚{html(e.content, k, 0, "")}‘'
elif e.quote_type == "DoubleQuote":
- return f'„{html(e.content, 0, "")}“'
+ return f'„{html(e.content, k, 0, "")}“'
elif e.style == "en":
if e.quote_type == "SingleQuote":
- return f'‘{html(e.content, 0, "")}’'
+ return f'‘{html(e.content, k, 0, "")}’'
elif e.quote_type == "DoubleQuote":
- return f'“{html(e.content, 0, "")}”'
+ return f'“{html(e.content, k, 0, "")}”'
else:
if e.quote_type == "SingleQuote":
- return f'\'{html(e.content, 0, "")}\''
+ return f'\'{html(e.content, k, 0, "")}\''
elif e.quote_type == "DoubleQuote":
- return f'"{html(e.content, 0, "")}"'
+ return f'"{html(e.content, k, 0, "")}"'
else:
- return f'"{html(e.content, 0, "")}"'
+ return f'"{html(e.content, k, 0, "")}"'
if isinstance(e, Str):
return e.text.replace(" ", " ")
if isinstance(e, Math):
- # TODO
- return "TODO: MATH"
+ formats = {
+ "DisplayMath": True,
+ "InlineMath": False
+ }
+ # FIXME: Currently, all bits of math are isolated from each other, this
+ # means that \defs and and alike work only inside a single math block
+ # and are forgotten in the next one.
+ return indent_level*indent_str + k.render(e.text, {"displayMode": formats[e.format]})
if isinstance(e, RawInline) and e.format == "html":
return e.text
@@ -161,7 +168,7 @@ def html(e: Element, indent_level: int=0, indent_str: str="\t") -> str:
return f'{e.text}\n'
if isinstance(e, Inline):
- return f"<{tag}{attributes}>{content_head}{html(e.content, 0, '')}{content_foot}{tag}>"
+ return f"<{tag}{attributes}>{content_head}{html(e.content, k, 0, '')}{content_foot}{tag}>"
out_str = ""
if not isinstance(e, Plain):
@@ -170,7 +177,7 @@ def html(e: Element, indent_level: int=0, indent_str: str="\t") -> str:
if hasattr(e, "_content"):
if len(e.content) > 0 and isinstance(e.content[0], Inline):
out_str += (indent_level+1)*indent_str
- out_str += html(e.content, indent_level+1, indent_str)
+ out_str += html(e.content, k, indent_level+1, indent_str)
if hasattr(e, "text"):
out_str += e.text
out_str += f"{content_foot}\n"
diff --git a/katex.py b/katex.py
index dc54da9..e1ae1eb 100644
--- a/katex.py
+++ b/katex.py
@@ -1,12 +1,39 @@
import socket
import subprocess
import tempfile
+import json
+import os
+from typing import Dict
+class KatexError(Exception):
+ pass
+
class KatexClient:
def __init__(self):
self._client = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
self._temp_dir = tempfile.TemporaryDirectory(prefix='formatitko')
- socket_file = self._temp_dir.name + "/katex-socket"
- self._client.bind(socket_file)
- self._server = subprocess.Popen(["node", "./katex-server/index.mjs", socket_file])
+ self._socket_file = self._temp_dir.name + "/katex-socket"
+ self._server_process = subprocess.Popen(["node", "./katex-server/index.mjs", self._socket_file])
+ while not os.path.exists(self._socket_file):
+ pass
+ while True:
+ try:
+ self._client.connect(self._socket_file)
+ except ConnectionRefusedError:
+ continue
+ break
+
+ def render(self, tex: str, options: Dict={}):
+ self._client.sendall((json.dumps({"formulas":[{"tex":tex, "options": options}]})+"\n").encode("utf-8"))
+ data = self._client.recv(128)
+ while data[-1] != 0x0a:
+ data += self._client.recv(128)
+ response = json.loads(data)
+ if "error" in response:
+ raise Exception(response["error"])
+ if "error" in response["results"][0]:
+ raise KatexError(response["results"][0]["error"])
+ else:
+ return response["results"][0]["html"]
+
diff --git a/test.md b/test.md
index 2fec3a2..84e2986 100644
--- a/test.md
+++ b/test.md
@@ -55,7 +55,15 @@ A non-breakable space bro
A lot of spaces
-A text with some $math$.
+A text with some inline math: $\sum_{i=1}^nn^2$. Plus some display math:
+$$
+\def\eqalign#1{\begin{align*}#1\end{align*}}
+\eqalign{
+ 2 x_2 + 6 x_3 &= 14 \cr
+ x_1 - 3 x_2 + 2 x_3 &= 5 \cr
+ -x_1 + 4 x_2 + \phantom{1} x_3 &= 2
+}
+$$
This should be seen by all^[This is a footnote].