Compare commits

...

48 commits

Author SHA1 Message Date
27ff4b7d58 Zabalíčkování KaTeX serveru 2024-10-27 22:34:58 +01:00
ef18947916 Merge remote-tracking branch 'origin/master' into jk-bakalarka 2024-10-05 12:00:10 +02:00
7ee84470e9 Workaround module import 2024-10-01 22:58:45 +02:00
9255f77d93 UCWTeX: Optional section eject 2024-10-01 21:14:42 +02:00
a9f41eb83e UCWTeX: textasciitilde 2024-10-01 21:13:07 +02:00
17920077da UCWTeX: Užší tabulka 2024-05-11 11:50:20 +02:00
5a61ea5fac UCWTeX: Alternativní figures 2024-05-11 11:50:04 +02:00
73af3473c7 UCWTeX: Fix languages 2024-05-11 11:49:30 +02:00
6bfb62fcdd UCWTeX bigradical to unicode 2024-05-11 11:46:58 +02:00
4e2ea4173e FLineMarkup 2024-05-07 15:56:02 +02:00
8bcb087979 UCWTeX drobnosti 2024-05-07 11:16:03 +02:00
2a5fd812e3 UCWTeX další chybějící UTF-8 znak. 2024-05-06 13:13:03 +02:00
c46a1f0302 UCWTeX: \vecoverrightarrow 2024-05-04 18:25:52 +02:00
9a993676dc UCWTeX: Reforma figure 2024-05-04 18:24:25 +02:00
87961754e8 UCWTeX: Vyčlenění formatitkolib 2024-05-04 18:23:52 +02:00
08df4dbd78 UCWTeX: Obrázky vždyu zarovnáváme na střed, popisky nejsou slanted 2024-05-04 18:19:40 +02:00
57e69cbee4 TeX: Nadpisy bez stránkových zlomů. 2024-05-02 13:34:59 +02:00
f86815e8ff TeX: Mezery v tabulce 2024-05-02 13:32:39 +02:00
bb05a3c913 Floatpage 2024-04-03 10:51:48 +02:00
9dcf87915e Merge remote-tracking branch 'origin/master' into jk-bakalarka 2024-03-18 21:22:31 +01:00
ac2c3475e4 UCWTeX: {sub,super}script pomocí matematiky 2024-03-18 21:21:26 +01:00
2fd0efe3a7 UCWTeX: Na výrobu pdf si pustíme luatex a naučíme ho hledat soubory 2024-03-18 21:21:26 +01:00
4bd05b098b UCWTex: SmallCaps 2024-03-18 21:21:26 +01:00
86839a9269 HTML: SmallCaps 2024-03-18 21:21:26 +01:00
774af0fedf UCWTeX: Lepší formátování nadpisů 2024-03-18 10:38:43 +01:00
38029e3587 fixup of fixup: context.unset_data
git#
2024-03-18 10:37:57 +01:00
6d629137fb Merge remote-tracking branch 'origin/master' into jk-bakalarka
Conflicts:
	src/formatitko/elements.py
	src/formatitko/nop_processor.py
	src/formatitko/output_generator.py

FileLink vs FLink
2024-03-17 22:40:15 +01:00
ed40bc4db8 UCWTeX: Formátování obsahu 2024-03-17 22:33:35 +01:00
292fcba574 UCWTeX: Další unicode převod 2024-03-17 22:32:23 +01:00
d783c7ae9c context: current_figure 2024-03-17 22:32:00 +01:00
71e5c5bbdc fixup: context.unset_data 2024-03-17 22:30:48 +01:00
fb80c61139 UCWTeX seznam obrázků 2024-03-02 19:06:29 +01:00
7230d87f6b Fix escape do TeXu 2024-03-02 19:06:03 +01:00
bf46105db8 Podsložka na TeX 2024-03-02 19:05:54 +01:00
41f51bf6fe Default pro highlight 2024-02-27 18:21:37 +01:00
f1f2f63cb5 Odkazy na interní objekty (obrázky) 2024-02-27 12:42:23 +01:00
a2468b54e1 Merge remote-tracking branch 'origin/master' into jk-bakalarka 2024-02-27 10:24:41 +01:00
945bb760e8 UCWTeX: Figure je float 2024-02-27 10:23:33 +01:00
88d653af15 Číslování 2024-02-27 10:22:37 +01:00
4dd1eb0314 TeX: Základní implementace citací 2024-02-25 23:54:02 +01:00
48e34eaf8e BakalářkoTeX 2024-02-25 22:24:45 +01:00
37c8ec4e2e Slanted font 2024-02-25 22:24:09 +01:00
62263fbe0f Merge remote-tracking branch 'origin/master' into jk-bakalarka 2024-02-25 18:02:59 +01:00
f97ee7de52 renamed: formatitko.tex -> src/formatitko/formatitko.tex 2024-02-18 00:18:22 +01:00
7783dc25f4 Drobnosti 2024-02-17 23:40:24 +01:00
405a4f396c Číslování sekcí 2024-02-17 20:55:12 +01:00
affc2c4279 Fix chybějících obrázků v testech 2024-02-17 11:18:11 +01:00
a15a711d0f Přechot na LuaTeX 2024-02-17 11:16:20 +01:00
18 changed files with 546 additions and 98 deletions

2
.gitmodules vendored
View file

@ -2,5 +2,5 @@
path = ucwmac
url = git://git.ucw.cz/ucwmac.git
[submodule "src/formatitko/katex-server"]
path = src/formatitko/katex-server
path = src/formatitko/katex_server
url = https://gitea.ks.matfyz.cz:/KSP/formatitko-katex-server

View file

@ -1,30 +0,0 @@
\input luatex85.sty
\input ucwmac2.tex
\parskip=5pt plus 3pt minus 2pt
\parindent=0sp
\def\strong#1{{%
\def\emph##1{{\bi{}##1}}%
\bf{}#1%
}}
\def\emph#1{{%
\def\strong##1{{\bi{}##1}}%
\it{}#1%
}}
\def\superscript#1{\leavevmode\raise3pt\hbox{\fiverm#1}}
\def\subscript#1{\leavevmode\lower1pt\hbox{\fiverm#1}}
\newcount\fncount
\fncount=1
\def\fnmark{\superscript{\the\fncount}}
\def\fn#1{\footnote\fnmark{#1}\advance\fncount by 1}
\def\section#1{{\parskip1em\settextsize{18}\bf #1}}
\def\subsection#1{{\parskip1em\settextsize{16}\bf #1}}
\def\subsubsection#1{{\parskip1em\settextsize{14}\bf #1}}
\def\subsubsubsection#1{{\parskip1em\settextsize{12}\bf #1}}
\def\subsubsubsubsection#1{{\parskip1em\settextsize{10}\bf #1}}
\def\subsubsubsubsubsection#1{{\parskip1em\settextsize{10}\bi #1}}
\long\def\blockquote#1{\vskip\lineskip\vskip\parskip\hbox{\vrule\hskip5pt\vbox{#1}}}
\def\strikeout#1{FIXME: Strikeout not implemented}
\def\underline#1{FIXME: Underline not implemented}

View file

@ -33,11 +33,19 @@ dependencies = [
[project.scripts]
formatitko = "formatitko.formatitko:main"
[tool.setuptools.package-data]
"formatitko.katex_server" = [
"*",
"node_modules/*",
"node_modules/katex/*",
"node_modules/katex/src/*",
"node_modules/katex/dist/*",
]
[tool.setuptools_scm]
[tool.setuptools.packages.find]
where = ["src"]
exclude = ["src/formatitko/katex-server/node_modules"]
[tool.pyright]
strictParameterNoneValue = false

View file

@ -1,4 +1,4 @@
from panflute import Doc, Element, Div, Span
from panflute import Doc, Element, Div, Span, Header, Figure
from typing import Union, Callable
from types import ModuleType
@ -19,6 +19,23 @@ CommandCallable = Callable[[Command, 'Context', 'NOPProcessor'], list[Element]]
#
# This class is basically an extension to panflute's doc, this is why metadata
# is read directly from it.
def default_section_number_generator(e: Header, context: 'Context') -> list[Union[str, int]]:
l = e.level
section_counters = context.get_data("section_counters")
section_counters[l-1] += 1
for i in range(l, len(section_counters)):
section_counters[i] = 0
return list(section_counters[:l])
def default_figure_number_generator(e: Figure, context: 'Context') -> Union[str, int]:
figure_type = e.attributes.get("type", "img")
figure_counters = context.get_data("figure_counters")
figure_counters.setdefault(figure_type, 0)
figure_counters[figure_type] += 1
return figure_counters[figure_type]
class Context:
parent: Union["Context", None]
_commands: dict[str, Union[CommandCallable, None]]
@ -32,6 +49,9 @@ class Context:
rel_dir: str # Relative path to the current dir from the root dir
deps: set[str]
section_counters: list[int]
number_generator: Callable[[Header, 'Context'], str]
def __init__(self, doc: Doc, path: str, parent: Union['Context', None]=None, trusted: bool=True):
self.parent = parent
self._commands = {}
@ -47,6 +67,12 @@ class Context:
self.add_dep(path)
if self.get_metadata("flags", immediate=True) is None:
self.set_metadata("flags", {})
if not parent:
self.set_data('section_number_generator', default_section_number_generator)
self.set_data('figure_number_generator', default_figure_number_generator)
self.set_data('section_counters', [0 for i in range(6)])
self.set_data('figure_counters', {})
self.set_data('obj_map', {})
def get_command(self, command: str) -> Union[CommandCallable, None]:
if command in self._commands:

View file

@ -1,4 +1,4 @@
from panflute import Quoted, Link
from panflute import Quoted, Emph, Link, Div
from .command import Command, InlineCommand, BlockCommand, CodeCommand
@ -14,6 +14,22 @@ class FQuoted(Quoted):
del kwargs["style"]
super().__init__(*args, **kwargs)
class Slanted(Emph):
pass
class FLink(Link):
obj_map: map
def __init__(self, *args, **kwargs):
self.obj_map = kwargs["obj_map"]
del kwargs["obj_map"]
super().__init__(*args, **kwargs)
class FileLink(Link):
pass
class FLineMarkup(Div):
def __init__(self, *args, **kwargs):
self.color = kwargs["color"]
del kwargs["color"]
super().__init__(*args, **kwargs)

View file

@ -2,9 +2,11 @@
import argparse
import sys
import os
import tempfile
import subprocess
import shutil
from pathlib import Path
# Import local files
from .util import import_md
@ -112,7 +114,12 @@ def main():
else:
filename = args.output_tex
outdir = tempfile.TemporaryDirectory(prefix="formatitko")
subprocess.run(["pdfcsplain", "-halt-on-error", "-output-directory="+outdir.name, "-jobname=formatitko", filename], check=True)
env = os.environ.copy()
d = Path("/".join(__file__.split("/")[:-1]))
env["TEXINPUTS"]=".:"+str(d/"tex")+":"+env.get("TEXINPUTS", "")
subprocess.run(["luatex", "-halt-on-error", "-output-directory="+outdir.name, "-jobname=formatitko", filename], check=True, env=env)
shutil.move(outdir.name+"/formatitko.pdf", args.output_pdf)
if args.deps is not None:

View file

@ -111,7 +111,7 @@ class HTMLGenerator(OutputGenerator):
def generate_CodeBlock(self, e: CodeBlock):
lexer = None
if e.classes and len(e.classes) > 0 and (e.attributes["highlight"] == True or e.attributes["highlight"] == 'True'):
if e.classes and len(e.classes) > 0 and (e.attributes.get("highlight", False) in [True, 'True']):
# Syntax highlighting using pygments
for cl in e.classes:
try:
@ -123,7 +123,7 @@ class HTMLGenerator(OutputGenerator):
warnings.warn(f"Syntax highligher does not have lexer for element with these classes: {e.classes}", UserWarning)
if lexer:
formatter = HtmlFormatter(style=e.attributes["style"], noclasses=True)
formatter = HtmlFormatter(style=e.attributes.get("style", self.context.get_metadata("highlight-style")), noclasses=True)
result = highlight(e.text, lexer, formatter)
self.writeraw(result)
else:
@ -344,6 +344,9 @@ class HTMLGenerator(OutputGenerator):
def generate_DefinitionList(self, e: DefinitionList):
self.writeln("<!-- FIXME: DefinitionLists not implemented -->")
def generate_SmallCaps(self, e: SmallCaps):
self.generate_simple_tag(e, attributes=self.common_attributes(e) | {"style": "font-variant: small-caps;"})
class StandaloneHTMLGenerator(HTMLGenerator):
def generate_Doc(self, e: Doc):

View file

@ -46,20 +46,20 @@ class KatexClient:
srcdir = os.path.dirname(os.path.realpath(__file__))
# Test if `node_modules` directory exists and if not, run `npm install`
if not os.path.isdir(srcdir + "/katex-server/node_modules"):
if not os.path.isdir(srcdir + "/katex_server/node_modules"):
print("Installing node dependencies for the first time...")
npm = shutil.which("npm") or shutil.which("yarnpkg")
if npm is None:
raise NPMNotFoundError("npm not found. Node.js is required to use KaTeX.")
subprocess.run([npm, "install"], cwd=srcdir+"/katex-server", check=True)
subprocess.run([npm, "install"], cwd=srcdir+"/katex_server", check=True)
self._katex_server_path = srcdir + "/katex-server/index.mjs"
self._katex_server_path = srcdir + "/katex_server/index.mjs"
self._server_process = subprocess.Popen(["node", self._katex_server_path, self._socket_file], stdout=subprocess.PIPE)
ok = self._server_process.stdout.readline()
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)

View file

@ -6,7 +6,7 @@ from panflute import MetaValue
from typing import Union, Callable
from .whitespace import NBSP
from .elements import FQuoted, FileLink
from .elements import FQuoted, Slanted, FLink, FileLink
from .context import Group, InlineGroup, BlockGroup, Context
from .whitespace import Whitespace
from .command import BlockCommand, InlineCommand, CodeCommand, Command
@ -69,6 +69,7 @@ class NOPProcessor:
Cite: self.transform_Cite,
Code: self.transform_Code,
Emph: self.transform_Emph,
Slanted: self.transform_Slanted,
Image: self.transform_Image,
LineBreak: self.transform_LineBreak,
Link: self.transform_Link,
@ -88,6 +89,7 @@ class NOPProcessor:
Underline: self.transform_Underline,
NBSP: self.transform_NBSP,
FQuoted: self.transform_FQuoted,
FLink: self.transform_FLink,
FileLink: self.transform_FileLink,
InlineCommand: self.transform_InlineCommand,
@ -264,6 +266,10 @@ class NOPProcessor:
e.content = self.transform(e.content)
return e
def transform_Slanted(self, e: Slanted) -> Slanted:
e.content = self.transform(e.content)
return e
def transform_Link(self, e: Link) -> Link:
e.content = self.transform(e.content)
return e
@ -300,6 +306,9 @@ class NOPProcessor:
e.content = self.transform(e.content)
return e
def transform_FLink(self, e: FLink) -> FLink:
return self.transform_Link(e)
def transform_FileLink(self, e: FileLink) -> FileLink:
e.content = self.transform(e.content)
return e

View file

@ -7,7 +7,7 @@ from panflute import stringify
from typing import Union, Callable
from .whitespace import NBSP
from .elements import FQuoted, FileLink
from .elements import FQuoted, Slanted, FLink, FileLink, FLineMarkup
from .context import Group, InlineGroup, BlockGroup, Context
@ -88,6 +88,7 @@ class OutputGenerator:
DefinitionItem: self.generate_DefinitionItem,
DefinitionList: self.generate_DefinitionList,
Div: self.generate_Div,
FLineMarkup: self.generate_FLineMarkup,
Figure: self.generate_Figure,
Header: self.generate_Header,
HorizontalRule: self.generate_HorizontalRule,
@ -108,6 +109,7 @@ class OutputGenerator:
Cite: self.generate_Cite,
Code: self.generate_Code,
Emph: self.generate_Emph,
Slanted: self.generate_Slanted,
Image: self.generate_Image,
LineBreak: self.generate_LineBreak,
Link: self.generate_Link,
@ -127,6 +129,7 @@ class OutputGenerator:
Underline: self.generate_Underline,
NBSP: self.generate_NBSP,
FQuoted: self.generate_FQuoted,
FLink: self.generate_FLink,
FileLink: self.generate_FileLink,
InlineGroup: self.generate_InlineGroup
}
@ -379,11 +382,17 @@ class OutputGenerator:
def generate_Emph(self, e: Emph):
self.generate_simple_tag(e)
def generate_Slanted(self, e: Slanted):
self.generate_Emph(e)
def generate_Image(self, e: Image):
self.generate_simple_tag(e)
def generate_Link(self, e: Link):
self.generate_simple_tag(e)
def generate_FLink(self, e: FLink):
self.generate_Link(e)
def generate_Note(self, e: Note):
self.generate_simple_tag(e)
@ -454,6 +463,9 @@ class OutputGenerator:
def generate_Div(self, e: Div):
self.generate_simple_tag(e)
def generate_FLineMarkup(self, e: FLineMarkup):
self.generate_Div(e)
def generate_Header(self, e: Header):
self.generate_simple_tag(e)

View file

@ -0,0 +1,189 @@
\input ltluatex.tex
\input luatex85.sty
\input ucwmac2.tex
\ucwmodule{luaofs}
\ucwmodule{verb}
\ucwmodule{link}
\clickablefalse
\pdfglyphtounicode{summationtext}{2211}
\pdfglyphtounicode{summationdisplay}{2211}
\pdfglyphtounicode{summation}{2211}
\pdfglyphtounicode{parenleftbig}{0028}
\pdfglyphtounicode{parenrightbig}{0029}
\pdfglyphtounicode{parenleftBig}{0028}
\pdfglyphtounicode{parenrightBig}{0029}
\pdfglyphtounicode{parenleftbigg}{0028}
\pdfglyphtounicode{parenrightbigg}{0029}
\pdfglyphtounicode{parenleftBigg}{0028}
\pdfglyphtounicode{parenrightBigg}{0029}
\pdfglyphtounicode{radicalbig}{221A}
\pdfglyphtounicode{radicalBig}{221A}
\pdfglyphtounicode{radicalbigg}{221A}
\pdfglyphtounicode{radicalBigg}{221A}
\pdfglyphtounicode{hatwidest}{0302}
\input formatitkolib.tex
\input minim-xmp.tex
\startmetadata
pdfaid:part 2
pdfaid:conformance U
stopmetadata
\pdfcompresslevel=0
\pdfobjcompresslevel=0
% \pdfobj{/Alternate /DeviceRGB}
\input glyphtounicode.tex
\pdfgentounicode=1
%Create an OutputIntent in order to correctly specify colours
\immediate\pdfobj stream attr{/N 3} file{sRGB.icc}
\pdfcatalog{%
/OutputIntents [
<<
/Type /OutputIntent
/S /GTS_PDFA1
/DestOutputProfile \the\pdflastobj\space 0 R
/OutputConditionIdentifier (sRGB)
/Info (sRGB)
>>
]
}
\parskip=5pt plus 3pt minus 2pt
\parindent=0sp
% Fonty
\ofsdeclarefamily [Pagella] {%
\loadtextfam qplr;%
qplb;%
qpli;%
qplbi;;%
}
% doporučen je horní, dolní a pravý okraj 25 mm, levý okraj 40 mm.
% Protože doba tisknutí prací je už pryč, my máme stejně velkou stránku uprostřed papíru
\voffset 25mm
\hoffset 32.5mm
\vsize\pdfpageheight
\advance\vsize -2\voffset
\hsize\pdfpagewidth
\advance\hsize -2\hoffset
\advance\voffset -\pdfvorigin
\advance\hoffset -\pdfhorigin
\def\MSfeat#1{:mode=node;script=latn;+tlig}
\registertfm qplr - file:texgyrepagella-regular.otf\MSfeat{}
\registertfm qplb - file:texgyrepagella-bold.otf\MSfeat{}
\registertfm qpli - file:texgyrepagella-italic.otf\MSfeat{}
\registertfm qplbi - file:texgyrepagella-bolditalic.otf\MSfeat{}
%\setfonts[Pagella/10]
%\def\h{\it} % hint
%\def\bh{\bi} % bold hint
\def\mod{\mathrel{\rm mod}}
\settextsize{12}
\long\def\floatinsert#1{\par{
\setbox0=\vbox{\boxmaxdepth=2pt\relax #1}
\dimen0=\dimexpr \ht0 + \dp0 + \baselineskip + \pagetotal - \pageshrink \relax
\ifdim\dimen0 > \pagegoal
\insert\topins{
\penalty 100
\splittopskip=0pt
\splitmaxdepth=\maxdimen
\floatingpenalty=0
\box0
\nobreak\bigskip\medskip
}
\else
\goodbreak\bigskip
\box0
\goodbreak\bigskip
\unparskip
\fi
}}
% Obecny plovouci objekt: \float{objekt}{popisek}{mezera pred}{mezera po}
\long\def\figure#1#2#3#4{
\medskip#3
\hbox to \hsize{\hfil\vtop{
\parindent=0pt
\leftskip=0pt plus 0.2\hsize
\rightskip=0pt plus 0.2\hsize
\parfillskip=0pt
\spaceskip=0.3333em
\settextsize{10}
#1
}\hfil}#4
\medskip
\smallskip
{
\setbox0=\hbox{\settextsize{10}#2}
\ifdim\wd0 < 0.8\hsize
\centerline{\box0}
\else
\centerline{\vtop{
\hsize=0.8\hsize
\parindent=0pt
\leftskip=0pt plus 0.3\hsize
\rightskip=0pt plus 0.3\hsize
\parfillskip=0pt
\spaceskip=0.3333em
\settextsize{10}#2
}}
\fi
}}
\long\def\floatpage#1{
\pageinsert
\vbox to \vsize{#1}
\endinsert
}
% Dva floaty vedle sebe: \float{objekt1}{popisek1}{id1}{objekt2}{popisek2}{id2}
\def\twofloats#1#2#3#4#5#6{\floatinsert{
\medskip
\centerline{\vbox{\halign{\hss##\hss&\qquad\hss##\hss\cr
#1&#4\cr
\noalign{\medskip\smallskip}
#2&#5\cr
}}}
}}
% Obsah a odkazy
\newwrite\tocfile
\immediate\openout\tocfile=toc-new.aux
% Voláme: \addtoc\tocmacro{number}{asterisks}{title}
\long\def\addtoc#1#2#3#4{%
\edef\brum{%
\write\tocfile{\string#1{\noexpand\the\noexpand\count0}{#2}{#3}{#4}}%
}
\brum%
}

View file

@ -0,0 +1,79 @@
\def\strong#1{{%
\def\emph##1{{\bi{}##1}}%
\bf{}#1%
}}
\def\emph#1{{%
\def\strong##1{{\bi{}##1}}%
\it{}#1%
}}
\def\textasciitilde{$\sim$}
\def\N{{\bb N}}
\def\R{{\bb R}}
\def\E{{\bb E}}
\def\O{{\cal O}}
\def\SYM{{\rm SYM}}
\def\frac#1#2{{{#1} \over {#2}}}
\def\superscript#1{$^{\hbox{\settextsize{0.8\textsize}#1}}$}
\def\subscript#1{$_{\hbox{\settextsize{0.8\textsize}#1}}$}
\newcount\fncount
\fncount=1
\def\fnmark{$^{\the\fncount}$}
\def\fn#1{\footnote\fnmark{#1}\advance\fncount by 1}
\def\sectioneject{\vfil\supereject}
\def\section#1#2{
\sectioneject
\vskip 16pt\vbox{\settextsize{20}\bf #1\kern 1em\relax#2%
\addtoc\tocsection{#1}{}{#2}%
}\nobreak\vskip 12pt
}
\def\subsection#1#2{
\vskip 12pt\vbox{\settextsize{18}\bf #1\kern 1em\relax#2%
\addtoc\tocsubsection{#1}{}{#2}%
}\nobreak\vskip 7pt
}
\def\subsubsection#1#2{
\vskip 10pt\vbox{\settextsize{16}\bf #1\kern 1em\relax#2%
\addtoc\tocsubsubsection{#1}{}{#2}%
}\nobreak\vskip 6pt
}
\def\subsubsubsection#1#2{
\vskip 8pt\vbox{\settextsize{14}\bf #1\kern 1em\relax#2}\nobreak\vskip 5pt
}
\def\subsubsubsubsection#1#2{
\vskip 7pt\vbox{\settextsize{12}\bf #1\kern 1em\relax#2}\nobreak\vskip 5pt
}
\def\subsubsubsubsubsection#1#2{
\vskip 7pt\vbox{\settextsize{12}\bf #1\kern 1em\relax#2}\nobreak\vskip 5pt
}
\long\def\blockquote#1{\vskip\lineskip\vskip\parskip\hbox{\vrule\hskip5pt\vbox{#1}}}
\def\strikeout#1{FIXME: Strikeout not implemented}
\def\underline#1{FIXME: Underline not implemented}
\def\mathbb#1{\hbox{\bb #1}}
\def\unparskip{\vskip-\parskip}
\catcode`@=11
\def\vecoverrightarrow#1{\mathpalette\vecoverrightarrowtmp{#1}}
\def\vecoverrightarrowtmp#1#2{\vbox{\m@th\ialign{##\crcr
\vecrightarrowfill\crcr\noalign{\kern-\p@\kern 0.09em\nointerlineskip}
$\hfil#1{#2\,}\hfil$\crcr}}}
\def\vecrightarrowfill{$\settextsize{5}\m@th\smash-\mkern-7mu%
\cleaders\hbox{$\mkern-2mu\smash-\mkern-2mu$}\hfill
\settextsize{5}\mkern-7mu\mathord\rightarrow$}
\catcode`@=12
\long\def\linemarkup#1#2{%
\par\noindent\hbox{%
\hbox{}\hskip -6pt {\colorlocal{#1}\vrule width 1pt \hskip 5pt}%
\hbox to \hsize{\vbox{#2}\hfil}%
%\hbox{}\hskip 5pt {\colorlocal{#1}\vrule width 1pt \hskip -6pt}%
}\par%
}

View file

@ -0,0 +1,22 @@
{
\def\pagelink#1{#1}
\def\toclink#1#2{%
#2
}
\def\stdskip{\vskip 3pt}
\def\tocsection#1#2#3#4{
\line{\bf\hbox to 2em{#2\hfil}#4~\hfil\pagelink{#1}}
}
\def\tocsubsection#1#2#3#4{
\line{\hskip 1.5cm \hbox to 3em{#2\hfil}#4~\hfil\pagelink{#1}}
}
\def\tocsubsubsection#1#2#3#4{
\line{\hskip 3cm \hbox to 4em{#2\hfil}#4~\hfil\pagelink{#1}}
}
\def\tocpicture#1#2#3#4{}
\vskip 1cm
\input toc.aux
}

View file

@ -0,0 +1,18 @@
{
\def\pagelink#1{#1}
\def\toclink#1#2{%
#2
}
\def\stdskip{\vskip 3pt}
\def\tocsection#1#2#3#4{}
\def\tocsubsection#1#2#3#4{}
\def\tocsubsubsection#1#2#3#4{}
\def\tocpicture#1#2#3#4{
\line{\hbox to 2em{#2\hfil}#4~\hfil\pagelink{#1}}\stdskip
}
\vskip 1cm
\input toc.aux
}

View file

@ -11,10 +11,14 @@ from .output_generator import OutputGenerator
from .images import ImageProcessor, ImageProcessorNamespaceSearcher
from .whitespace import NBSP
from .elements import FQuoted
from .elements import FQuoted, FLineMarkup
from .context import Group, InlineGroup, BlockGroup, Context
from .util import inlinify
def color_to_rgb(color):
import matplotlib.colors
return matplotlib.colors.to_rgb(color)
class UCWTexGenerator(OutputGenerator):
imageProcessor: ImageProcessor
_bold: int
@ -24,22 +28,30 @@ class UCWTexGenerator(OutputGenerator):
self.imageProcessor = imageProcessor
self._bold = 0
self._italic = 0
self._floatpages = {}
super().__init__(output_file, *args, **kwargs)
def escape_special_chars(self, text: str) -> str:
text = text.replace("&", r"\&")
text = text.replace("%", r"\%")
text = text.replace("$", r"\$")
text = text.replace("#", r"\#")
text = text.replace("_", r"\_")
text = text.replace("{", r"\{")
text = text.replace("}", r"\}")
text = text.replace("~", r"\textasciitilde{}")
text = text.replace("^", r"\textasciicircum{}")
text = text.replace("\\", r"\textbackslash{}")
text = text.replace(" ", "~") # We use unicode no-break spaces to force nbsp in output
text = text.replace("", "")
return text
if '\\' in text:
print("ESCAPE", text)
out = ""
for char in text:
out += {
'&': r"\&",
'%': r"\%",
'$': r"\$",
'#': r"\#",
'_': r"\_",
'{': r"\{",
'}': r"\}",
'~': r"\textasciitilde{}",
'^': r"\textasciicircum{}",
'\\': r"\textbackslash{}",
' ': r"~",
'': r"",
}.get(char, char)
return out
def generate(self, e: Union[Element, ListContainer]):
if hasattr(e, "attributes") and "only" in e.attributes and e.attributes["only"] != "tex":
@ -67,21 +79,17 @@ class UCWTexGenerator(OutputGenerator):
self.writepar(r"\vskip5pt\hrule\hfil\vskip5pt{}")
def generate_Doc(self, e: Doc):
self.writeln(r"\input ucwmac2.tex")
self.writeln(r"\ucwmodule{ofs}")
self.writeln(r"\ucwmodule{verb}")
self.writeln(r"\ucwmodule{link}")
self.writeln(r"\input formatitko.tex")
self.generate(e.content)
self.writeln(r"\bye")
def get_language_macro(self, lang: str):
if lang == "cs":
return r"\chyph\lefthyphenmin=2\righthyphenmin=2{}"
return r"\uselanguage{czech}\frenchspacing\lefthyphenmin=2\righthyphenmin=2{}"
elif lang == "sk":
return r"\shyph\lefthyphenmin=2\righthyphenmin=2{}"
return r"\uselanguage{slovak}\frenchspacing\lefthyphenmin=2\righthyphenmin=2{}"
elif lang == "en":
return r"\ehyph\lefthyphenmin=2\righthyphenmin=2{}"
return r"\uselanguage{USenglish}\nonfrenchspacing\lefthyphenmin=2\righthyphenmin=2{}"
else:
return ""
@ -101,7 +109,7 @@ class UCWTexGenerator(OutputGenerator):
def generate_Header(self, e: Header):
self.ensure_empty(2)
self.write("\\"+"sub"*(e.level-1)+"section{")
self.write("\\"+"sub"*(e.level-1)+"section{"+".".join(map(str, e.attributes["number"]))+"}{")
self.generate(e.content)
self.write(r"}")
self.ensure_empty(2)
@ -147,31 +155,58 @@ class UCWTexGenerator(OutputGenerator):
width = str(int(e.attributes["width"][:-1])/100) + "\\hsize"
width = "width " + width
if isinstance(e.parent.parent, Figure):
self.writeln(f'\\putimage{{{width}}}{{{url}}}')
else:
self.writepar(f'\\putimage{{{width}}}{{{url}}}')
self.writeln(f'\\centerline{{\\putimage{{{width}}}{{{url}}}}}')
def generate_Code(self, e: Code):
self.write(r"\verb`")
self.write(e.text)
self.write(r"`")
def generate_Figure(self, e: Figure):
self.ensure_empty(2)
self.writeln(r"\vskip5pt")
self.writeln(r"\centerline{")
def generate_nonfloat_Figure(self, e: Figure):
self.writeln(r"\figure{")
self.indent_more()
self.generate(e.content)
self.indent_less()
self.writeln(r"}")
self.writeln(r"\centerline{")
self.writeln(r"}{")
self.indent_more()
if 'number' in e.attributes:
type_text = e.attributes.get("type_text", "Obrázek")
self.writeln(f"{type_text} {e.attributes['number']}:")
self.generate(e.caption)
if 'number' in e.attributes:
tocmac = e.attributes.get("tocmac", "tocpicture")
if tocmac:
self.writeln("\\addtoc\\"+tocmac+r"{"+str(e.attributes['number'])+"}{}{")
self.indent_more()
self.generate(e.caption.content)
self.indent_less()
self.writeln("}")
self.indent_less()
self.writeln(r"}")
self.writeln(r"\vskip5pt{}")
self.ensure_empty(2)
self.writeln(r"}{}{}")
def generate_Figure(self, e: Figure):
if "floatpage" in e.attributes:
fp = e.attributes["floatpage"]
flush = fp[-1]=="!"
if flush:
fp = fp[:-1]
self._floatpages.setdefault(fp, [])
self._floatpages[fp].append(e)
if flush:
self.writeln(r"\floatpage{")
self.writeln(r"\vfill")
for x in self._floatpages[fp]:
self.generate_nonfloat_Figure(x)
self.writeln(r"\vfill")
self.writeln(r"}")
del self._floatpages[fp]
else:
self.ensure_empty(2)
self.writeln(r"\floatinsert{")
self.generate_nonfloat_Figure(e)
self.writeln(r"}")
self.ensure_empty(2)
def generate_Emph(self, e: Emph):
if self._bold > 0:
@ -183,6 +218,11 @@ class UCWTexGenerator(OutputGenerator):
self._italic-=1
self.write(r"}")
def generate_Slanted(self, e: Emph):
self.write(r"{\sl{}")
self.generate(e.content)
self.write(r"}")
def generate_Strong(self, e: Strong):
if self._italic > 0:
self.write(r"{\bi{}")
@ -194,15 +234,15 @@ class UCWTexGenerator(OutputGenerator):
self.write(r"}")
def generate_Caption(self, e: Caption):
self.generate_Emph(e)
self.generate(e.content)
def generate_Math(self, e: Math):
if e.format == "DisplayMath":
self.ensure_empty(2)
self.ensure_empty(1)
self.writeraw("$$")
self.writeraw(e.text.strip())
self.writeraw("$$")
self.ensure_empty(2)
self.ensure_empty(1)
else:
self.write("$")
self.write(e.text)
@ -214,22 +254,23 @@ class UCWTexGenerator(OutputGenerator):
self.write(r"}")
def generate_Table(self, e: Table):
hskip = r"\hskip 0.6em\relax"
aligns = {
"AlignLeft": r"\quad#\quad\hfil",
"AlignRight": r"\quad\hfil#\quad",
"AlignCenter": r"\quad\hfil#\hfil\quad",
"AlignDefault": r"\quad#\quad\hfil"
"AlignLeft": hskip+r"\relax#\hfil"+hskip,
"AlignRight": hskip+r"\hfil#"+hskip,
"AlignCenter": hskip+r"\hfil#\hfil"+hskip,
"AlignDefault": hskip+r"#\hfil"+hskip,
}
self.writeln(r"\vskip1em")
self.writeln(r"\halign{\strut"+"&".join([aligns[col[0]] for col in e.colspec])+r"\cr")
self.writeln(r"\leavevmode\vbox{\halign{\strut"+"&".join([aligns[col[0]] for col in e.colspec])+r"\cr")
self.indent_more()
self.generate(e.head.content)
self.writeln(r"\noalign{\hrule}")
self.writeln(r"\noalign{\vskip 0.3em\hrule\vskip 0.3em}")
self.generate(e.content[0].content)
self.writeln(r"\noalign{\hrule}")
self.writeln(r"\noalign{\vskip 0.3em\hrule\vskip 0.3em}")
self.generate(e.foot.content)
self.indent_less()
self.writeln("}")
self.writeln("}}")
self.writeln(r"\vskip1em")
def generate_TableRow(self, e: TableRow):
@ -263,6 +304,16 @@ class UCWTexGenerator(OutputGenerator):
def generate_Div(self, e: Div):
self.generate(e.content)
def generate_FLineMarkup(self, e: FLineMarkup):
self.ensure_empty(2)
r,g,b = color_to_rgb(e.color)
self.writeln(r"\linemarkup{\rgb{"+f"{r} {g} {b}"+"}}{")
self.indent_more()
self.generate(e.content)
self.indent_less()
self.writeln(r"}")
self.ensure_empty(2)
def generate_LineBlock(self, e: LineBlock):
self.writeln()
@ -323,6 +374,11 @@ class UCWTexGenerator(OutputGenerator):
self.writeln(r"}")
def generate_Link(self, e: Link):
if len(e.content) == 0:
if e.url.startswith('#'):
obj = e.obj_map[e.url[1:]]
self.write(str(obj.attributes["number"]))
return
if len(e.content) == 1 and isinstance(e.content[0], Str) and e.content[0].text == e.url:
self.write(r"\url{")
else:
@ -348,7 +404,7 @@ class UCWTexGenerator(OutputGenerator):
self.writeln("% FIXME: Citations not implemented")
def generate_Cite(self, e: Cite):
self.writeln("% FIXME: Cites not implemented")
self.generate(e.content)
def generate_Definition(self, e: Definition):
self.writeln("% FIXME: Definitions not implemented")
@ -364,3 +420,8 @@ class UCWTexGenerator(OutputGenerator):
def generate_Strikeout(self, e: Strikeout):
self.writeln("% FIXME: Strikeouts not implemented")
def generate_SmallCaps(self, e: Strikeout):
self.write(r"{\csc{}")
self.generate(e.content)
self.write(r"}")

View file

@ -14,7 +14,7 @@ import importlib
import json
from .whitespace import NBSP
from .elements import FQuoted
from .elements import FQuoted, Slanted, FLink
from .context import Group, InlineGroup, BlockGroup
from .util import nullify, import_md
from .context import Context, CommandCallable
@ -228,12 +228,12 @@ class TransformProcessor(NOPProcessor):
importedDoc = import_md(open(filename, "r").read())
self.transform(importedDoc.content)
elif e.attributes["type"] == "module":
matches = re.match(r"^(\w+)(?: as (\w+))?$", e.content[0].text[1:])
matches = re.match(r"^([\w\.]+)(?: as (\w+))?$", e.content[0].text[1:])
if not matches:
raise SyntaxError(f"`{e.content[0].text[1:]}`: invalid syntax")
module = importlib.import_module(matches.group(1))
module_name = matches.group(1) if matches.group(2) is None else matches.group(2)
self.context.add_commands_from_module(module, module_name)
self.context.add_commands_from_module(module, "")
elif e.attributes["type"] == "metadata":
filename = self.context.dir + "/" + e.content[0].text[1:]
self.context.add_dep(filename)
@ -260,6 +260,11 @@ class TransformProcessor(NOPProcessor):
raise TypeError(f"Cannot print value of metadatum '{e.content[0].text[1:]}' of type '{type(val)}'")
return e
if "slanted" in e.classes:
# `.slanted` class for Span
# Content of Span is enclosed into Slanted (subclass os Emph)
return self.transform(Slanted(*e.content))
return super().transform_Span(e)
def transform_CodeBlock(self, e: CodeBlock) -> Union[CodeBlock, Div, Null]:
@ -306,3 +311,26 @@ class TransformProcessor(NOPProcessor):
else:
return e
def transform_Header(self, e: Header) -> Header:
if "number" not in e.attributes:
if 'unnumbered' in e.classes:
e.attributes["number"] = ""
else:
e.attributes["number"] = self.context.get_data("section_number_generator")(e, self.context)
return e
def transform_Figure(self, e: Figure) -> Figure:
if "number" not in e.attributes:
if 'unnumbered' in e.classes:
e.attributes["number"] = ""
else:
e.attributes["number"] = self.context.get_data("figure_number_generator")(e, self.context)
self.context.get_data("obj_map")[e.identifier] = e
self.context.set_data("current_figure", e)
r = super().transform_Figure(e)
self.context.unset_data("current_figure")
return r
def transform_Link(self, e: Link) -> Link:
e = FLink(*e.content, url=e.url, identifier=e.identifier, attributes=e.attributes, classes=e.classes, obj_map=self.context.get_data("obj_map"))
return super().transform_Link(e)

View file

@ -66,14 +66,14 @@ raise Exception("Jsem piča")
-->
![This is a figure, go figure...](logo.svg){width=25%}What
![This is a figure, go figure...](logo.pdf){width=50%}
![Fakt epesní reproduktor](reproduktor.jpeg){width=10em}
![Fakt epesní reproduktor](reproduktor.png "Hodně rozpixelovaný obrázek reproduktoru"){width=10em file-width=1000}
```
![This is a figure, go figure...](logo.jpg){width=50%}
![This is a figure, go figure...](logo1.png){width=10em}
![Fakt epesní reproduktor](reproduktor.jpeg){width=10em}
![Fakt epesní reproduktor](reproduktor.png "Hodně rozpixelovaný obrázek reproduktoru"){width=10em file-width=1000}