pytex-preprocessor 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pytex/__init__.py +87 -0
- pytex/commands/__init__.py +51 -0
- pytex/commands/biblatex.py +98 -0
- pytex/commands/builtin.py +598 -0
- pytex/commands/captions.py +56 -0
- pytex/commands/cleveref.py +43 -0
- pytex/commands/colors.py +60 -0
- pytex/commands/conditionals.py +62 -0
- pytex/commands/counters.py +85 -0
- pytex/commands/definitions.py +109 -0
- pytex/commands/floats.py +93 -0
- pytex/commands/font.py +138 -0
- pytex/commands/fontawesome.py +88 -0
- pytex/commands/fontspec.py +75 -0
- pytex/commands/geometry.py +25 -0
- pytex/commands/glossaries.py +126 -0
- pytex/commands/graphics.py +68 -0
- pytex/commands/hooks.py +58 -0
- pytex/commands/hyperref.py +57 -0
- pytex/commands/lengths.py +200 -0
- pytex/commands/listings.py +63 -0
- pytex/commands/mdframed.py +43 -0
- pytex/commands/picture.py +32 -0
- pytex/commands/setspace.py +38 -0
- pytex/commands/tables.py +123 -0
- pytex/helpers/__init__.py +3 -0
- pytex/helpers/coerce.py +13 -0
- pytex/helpers/parenting.py +13 -0
- pytex/helpers/sanitize.py +54 -0
- pytex/helpers/with_package.py +61 -0
- pytex/interface/__init__.py +3 -0
- pytex/interface/control_sequence.py +29 -0
- pytex/interface/package.py +52 -0
- pytex/interface/tex.py +41 -0
- pytex/model/__init__.py +25 -0
- pytex/model/color.py +203 -0
- pytex/model/concat.py +31 -0
- pytex/model/control_sequence.py +72 -0
- pytex/model/document.py +120 -0
- pytex/model/document_class.py +29 -0
- pytex/model/empty.py +19 -0
- pytex/model/environment.py +30 -0
- pytex/model/image.py +137 -0
- pytex/model/include.py +21 -0
- pytex/model/length.py +54 -0
- pytex/model/math.py +401 -0
- pytex/model/package.py +132 -0
- pytex/model/raw.py +61 -0
- pytex/packages.py +221 -0
- pytex/registry.py +49 -0
- pytex_builder/__init__.py +8 -0
- pytex_builder/build.py +175 -0
- pytex_builder/console.py +77 -0
- pytex_builder/render.py +90 -0
- pytex_builder/tectonic.py +370 -0
- pytex_hsrtreport/__init__.py +116 -0
- pytex_hsrtreport/assets/fonts/Blender/Blender-Bold.ttf +0 -0
- pytex_hsrtreport/assets/fonts/Blender/Blender-BoldItalic.ttf +0 -0
- pytex_hsrtreport/assets/fonts/Blender/Blender-Book.ttf +0 -0
- pytex_hsrtreport/assets/fonts/Blender/Blender-BookItalic.ttf +0 -0
- pytex_hsrtreport/assets/fonts/Blender/Blender-Medium.ttf +0 -0
- pytex_hsrtreport/assets/fonts/Blender/Blender-MediumItalic.ttf +0 -0
- pytex_hsrtreport/assets/fonts/Blender/Blender-Strong.ttf +0 -0
- pytex_hsrtreport/assets/fonts/Blender/Blender-Thin.ttf +0 -0
- pytex_hsrtreport/assets/fonts/Blender/Blender-ThinItalic.ttf +0 -0
- pytex_hsrtreport/assets/fonts/DIN/DIN-Black.ttf +0 -0
- pytex_hsrtreport/assets/fonts/DIN/DIN-Bold.ttf +0 -0
- pytex_hsrtreport/assets/fonts/DIN/DIN-BoldItalic.ttf +0 -0
- pytex_hsrtreport/assets/fonts/DIN/DIN-Italic.ttf +0 -0
- pytex_hsrtreport/assets/fonts/DIN/DIN-Medium.ttf +0 -0
- pytex_hsrtreport/assets/fonts/DIN/DIN-Regular.ttf +0 -0
- pytex_hsrtreport/assets/fonts/Times New Roman.ttf +0 -0
- pytex_hsrtreport/assets/logos/ASTA.svg +79 -0
- pytex_hsrtreport/assets/logos/DUMMY.png +0 -0
- pytex_hsrtreport/assets/logos/DUMMY_FOOT.png +0 -0
- pytex_hsrtreport/assets/logos/ECHO.svg +226 -0
- pytex_hsrtreport/assets/logos/HSRT.pdf +0 -0
- pytex_hsrtreport/assets/logos/INF.pdf +0 -0
- pytex_hsrtreport/assets/logos/STUPA.pdf +0 -0
- pytex_hsrtreport/assets/logos/Skyline.pdf +0 -0
- pytex_hsrtreport/boxes.py +215 -0
- pytex_hsrtreport/citations.py +21 -0
- pytex_hsrtreport/cleveref_names.py +47 -0
- pytex_hsrtreport/colors.py +30 -0
- pytex_hsrtreport/document.py +307 -0
- pytex_hsrtreport/fonts.py +66 -0
- pytex_hsrtreport/glossary.py +61 -0
- pytex_hsrtreport/hyperref_config.py +49 -0
- pytex_hsrtreport/listings.py +90 -0
- pytex_hsrtreport/logos.py +234 -0
- pytex_hsrtreport/pagebreak.py +67 -0
- pytex_hsrtreport/pagesetup.py +33 -0
- pytex_hsrtreport/tex/pagesetup.tex +76 -0
- pytex_hsrtreport/titlepage.py +136 -0
- pytex_hsrtreport/variants.py +24 -0
- pytex_hsrtreport/voting.py +96 -0
- pytex_hsrtreport/watermark.py +63 -0
- pytex_hsrtreport/wordcount.py +33 -0
- pytex_koma/__init__.py +90 -0
- pytex_koma/commands.py +296 -0
- pytex_koma/document.py +138 -0
- pytex_markdown/__init__.py +62 -0
- pytex_markdown/convert.py +271 -0
- pytex_markdown/escape.py +11 -0
- pytex_preprocessor-0.1.0.dist-info/METADATA +82 -0
- pytex_preprocessor-0.1.0.dist-info/RECORD +119 -0
- pytex_preprocessor-0.1.0.dist-info/WHEEL +5 -0
- pytex_preprocessor-0.1.0.dist-info/entry_points.txt +2 -0
- pytex_preprocessor-0.1.0.dist-info/top_level.txt +7 -0
- pytex_protocol/__init__.py +37 -0
- pytex_protocol/convert.py +202 -0
- pytex_protocol/document.py +91 -0
- pytex_protocol/entries.py +96 -0
- pytex_protocol/frontmatter.py +80 -0
- pytex_protocol/header.py +139 -0
- pytex_protocol/shortcodes.py +130 -0
- pytex_protocol/signatures.py +84 -0
- pytex_tikz/__init__.py +25 -0
- pytex_tikz/tikz.py +272 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
from typing import Final
|
|
2
|
+
|
|
3
|
+
from pytex.helpers.with_package import with_package
|
|
4
|
+
from pytex.interface.tex import TeX
|
|
5
|
+
from pytex.model.control_sequence import ControlSequence, Parameter
|
|
6
|
+
from pytex.model.package import DefinePackage
|
|
7
|
+
from pytex.model.raw import Raw
|
|
8
|
+
from pytex.packages import ACCSUPP, IFTHEN, PGFFOR, XCOLOR
|
|
9
|
+
from pytex.registry import Registry
|
|
10
|
+
|
|
11
|
+
__all__ = ["DraftWatermark", "WatermarkCounter", "WatermarkPackages"]
|
|
12
|
+
|
|
13
|
+
DRAFTWATERMARK: Final = DefinePackage("draftwatermark")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _watermark_text(text: str) -> str:
|
|
17
|
+
"""Build the tiled watermark grid: 100 rows × 16 cols, accessibility-friendly."""
|
|
18
|
+
safe = text.replace("\\", "\\\\").replace("{", "\\{").replace("}", "\\}")
|
|
19
|
+
return (
|
|
20
|
+
r"\setcounter{it}{1}"
|
|
21
|
+
+ r"\whiledo{\theit<100}{"
|
|
22
|
+
+ r"\foreach \col in {0,...,15}{\color{black!5}\BeginAccSupp{ActualText=}"
|
|
23
|
+
+ f"{safe}~~"
|
|
24
|
+
+ r"\EndAccSupp{}}\\"
|
|
25
|
+
+ r"\stepcounter{it}}"
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@Registry.add
|
|
30
|
+
@with_package(DRAFTWATERMARK)
|
|
31
|
+
@with_package(IFTHEN)
|
|
32
|
+
@with_package(PGFFOR)
|
|
33
|
+
@with_package(ACCSUPP)
|
|
34
|
+
@with_package(XCOLOR)
|
|
35
|
+
def DraftWatermark(
|
|
36
|
+
text: str,
|
|
37
|
+
scale: float = 0.08,
|
|
38
|
+
angle: float = 45,
|
|
39
|
+
color: str = "black!12",
|
|
40
|
+
) -> TeX:
|
|
41
|
+
"""Configure draftwatermark with tiled accessibility-safe text grid."""
|
|
42
|
+
body = (
|
|
43
|
+
f"scale={scale},angle={angle},"
|
|
44
|
+
+ f"text={{\\begin{{tabular}}{{c}}{_watermark_text(text)}\\end{{tabular}}}},"
|
|
45
|
+
+ f"color={color}"
|
|
46
|
+
)
|
|
47
|
+
return ControlSequence("DraftwatermarkOptions", (Parameter(Raw(body)),))
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@Registry.add
|
|
51
|
+
def WatermarkCounter() -> TeX:
|
|
52
|
+
"""Declares the `it` counter used by DraftWatermark. Emit once in preamble."""
|
|
53
|
+
return Raw("\\newcounter{it}")
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@Registry.add
|
|
57
|
+
def WatermarkPackages() -> TeX:
|
|
58
|
+
"""Render `\\usepackage` lines for all packages required by watermark."""
|
|
59
|
+
return ControlSequence(
|
|
60
|
+
"RequirePackage",
|
|
61
|
+
(Parameter("draftwatermark"),),
|
|
62
|
+
required_packages=frozenset({IFTHEN, PGFFOR, ACCSUPP, XCOLOR, DRAFTWATERMARK}),
|
|
63
|
+
)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from pytex.commands.definitions import Newcommand
|
|
2
|
+
from pytex.interface.tex import TeX
|
|
3
|
+
from pytex.model.concat import Concat
|
|
4
|
+
from pytex.model.raw import Raw
|
|
5
|
+
from pytex.registry import Registry
|
|
6
|
+
|
|
7
|
+
__all__ = ["WordcountCommands"]
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@Registry.add
|
|
11
|
+
def WordcountCommands() -> TeX:
|
|
12
|
+
"""Define `\\quickwordcount{<doc>}` + `\\detailtexcount{<doc>}` macros.
|
|
13
|
+
|
|
14
|
+
Both shell out to `texcount` and require `-shell-escape` build.
|
|
15
|
+
"""
|
|
16
|
+
return Concat(
|
|
17
|
+
Newcommand(
|
|
18
|
+
r"\quickwordcount",
|
|
19
|
+
Raw(
|
|
20
|
+
r"\immediate\write18{texcount -1 -sum -merge -q #1.tex > Build/words.sum }" # noqa: E501
|
|
21
|
+
+ r"\input{Build/words.sum} words"
|
|
22
|
+
),
|
|
23
|
+
nargs=1,
|
|
24
|
+
),
|
|
25
|
+
Newcommand(
|
|
26
|
+
r"\detailtexcount",
|
|
27
|
+
Raw(
|
|
28
|
+
r"\immediate\write18{texcount -merge -sum -q #1.tex > Build/.wcdetail }"
|
|
29
|
+
+ r"\verbatiminput{Build/.wcdetail}"
|
|
30
|
+
),
|
|
31
|
+
nargs=1,
|
|
32
|
+
),
|
|
33
|
+
)
|
pytex_koma/__init__.py
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
from . import commands
|
|
2
|
+
from .commands import (
|
|
3
|
+
Addchap,
|
|
4
|
+
Addmargin,
|
|
5
|
+
Addpart,
|
|
6
|
+
Addsec,
|
|
7
|
+
Addtokomafont,
|
|
8
|
+
Appendix,
|
|
9
|
+
Areaset,
|
|
10
|
+
Automark,
|
|
11
|
+
Backmatter,
|
|
12
|
+
Captionabove,
|
|
13
|
+
Captionbelow,
|
|
14
|
+
Cfoot,
|
|
15
|
+
Chead,
|
|
16
|
+
Clearpairofpagestyles,
|
|
17
|
+
Clearscrheadfoot,
|
|
18
|
+
Dedication,
|
|
19
|
+
Dictum,
|
|
20
|
+
Extratitle,
|
|
21
|
+
Frontmatter,
|
|
22
|
+
Ifoot,
|
|
23
|
+
Ihead,
|
|
24
|
+
KOMAoption,
|
|
25
|
+
KOMAoptions,
|
|
26
|
+
Labeling,
|
|
27
|
+
Lowertitleback,
|
|
28
|
+
Mainmatter,
|
|
29
|
+
Marginline,
|
|
30
|
+
Minisec,
|
|
31
|
+
Ofoot,
|
|
32
|
+
Ohead,
|
|
33
|
+
Pagestyle,
|
|
34
|
+
Publishers,
|
|
35
|
+
Recalctypearea,
|
|
36
|
+
Setkomafont,
|
|
37
|
+
Subject,
|
|
38
|
+
Subtitle,
|
|
39
|
+
Titlehead,
|
|
40
|
+
Typearea,
|
|
41
|
+
Uppertitleback,
|
|
42
|
+
Usekomafont,
|
|
43
|
+
)
|
|
44
|
+
from .document import KOMA_CLASSES, KomaDocument
|
|
45
|
+
|
|
46
|
+
__all__ = [
|
|
47
|
+
"KOMA_CLASSES",
|
|
48
|
+
"Addchap",
|
|
49
|
+
"Addmargin",
|
|
50
|
+
"Addpart",
|
|
51
|
+
"Addsec",
|
|
52
|
+
"Addtokomafont",
|
|
53
|
+
"Appendix",
|
|
54
|
+
"Areaset",
|
|
55
|
+
"Automark",
|
|
56
|
+
"Backmatter",
|
|
57
|
+
"Captionabove",
|
|
58
|
+
"Captionbelow",
|
|
59
|
+
"Cfoot",
|
|
60
|
+
"Chead",
|
|
61
|
+
"Clearpairofpagestyles",
|
|
62
|
+
"Clearscrheadfoot",
|
|
63
|
+
"Dedication",
|
|
64
|
+
"Dictum",
|
|
65
|
+
"Extratitle",
|
|
66
|
+
"Frontmatter",
|
|
67
|
+
"Ifoot",
|
|
68
|
+
"Ihead",
|
|
69
|
+
"KOMAoption",
|
|
70
|
+
"KOMAoptions",
|
|
71
|
+
"KomaDocument",
|
|
72
|
+
"Labeling",
|
|
73
|
+
"Lowertitleback",
|
|
74
|
+
"Mainmatter",
|
|
75
|
+
"Marginline",
|
|
76
|
+
"Minisec",
|
|
77
|
+
"Ofoot",
|
|
78
|
+
"Ohead",
|
|
79
|
+
"Pagestyle",
|
|
80
|
+
"Publishers",
|
|
81
|
+
"Recalctypearea",
|
|
82
|
+
"Setkomafont",
|
|
83
|
+
"Subject",
|
|
84
|
+
"Subtitle",
|
|
85
|
+
"Titlehead",
|
|
86
|
+
"Typearea",
|
|
87
|
+
"Uppertitleback",
|
|
88
|
+
"Usekomafont",
|
|
89
|
+
"commands",
|
|
90
|
+
]
|
pytex_koma/commands.py
ADDED
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
from pytex.helpers.with_package import with_package
|
|
2
|
+
from pytex.interface.tex import TeX
|
|
3
|
+
from pytex.model.control_sequence import ControlSequence, Parameter
|
|
4
|
+
from pytex.model.environment import Environment
|
|
5
|
+
from pytex.packages import SCRLAYER_SCRPAGE, TYPEAREA
|
|
6
|
+
from pytex.registry import Registry
|
|
7
|
+
|
|
8
|
+
__all__ = [
|
|
9
|
+
"Addchap",
|
|
10
|
+
"Addmargin",
|
|
11
|
+
"Addpart",
|
|
12
|
+
"Addsec",
|
|
13
|
+
"Addtokomafont",
|
|
14
|
+
"Appendix",
|
|
15
|
+
"Areaset",
|
|
16
|
+
"Automark",
|
|
17
|
+
"Backmatter",
|
|
18
|
+
"Captionabove",
|
|
19
|
+
"Captionbelow",
|
|
20
|
+
"Cfoot",
|
|
21
|
+
"Chead",
|
|
22
|
+
"Clearpairofpagestyles",
|
|
23
|
+
"Clearscrheadfoot",
|
|
24
|
+
"Dedication",
|
|
25
|
+
"Dictum",
|
|
26
|
+
"Extratitle",
|
|
27
|
+
"Frontmatter",
|
|
28
|
+
"Ifoot",
|
|
29
|
+
"Ihead",
|
|
30
|
+
"KOMAoption",
|
|
31
|
+
"KOMAoptions",
|
|
32
|
+
"Labeling",
|
|
33
|
+
"Lowertitleback",
|
|
34
|
+
"Mainmatter",
|
|
35
|
+
"Marginline",
|
|
36
|
+
"Minisec",
|
|
37
|
+
"Ofoot",
|
|
38
|
+
"Ohead",
|
|
39
|
+
"Pagestyle",
|
|
40
|
+
"Publishers",
|
|
41
|
+
"Recalctypearea",
|
|
42
|
+
"Setkomafont",
|
|
43
|
+
"Subject",
|
|
44
|
+
"Subtitle",
|
|
45
|
+
"Titlehead",
|
|
46
|
+
"Typearea",
|
|
47
|
+
"Uppertitleback",
|
|
48
|
+
"Usekomafont",
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _sectioning(name: str, title: TeX | str, short: TeX | str | None) -> TeX:
|
|
53
|
+
if short is None:
|
|
54
|
+
return ControlSequence(name, (Parameter(title),))
|
|
55
|
+
return ControlSequence(name, (Parameter(short, optional=True), Parameter(title)))
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@Registry.add
|
|
59
|
+
def Addpart(title: TeX | str, short: TeX | str | None = None) -> TeX:
|
|
60
|
+
return _sectioning("addpart", title, short)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@Registry.add
|
|
64
|
+
def Addchap(title: TeX | str, short: TeX | str | None = None) -> TeX:
|
|
65
|
+
return _sectioning("addchap", title, short)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@Registry.add
|
|
69
|
+
def Addsec(title: TeX | str, short: TeX | str | None = None) -> TeX:
|
|
70
|
+
return _sectioning("addsec", title, short)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
@Registry.add
|
|
74
|
+
def Minisec(title: TeX | str) -> TeX:
|
|
75
|
+
return ControlSequence("minisec", (Parameter(title),))
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@Registry.add
|
|
79
|
+
def Frontmatter() -> TeX:
|
|
80
|
+
return ControlSequence("frontmatter", ())
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
@Registry.add
|
|
84
|
+
def Mainmatter() -> TeX:
|
|
85
|
+
return ControlSequence("mainmatter", ())
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
@Registry.add
|
|
89
|
+
def Backmatter() -> TeX:
|
|
90
|
+
return ControlSequence("backmatter", ())
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
@Registry.add
|
|
94
|
+
def Appendix() -> TeX:
|
|
95
|
+
return ControlSequence("appendix", ())
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
@Registry.add
|
|
99
|
+
def Subtitle(text: TeX | str) -> TeX:
|
|
100
|
+
return ControlSequence("subtitle", (Parameter(text),))
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
@Registry.add
|
|
104
|
+
def Subject(text: TeX | str) -> TeX:
|
|
105
|
+
return ControlSequence("subject", (Parameter(text),))
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
@Registry.add
|
|
109
|
+
def Publishers(text: TeX | str) -> TeX:
|
|
110
|
+
return ControlSequence("publishers", (Parameter(text),))
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
@Registry.add
|
|
114
|
+
def Titlehead(text: TeX | str) -> TeX:
|
|
115
|
+
return ControlSequence("titlehead", (Parameter(text),))
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
@Registry.add
|
|
119
|
+
def Dedication(text: TeX | str) -> TeX:
|
|
120
|
+
return ControlSequence("dedication", (Parameter(text),))
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
@Registry.add
|
|
124
|
+
def Uppertitleback(text: TeX | str) -> TeX:
|
|
125
|
+
return ControlSequence("uppertitleback", (Parameter(text),))
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
@Registry.add
|
|
129
|
+
def Lowertitleback(text: TeX | str) -> TeX:
|
|
130
|
+
return ControlSequence("lowertitleback", (Parameter(text),))
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
@Registry.add
|
|
134
|
+
def Extratitle(text: TeX | str) -> TeX:
|
|
135
|
+
return ControlSequence("extratitle", (Parameter(text),))
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
@Registry.add
|
|
139
|
+
def Dictum(text: TeX | str, author: TeX | str | None = None) -> TeX:
|
|
140
|
+
if author is None:
|
|
141
|
+
return ControlSequence("dictum", (Parameter(text),))
|
|
142
|
+
return ControlSequence(
|
|
143
|
+
"dictum",
|
|
144
|
+
(Parameter(author, optional=True), Parameter(text)),
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
@Registry.add
|
|
149
|
+
def KOMAoptions(options: dict[str, str]) -> TeX:
|
|
150
|
+
return ControlSequence("KOMAoptions", (Parameter(options),))
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
@Registry.add
|
|
154
|
+
def KOMAoption(key: str, value: str) -> TeX:
|
|
155
|
+
return ControlSequence("KOMAoption", (Parameter(key), Parameter(value)))
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
@Registry.add
|
|
159
|
+
def Setkomafont(element: str, definition: TeX | str) -> TeX:
|
|
160
|
+
return ControlSequence(
|
|
161
|
+
"setkomafont",
|
|
162
|
+
(Parameter(element), Parameter(definition)),
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
@Registry.add
|
|
167
|
+
def Addtokomafont(element: str, definition: TeX | str) -> TeX:
|
|
168
|
+
return ControlSequence(
|
|
169
|
+
"addtokomafont",
|
|
170
|
+
(Parameter(element), Parameter(definition)),
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
@Registry.add
|
|
175
|
+
def Usekomafont(element: str) -> TeX:
|
|
176
|
+
return ControlSequence("usekomafont", (Parameter(element),))
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
@Registry.add
|
|
180
|
+
def Captionabove(text: TeX | str) -> TeX:
|
|
181
|
+
return ControlSequence("captionabove", (Parameter(text),))
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
@Registry.add
|
|
185
|
+
def Captionbelow(text: TeX | str) -> TeX:
|
|
186
|
+
return ControlSequence("captionbelow", (Parameter(text),))
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
@Registry.add
|
|
190
|
+
def Marginline(text: TeX | str) -> TeX:
|
|
191
|
+
return ControlSequence("marginline", (Parameter(text),))
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
@Registry.add
|
|
195
|
+
def Addmargin(body: TeX | str, amount: str) -> TeX:
|
|
196
|
+
return Environment("addmargin", body, (Parameter(amount),))
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
@Registry.add
|
|
200
|
+
def Labeling(body: TeX | str, sep: str = "") -> TeX:
|
|
201
|
+
params = (Parameter(sep, optional=True),) if sep else ()
|
|
202
|
+
return Environment("labeling", body, params)
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
@Registry.add
|
|
206
|
+
@with_package(TYPEAREA)
|
|
207
|
+
def Areaset(width: str, height: str, bcor: str | None = None) -> TeX:
|
|
208
|
+
if bcor is None:
|
|
209
|
+
return ControlSequence("areaset", (Parameter(width), Parameter(height)))
|
|
210
|
+
return ControlSequence(
|
|
211
|
+
"areaset",
|
|
212
|
+
(Parameter(bcor, optional=True), Parameter(width), Parameter(height)),
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
@Registry.add
|
|
217
|
+
@with_package(TYPEAREA)
|
|
218
|
+
def Typearea(divisor: int | str) -> TeX:
|
|
219
|
+
return ControlSequence("typearea", (Parameter(str(divisor)),))
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
@Registry.add
|
|
223
|
+
@with_package(TYPEAREA)
|
|
224
|
+
def Recalctypearea() -> TeX:
|
|
225
|
+
return ControlSequence("recalctypearea", ())
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
@Registry.add
|
|
229
|
+
@with_package(SCRLAYER_SCRPAGE)
|
|
230
|
+
def Pagestyle(name: str) -> TeX:
|
|
231
|
+
return ControlSequence("pagestyle", (Parameter(name),))
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
@Registry.add
|
|
235
|
+
@with_package(SCRLAYER_SCRPAGE)
|
|
236
|
+
def Clearpairofpagestyles() -> TeX:
|
|
237
|
+
return ControlSequence("clearpairofpagestyles", ())
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
@Registry.add
|
|
241
|
+
@with_package(SCRLAYER_SCRPAGE)
|
|
242
|
+
def Clearscrheadfoot() -> TeX:
|
|
243
|
+
return ControlSequence("clearscrheadfoot", ())
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
@Registry.add
|
|
247
|
+
@with_package(SCRLAYER_SCRPAGE)
|
|
248
|
+
def Automark(level: str, second: str | None = None) -> TeX:
|
|
249
|
+
if second is None:
|
|
250
|
+
return ControlSequence("automark", (Parameter(level),))
|
|
251
|
+
return ControlSequence(
|
|
252
|
+
"automark",
|
|
253
|
+
(Parameter(second, optional=True), Parameter(level)),
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def _scoped_head_foot(name: str, scope: str | None, body: TeX | str) -> TeX:
|
|
258
|
+
if scope is None:
|
|
259
|
+
return ControlSequence(name, (Parameter(body),))
|
|
260
|
+
return ControlSequence(name, (Parameter(scope, optional=True), Parameter(body)))
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
@Registry.add
|
|
264
|
+
@with_package(SCRLAYER_SCRPAGE)
|
|
265
|
+
def Ihead(body: TeX | str, scope: str | None = None) -> TeX:
|
|
266
|
+
return _scoped_head_foot("ihead", scope, body)
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
@Registry.add
|
|
270
|
+
@with_package(SCRLAYER_SCRPAGE)
|
|
271
|
+
def Chead(body: TeX | str, scope: str | None = None) -> TeX:
|
|
272
|
+
return _scoped_head_foot("chead", scope, body)
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
@Registry.add
|
|
276
|
+
@with_package(SCRLAYER_SCRPAGE)
|
|
277
|
+
def Ohead(body: TeX | str, scope: str | None = None) -> TeX:
|
|
278
|
+
return _scoped_head_foot("ohead", scope, body)
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
@Registry.add
|
|
282
|
+
@with_package(SCRLAYER_SCRPAGE)
|
|
283
|
+
def Ifoot(body: TeX | str, scope: str | None = None) -> TeX:
|
|
284
|
+
return _scoped_head_foot("ifoot", scope, body)
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
@Registry.add
|
|
288
|
+
@with_package(SCRLAYER_SCRPAGE)
|
|
289
|
+
def Cfoot(body: TeX | str, scope: str | None = None) -> TeX:
|
|
290
|
+
return _scoped_head_foot("cfoot", scope, body)
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
@Registry.add
|
|
294
|
+
@with_package(SCRLAYER_SCRPAGE)
|
|
295
|
+
def Ofoot(body: TeX | str, scope: str | None = None) -> TeX:
|
|
296
|
+
return _scoped_head_foot("ofoot", scope, body)
|
pytex_koma/document.py
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# pyright: reportAny=false
|
|
2
|
+
from collections.abc import Iterator
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
|
|
5
|
+
from pytex.interface.package import PackageOption
|
|
6
|
+
from pytex.model.document import Document
|
|
7
|
+
from pytex.registry import Registry
|
|
8
|
+
|
|
9
|
+
__all__ = ["KomaDocument"]
|
|
10
|
+
|
|
11
|
+
KOMA_CLASSES: frozenset[str] = frozenset(
|
|
12
|
+
{"scrartcl", "scrreprt", "scrbook", "scrlttr2"}
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
PAPER_FLAGS: frozenset[str] = frozenset(
|
|
16
|
+
{"a4paper", "a5paper", "b5paper", "letterpaper", "executivepaper", "legalpaper"}
|
|
17
|
+
)
|
|
18
|
+
FONTSIZE_FLAGS: frozenset[str] = frozenset({"10pt", "11pt", "12pt"})
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _on_off(value: bool, on: str, off: str) -> str:
|
|
22
|
+
return on if value else off
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@Registry.add
|
|
26
|
+
@dataclass
|
|
27
|
+
class KomaDocument(Document):
|
|
28
|
+
document_class: str = "scrartcl"
|
|
29
|
+
|
|
30
|
+
paper: str | None = None
|
|
31
|
+
fontsize: str | None = None
|
|
32
|
+
bcor: str | None = None
|
|
33
|
+
div: int | str | None = None
|
|
34
|
+
pagesize: str | None = None
|
|
35
|
+
|
|
36
|
+
two_side: bool | None = None
|
|
37
|
+
two_column: bool | None = None
|
|
38
|
+
landscape: bool | None = None
|
|
39
|
+
title_page: bool | None = None
|
|
40
|
+
draft: bool | None = None
|
|
41
|
+
|
|
42
|
+
open_at: str | None = None
|
|
43
|
+
chapter_prefix: bool | None = None
|
|
44
|
+
appendix_prefix: bool | None = None
|
|
45
|
+
|
|
46
|
+
headings: str | None = None
|
|
47
|
+
parskip: str | None = None
|
|
48
|
+
numbers: str | None = None
|
|
49
|
+
captions: str | None = None
|
|
50
|
+
toc: str | None = None
|
|
51
|
+
listof: str | None = None
|
|
52
|
+
bibliography: str | None = None
|
|
53
|
+
index: str | None = None
|
|
54
|
+
footnotes: str | None = None
|
|
55
|
+
|
|
56
|
+
head_include: bool | None = None
|
|
57
|
+
foot_include: bool | None = None
|
|
58
|
+
mp_include: bool | None = None
|
|
59
|
+
|
|
60
|
+
use_geometry: bool | None = None
|
|
61
|
+
|
|
62
|
+
extra_class_options: set[PackageOption] = field(default_factory=set)
|
|
63
|
+
|
|
64
|
+
def __post_init__(self) -> None:
|
|
65
|
+
super().__post_init__()
|
|
66
|
+
if self.document_class not in KOMA_CLASSES:
|
|
67
|
+
raise ValueError(
|
|
68
|
+
f"Unknown KOMA-Script class {self.document_class!r}; "
|
|
69
|
+
+ f"expected one of {sorted(KOMA_CLASSES)}"
|
|
70
|
+
)
|
|
71
|
+
self.document_class_options: set[PackageOption] = (
|
|
72
|
+
set(self.document_class_options)
|
|
73
|
+
| set(self.extra_class_options)
|
|
74
|
+
| set(self._class_option_flags())
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
def _class_option_flags(self) -> Iterator[PackageOption]:
|
|
78
|
+
"""Translate the typed KOMA fields into raw class options."""
|
|
79
|
+
# Value-bearing options: a known keyword flag, otherwise a key=value pair.
|
|
80
|
+
if self.paper is not None:
|
|
81
|
+
yield self.paper if self.paper in PAPER_FLAGS else ("paper", self.paper)
|
|
82
|
+
if self.fontsize is not None:
|
|
83
|
+
yield (
|
|
84
|
+
self.fontsize
|
|
85
|
+
if self.fontsize in FONTSIZE_FLAGS
|
|
86
|
+
else ("fontsize", self.fontsize)
|
|
87
|
+
)
|
|
88
|
+
if self.bcor is not None:
|
|
89
|
+
yield ("BCOR", self.bcor)
|
|
90
|
+
if self.div is not None:
|
|
91
|
+
yield ("DIV", str(self.div))
|
|
92
|
+
if self.pagesize is not None:
|
|
93
|
+
yield ("pagesize", self.pagesize)
|
|
94
|
+
|
|
95
|
+
# Boolean toggles mapped to their on/off keywords.
|
|
96
|
+
if self.two_side is not None:
|
|
97
|
+
yield _on_off(self.two_side, "twoside", "oneside")
|
|
98
|
+
if self.two_column is not None:
|
|
99
|
+
yield _on_off(self.two_column, "twocolumn", "onecolumn")
|
|
100
|
+
if self.landscape is True:
|
|
101
|
+
yield "landscape"
|
|
102
|
+
if self.title_page is not None:
|
|
103
|
+
yield _on_off(self.title_page, "titlepage", "notitlepage")
|
|
104
|
+
if self.draft is not None:
|
|
105
|
+
yield _on_off(self.draft, "draft", "final")
|
|
106
|
+
|
|
107
|
+
if self.open_at is not None:
|
|
108
|
+
yield ("open", self.open_at)
|
|
109
|
+
if self.chapter_prefix is not None:
|
|
110
|
+
yield ("chapterprefix", _on_off(self.chapter_prefix, "true", "false"))
|
|
111
|
+
if self.appendix_prefix is not None:
|
|
112
|
+
yield ("appendixprefix", _on_off(self.appendix_prefix, "true", "false"))
|
|
113
|
+
|
|
114
|
+
# Plain key=value options taken verbatim from same-named fields.
|
|
115
|
+
for key in (
|
|
116
|
+
"headings",
|
|
117
|
+
"parskip",
|
|
118
|
+
"numbers",
|
|
119
|
+
"captions",
|
|
120
|
+
"toc",
|
|
121
|
+
"listof",
|
|
122
|
+
"bibliography",
|
|
123
|
+
"index",
|
|
124
|
+
"footnotes",
|
|
125
|
+
):
|
|
126
|
+
value = getattr(self, key)
|
|
127
|
+
if value is not None:
|
|
128
|
+
yield (key, value)
|
|
129
|
+
|
|
130
|
+
if self.head_include is not None:
|
|
131
|
+
yield "headinclude" if self.head_include else "headexclude"
|
|
132
|
+
if self.foot_include is not None:
|
|
133
|
+
yield "footinclude" if self.foot_include else "footexclude"
|
|
134
|
+
if self.mp_include is not None:
|
|
135
|
+
yield "mpinclude" if self.mp_include else "mpexclude"
|
|
136
|
+
|
|
137
|
+
if self.use_geometry is not None:
|
|
138
|
+
yield "usegeometry" if self.use_geometry else "nogeometry"
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""Markdown -> native PyTeX conversion.
|
|
2
|
+
|
|
3
|
+
Exposes two registered factories:
|
|
4
|
+
|
|
5
|
+
* ``Markdown(content, ...)`` - convert a Markdown string to a ``TeX`` tree.
|
|
6
|
+
* ``IncludeMarkdown(path, ...)`` - read a file and convert it.
|
|
7
|
+
|
|
8
|
+
GitHub-style callouts (``> [!NOTE]`` ...) become HSRT ``ColoredBox`` presets,
|
|
9
|
+
so this package depends on ``pytex_hsrtreport``.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from typing import TYPE_CHECKING
|
|
16
|
+
|
|
17
|
+
import marko
|
|
18
|
+
|
|
19
|
+
from pytex.registry import Registry
|
|
20
|
+
|
|
21
|
+
from .convert import MarkdownConverter
|
|
22
|
+
from .escape import escape_latex
|
|
23
|
+
|
|
24
|
+
if TYPE_CHECKING:
|
|
25
|
+
from os import PathLike
|
|
26
|
+
|
|
27
|
+
from pytex.interface.tex import TeX
|
|
28
|
+
|
|
29
|
+
__all__ = ["IncludeMarkdown", "Markdown", "MarkdownConverter", "escape_latex"]
|
|
30
|
+
|
|
31
|
+
PARSER = marko.Markdown()
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@Registry.add
|
|
35
|
+
def Markdown(
|
|
36
|
+
content: str,
|
|
37
|
+
*,
|
|
38
|
+
base_level: int = 0,
|
|
39
|
+
callouts: bool = True,
|
|
40
|
+
) -> TeX:
|
|
41
|
+
"""Convert a Markdown string to a ``TeX`` tree.
|
|
42
|
+
|
|
43
|
+
``base_level`` shifts heading depth: ``0`` maps ``#`` to ``\\section`` (the
|
|
44
|
+
default), ``-1`` maps it to ``\\chapter``. ``callouts`` toggles converting
|
|
45
|
+
``> [!NOTE]`` blocks into HSRT colored boxes.
|
|
46
|
+
"""
|
|
47
|
+
ast = PARSER.parse(content)
|
|
48
|
+
converter = MarkdownConverter(base_level=base_level, callouts=callouts)
|
|
49
|
+
return converter.block(ast)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@Registry.add
|
|
53
|
+
def IncludeMarkdown(
|
|
54
|
+
path: str | PathLike[str],
|
|
55
|
+
*,
|
|
56
|
+
base_level: int = 0,
|
|
57
|
+
callouts: bool = True,
|
|
58
|
+
encoding: str = "utf-8",
|
|
59
|
+
) -> TeX:
|
|
60
|
+
"""Read a Markdown file and convert it (see :func:`Markdown`)."""
|
|
61
|
+
content = Path(path).read_text(encoding=encoding)
|
|
62
|
+
return Markdown(content, base_level=base_level, callouts=callouts)
|