Compare commits
2 commits
1b971ea3b4
...
dc3b6510bb
Author | SHA1 | Date | |
---|---|---|---|
dc3b6510bb | |||
b7ebe6d4a0 |
3 changed files with 45 additions and 9 deletions
|
@ -30,12 +30,22 @@ def main():
|
||||||
parser.add_argument("-t", "--output-tex", help="The TEX file to write into.")
|
parser.add_argument("-t", "--output-tex", help="The TEX file to write into.")
|
||||||
parser.add_argument("-m", "--output-md", help="The Markdown file to write into. (Uses pandoc to generate markdown)")
|
parser.add_argument("-m", "--output-md", help="The Markdown file to write into. (Uses pandoc to generate markdown)")
|
||||||
parser.add_argument("-j", "--output-json", help="The JSON file to dump the pandoc-compatible AST into.")
|
parser.add_argument("-j", "--output-json", help="The JSON file to dump the pandoc-compatible AST into.")
|
||||||
parser.add_argument("input_filename", help="The markdown file to process.")
|
parser.add_argument("--katex-server", action='store_true', help="Starts a KaTeX server and prints the socket filename onto stdout. Useful for running formatitko many times without starting the KaTeX server each time.")
|
||||||
|
parser.add_argument("-k", "--katex-socket", help="The KaTeX server socket filename obtained by running with `--katex-server`.")
|
||||||
|
parser.add_argument("input_filename", help="The markdown file to process.", nargs="?" if "--katex-server" in sys.argv else None)
|
||||||
parser.add_argument("--debug", action='store_true')
|
parser.add_argument("--debug", action='store_true')
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
# TODO: Accept path to unix socket for katexClient, then don't init our own,
|
|
||||||
# just connect to an existing one. For formátíking many files in a row.
|
|
||||||
|
|
||||||
|
if args.katex_server:
|
||||||
|
with KatexClient(connect=False) as katexClient:
|
||||||
|
print(katexClient.get_socket())
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
pass
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print("Exiting...")
|
||||||
|
return
|
||||||
|
|
||||||
# Use panflute to parse the input MD file
|
# Use panflute to parse the input MD file
|
||||||
doc = import_md(open(args.input_filename, "r").read())
|
doc = import_md(open(args.input_filename, "r").read())
|
||||||
|
|
||||||
|
@ -49,7 +59,7 @@ def main():
|
||||||
|
|
||||||
if args.output_html is not None:
|
if args.output_html is not None:
|
||||||
# Initialize KaTeX client (this runs the node app and connects to a unix socket)
|
# Initialize KaTeX client (this runs the node app and connects to a unix socket)
|
||||||
with KatexClient() as katexClient:
|
with KatexClient(socket=args.katex_socket) as katexClient:
|
||||||
with open(args.output_html, "w") as file:
|
with open(args.output_html, "w") as file:
|
||||||
HTMLGenerator(file, katexClient, imageProcessor).generate(doc)
|
HTMLGenerator(file, katexClient, imageProcessor).generate(doc)
|
||||||
|
|
||||||
|
|
|
@ -83,7 +83,7 @@ async function handleClient(client) {
|
||||||
* the one from the parent group and can add its own stuff without
|
* the one from the parent group and can add its own stuff without
|
||||||
* affecting the parent.
|
* affecting the parent.
|
||||||
*/
|
*/
|
||||||
const macroStack = [{}]
|
let macroStack = [{}]
|
||||||
for await (const line of rl) {
|
for await (const line of rl) {
|
||||||
try {
|
try {
|
||||||
// The custom commands for pushing and popping the macro stack.
|
// The custom commands for pushing and popping the macro stack.
|
||||||
|
@ -94,6 +94,9 @@ async function handleClient(client) {
|
||||||
} else if (line === "endgroup") {
|
} else if (line === "endgroup") {
|
||||||
macroStack.pop()
|
macroStack.pop()
|
||||||
continue
|
continue
|
||||||
|
} else if (line === "init") {
|
||||||
|
macroStack = [{}]
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
const query = JSON.parse(line)
|
const query = JSON.parse(line)
|
||||||
const results = []
|
const results = []
|
||||||
|
|
|
@ -19,8 +19,21 @@ class KatexClient:
|
||||||
_server_process: subprocess.Popen[bytes]
|
_server_process: subprocess.Popen[bytes]
|
||||||
_socket_file: str
|
_socket_file: str
|
||||||
_temp_dir: tempfile.TemporaryDirectory[str]
|
_temp_dir: tempfile.TemporaryDirectory[str]
|
||||||
|
_connected: bool
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, socket: str=None, connect: bool=True):
|
||||||
|
if socket is not None:
|
||||||
|
self._socket_file = socket
|
||||||
|
else:
|
||||||
|
self.open_socket()
|
||||||
|
if connect:
|
||||||
|
self.connect()
|
||||||
|
self._client.sendall("init\n".encode("utf-8")) # Reinitialize KaTeX Server in case it was reused.
|
||||||
|
self._connected = True
|
||||||
|
else:
|
||||||
|
self._connected = False
|
||||||
|
|
||||||
|
def open_socket(self):
|
||||||
# Create temporary directory for socket
|
# Create temporary directory for socket
|
||||||
self._temp_dir = tempfile.TemporaryDirectory(prefix='formatitko')
|
self._temp_dir = tempfile.TemporaryDirectory(prefix='formatitko')
|
||||||
self._socket_file = self._temp_dir.name + "/katex-socket"
|
self._socket_file = self._temp_dir.name + "/katex-socket"
|
||||||
|
@ -40,15 +53,20 @@ class KatexClient:
|
||||||
|
|
||||||
self._server_process = subprocess.Popen(["node", srcdir + "/katex-server/index.mjs", self._socket_file], stdout=subprocess.PIPE)
|
self._server_process = subprocess.Popen(["node", srcdir + "/katex-server/index.mjs", self._socket_file], stdout=subprocess.PIPE)
|
||||||
|
|
||||||
self._client = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
|
||||||
|
|
||||||
ok = self._server_process.stdout.readline()
|
ok = self._server_process.stdout.readline()
|
||||||
if ok != b"OK\n":
|
if ok != b"OK\n":
|
||||||
raise KatexServerError("Failed to connect to katex-server")
|
raise KatexServerError("Failed to connect to katex-server")
|
||||||
|
|
||||||
|
def connect(self):
|
||||||
|
self._client = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||||
self._client.connect(self._socket_file)
|
self._client.connect(self._socket_file)
|
||||||
|
|
||||||
|
def get_socket(self):
|
||||||
|
return self._socket_file
|
||||||
|
|
||||||
def render(self, tex: str, options: dict={}):
|
def render(self, tex: str, options: dict={}):
|
||||||
|
if not self._connected:
|
||||||
|
raise KatexServerError("KatexClient not connected to Katex server. It should be initialized with connect=True.")
|
||||||
# Send formulas to translate
|
# Send formulas to translate
|
||||||
self._client.sendall((json.dumps({"formulas":[{"tex":tex}], "options":options})+"\n").encode("utf-8"))
|
self._client.sendall((json.dumps({"formulas":[{"tex":tex}], "options":options})+"\n").encode("utf-8"))
|
||||||
|
|
||||||
|
@ -67,13 +85,18 @@ class KatexClient:
|
||||||
|
|
||||||
# Special commands implemented in the JS file for grouping defs together.
|
# Special commands implemented in the JS file for grouping defs together.
|
||||||
def begingroup(self):
|
def begingroup(self):
|
||||||
|
if not self._connected:
|
||||||
|
raise KatexServerError("KatexClient not connected to Katex server. It should be initialized with connect=True.")
|
||||||
self._client.sendall("begingroup\n".encode("utf-8"))
|
self._client.sendall("begingroup\n".encode("utf-8"))
|
||||||
|
|
||||||
def endgroup(self):
|
def endgroup(self):
|
||||||
|
if not self._connected:
|
||||||
|
raise KatexServerError("KatexClient not connected to Katex server. It should be initialized with connect=True.")
|
||||||
self._client.sendall("endgroup\n".encode("utf-8"))
|
self._client.sendall("endgroup\n".encode("utf-8"))
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def __exit__(self, type, value, tb):
|
def __exit__(self, type, value, tb):
|
||||||
self._server_process.terminate()
|
if hasattr(self, "_server_process") and self._server_process is not None:
|
||||||
|
self._server_process.terminate()
|
||||||
|
|
Loading…
Reference in a new issue