Browse Source

Partials are now also isolated in output TeX and KaTeX. Also language is now so special it pops out to TeX as a macro at the start of each group.

pull/28/head
Jan Černohorský 2 years ago
parent
commit
5e475f6881
  1. 2
      context.py
  2. 11
      formatitko.py
  3. 2
      formatitko.tex
  4. 8
      group.py
  5. 7
      html.py
  6. 16
      katex-server/index.mjs
  7. 10
      katex.py
  8. 6
      test-partial.md
  9. 19
      test.md
  10. 8
      tex.py
  11. 4
      transform.py

2
context.py

@ -51,6 +51,8 @@ class Context:
return None return None
def set_metadata(self, key, value): def set_metadata(self, key, value):
if key == "language":
print("WARN: Setting language this way doesn't propagate to TeX. Either use the Front Matter or specify it additionally using the \\languagexx macro.")
meta = self.doc.metadata meta = self.doc.metadata
key = key.split(".") key = key.split(".")
for k in key[:-1]: for k in key[:-1]:

11
formatitko.py

@ -9,6 +9,7 @@ from typing import List
from transform import transform from transform import transform
from util import * from util import *
from context import Context from context import Context
from group import Group
from katex import KatexClient from katex import KatexClient
from html import html from html import html
from tex import tex from tex import tex
@ -16,15 +17,17 @@ from tex import tex
from mj_show import show from mj_show import show
doc = import_md(open(sys.argv[1], "r").read()) doc = import_md(open(sys.argv[1], "r").read())
language = doc.get_metadata("language", None, True)
print(show(doc)) print(show(doc))
context = Context(doc, sys.argv[1]) context = Context(doc, sys.argv[1])
doc = doc.walk(transform, context) doc = doc.walk(transform, context)
print("---------------------") doc.content = [Group(*doc.content, metadata={"language":language})]
print(show(doc)) #print("---------------------")
#print(show(doc))
#print(convert_text(doc, input_format="panflute", output_format="markdown")) #print(convert_text(doc, input_format="panflute", output_format="markdown"))
katexClient = KatexClient() katexClient = KatexClient()
#print(katexClient.render("\\def\\Bruh{K^A\\TeX}"))
#print(katexClient.render("\\Bruh"))
open("output.html", "w").write("<head> <meta charset='utf-8'> <link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/katex.min.css' integrity='sha384-vKruj+a13U8yHIkAyGgK1J3ArTLzrFGBbBc0tDp4ad/EyewESeXE/Iv67Aj8gKZ0' crossorigin='anonymous'> </head>" + html(doc, katexClient)) open("output.html", "w").write("<head> <meta charset='utf-8'> <link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/katex.min.css' integrity='sha384-vKruj+a13U8yHIkAyGgK1J3ArTLzrFGBbBc0tDp4ad/EyewESeXE/Iv67Aj8gKZ0' crossorigin='anonymous'> </head>" + html(doc, katexClient))
open("output.tex", "w").write("\input formatitko.tex\n" + tex(doc)) open("output.tex", "w").write("\input formatitko.tex\n" + tex(doc))
#print(tex(doc)) #print(tex(doc))

2
formatitko.tex

@ -35,6 +35,8 @@
\def\figure#1#2{\vskip5pt\centerline{#1}\centerline{#2}\vskip5pt} \def\figure#1#2{\vskip5pt\centerline{#1}\centerline{#2}\vskip5pt}
\def\caption#1{{\it #1}} \def\caption#1{{\it #1}}
\let\image\putimage \let\image\putimage
\def\languagecs{} % KSP should define this to \cze probably
\def\languageen{} % KSP should define this to \eng probably
\def\table#1{#1} \def\table#1{#1}
\def\tablebody#1{#1} \def\tablebody#1{#1}
\def\tablerow#1{#1} \def\tablerow#1{#1}

8
group.py

@ -0,0 +1,8 @@
from panflute import Block
from typing import Dict
class Group(Block):
def __init__(self, *args, identifier='', classes=[], attributes={}, metadata={}):
self._set_ica(identifier, classes, attributes)
self._set_content(args, Block)
self.metadata = metadata

7
html.py

@ -8,6 +8,7 @@ from whitespace import NBSP
from transform import FQuoted from transform import FQuoted
from katex import KatexClient from katex import KatexClient
from util import inlinify from util import inlinify
from group import Group
def html(e: Element, k: KatexClient, indent_level: int=0, indent_str: str="\t") -> str: def html(e: Element, k: KatexClient, indent_level: int=0, indent_str: str="\t") -> str:
@ -174,6 +175,12 @@ def html(e: Element, k: KatexClient, indent_level: int=0, indent_str: str="\t")
else: else:
return f'"{html(e.content, k, 0, "")}"' return f'"{html(e.content, k, 0, "")}"'
if isinstance(e, Group):
k.begingroup()
ret = html(e.content, k, indent_level, indent_str)
k.endgroup()
return ret
if isinstance(e, Math): if isinstance(e, Math):
formats = { formats = {
"DisplayMath": True, "DisplayMath": True,

16
katex-server/index.mjs

@ -78,16 +78,28 @@ function socketWrite(socket, data) {
async function handleClient(client) { async function handleClient(client) {
const rl = readline.createInterface({ input: client }) const rl = readline.createInterface({ input: client })
const macroStack = [{}]
for await (const line of rl) { for await (const line of rl) {
try { try {
if (line === "begingroup") {
macroStack.push({...macroStack.slice(-1)[0]})
continue
} else if (line === "endgroup") {
macroStack.pop()
continue
}
const query = JSON.parse(line) const query = JSON.parse(line)
const results = [] const results = []
for (const input of query.formulas) { for (const input of query.formulas) {
const options = input.options ?? query.options ?? defaultOptions const options = input.options ?? query.options ?? defaultOptions
if (options.macros) {
for (const macro of Object.keys(options.macros)) {
macroStack.slice(-1)[macro] = options.macros[macro]
}
}
options.macros = macroStack.slice(-1)[0]
try { try {
const html = katex.renderToString(input.tex, options) const html = katex.renderToString(input.tex, options)
results.push({ html }) results.push({ html })
} catch (e) { } catch (e) {
results.push({ error: String(e) }) results.push({ error: String(e) })

10
katex.py

@ -25,8 +25,9 @@ class KatexClient:
break break
def render(self, tex: str, options: Dict={}): def render(self, tex: str, options: Dict={}):
self._client.sendall((json.dumps({"formulas":[{"tex":tex, "options": options}]})+"\n").encode("utf-8")) options["globalGroup"] = True
data = self._client.recv(128) self._client.sendall((json.dumps({"formulas":[{"tex":tex}], "options":options})+"\n").encode("utf-8"))
data = self._client.recv(1024)
while data[-1] != 0x0a: while data[-1] != 0x0a:
data += self._client.recv(128) data += self._client.recv(128)
response = json.loads(data) response = json.loads(data)
@ -37,3 +38,8 @@ class KatexClient:
else: else:
return response["results"][0]["html"] return response["results"][0]["html"]
def begingroup(self):
self._client.sendall("begingroup\n".encode("utf-8"))
def endgroup(self):
self._client.sendall("endgroup\n".encode("utf-8"))

6
test-partial.md

@ -1,5 +1,6 @@
--- ---
title: A subfile! title: A subfile!
language: "cs"
--- ---
I am a little piece of content I am a little piece of content
@ -45,3 +46,8 @@ I am a duck.
This should be only shown to included cats. This should be only shown to included cats.
::: :::
$$
\def\eqalign#1{NO, just, nooooo}
\eqalign{}
$$

19
test.md

@ -2,6 +2,7 @@
title: 'Wooooo a title' title: 'Wooooo a title'
subtitle: 'A subtitle' subtitle: 'A subtitle'
are_we_there_yet: False are_we_there_yet: False
language: "en"
--- ---
[#test-import.md]{} [#test-import.md]{}
@ -52,14 +53,14 @@ This should only be shown to cats the second time
![This is a figure, go figure...](/tmp/logo.png){width=10em} ![This is a figure, go figure...](/tmp/logo.png){width=10em}
![This is a figure, go figure...](/tmp/logo.svg){width=10em} ![Fakt epesní reproduktor](/tmp/reproduktor.jpeg){width=10em}
```python {.run} ```python {.run}
ctx.set_metadata("language", "cs") ctx.set_metadata("language", "cs")
``` ```
[!opendatatask]{} [!opendatatask]{}
```python {.run} ```python {.run}
ctx.unset_metadata("language") ctx.set_metadata("language","en")
``` ```
[This too!]{if=cat} [This too!]{if=cat}
@ -86,28 +87,22 @@ H~2~O is a liquid. 2^10^ is 1024.
[Underline]{.underline} [Underline]{.underline}
:::{only=tex} :::{only=html}
$$ $$
\eqalign{ \def\eqalign#1{\begin{align*}#1\end{align*}}
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
}
$$ $$
::: :::
:::{only=html}
$$ $$
\def\eqalign#1{\begin{align*}#1\end{align*}}
\eqalign{ \eqalign{
2 x_2 + 6 x_3 &= 14 \cr 2 x_2 + 6 x_3 &= 14 \cr
x_1 - 3 x_2 + 2 x_3 &= 5 \cr x_1 - 3 x_2 + 2 x_3 &= 5 \cr
-x_1 + 4 x_2 + \phantom{1} x_3 &= 2 -x_1 + 4 x_2 + \phantom{1} x_3 &= 2
} }
$$ $$
:::
<!-- TODO: This sucks --> :::{partial=test-partial.md}
:::
--- ---

8
tex.py

@ -3,6 +3,7 @@ from panflute import *
from whitespace import NBSP from whitespace import NBSP
from transform import FQuoted from transform import FQuoted
from util import inlinify from util import inlinify
from group import Group
# Heavily inspired by: git://git.ucw.cz/labsconf2022.git # Heavily inspired by: git://git.ucw.cz/labsconf2022.git
def tex(e, indent_level: int=0, indent_str: str="\t") -> str: def tex(e, indent_level: int=0, indent_str: str="\t") -> str:
@ -156,6 +157,13 @@ def tex(e, indent_level: int=0, indent_str: str="\t") -> str:
if isinstance(e, LineBlock): if isinstance(e, LineBlock):
return f'{tex(e.content, indent_level+1, indent_str)}\n' return f'{tex(e.content, indent_level+1, indent_str)}\n'
if isinstance(e, Group):
tag = "begingroup"
open = ""
if "language" in e.metadata and e.metadata["language"] is not None:
open = "\\language"+e.metadata["language"]
close = "\\endgroup"
if isinstance(e, Div): if isinstance(e, Div):
return f'{tex(e.content, indent_level+1, indent_str)}' return f'{tex(e.content, indent_level+1, indent_str)}'

4
transform.py

@ -6,6 +6,7 @@ from whitespace import *
from command import * from command import *
from util import * from util import *
from context import * from context import *
from group import Group
class FQuoted(Quoted): class FQuoted(Quoted):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@ -41,8 +42,9 @@ def transform(e: Element, c: Context) -> Element: # Returns next sibling element
if (isinstance(e, Div)) and "partial" in e.attributes: if (isinstance(e, Div)) and "partial" in e.attributes:
includedDoc = import_md(open(e.attributes["partial"], "r").read()) includedDoc = import_md(open(e.attributes["partial"], "r").read())
nContext = Context(includedDoc, e.attributes["partial"], c) nContext = Context(includedDoc, e.attributes["partial"], c)
language = includedDoc.get_metadata("language")
includedDoc = includedDoc.walk(transform, nContext) includedDoc = includedDoc.walk(transform, nContext)
e = Div(*includedDoc.content) e = Group(*includedDoc.content, metadata={"language": language})
if isinstance(e, Quoted): if isinstance(e, Quoted):

Loading…
Cancel
Save