Compare commits

...

43 Commits

Author SHA1 Message Date
Jiří Kalvoda 17920077da UCWTeX: Užší tabulka 7 days ago
Jiří Kalvoda 5a61ea5fac UCWTeX: Alternativní figures 7 days ago
Jiří Kalvoda 73af3473c7 UCWTeX: Fix languages 7 days ago
Jiří Kalvoda 6bfb62fcdd UCWTeX bigradical to unicode 7 days ago
Jiří Kalvoda 4e2ea4173e FLineMarkup 2 weeks ago
Jiří Kalvoda 8bcb087979 UCWTeX drobnosti 2 weeks ago
Jiří Kalvoda 2a5fd812e3 UCWTeX další chybějící UTF-8 znak. 2 weeks ago
Jiří Kalvoda c46a1f0302 UCWTeX: \vecoverrightarrow 2 weeks ago
Jiří Kalvoda 9a993676dc UCWTeX: Reforma figure 2 weeks ago
Jiří Kalvoda 87961754e8 UCWTeX: Vyčlenění formatitkolib 2 weeks ago
Jiří Kalvoda 08df4dbd78 UCWTeX: Obrázky vždyu zarovnáváme na střed, popisky nejsou slanted 2 weeks ago
Jiří Kalvoda 57e69cbee4 TeX: Nadpisy bez stránkových zlomů. 2 weeks ago
Jiří Kalvoda f86815e8ff TeX: Mezery v tabulce 2 weeks ago
Jiří Kalvoda bb05a3c913 Floatpage 1 month ago
Jiří Kalvoda 9dcf87915e Merge remote-tracking branch 'origin/master' into jk-bakalarka 2 months ago
Jiří Kalvoda ac2c3475e4 UCWTeX: {sub,super}script pomocí matematiky 2 months ago
Jiří Kalvoda 2fd0efe3a7 UCWTeX: Na výrobu pdf si pustíme luatex a naučíme ho hledat soubory 2 months ago
Jiří Kalvoda 4bd05b098b UCWTex: SmallCaps 2 months ago
Jiří Kalvoda 86839a9269 HTML: SmallCaps 2 months ago
Jiří Kalvoda 774af0fedf UCWTeX: Lepší formátování nadpisů 2 months ago
Jiří Kalvoda 38029e3587 fixup of fixup: context.unset_data 2 months ago
Jiří Kalvoda 6d629137fb Merge remote-tracking branch 'origin/master' into jk-bakalarka 2 months ago
Jiří Kalvoda ed40bc4db8 UCWTeX: Formátování obsahu 2 months ago
Jiří Kalvoda 292fcba574 UCWTeX: Další unicode převod 2 months ago
Jiří Kalvoda d783c7ae9c context: current_figure 2 months ago
Jiří Kalvoda 71e5c5bbdc fixup: context.unset_data 2 months ago
Jiří Kalvoda fb80c61139 UCWTeX seznam obrázků 3 months ago
Jiří Kalvoda 7230d87f6b Fix escape do TeXu 3 months ago
Jiří Kalvoda bf46105db8 Podsložka na TeX 3 months ago
Jiří Kalvoda 41f51bf6fe Default pro highlight 3 months ago
Jiří Kalvoda f1f2f63cb5 Odkazy na interní objekty (obrázky) 3 months ago
Jiří Kalvoda a2468b54e1 Merge remote-tracking branch 'origin/master' into jk-bakalarka 3 months ago
Jiří Kalvoda 945bb760e8 UCWTeX: Figure je float 3 months ago
Jiří Kalvoda 88d653af15 Číslování 3 months ago
Jiří Kalvoda 4dd1eb0314 TeX: Základní implementace citací 3 months ago
Jiří Kalvoda 48e34eaf8e BakalářkoTeX 3 months ago
Jiří Kalvoda 37c8ec4e2e Slanted font 3 months ago
Jiří Kalvoda 62263fbe0f Merge remote-tracking branch 'origin/master' into jk-bakalarka 3 months ago
Jiří Kalvoda f97ee7de52 renamed: formatitko.tex -> src/formatitko/formatitko.tex 3 months ago
Jiří Kalvoda 7783dc25f4 Drobnosti 3 months ago
Jiří Kalvoda 405a4f396c Číslování sekcí 3 months ago
Jiří Kalvoda affc2c4279 Fix chybějících obrázků v testech 3 months ago
Jiří Kalvoda a15a711d0f Přechot na LuaTeX 3 months ago
  1. 30
      formatitko.tex
  2. 28
      src/formatitko/context.py
  3. 18
      src/formatitko/elements.py
  4. 9
      src/formatitko/formatitko.py
  5. 7
      src/formatitko/html_generator.py
  6. 11
      src/formatitko/nop_processor.py
  7. 14
      src/formatitko/output_generator.py
  8. 189
      src/formatitko/tex/formatitko.tex
  9. 74
      src/formatitko/tex/formatitkolib.tex
  10. 22
      src/formatitko/tex/table_of_contents.tex
  11. 18
      src/formatitko/tex/table_of_contents_pictures.tex
  12. 155
      src/formatitko/tex_generator.py
  13. 30
      src/formatitko/transform_processor.py
  14. 10
      test/test-files/test-partial.md

30
formatitko.tex

@ -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}

28
src/formatitko/context.py

@ -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:

18
src/formatitko/elements.py

@ -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)

9
src/formatitko/formatitko.py

@ -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:

7
src/formatitko/html_generator.py

@ -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):

11
src/formatitko/nop_processor.py

@ -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

14
src/formatitko/output_generator.py

@ -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)

189
src/formatitko/tex/formatitko.tex

@ -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%
}

74
src/formatitko/tex/formatitkolib.tex

@ -0,0 +1,74 @@
\def\strong#1{{%
\def\emph##1{{\bi{}##1}}%
\bf{}#1%
}}
\def\emph#1{{%
\def\strong##1{{\bi{}##1}}%
\it{}#1%
}}
\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\section#1#2{
\vfil\supereject
\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%
}

22
src/formatitko/tex/table_of_contents.tex

@ -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
}

18
src/formatitko/tex/table_of_contents_pictures.tex

@ -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
}

155
src/formatitko/tex_generator.py

@ -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"}")

30
src/formatitko/transform_processor.py

@ -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
@ -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)

10
test/test-files/test-partial.md

@ -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}
![This is a figure, go figure...](logo.jpg){width=50%}
![Fakt epesní reproduktor](reproduktor.png "Hodně rozpixelovaný obrázek reproduktoru"){width=10em file-width=1000}

Loading…
Cancel
Save