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,307 @@
|
|
|
1
|
+
from collections.abc import Iterator
|
|
2
|
+
from dataclasses import dataclass, field
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Final, override
|
|
5
|
+
|
|
6
|
+
from pytex.commands.colors import Definecolor
|
|
7
|
+
from pytex.commands.fontspec import Setmainfont, Setsansfont
|
|
8
|
+
from pytex.commands.geometry import Geometry
|
|
9
|
+
from pytex.helpers.coerce import coerce_tex
|
|
10
|
+
from pytex.interface.package import PackageProtocol
|
|
11
|
+
from pytex.interface.tex import TeX
|
|
12
|
+
from pytex.model.color import Color, collect_colors
|
|
13
|
+
from pytex.model.concat import Concat
|
|
14
|
+
from pytex.model.document_class import DocumentClass
|
|
15
|
+
from pytex.model.empty import Empty
|
|
16
|
+
from pytex.model.environment import Environment
|
|
17
|
+
from pytex.model.raw import Raw
|
|
18
|
+
from pytex.packages import (
|
|
19
|
+
ARRAY,
|
|
20
|
+
BABEL,
|
|
21
|
+
BIBLATEX,
|
|
22
|
+
CLEVEREF,
|
|
23
|
+
CSQUOTES,
|
|
24
|
+
ETOOLBOX,
|
|
25
|
+
FONTAWESOME,
|
|
26
|
+
GEOMETRY,
|
|
27
|
+
GLOSSARIES,
|
|
28
|
+
GRAPHICX,
|
|
29
|
+
HYPERREF,
|
|
30
|
+
LISTINGS,
|
|
31
|
+
LMODERN,
|
|
32
|
+
LONGTABLE,
|
|
33
|
+
MDFRAMED,
|
|
34
|
+
NEEDSPACE,
|
|
35
|
+
PGF,
|
|
36
|
+
PGFFOR,
|
|
37
|
+
RAGGED2E,
|
|
38
|
+
SCRLAYER_SCRPAGE,
|
|
39
|
+
SETSPACE,
|
|
40
|
+
TIKZ,
|
|
41
|
+
XCOLOR,
|
|
42
|
+
)
|
|
43
|
+
from pytex.registry import Registry
|
|
44
|
+
from pytex_koma.document import KomaDocument
|
|
45
|
+
|
|
46
|
+
from .cleveref_names import GermanCrefNames
|
|
47
|
+
from .colors import HSRTColors
|
|
48
|
+
from .fonts import HSRTFontSetup
|
|
49
|
+
from .glossary import AcrShortcut, HSRTGlossarySetup
|
|
50
|
+
from .hyperref_config import (
|
|
51
|
+
HSRT_CITE_COLOR,
|
|
52
|
+
HSRT_LINK_COLOR,
|
|
53
|
+
HSRT_URL_COLOR,
|
|
54
|
+
HSRTHyperref,
|
|
55
|
+
)
|
|
56
|
+
from .listings import HSRTListingStyles
|
|
57
|
+
from .logos import DefaultLogos, footer_logo_hook
|
|
58
|
+
from .pagesetup import HSRTPageSetup
|
|
59
|
+
from .titlepage import TitlePage, TitlePageDataLine
|
|
60
|
+
from .variants import Variant, default_logo_names
|
|
61
|
+
|
|
62
|
+
__all__ = ["HSRTReport"]
|
|
63
|
+
|
|
64
|
+
BASE_PACKAGES: Final[frozenset[PackageProtocol]] = frozenset(
|
|
65
|
+
{
|
|
66
|
+
LMODERN,
|
|
67
|
+
GEOMETRY,
|
|
68
|
+
GRAPHICX,
|
|
69
|
+
XCOLOR,
|
|
70
|
+
TIKZ,
|
|
71
|
+
PGF,
|
|
72
|
+
PGFFOR,
|
|
73
|
+
LISTINGS,
|
|
74
|
+
HYPERREF,
|
|
75
|
+
CLEVEREF,
|
|
76
|
+
BIBLATEX,
|
|
77
|
+
CSQUOTES,
|
|
78
|
+
GLOSSARIES,
|
|
79
|
+
MDFRAMED,
|
|
80
|
+
FONTAWESOME,
|
|
81
|
+
SCRLAYER_SCRPAGE,
|
|
82
|
+
ETOOLBOX,
|
|
83
|
+
SETSPACE,
|
|
84
|
+
RAGGED2E,
|
|
85
|
+
ARRAY,
|
|
86
|
+
LONGTABLE,
|
|
87
|
+
NEEDSPACE,
|
|
88
|
+
BABEL,
|
|
89
|
+
}
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
DEFAULT_GEOMETRY: Final[dict[str, str]] = {
|
|
93
|
+
"a4paper": "",
|
|
94
|
+
"top": "2cm",
|
|
95
|
+
"bottom": "2cm",
|
|
96
|
+
"left": "2cm",
|
|
97
|
+
"right": "2cm",
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
# Back-matter print commands. \printglossary/\printbibliography emit their own
|
|
101
|
+
# \chapter* heading (and page break), so no manual \clearpage precedes them.
|
|
102
|
+
BACKMATTER_HEADER = r"\newpage\appendix\backmatter\HSRTBackMattertrue"
|
|
103
|
+
GLOSSARY_PRINT = r"\renewcommand*{\entryname}{Wort}\printglossary"
|
|
104
|
+
ACRONYM_PRINT = r"\renewcommand*{\entryname}{Abkürzung}\printglossary[type=\acronymtype,title=Abkürzungen]" # noqa: E501
|
|
105
|
+
BIBLIOGRAPHY_PRINT = r"\clearpage\chapter*{Literaturverzeichnis}\label{chap:bibliography}\printbibliography[heading=none,title={}]" # noqa: E501
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _emit(dest: Path, data: bytes) -> str:
|
|
109
|
+
"""Write `data` to `dest` (creating parent dirs) and return its posix path."""
|
|
110
|
+
dest.parent.mkdir(parents=True, exist_ok=True)
|
|
111
|
+
dest.write_bytes(data)
|
|
112
|
+
return dest.as_posix()
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
@Registry.add
|
|
116
|
+
@dataclass
|
|
117
|
+
class HSRTReport(KomaDocument):
|
|
118
|
+
"""HSRT report: scrbook + KomaDocument + auto preamble + colour-collector."""
|
|
119
|
+
|
|
120
|
+
document_class: str = "scrbook"
|
|
121
|
+
|
|
122
|
+
variant: Variant = Variant.INF
|
|
123
|
+
show_toc: bool = True
|
|
124
|
+
show_titlepage: bool = True
|
|
125
|
+
show_glossary: bool = False
|
|
126
|
+
show_acronyms: bool = False
|
|
127
|
+
show_bibliography: bool = False
|
|
128
|
+
show_footer_logos: bool = False
|
|
129
|
+
|
|
130
|
+
title: TeX | str | None = None
|
|
131
|
+
author: TeX | str | None = None
|
|
132
|
+
abstract: TeX | str | None = None
|
|
133
|
+
keywords: TeX | str | None = None
|
|
134
|
+
data_lines: tuple[TitlePageDataLine, ...] = ()
|
|
135
|
+
|
|
136
|
+
inline_logos: bool = True
|
|
137
|
+
inline_fonts: bool = True
|
|
138
|
+
main_font: str | None = None
|
|
139
|
+
sans_font: str | None = None
|
|
140
|
+
geometry_options: dict[str, str] = field(
|
|
141
|
+
default_factory=lambda: dict(DEFAULT_GEOMETRY)
|
|
142
|
+
)
|
|
143
|
+
user_preamble: TeX | str = Empty
|
|
144
|
+
|
|
145
|
+
def __post_init__(self) -> None:
|
|
146
|
+
super().__post_init__()
|
|
147
|
+
if self.document_class != "scrbook":
|
|
148
|
+
raise ValueError(
|
|
149
|
+
"HSRTReport requires document_class='scrbook', "
|
|
150
|
+
+ f"got {self.document_class!r}"
|
|
151
|
+
)
|
|
152
|
+
self.extra_packages: frozenset[PackageProtocol] = (
|
|
153
|
+
frozenset(self.extra_packages) | BASE_PACKAGES
|
|
154
|
+
)
|
|
155
|
+
self.preamble: TeX | str = self._build_preamble()
|
|
156
|
+
|
|
157
|
+
def discovered_colors(self) -> tuple[Color, ...]:
|
|
158
|
+
"""Walk body + preamble, return every `Color` instance needing `\\definecolor`.
|
|
159
|
+
|
|
160
|
+
Also includes HSRT hyperref colours (stored as Python data inside the
|
|
161
|
+
hypersetup options dict, so unreachable via the tree walk).
|
|
162
|
+
"""
|
|
163
|
+
seen: dict[str, Color] = {}
|
|
164
|
+
for c in (HSRT_CITE_COLOR, HSRT_LINK_COLOR, HSRT_URL_COLOR):
|
|
165
|
+
seen.setdefault(c.name, c)
|
|
166
|
+
for root in (self.body, self.user_preamble):
|
|
167
|
+
for color in collect_colors(coerce_tex(root)):
|
|
168
|
+
seen.setdefault(color.name, color)
|
|
169
|
+
return tuple(seen.values())
|
|
170
|
+
|
|
171
|
+
def _color_definitions(self) -> TeX:
|
|
172
|
+
return Concat(
|
|
173
|
+
*(
|
|
174
|
+
Definecolor(c.name, c.spec.model, c.spec.value)
|
|
175
|
+
for c in self.discovered_colors()
|
|
176
|
+
if c.spec is not None
|
|
177
|
+
)
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
def _build_preamble(self) -> TeX:
|
|
181
|
+
return Concat(*self._preamble_parts())
|
|
182
|
+
|
|
183
|
+
def _preamble_parts(self) -> Iterator[TeX | str]:
|
|
184
|
+
yield Raw(r"\KOMAoptions{open=any,twoside=false}")
|
|
185
|
+
yield Geometry(self.geometry_options)
|
|
186
|
+
yield HSRTColors()
|
|
187
|
+
yield self._color_definitions()
|
|
188
|
+
yield HSRTHyperref()
|
|
189
|
+
yield GermanCrefNames()
|
|
190
|
+
if self.show_glossary or self.show_acronyms:
|
|
191
|
+
yield HSRTGlossarySetup()
|
|
192
|
+
yield HSRTListingStyles()
|
|
193
|
+
yield AcrShortcut()
|
|
194
|
+
# Page setup first — provides \providecommand{\blenderfont} fallback
|
|
195
|
+
# that HSRTFontSetup's \renewcommand{\blenderfont} requires.
|
|
196
|
+
yield HSRTPageSetup()
|
|
197
|
+
# The skyline is drawn on every page; footer logos only when requested.
|
|
198
|
+
logo_names = default_logo_names(self.variant) if self.show_footer_logos else ()
|
|
199
|
+
yield Raw(footer_logo_hook(logo_names), allow_replacements=False)
|
|
200
|
+
if self.inline_fonts:
|
|
201
|
+
yield HSRTFontSetup()
|
|
202
|
+
if self.main_font is not None:
|
|
203
|
+
yield Setmainfont(self.main_font)
|
|
204
|
+
if self.sans_font is not None:
|
|
205
|
+
yield Setsansfont(self.sans_font)
|
|
206
|
+
# \title / \author for running headers
|
|
207
|
+
if self.title is not None:
|
|
208
|
+
yield Raw(f"\\title{{{coerce_tex(self.title).rendered}}}")
|
|
209
|
+
if self.author is not None:
|
|
210
|
+
yield Raw(f"\\author{{{coerce_tex(self.author).rendered}}}")
|
|
211
|
+
if self.user_preamble is not Empty:
|
|
212
|
+
yield self.user_preamble
|
|
213
|
+
|
|
214
|
+
def _build_full_body(self) -> TeX:
|
|
215
|
+
"""Wrap user body with front/main/back matter, ToC, glossary, bibliography."""
|
|
216
|
+
return Concat(*self._body_parts())
|
|
217
|
+
|
|
218
|
+
def _body_parts(self) -> Iterator[TeX | str]:
|
|
219
|
+
# -- Front matter --
|
|
220
|
+
yield Raw(r"\frontmatter")
|
|
221
|
+
if self.show_titlepage and self.title is not None:
|
|
222
|
+
yield TitlePage(
|
|
223
|
+
title=self.title,
|
|
224
|
+
abstract=self.abstract or "",
|
|
225
|
+
keywords=self.keywords or "",
|
|
226
|
+
data_lines=self.data_lines,
|
|
227
|
+
logo_names=default_logo_names(self.variant),
|
|
228
|
+
)
|
|
229
|
+
if self.show_toc:
|
|
230
|
+
yield Raw(r"\newpage\tableofcontents")
|
|
231
|
+
|
|
232
|
+
# -- Main matter --
|
|
233
|
+
yield Raw(r"\mainmatter")
|
|
234
|
+
yield coerce_tex(self.body)
|
|
235
|
+
|
|
236
|
+
# -- Back matter --
|
|
237
|
+
# The header is only emitted when there is actual back-matter content:
|
|
238
|
+
# \backmatter calls hyperref's \bookmarksetup which fires \@ in vertical
|
|
239
|
+
# mode and crashes, so skip it entirely when there is nothing to show.
|
|
240
|
+
if self.show_glossary or self.show_acronyms or self.show_bibliography:
|
|
241
|
+
yield Raw(BACKMATTER_HEADER)
|
|
242
|
+
if self.show_glossary:
|
|
243
|
+
yield Raw(GLOSSARY_PRINT)
|
|
244
|
+
if self.show_acronyms:
|
|
245
|
+
yield Raw(ACRONYM_PRINT)
|
|
246
|
+
if self.show_bibliography:
|
|
247
|
+
yield Raw(BIBLIOGRAPHY_PRINT)
|
|
248
|
+
|
|
249
|
+
def write_inline_fonts(self, target_dir: str = ".") -> tuple[str, ...]:
|
|
250
|
+
"""Write bundled font TTF files to ``<target_dir>/fonts/`` for compilation.
|
|
251
|
+
|
|
252
|
+
Call this before the TeX run so fontspec can resolve the font paths
|
|
253
|
+
embedded in the preamble by `HSRTFontSetup`.
|
|
254
|
+
"""
|
|
255
|
+
if not self.inline_fonts:
|
|
256
|
+
return ()
|
|
257
|
+
from .fonts import FONT_OUTPUT_DIR, all_font_paths, rel
|
|
258
|
+
|
|
259
|
+
base = Path(target_dir)
|
|
260
|
+
return tuple(
|
|
261
|
+
_emit(base / FONT_OUTPUT_DIR / rel(font_path), font_path.read_bytes())
|
|
262
|
+
for font_path in all_font_paths()
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
def write_inline_logos(self, target_dir: str = ".") -> tuple[str, ...]:
|
|
266
|
+
"""Write the logos used by the tikz overlays to ``<target_dir>/logos/``.
|
|
267
|
+
|
|
268
|
+
The titlepage overlay and footer hook reference logos by relative path
|
|
269
|
+
(``logos/<file>``); this materialises those files next to the .tex so
|
|
270
|
+
tectonic can read them without tripping its absolute-path restrictions.
|
|
271
|
+
SVG sources are converted to PDF via `IncludeImage`.
|
|
272
|
+
"""
|
|
273
|
+
from pytex.model.image import IncludeImage
|
|
274
|
+
|
|
275
|
+
from .logos import LOGO_OUTPUT_DIR, logo_output_name, logo_path
|
|
276
|
+
|
|
277
|
+
# Titlepage overlay + footer hook use the variant defaults; the footer
|
|
278
|
+
# skyline is emitted on every page regardless of show_footer_logos.
|
|
279
|
+
names = sorted(set(default_logo_names(self.variant)) | {"Skyline"})
|
|
280
|
+
base = Path(target_dir)
|
|
281
|
+
return tuple(
|
|
282
|
+
# IncludeImage.read_bytes converts svg -> pdf on the fly.
|
|
283
|
+
_emit(
|
|
284
|
+
base / LOGO_OUTPUT_DIR / logo_output_name(name),
|
|
285
|
+
IncludeImage(path=logo_path(name), inline_base64=False).read_bytes(),
|
|
286
|
+
)
|
|
287
|
+
for name in names
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
def default_logos(self) -> TeX:
|
|
291
|
+
return DefaultLogos(self.variant, inline_base64=self.inline_logos)
|
|
292
|
+
|
|
293
|
+
@property
|
|
294
|
+
@override
|
|
295
|
+
def rendered(self) -> str:
|
|
296
|
+
return Concat(
|
|
297
|
+
DocumentClass(self.document_class, self.document_class_options),
|
|
298
|
+
# hyperfootnotes is only honoured as a hyperref load option, so it
|
|
299
|
+
# must be queued before \usepackage{hyperref}. The HSRT footnote
|
|
300
|
+
# setup never places hyperref's Hfootnote destination, so leaving
|
|
301
|
+
# footnote-mark links enabled produces dangling links.
|
|
302
|
+
Raw(r"\PassOptionsToPackage{hyperfootnotes=false}{hyperref}"),
|
|
303
|
+
*self.ordered_packages(),
|
|
304
|
+
self.inline_image_block,
|
|
305
|
+
self.preamble,
|
|
306
|
+
Environment("document", self._build_full_body()),
|
|
307
|
+
).rendered
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
from importlib.resources import files
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Final
|
|
4
|
+
|
|
5
|
+
from pytex.commands.fontspec import Newfontfamily, Setmainfont, Setsansfont
|
|
6
|
+
from pytex.interface.tex import TeX
|
|
7
|
+
from pytex.model.concat import Concat
|
|
8
|
+
from pytex.model.raw import Raw
|
|
9
|
+
from pytex.registry import Registry
|
|
10
|
+
|
|
11
|
+
FONT_DIR: Final[Path] = Path(str(files("pytex_hsrtreport").joinpath("assets/fonts")))
|
|
12
|
+
|
|
13
|
+
# Output dir for the bundled TTFs, relative to the .tex file. `HSRTReport`'s
|
|
14
|
+
# `write_inline_fonts` copies the real font files here; fontspec's Path= option
|
|
15
|
+
# (see `_font_opts`) loads them from <this>/<subfamily>/.
|
|
16
|
+
FONT_OUTPUT_DIR: Final[str] = "fonts"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def all_font_paths() -> tuple[Path, ...]:
|
|
20
|
+
"""Return all bundled TTF paths, sorted for reproducible output."""
|
|
21
|
+
return tuple(sorted(FONT_DIR.rglob("*.ttf")))
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def rel(font_path: Path) -> str:
|
|
25
|
+
"""Path of a font file relative to `FONT_DIR`."""
|
|
26
|
+
return font_path.relative_to(FONT_DIR).as_posix()
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _font_opts(subfamily: str, upright: str, italic: str) -> dict[str, str]:
|
|
30
|
+
return {
|
|
31
|
+
"Path": f"{FONT_OUTPUT_DIR}/{subfamily}/",
|
|
32
|
+
"Extension": ".ttf",
|
|
33
|
+
"UprightFont": upright,
|
|
34
|
+
"BoldFont": "*-Bold",
|
|
35
|
+
"ItalicFont": italic,
|
|
36
|
+
"BoldItalicFont": "*-BoldItalic",
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@Registry.add
|
|
41
|
+
def HSRTFontSetup() -> TeX:
|
|
42
|
+
"""fontspec setup for bundled DIN (main) and Blender (sans) fonts.
|
|
43
|
+
|
|
44
|
+
Mirrors ``Config/Fonts.tex`` from the original template. The font files
|
|
45
|
+
are expected at ``fonts/DIN/`` and ``fonts/Blender/`` relative to the
|
|
46
|
+
output ``.tex`` file, which is where ``HSRTReport.write_inline_fonts``
|
|
47
|
+
copies the bundled TTFs before the TeX run.
|
|
48
|
+
"""
|
|
49
|
+
blender_opts = _font_opts("Blender", "*-Medium", "*-MediumItalic")
|
|
50
|
+
din_opts = _font_opts("DIN", "*-Regular", "*-Italic")
|
|
51
|
+
return Concat(
|
|
52
|
+
Newfontfamily("\\BlenderFont", "Blender", options=blender_opts),
|
|
53
|
+
Newfontfamily("\\DINFont", "DIN", options=din_opts),
|
|
54
|
+
Raw(r"\renewcommand{\blenderfont}{\BlenderFont}"),
|
|
55
|
+
Raw(r"\renewcommand{\dinfont}{\DINFont}"),
|
|
56
|
+
Setsansfont("Blender", options=blender_opts),
|
|
57
|
+
Setmainfont("DIN", options=din_opts),
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
__all__ = [
|
|
62
|
+
"FONT_OUTPUT_DIR",
|
|
63
|
+
"HSRTFontSetup",
|
|
64
|
+
"all_font_paths",
|
|
65
|
+
"rel",
|
|
66
|
+
]
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
from pytex.commands.glossaries import (
|
|
2
|
+
Glsenablehyper,
|
|
3
|
+
Makeglossaries,
|
|
4
|
+
Setglossarystyle,
|
|
5
|
+
)
|
|
6
|
+
from pytex.interface.tex import TeX
|
|
7
|
+
from pytex.model.concat import Concat
|
|
8
|
+
from pytex.model.raw import Raw
|
|
9
|
+
from pytex.registry import Registry
|
|
10
|
+
|
|
11
|
+
__all__ = ["AcrShortcut", "HSRTGlossarySetup"]
|
|
12
|
+
|
|
13
|
+
# Custom L/C/R column types used by the manualfixedwidth glossary style. Each
|
|
14
|
+
# fixes a horizontal alignment while still allowing manual \newline breaks.
|
|
15
|
+
COLUMN_TYPES = (
|
|
16
|
+
r"\newcolumntype{L}[1]{>{\raggedright\let\newline\\\arraybackslash\hspace{0pt}}p{#1}}"
|
|
17
|
+
+ r"\newcolumntype{C}[1]{>{\centering\let\newline\\\arraybackslash\hspace{0pt}}p{#1}}"
|
|
18
|
+
+ r"\newcolumntype{R}[1]{>{\raggedleft\let\newline\\\arraybackslash\hspace{0pt}}p{#1}}"
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
# A three-column glossary style with fixed widths (30%/58%/10% of \textwidth).
|
|
22
|
+
GLOSSARY_STYLE = (
|
|
23
|
+
r"\newglossarystyle{manualfixedwidth}{"
|
|
24
|
+
+ r"\setglossarystyle{long3colheader}"
|
|
25
|
+
+ r"\renewenvironment{theglossary}{\begin{longtable}{@{}"
|
|
26
|
+
+ r"L{\dimexpr0.30\textwidth-\tabcolsep\relax}"
|
|
27
|
+
+ r" p{\dimexpr0.58\textwidth-\tabcolsep\relax}"
|
|
28
|
+
+ r" L{\dimexpr0.10\textwidth-\tabcolsep\relax}@{}}}{\end{longtable}}"
|
|
29
|
+
+ r"\renewcommand*{\glsgroupskip}{}"
|
|
30
|
+
+ r"\renewcommand{\arraystretch}{1.1}}"
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
# German column/section labels for the glossary and acronym lists.
|
|
34
|
+
GLOSSARY_LABELS = (
|
|
35
|
+
r"\renewcommand*{\entryname}{Wort/Abkürzung}"
|
|
36
|
+
+ r"\renewcommand*{\descriptionname}{Bedeutung}"
|
|
37
|
+
+ r"\renewcommand*{\pagelistname}{Seite(n)}"
|
|
38
|
+
+ r"\renewcommand{\acronymname}{Abkürzungsverzeichnis}"
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@Registry.add
|
|
43
|
+
def HSRTGlossarySetup() -> TeX:
|
|
44
|
+
"""Standard HSRT glossary setup.
|
|
45
|
+
|
|
46
|
+
makeglossaries, manualfixedwidth style, German labels.
|
|
47
|
+
"""
|
|
48
|
+
return Concat(
|
|
49
|
+
Makeglossaries(),
|
|
50
|
+
Raw(COLUMN_TYPES),
|
|
51
|
+
Raw(GLOSSARY_STYLE),
|
|
52
|
+
Setglossarystyle("manualfixedwidth"),
|
|
53
|
+
Glsenablehyper(),
|
|
54
|
+
Raw(GLOSSARY_LABELS),
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@Registry.add
|
|
59
|
+
def AcrShortcut() -> TeX:
|
|
60
|
+
"""Shortcut: `\\acr` aliases `\\acrshort`."""
|
|
61
|
+
return Raw(r"\newcommand{\acr}{\acrshort}")
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
from typing import Final
|
|
2
|
+
|
|
3
|
+
from pytex.interface.tex import TeX
|
|
4
|
+
from pytex.model.color import Color
|
|
5
|
+
from pytex.model.control_sequence import ControlSequence, Parameter
|
|
6
|
+
from pytex.model.raw import Raw
|
|
7
|
+
from pytex.registry import Registry
|
|
8
|
+
|
|
9
|
+
__all__ = ["HSRTHyperref"]
|
|
10
|
+
|
|
11
|
+
type HyperOption = bool | int | str | TeX
|
|
12
|
+
|
|
13
|
+
HSRT_CITE_COLOR: Final[Color] = Color.rgb(0.286, 0.427, 0.537, name="hsrtcite")
|
|
14
|
+
HSRT_LINK_COLOR: Final[Color] = Color.rgb(0.161, 0.310, 0.427, name="hsrtlink")
|
|
15
|
+
HSRT_URL_COLOR: Final[Color] = Color.rgb(0.071, 0.212, 0.322, name="hsrturl")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
HSRT_HYPER_OPTIONS: Final[dict[str, HyperOption]] = {
|
|
19
|
+
"pdfpagemode": "UseOutlines",
|
|
20
|
+
"bookmarksopen": True,
|
|
21
|
+
"bookmarksopenlevel": 0,
|
|
22
|
+
# plainpages=false + hypertexnames=true gives roman frontmatter pages their
|
|
23
|
+
# own named anchors (page.i, ...) so glossary/index \hyperpage links to
|
|
24
|
+
# those pages resolve instead of dangling against absolute arabic anchors.
|
|
25
|
+
"plainpages": False,
|
|
26
|
+
"hypertexnames": True,
|
|
27
|
+
"colorlinks": True,
|
|
28
|
+
"citecolor": HSRT_CITE_COLOR,
|
|
29
|
+
"linkcolor": HSRT_LINK_COLOR,
|
|
30
|
+
"urlcolor": HSRT_URL_COLOR,
|
|
31
|
+
"pdfstartview": "FitV",
|
|
32
|
+
"unicode": True,
|
|
33
|
+
"breaklinks": True,
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _format(value: HyperOption) -> str:
|
|
38
|
+
if isinstance(value, bool):
|
|
39
|
+
return "true" if value else "false"
|
|
40
|
+
if isinstance(value, TeX):
|
|
41
|
+
return value.rendered
|
|
42
|
+
return str(value)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@Registry.add
|
|
46
|
+
def HSRTHyperref() -> TeX:
|
|
47
|
+
"""Hypersetup using `HSRT_HYPER_OPTIONS` (structured Python, not a TeX blob)."""
|
|
48
|
+
body = ",".join(f"{k}={_format(v)}" for k, v in HSRT_HYPER_OPTIONS.items())
|
|
49
|
+
return ControlSequence("hypersetup", (Parameter(Raw(body)),))
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
from typing import Final
|
|
2
|
+
|
|
3
|
+
from pytex.commands.colors import SelectColor
|
|
4
|
+
from pytex.commands.font import (
|
|
5
|
+
Bfseries,
|
|
6
|
+
Footnotesize,
|
|
7
|
+
Scriptsize,
|
|
8
|
+
Ttfamily,
|
|
9
|
+
)
|
|
10
|
+
from pytex.commands.listings import Lstdefinestyle, Lstset
|
|
11
|
+
from pytex.interface.tex import TeX
|
|
12
|
+
from pytex.model.concat import Concat
|
|
13
|
+
from pytex.registry import Registry
|
|
14
|
+
|
|
15
|
+
__all__ = ["HSRTListingStyles", "style_options"]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _font(*parts: TeX) -> TeX:
|
|
19
|
+
return Concat(*parts)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
HSRT_LISTING_BASE: Final[dict[str, TeX | str]] = {
|
|
23
|
+
"basicstyle": _font(Footnotesize(), Ttfamily()),
|
|
24
|
+
"breaklines": "true",
|
|
25
|
+
"numbers": "left",
|
|
26
|
+
"frame": "single",
|
|
27
|
+
"float": "H",
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
HSRT_LISTING_STYLES: Final[dict[str, dict[str, TeX | str]]] = {
|
|
32
|
+
"htmlCode": {
|
|
33
|
+
"language": "html",
|
|
34
|
+
"basicstyle": _font(Scriptsize(), Ttfamily()),
|
|
35
|
+
"keywordstyle": _font(SelectColor("blue"), Bfseries(), Ttfamily()),
|
|
36
|
+
"commentstyle": _font(SelectColor("gray"), Ttfamily()),
|
|
37
|
+
"escapechar": "|",
|
|
38
|
+
},
|
|
39
|
+
"phpCode": {
|
|
40
|
+
"language": "php",
|
|
41
|
+
"morekeywords": "{php}",
|
|
42
|
+
"basicstyle": _font(Footnotesize(), Ttfamily()),
|
|
43
|
+
"keywordstyle": _font(SelectColor("blue"), Bfseries(), Ttfamily()),
|
|
44
|
+
"commentstyle": _font(SelectColor("gray"), Ttfamily()),
|
|
45
|
+
"escapechar": "|",
|
|
46
|
+
},
|
|
47
|
+
"jsCode": {
|
|
48
|
+
"language": "javascript",
|
|
49
|
+
"basicstyle": _font(Scriptsize(), Ttfamily()),
|
|
50
|
+
"keywordstyle": _font(SelectColor("blue"), Bfseries(), Ttfamily()),
|
|
51
|
+
"commentstyle": _font(SelectColor("gray"), Ttfamily()),
|
|
52
|
+
"escapechar": "|",
|
|
53
|
+
},
|
|
54
|
+
"shellCodeNOPASSWD": {
|
|
55
|
+
"language": "sh",
|
|
56
|
+
"deletekeywords": "{for,kill,cat}",
|
|
57
|
+
"morekeywords": "{sudo}",
|
|
58
|
+
"basicstyle": _font(Scriptsize(), Ttfamily()),
|
|
59
|
+
"keywordstyle": _font(SelectColor("blue"), Bfseries(), Ttfamily()),
|
|
60
|
+
"commentstyle": _font(SelectColor("gray"), Ttfamily()),
|
|
61
|
+
"escapechar": "|",
|
|
62
|
+
"numbers": "none",
|
|
63
|
+
},
|
|
64
|
+
"shellCode": {
|
|
65
|
+
"language": "sh",
|
|
66
|
+
"morekeywords": "{sudo,chmod,chown,cp,su,rm,python}",
|
|
67
|
+
"basicstyle": _font(Scriptsize(), Ttfamily()),
|
|
68
|
+
"keywordstyle": _font(SelectColor("blue"), Bfseries(), Ttfamily()),
|
|
69
|
+
"commentstyle": _font(SelectColor("gray"), Ttfamily()),
|
|
70
|
+
"escapechar": "|",
|
|
71
|
+
},
|
|
72
|
+
"URL": {
|
|
73
|
+
"basicstyle": _font(Footnotesize(), Ttfamily()),
|
|
74
|
+
"commentstyle": _font(SelectColor("gray"), Ttfamily()),
|
|
75
|
+
"escapechar": "|",
|
|
76
|
+
"numbers": "none",
|
|
77
|
+
},
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@Registry.add
|
|
82
|
+
def HSRTListingStyles() -> TeX:
|
|
83
|
+
return Concat(
|
|
84
|
+
Lstset(HSRT_LISTING_BASE),
|
|
85
|
+
*(Lstdefinestyle(name, opts) for name, opts in HSRT_LISTING_STYLES.items()),
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def style_options(name: str) -> dict[str, TeX | str]:
|
|
90
|
+
return dict(HSRT_LISTING_STYLES[name])
|