texsmith 0.0.2.dev0__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.
Files changed (252) hide show
  1. texsmith/__init__.py +107 -0
  2. texsmith/_alias.py +59 -0
  3. texsmith/adapters/__init__.py +6 -0
  4. texsmith/adapters/docker.py +258 -0
  5. texsmith/adapters/handlers/__init__.py +3 -0
  6. texsmith/adapters/handlers/_assets.py +363 -0
  7. texsmith/adapters/handlers/_helpers.py +62 -0
  8. texsmith/adapters/handlers/_mermaid.py +122 -0
  9. texsmith/adapters/handlers/admonitions.py +267 -0
  10. texsmith/adapters/handlers/basic.py +228 -0
  11. texsmith/adapters/handlers/blocks.py +851 -0
  12. texsmith/adapters/handlers/code.py +309 -0
  13. texsmith/adapters/handlers/inline.py +937 -0
  14. texsmith/adapters/handlers/links.py +239 -0
  15. texsmith/adapters/handlers/media.py +380 -0
  16. texsmith/adapters/latex/__init__.py +10 -0
  17. texsmith/adapters/latex/engines/__init__.py +726 -0
  18. texsmith/adapters/latex/engines/latex/__init__.py +26 -0
  19. texsmith/adapters/latex/engines/latex/log.py +720 -0
  20. texsmith/adapters/latex/engines/latex/runner.py +28 -0
  21. texsmith/adapters/latex/engines/tectonic/__init__.py +38 -0
  22. texsmith/adapters/latex/formatter.py +297 -0
  23. texsmith/adapters/latex/latexmk.py +148 -0
  24. texsmith/adapters/latex/partials/acronym.tex +1 -0
  25. texsmith/adapters/latex/partials/add.tex +1 -0
  26. texsmith/adapters/latex/partials/addition.tex +1 -0
  27. texsmith/adapters/latex/partials/blockquote.tex +3 -0
  28. texsmith/adapters/latex/partials/callout.tex +3 -0
  29. texsmith/adapters/latex/partials/choices.tex +5 -0
  30. texsmith/adapters/latex/partials/citation.tex +1 -0
  31. texsmith/adapters/latex/partials/codeblock.tex +7 -0
  32. texsmith/adapters/latex/partials/codeblock_listings.tex +5 -0
  33. texsmith/adapters/latex/partials/codeblock_pygments.tex +5 -0
  34. texsmith/adapters/latex/partials/codeblock_verbatim.tex +12 -0
  35. texsmith/adapters/latex/partials/codeinline.tex +1 -0
  36. texsmith/adapters/latex/partials/codeinlinett.tex +1 -0
  37. texsmith/adapters/latex/partials/comment.tex +1 -0
  38. texsmith/adapters/latex/partials/del.tex +1 -0
  39. texsmith/adapters/latex/partials/deletion.tex +1 -0
  40. texsmith/adapters/latex/partials/description_list.tex +5 -0
  41. texsmith/adapters/latex/partials/enquote.tex +1 -0
  42. texsmith/adapters/latex/partials/epigraph.tex +1 -0
  43. texsmith/adapters/latex/partials/exercises_solutions.tex +7 -0
  44. texsmith/adapters/latex/partials/figure.tex +33 -0
  45. texsmith/adapters/latex/partials/figure_tcolorbox.tex +15 -0
  46. texsmith/adapters/latex/partials/footnote.tex +3 -0
  47. texsmith/adapters/latex/partials/glossary.tex +1 -0
  48. texsmith/adapters/latex/partials/heading.tex +14 -0
  49. texsmith/adapters/latex/partials/highlight.tex +25 -0
  50. texsmith/adapters/latex/partials/horizontal_rule.tex +1 -0
  51. texsmith/adapters/latex/partials/href.tex +1 -0
  52. texsmith/adapters/latex/partials/icon.tex +1 -0
  53. texsmith/adapters/latex/partials/include.tex +1 -0
  54. texsmith/adapters/latex/partials/index.tex +1 -0
  55. texsmith/adapters/latex/partials/italic.tex +1 -0
  56. texsmith/adapters/latex/partials/keystroke.tex +46 -0
  57. texsmith/adapters/latex/partials/label.tex +1 -0
  58. texsmith/adapters/latex/partials/list_acronyms.tex +5 -0
  59. texsmith/adapters/latex/partials/list_glossary.tex +8 -0
  60. texsmith/adapters/latex/partials/multicolumn.tex +3 -0
  61. texsmith/adapters/latex/partials/ordered_list.tex +5 -0
  62. texsmith/adapters/latex/partials/pagestyle.tex +1 -0
  63. texsmith/adapters/latex/partials/ref.tex +1 -0
  64. texsmith/adapters/latex/partials/regex.tex +1 -0
  65. texsmith/adapters/latex/partials/smallcaps.tex +1 -0
  66. texsmith/adapters/latex/partials/strikethrough.tex +1 -0
  67. texsmith/adapters/latex/partials/strong.tex +1 -0
  68. texsmith/adapters/latex/partials/subscript.tex +1 -0
  69. texsmith/adapters/latex/partials/substitution.tex +1 -0
  70. texsmith/adapters/latex/partials/superscript.tex +1 -0
  71. texsmith/adapters/latex/partials/tabbed.tex +3 -0
  72. texsmith/adapters/latex/partials/table.tex +48 -0
  73. texsmith/adapters/latex/partials/underline.tex +1 -0
  74. texsmith/adapters/latex/partials/unordered_list.tex +5 -0
  75. texsmith/adapters/latex/partials/url.tex +1 -0
  76. texsmith/adapters/latex/pygments.py +98 -0
  77. texsmith/adapters/latex/pyxindy.py +64 -0
  78. texsmith/adapters/latex/renderer.py +220 -0
  79. texsmith/adapters/latex/tectonic.py +366 -0
  80. texsmith/adapters/latex/utils.py +86 -0
  81. texsmith/adapters/markdown/__init__.py +342 -0
  82. texsmith/adapters/plugins/__init__.py +8 -0
  83. texsmith/adapters/plugins/material.py +174 -0
  84. texsmith/adapters/plugins/snippet.py +1734 -0
  85. texsmith/adapters/transformers/__init__.py +122 -0
  86. texsmith/adapters/transformers/base.py +140 -0
  87. texsmith/adapters/transformers/strategies.py +1456 -0
  88. texsmith/adapters/transformers/utils.py +59 -0
  89. texsmith/api/__init__.py +80 -0
  90. texsmith/api/_utils.py +56 -0
  91. texsmith/api/document.py +645 -0
  92. texsmith/api/pipeline.py +229 -0
  93. texsmith/api/service.py +648 -0
  94. texsmith/api/templates.py +287 -0
  95. texsmith/core/__init__.py +6 -0
  96. texsmith/core/bibliography/__init__.py +57 -0
  97. texsmith/core/bibliography/collection.py +354 -0
  98. texsmith/core/bibliography/doi.py +194 -0
  99. texsmith/core/bibliography/issues.py +15 -0
  100. texsmith/core/bibliography/parsing.py +45 -0
  101. texsmith/core/callouts.py +99 -0
  102. texsmith/core/config.py +191 -0
  103. texsmith/core/context.py +242 -0
  104. texsmith/core/conversion/__init__.py +103 -0
  105. texsmith/core/conversion/core.py +780 -0
  106. texsmith/core/conversion/debug.py +87 -0
  107. texsmith/core/conversion/inputs.py +474 -0
  108. texsmith/core/conversion/renderer.py +578 -0
  109. texsmith/core/conversion/templates.py +646 -0
  110. texsmith/core/conversion_contexts.py +95 -0
  111. texsmith/core/diagnostics.py +118 -0
  112. texsmith/core/exceptions.py +41 -0
  113. texsmith/core/fonts/__init__.py +3 -0
  114. texsmith/core/fragments/__init__.py +716 -0
  115. texsmith/core/fragments/base.py +117 -0
  116. texsmith/core/metadata.py +280 -0
  117. texsmith/core/mustache.py +86 -0
  118. texsmith/core/partials.py +20 -0
  119. texsmith/core/rules.py +394 -0
  120. texsmith/core/templates/__init__.py +58 -0
  121. texsmith/core/templates/base.py +343 -0
  122. texsmith/core/templates/builtins.py +68 -0
  123. texsmith/core/templates/context_usage.py +137 -0
  124. texsmith/core/templates/loader.py +303 -0
  125. texsmith/core/templates/manifest.py +861 -0
  126. texsmith/core/templates/runtime.py +347 -0
  127. texsmith/core/templates/text.py +14 -0
  128. texsmith/core/templates/wrapper.py +340 -0
  129. texsmith/core/user_dir.py +179 -0
  130. texsmith/devtools.py +28 -0
  131. texsmith/extensions/__init__.py +162 -0
  132. texsmith/extensions/index/__init__.py +21 -0
  133. texsmith/extensions/index/markdown.py +94 -0
  134. texsmith/extensions/index/mkdocs_plugin.py +136 -0
  135. texsmith/extensions/index/registry.py +57 -0
  136. texsmith/extensions/index/renderer.py +183 -0
  137. texsmith/extensions/index/templates/index.tex +1 -0
  138. texsmith/extensions/latex_raw.py +115 -0
  139. texsmith/extensions/latex_text.py +117 -0
  140. texsmith/extensions/mermaid.py +267 -0
  141. texsmith/extensions/missing_footnotes.py +125 -0
  142. texsmith/extensions/multi_citations.py +54 -0
  143. texsmith/extensions/progressbar/__init__.py +9 -0
  144. texsmith/extensions/progressbar/markdown.py +212 -0
  145. texsmith/extensions/progressbar/renderer.py +117 -0
  146. texsmith/extensions/smallcaps.py +48 -0
  147. texsmith/extensions/texlogos/__init__.py +10 -0
  148. texsmith/extensions/texlogos/markdown.py +236 -0
  149. texsmith/extensions/texlogos/renderer.py +81 -0
  150. texsmith/extensions/texlogos/specs.py +66 -0
  151. texsmith/fonts/__init__.py +57 -0
  152. texsmith/fonts/cache.py +46 -0
  153. texsmith/fonts/constants.py +60 -0
  154. texsmith/fonts/coverage.py +275 -0
  155. texsmith/fonts/downloader.py +103 -0
  156. texsmith/fonts/fallback.py +438 -0
  157. texsmith/fonts/html_scripts.py +168 -0
  158. texsmith/fonts/logging.py +127 -0
  159. texsmith/fonts/pipeline.py +338 -0
  160. texsmith/fonts/scripts.py +493 -0
  161. texsmith/fonts/ucharclasses.py +164 -0
  162. texsmith/fragments/__init__.py +11 -0
  163. texsmith/fragments/bibliography/__init__.py +65 -0
  164. texsmith/fragments/bibliography/fragment.toml +3 -0
  165. texsmith/fragments/bibliography/ts-bibliography-backmatter.jinja.tex +35 -0
  166. texsmith/fragments/bibliography/ts-bibliography.jinja.tex +10 -0
  167. texsmith/fragments/callouts/__init__.py +88 -0
  168. texsmith/fragments/callouts/fragment.toml +3 -0
  169. texsmith/fragments/callouts/ts-callouts.jinja.sty +129 -0
  170. texsmith/fragments/code/__init__.py +82 -0
  171. texsmith/fragments/code/fragment.toml +3 -0
  172. texsmith/fragments/code/ts-code.jinja.sty +140 -0
  173. texsmith/fragments/extra/__init__.py +180 -0
  174. texsmith/fragments/extra/fragment.toml +3 -0
  175. texsmith/fragments/extra/ts-extra.jinja.tex +13 -0
  176. texsmith/fragments/fonts/__init__.py +880 -0
  177. texsmith/fragments/fonts/fragment.toml +3 -0
  178. texsmith/fragments/fonts/ts-fonts.jinja.sty +292 -0
  179. texsmith/fragments/frame/__init__.py +170 -0
  180. texsmith/fragments/frame/fragment.toml +3 -0
  181. texsmith/fragments/frame/ts-frame.tex.jinja +49 -0
  182. texsmith/fragments/geometry/__init__.py +169 -0
  183. texsmith/fragments/geometry/fragment.toml +3 -0
  184. texsmith/fragments/geometry/paper.py +526 -0
  185. texsmith/fragments/geometry/ts_geometry.tex.jinja +53 -0
  186. texsmith/fragments/glossary/__init__.py +67 -0
  187. texsmith/fragments/glossary/fragment.toml +3 -0
  188. texsmith/fragments/glossary/ts-glossary-backmatter.jinja.tex +5 -0
  189. texsmith/fragments/glossary/ts-glossary.jinja.sty +28 -0
  190. texsmith/fragments/index/__init__.py +66 -0
  191. texsmith/fragments/index/fragment.toml +3 -0
  192. texsmith/fragments/index/ts-index-backmatter.jinja.tex +3 -0
  193. texsmith/fragments/index/ts-index.jinja.sty +12 -0
  194. texsmith/fragments/keystrokes/__init__.py +69 -0
  195. texsmith/fragments/keystrokes/fragment.toml +3 -0
  196. texsmith/fragments/keystrokes/ts-keystrokes.jinja.sty +20 -0
  197. texsmith/fragments/todolist/__init__.py +71 -0
  198. texsmith/fragments/todolist/fragment.toml +3 -0
  199. texsmith/fragments/todolist/ts-todolist.jinja.sty +21 -0
  200. texsmith/fragments/typesetting/__init__.py +214 -0
  201. texsmith/fragments/typesetting/fragment.toml +3 -0
  202. texsmith/fragments/typesetting/ts-typesetting.tex.jinja +81 -0
  203. texsmith/index.py +26 -0
  204. texsmith/plugins/__init__.py +14 -0
  205. texsmith/progressbar.py +8 -0
  206. texsmith/quotes.py +40 -0
  207. texsmith/smart_dashes.py +66 -0
  208. texsmith/templates/__init__.py +3 -0
  209. texsmith/templates/article/README.md +33 -0
  210. texsmith/templates/article/__init__.py +281 -0
  211. texsmith/templates/article/template/manifest.toml +125 -0
  212. texsmith/templates/article/template/mermaid-config.json +18 -0
  213. texsmith/templates/article/template/template.tex +74 -0
  214. texsmith/templates/book/README.md +26 -0
  215. texsmith/templates/book/__init__.py +75 -0
  216. texsmith/templates/book/overrides/codeblock.tex +7 -0
  217. texsmith/templates/book/overrides/codeinline.tex +1 -0
  218. texsmith/templates/book/template/fixtoc.sty +81 -0
  219. texsmith/templates/book/template/manifest.toml +198 -0
  220. texsmith/templates/book/template/template.tex +314 -0
  221. texsmith/templates/common/__init__.py +1 -0
  222. texsmith/templates/common/latexmkrc +46 -0
  223. texsmith/templates/letter/README.md +59 -0
  224. texsmith/templates/letter/__init__.py +495 -0
  225. texsmith/templates/letter/demo.md +31 -0
  226. texsmith/templates/letter/fonts/modernline bold.otf +0 -0
  227. texsmith/templates/letter/fonts/modernline.otf +0 -0
  228. texsmith/templates/letter/manifest.toml +197 -0
  229. texsmith/templates/letter/template/callouts.jinja.sty +290 -0
  230. texsmith/templates/letter/template/template.tex +123 -0
  231. texsmith/templates/snippet/README.md +21 -0
  232. texsmith/templates/snippet/__init__.py +80 -0
  233. texsmith/templates/snippet/template/manifest.toml +66 -0
  234. texsmith/templates/snippet/template/template.tex +47 -0
  235. texsmith/texlogos.py +15 -0
  236. texsmith/ui/__init__.py +6 -0
  237. texsmith/ui/cli/__init__.py +22 -0
  238. texsmith/ui/cli/_options.py +338 -0
  239. texsmith/ui/cli/app.py +65 -0
  240. texsmith/ui/cli/bibliography.py +300 -0
  241. texsmith/ui/cli/commands/__init__.py +14 -0
  242. texsmith/ui/cli/commands/render.py +1128 -0
  243. texsmith/ui/cli/commands/templates.py +397 -0
  244. texsmith/ui/cli/diagnostics.py +36 -0
  245. texsmith/ui/cli/presenter.py +663 -0
  246. texsmith/ui/cli/state.py +263 -0
  247. texsmith/ui/cli/utils.py +235 -0
  248. texsmith-0.0.2.dev0.dist-info/METADATA +187 -0
  249. texsmith-0.0.2.dev0.dist-info/RECORD +252 -0
  250. texsmith-0.0.2.dev0.dist-info/WHEEL +4 -0
  251. texsmith-0.0.2.dev0.dist-info/entry_points.txt +22 -0
  252. texsmith-0.0.2.dev0.dist-info/licenses/LICENSE.md +21 -0
@@ -0,0 +1,197 @@
1
+ [compat]
2
+ texsmith = ">=0.6,<1.0"
3
+
4
+ [latex.template]
5
+ name = "formal-letter"
6
+ version = "0.1.0"
7
+ entrypoint = "template/template.tex"
8
+ engine = "xelatex"
9
+ shell_escape = false
10
+ texlive_year = 2023
11
+ tlmgr_packages = [
12
+ "babel",
13
+ "fontspec",
14
+ "microtype",
15
+ "koma-script",
16
+ ]
17
+ description = """
18
+ Formal letter template based on KOMA-Script with configurable
19
+ sender/recipient and standards."""
20
+
21
+ fragments = [
22
+ "ts-fonts",
23
+ "ts-extra",
24
+ "ts-keystrokes",
25
+ "ts-callouts",
26
+ "ts-code",
27
+ "ts-glossary",
28
+ "ts-bibliography",
29
+ "ts-todolist",
30
+ ]
31
+
32
+ [latex.template.attributes.cursive]
33
+ default = false
34
+ type = "boolean"
35
+ sources = ["cursive"]
36
+ description = "Toggle cursive signature font."
37
+
38
+ [latex.template.attributes.language]
39
+ default = "en-UK"
40
+ type = "string"
41
+ allow_empty = false
42
+ sources = ["language"]
43
+ description = "Language for babel."
44
+
45
+ [latex.template.attributes.standard]
46
+ default = ""
47
+ type = "string"
48
+ sources = ["standard", "format"]
49
+ description = "Letter standard/format (e.g., sn, nf)."
50
+
51
+ [latex.template.attributes.date]
52
+ default = ""
53
+ type = "string"
54
+ escape = "latex"
55
+ allow_empty = true
56
+ sources = ["date"]
57
+
58
+ [latex.template.attributes.object]
59
+ default = ""
60
+ type = "string"
61
+ escape = "latex"
62
+ sources = ["object"]
63
+ description = "Subject line."
64
+
65
+ [latex.template.attributes.from_name]
66
+ default = ""
67
+ type = "string"
68
+ escape = "latex"
69
+ allow_empty = false
70
+ required = true
71
+ sources = ["from_name"]
72
+ description = "Sender full name."
73
+
74
+ [latex.template.attributes.from_address]
75
+ default = []
76
+ type = "list"
77
+ sources = ["from_address"]
78
+
79
+ [latex.template.attributes.back_address]
80
+ default = ""
81
+ type = "string"
82
+ escape = "latex"
83
+ sources = ["back_address"]
84
+
85
+ [latex.template.attributes.from_location]
86
+ default = ""
87
+ type = "string"
88
+ escape = "latex"
89
+ sources = ["from_location"]
90
+
91
+ [latex.template.attributes.to_name]
92
+ default = ""
93
+ type = "string"
94
+ escape = "latex"
95
+ allow_empty = false
96
+ required = true
97
+ sources = ["to_name"]
98
+ description = "Recipient full name."
99
+
100
+ [latex.template.attributes.to_address]
101
+ default = []
102
+ type = "list"
103
+ sources = ["to_address"]
104
+
105
+ [latex.template.attributes.closing]
106
+ default = ""
107
+ type = "string"
108
+ escape = "latex"
109
+ sources = ["closing"]
110
+ description = "Closing phrase."
111
+
112
+ [latex.template.attributes.opening]
113
+ default = ""
114
+ type = "string"
115
+ escape = "latex"
116
+ sources = ["opening"]
117
+ description = "Opening phrase."
118
+
119
+ [latex.template.attributes.signature]
120
+ default = ""
121
+ type = "any"
122
+ sources = ["signature"]
123
+ description = "Signature block (text or raw LaTeX)."
124
+
125
+ [latex.template.attributes.source_dir]
126
+ default = ""
127
+ type = "string"
128
+ allow_empty = true
129
+ sources = ["source_dir"]
130
+
131
+ [latex.template.attributes.output_dir]
132
+ default = ""
133
+ type = "string"
134
+ allow_empty = true
135
+ format = "raw"
136
+ sources = ["output_dir"]
137
+
138
+ [latex.template.attributes.signature_align]
139
+ default = "left"
140
+ type = "string"
141
+ sources = ["signature_align"]
142
+
143
+ [latex.template.attributes.reference]
144
+ default = ""
145
+ type = "string"
146
+ escape = "latex"
147
+ sources = ["reference"]
148
+ description = "Reference field content."
149
+
150
+ [latex.template.attributes.reference_fields]
151
+ default = false
152
+ type = "boolean"
153
+ sources = ["reference_fields"]
154
+ description = "Whether to render reference fields block."
155
+
156
+ [latex.template.attributes.postscript]
157
+ default = ""
158
+ type = "string"
159
+ escape = "latex"
160
+ sources = ["postscript"]
161
+ description = "Postscript paragraph."
162
+
163
+ [latex.template.attributes.fold_marks]
164
+ default = false
165
+ type = "boolean"
166
+ sources = ["fold_marks"]
167
+ description = "Toggle fold marks."
168
+
169
+ [latex.template.attributes.margin]
170
+ default = "default"
171
+ type = "string"
172
+ normaliser = "margin_style"
173
+ sources = ["margin"]
174
+ description = "Margin style (default, wide, narrow)."
175
+
176
+ [latex.template.attributes.preamble]
177
+ default = ""
178
+ type = "string"
179
+ allow_empty = true
180
+ sources = ["preamble"]
181
+
182
+ [latex.template.attributes.page_numbers]
183
+ default = false
184
+ type = "boolean"
185
+ sources = ["page_numbers"]
186
+ description = "Enable page numbers."
187
+
188
+ [latex.template.slots.mainmatter]
189
+ default = true
190
+ base_level = 10
191
+ strip_heading = true
192
+
193
+ [latex.template.slots.backmatter]
194
+ strip_heading = true
195
+
196
+ [latex.template.assets]
197
+ "fonts/modernline.otf" = { source = "fonts/modernline.otf" }
@@ -0,0 +1,290 @@
1
+ % callouts.sty — Callout boxes with tcolorbox + FontAwesome
2
+ \NeedsTeXFormat{LaTeX2e}
3
+ \ProvidesPackage{callouts}[2025/10/27 Callout boxes with tcolorbox + FontAwesome]
4
+
5
+ % --- Required packages ---
6
+ \RequirePackage{xcolor}
7
+ \RequirePackage{tcolorbox}
8
+ \tcbuselibrary{breakable,skins}
9
+ \RequirePackage{fontawesome5}
10
+
11
+ % --- Shared color palette ---
12
+ \definecolor{calloutNoteBg}{HTML}{ECF3FF}
13
+ \definecolor{calloutNoteFrame}{HTML}{448AFF}
14
+ \definecolor{calloutAbstractBg}{HTML}{E5F7FF}
15
+ \definecolor{calloutAbstractFrame}{HTML}{00B0FF}
16
+ \definecolor{calloutInfoBg}{HTML}{E5F8FB}
17
+ \definecolor{calloutInfoFrame}{HTML}{00B8D4}
18
+ \definecolor{calloutTipBg}{HTML}{E5F8F6}
19
+ \definecolor{calloutTipFrame}{HTML}{00BFA5}
20
+ \definecolor{calloutSuccessBg}{HTML}{E5F9ED}
21
+ \definecolor{calloutSuccessFrame}{HTML}{00C853}
22
+ \definecolor{calloutQuestionBg}{HTML}{EFFCE7}
23
+ \definecolor{calloutQuestionFrame}{HTML}{64DD17}
24
+ \definecolor{calloutWarningBg}{HTML}{FFF1D6}
25
+ \definecolor{calloutWarningFrame}{HTML}{FFB200}
26
+ \definecolor{calloutCautionBg}{HTML}{FFF8E1}
27
+ \definecolor{calloutCautionFrame}{HTML}{FF9100}
28
+ \definecolor{calloutFailureBg}{HTML}{FFEDED}
29
+ \definecolor{calloutFailureFrame}{HTML}{FF5252}
30
+ \definecolor{calloutDangerBg}{HTML}{FFE2E7}
31
+ \definecolor{calloutDangerFrame}{HTML}{C62828}
32
+ \definecolor{calloutImportantBg}{HTML}{FFE0F0}
33
+ \definecolor{calloutImportantFrame}{HTML}{D81B60}
34
+ \definecolor{calloutBugBg}{HTML}{FEE5EE}
35
+ \definecolor{calloutBugFrame}{HTML}{F50057}
36
+ \definecolor{calloutExampleBg}{HTML}{F2EDFF}
37
+ \definecolor{calloutExampleFrame}{HTML}{7C4DFF}
38
+ \definecolor{calloutQuoteBg}{HTML}{F5F5F5}
39
+ \definecolor{calloutQuoteFrame}{HTML}{9E9E9E}
40
+ \definecolor{calloutExerciseBg}{HTML}{F5F5F5}
41
+ \definecolor{calloutExerciseFrame}{HTML}{202020}
42
+ \definecolor{calloutDefaultBg}{HTML}{F0F0F0}
43
+ \definecolor{calloutDefaultFrame}{HTML}{808080}
44
+
45
+ \BLOCK{ set style = callout_style | default("fancy") }
46
+
47
+ \BLOCK{ if style == "classic" }
48
+ % --- Classic (black & white) style ---
49
+ \newfontfamily\texsmithCalloutIconFont{Noto Emoji}[Renderer=Harfbuzz]
50
+ \newcommand{\texsmithCalloutIcon}[1]{%
51
+ \ifdefined\texsmithCalloutIconFont
52
+ {\texsmithCalloutIconFont #1}%
53
+ \else
54
+ #1%
55
+ \fi
56
+ }
57
+ \tcbset{callout base/.style={
58
+ breakable,
59
+ enhanced,
60
+ title filled=false,
61
+ arc=0mm,
62
+ boxrule=0mm,
63
+ titlerule=0mm,
64
+ lefttitle=0mm,
65
+ leftupper=1mm,
66
+ left=2mm,
67
+ colback=white,
68
+ colbacktitle=white,
69
+ colframe=black!80,
70
+ coltitle=black!80,
71
+ parbox=false,
72
+ frame hidden,
73
+ borderline west={1mm}{0mm}{black!60},
74
+ }}
75
+ \tcbset{
76
+ callout note/.style={callout base,title={\makebox[1.6em][c]{\texsmithCalloutIcon{📝}}}},
77
+ callout abstract/.style={callout base,title={\makebox[1.6em][c]{\texsmithCalloutIcon{📄}}}},
78
+ callout summary/.style={callout base,title={\makebox[1.6em][c]{\texsmithCalloutIcon{📋}}}},
79
+ callout info/.style={callout base,title={\makebox[1.6em][c]{\texsmithCalloutIcon{ℹ}}}},
80
+ callout tip/.style={callout base,title={\makebox[1.6em][c]{\texsmithCalloutIcon{⭐}}}},
81
+ callout success/.style={callout base,title={\makebox[1.6em][c]{\texsmithCalloutIcon{✅}}}},
82
+ callout warning/.style={callout base,title={\makebox[1.6em][c]{\texsmithCalloutIcon{⚠}}}},
83
+ callout caution/.style={callout base,title={\makebox[1.6em][c]{\texsmithCalloutIcon{⚠}}}},
84
+ callout failure/.style={callout base,title={\makebox[1.6em][c]{\texsmithCalloutIcon{❗}}}},
85
+ callout important/.style={callout base,title={\makebox[1.6em][c]{\texsmithCalloutIcon{❗}}}},
86
+ callout hint/.style={callout base,title={\makebox[1.6em][c]{\texsmithCalloutIcon{💡}}}},
87
+ callout danger/.style={callout base,title={\makebox[1.6em][c]{\texsmithCalloutIcon{🔥}}}},
88
+ callout bug/.style={callout base,title={\makebox[1.6em][c]{\texsmithCalloutIcon{🐞}}}},
89
+ callout example/.style={callout base,title={\makebox[1.6em][c]{\texsmithCalloutIcon{🧪}}}},
90
+ callout quote/.style={callout base,title={\makebox[1.6em][c]{\texsmithCalloutIcon{❝}}}},
91
+ callout question/.style={callout base,title={\makebox[1.6em][c]{\texsmithCalloutIcon{❓}}}},
92
+ callout solution/.style={callout base,title={\makebox[1.6em][c]{\texsmithCalloutIcon{💬}}}},
93
+ callout default/.style={callout base,title={\makebox[1.6em][c]{\texsmithCalloutIcon{ℹ}}}},
94
+ }
95
+ \newcommand{\texsmithCalloutTitleFormat}[1]{~#1}
96
+ \newtcolorbox{callout}[2][]{%
97
+ callout base,
98
+ #1,
99
+ after title={\texsmithCalloutTitleFormat{#2}}%
100
+ }
101
+
102
+ \BLOCK{ elif style == "minimal" }
103
+ % --- Minimal (bordered, no icons) style ---
104
+ \tcbset{callout base/.style={
105
+ breakable,
106
+ enhanced,
107
+ title filled=false,
108
+ arc=0.7mm,
109
+ boxrule=0.3mm,
110
+ titlerule=0mm,
111
+ lefttitle=0mm,
112
+ leftupper=1mm,
113
+ colback=white,
114
+ colframe=black,
115
+ parbox=false,
116
+ }}
117
+ \tcbset{
118
+ callout note/.style={callout base},
119
+ callout abstract/.style={callout base},
120
+ callout summary/.style={callout base},
121
+ callout info/.style={callout base},
122
+ callout tip/.style={callout base},
123
+ callout success/.style={callout base},
124
+ callout warning/.style={callout base},
125
+ callout caution/.style={callout base},
126
+ callout failure/.style={callout base},
127
+ callout important/.style={callout base},
128
+ callout hint/.style={callout base},
129
+ callout danger/.style={callout base},
130
+ callout bug/.style={callout base},
131
+ callout example/.style={callout base},
132
+ callout quote/.style={callout base},
133
+ callout question/.style={callout base},
134
+ callout solution/.style={callout base},
135
+ callout default/.style={callout base},
136
+ }
137
+ \newtcolorbox{callout}[2][]{%
138
+ callout base,
139
+ before upper={\textbf{#2}\par\smallskip},
140
+ #1,
141
+ }
142
+
143
+ \BLOCK{ else }
144
+ % --- Fancy (colored) style ---
145
+ \newcommand{\texsmithCalloutTitleFormat}[1]{~#1}
146
+ \tcbset{callout base/.style={
147
+ breakable,
148
+ enhanced,
149
+ title filled,
150
+ arc=0mm,
151
+ boxrule=0mm,
152
+ titlerule=0mm,
153
+ lefttitle=1mm,
154
+ leftupper=1mm,
155
+ colback=white,
156
+ parbox=false,
157
+ frame hidden,
158
+ borderline west={0.3mm}{0mm}{black!70},
159
+ }}
160
+ \tcbset{
161
+ callout note/.style={
162
+ colbacktitle=calloutNoteBg,
163
+ colframe=calloutNoteFrame,
164
+ coltitle=calloutNoteFrame!80!black,
165
+ borderline west={0.3mm}{0mm}{calloutNoteFrame},
166
+ title={\makebox[1.3em][c]{\faBookmark}},
167
+ },
168
+ callout abstract/.style={
169
+ colbacktitle=calloutAbstractBg,
170
+ colframe=calloutAbstractFrame,
171
+ coltitle=calloutAbstractFrame!80!black,
172
+ borderline west={0.3mm}{0mm}{calloutAbstractFrame},
173
+ title={\makebox[1.3em][c]{\faLaptopCode}},
174
+ },
175
+ callout summary/.style={
176
+ colbacktitle=calloutAbstractBg,
177
+ colframe=calloutAbstractFrame,
178
+ coltitle=calloutAbstractFrame!80!black,
179
+ borderline west={0.3mm}{0mm}{calloutAbstractFrame},
180
+ title={\makebox[1.3em][c]{\faList}},
181
+ },
182
+ callout info/.style={
183
+ colbacktitle=calloutInfoBg,
184
+ colframe=calloutInfoFrame,
185
+ coltitle=calloutInfoFrame!80!black,
186
+ borderline west={0.3mm}{0mm}{calloutInfoFrame},
187
+ title={\makebox[1.3em][c]{\faComment}},
188
+ },
189
+ callout tip/.style={
190
+ colbacktitle=calloutTipBg,
191
+ colframe=calloutTipFrame,
192
+ coltitle=calloutTipFrame!80!black,
193
+ borderline west={0.3mm}{0mm}{calloutTipFrame},
194
+ title={\makebox[1.3em][c]{\faStar}},
195
+ },
196
+ callout success/.style={
197
+ colbacktitle=calloutSuccessBg,
198
+ colframe=calloutSuccessFrame,
199
+ coltitle=calloutSuccessFrame!80!black,
200
+ borderline west={0.3mm}{0mm}{calloutSuccessFrame},
201
+ title={\makebox[1.3em][c]{\faCheck}},
202
+ },
203
+ callout warning/.style={
204
+ colbacktitle=calloutWarningBg,
205
+ colframe=calloutWarningFrame,
206
+ coltitle=calloutWarningFrame!80!black,
207
+ borderline west={0.3mm}{0mm}{calloutWarningFrame},
208
+ title={\makebox[1.3em][c]{\faBolt}},
209
+ },
210
+ callout caution/.style={
211
+ colbacktitle=calloutCautionBg,
212
+ colframe=calloutCautionFrame,
213
+ coltitle=calloutCautionFrame!80!black,
214
+ borderline west={0.3mm}{0mm}{calloutCautionFrame},
215
+ title={\makebox[1.3em][c]{\faExclamationTriangle}},
216
+ },
217
+ callout failure/.style={
218
+ colbacktitle=calloutFailureBg,
219
+ colframe=calloutFailureFrame,
220
+ coltitle=calloutFailureFrame!80!black,
221
+ borderline west={0.3mm}{0mm}{calloutFailureFrame},
222
+ title={\makebox[1.3em][c]{\faExclamationTriangle}},
223
+ },
224
+ callout important/.style={
225
+ colbacktitle=calloutImportantBg,
226
+ colframe=calloutImportantFrame,
227
+ coltitle=calloutImportantFrame!80!black,
228
+ borderline west={0.3mm}{0mm}{calloutImportantFrame},
229
+ title={\makebox[1.3em][c]{\faExclamationTriangle}},
230
+ },
231
+ callout hint/.style={
232
+ colbacktitle=calloutTipBg,
233
+ colframe=calloutTipFrame,
234
+ coltitle=calloutTipFrame!80!black,
235
+ borderline west={0.3mm}{0mm}{calloutTipFrame},
236
+ title={\makebox[1.3em][c]{\faLightbulb}},
237
+ },
238
+ callout danger/.style={
239
+ colbacktitle=calloutDangerBg,
240
+ colframe=calloutDangerFrame,
241
+ coltitle=calloutDangerFrame!80!black,
242
+ borderline west={0.3mm}{0mm}{calloutDangerFrame},
243
+ title={\makebox[1.3em][c]{\faFire}},
244
+ },
245
+ callout bug/.style={
246
+ colbacktitle=calloutBugBg,
247
+ colframe=calloutBugFrame,
248
+ coltitle=calloutBugFrame!80!black,
249
+ borderline west={0.3mm}{0mm}{calloutBugFrame},
250
+ title={\makebox[1.3em][c]{\faBomb}},
251
+ },
252
+ callout example/.style={
253
+ colbacktitle=calloutExampleBg,
254
+ colframe=calloutExampleFrame,
255
+ coltitle=calloutExampleFrame!80!black,
256
+ borderline west={0.3mm}{0mm}{calloutExampleFrame},
257
+ title={\makebox[1.3em][c]{\faFlask}},
258
+ },
259
+ callout quote/.style={
260
+ colbacktitle=calloutQuoteBg,
261
+ colframe=calloutQuoteFrame,
262
+ coltitle=calloutQuoteFrame!80!black,
263
+ borderline west={0.3mm}{0mm}{calloutQuoteFrame},
264
+ title={\makebox[1.3em][c]{\faQuestionCircle}},
265
+ },
266
+ callout question/.style={
267
+ colbacktitle=calloutQuestionBg,
268
+ colframe=calloutQuestionFrame,
269
+ coltitle=calloutQuestionFrame!80!black,
270
+ borderline west={0.3mm}{0mm}{calloutQuestionFrame},
271
+ title={\makebox[1.3em][c]{\faQuestionCircle}},
272
+ },
273
+ callout solution/.style={
274
+ colbacktitle=gray!40!white,
275
+ title={\textcolor{black}{\makebox[1.3em][l]{\faComment}}},
276
+ },
277
+ callout default/.style={
278
+ colbacktitle=calloutDefaultBg,
279
+ colframe=calloutDefaultFrame,
280
+ coltitle=calloutDefaultFrame!80!black,
281
+ borderline west={0.3mm}{0mm}{calloutDefaultFrame},
282
+ title={\textcolor{black}{\makebox[1.3em][l]{\faComment}}},
283
+ },
284
+ }
285
+ \newtcolorbox{callout}[2][]{%
286
+ callout base,
287
+ #1,
288
+ after title={\texsmithCalloutTitleFormat{#2}}%
289
+ }
290
+ \BLOCK{ endif }
@@ -0,0 +1,123 @@
1
+ \documentclass[
2
+ paper=a4,
3
+ parskip=half,
4
+ firstfoot=false,
5
+ enlargefirstpage=true,
6
+ ]{scrlttr2}
7
+ \usepackage{xcolor}
8
+ \definecolor{texsmithLinkColor}{HTML}{0B3D91}
9
+ \VAR{extra_packages}
10
+ \usepackage{graphicx}
11
+ \usepackage[\VAR{babel_language|default('english')}]{babel}
12
+ \usepackage[
13
+ colorlinks=true,
14
+ linkcolor=texsmithLinkColor,
15
+ urlcolor=texsmithLinkColor,
16
+ citecolor=texsmithLinkColor]{hyperref}
17
+ \LoadLetterOption{\VAR{letter_standard_option}}
18
+ \KOMAoptions{foldmarks=\VAR{foldmarks_option}}
19
+ \BLOCK{ set margin_style = margin|default('default')|lower }
20
+ \BLOCK{ set margin_literal = margin_style not in ["narrow", "default", "wide"] }
21
+ \BLOCK{ if margin_style == "narrow" }
22
+ \KOMAoptions{fromalign=left, backaddress=false}
23
+ \setlength{\oddsidemargin}{1cm}
24
+ \BLOCK{ elif margin_style == "wide" }
25
+ \KOMAoptions{fromalign=left, backaddress=false}
26
+ \setlength{\oddsidemargin}{2cm}
27
+ \BLOCK{ elif margin_literal }
28
+ \KOMAoptions{fromalign=left, backaddress=false}
29
+ \setlength{\oddsidemargin}{0cm}
30
+ \addtolength{\textwidth}{-\VAR{margin}}
31
+ \BLOCK{ endif }
32
+ \BLOCK{ if use_cursive_signature }
33
+ \setmainfont[Path=fonts/,Extension=.otf,Ligatures=Common,Mapping=]{modernline}
34
+ \newcommand{\TexsmithLetterEndash}{\kern0.05em-\kern0.05em}
35
+ \newcommand{\TexsmithLetterEmdash}{\kern0.05em-\kern0.05em-\kern0.05em}
36
+ \catcode"2013=\active
37
+ \catcode"2014=\active
38
+ \begingroup\lccode`~="2013\lowercase{\endgroup\protected\def~}{\TexsmithLetterEndash}
39
+ \begingroup\lccode`~="2014\lowercase{\endgroup\protected\def~}{\TexsmithLetterEmdash}
40
+ \BLOCK{ endif }
41
+
42
+ \BLOCK{ if preamble }
43
+ % Custom document preamble injected from overrides.
44
+ \VAR{preamble}
45
+
46
+ \BLOCK{ endif }
47
+
48
+ \BLOCK{ if use_cursive_signature }
49
+ \newfontfamily\SignatureFont[Path=fonts/,Extension=.otf]{modernline}
50
+ \newcommand{\SignatureText}[1]{{\SignatureFont #1}}
51
+ \BLOCK{ else }
52
+ \newcommand{\SignatureText}[1]{#1}
53
+ \BLOCK{ endif }
54
+
55
+ \newcommand{\SignatureBlock}{%
56
+ \BLOCK{ if has_signature_image }
57
+ \includegraphics[height=1.6cm]{\VAR{signature_image_path}}
58
+ \\[-0.25\baselineskip]%
59
+ \BLOCK{ endif }
60
+ \SignatureText{\VAR{signature_text}}%
61
+ }
62
+
63
+ \setkomavar{fromname}{\VAR{from_name}}
64
+ \setkomavar{fromaddress}{%
65
+ \BLOCK{ if has_sender_address }
66
+ \VAR{from_address_lines|join('\\\\\n')}
67
+ \BLOCK{ endif }
68
+ }
69
+ \BLOCK{ if from_location_value -}
70
+ \setkomavar{location}{\VAR{from_location_value}}\BLOCK{ endif }
71
+ \BLOCK{ set effective_date = date_value|default('')|trim }
72
+ \setkomavar{date}{\BLOCK{ if effective_date -}
73
+ \VAR{date_value}\BLOCK{ else }\today\BLOCK{ endif }}
74
+ \BLOCK{ if has_subject }
75
+ \setkomavar{subject}{\VAR{object_value}}
76
+ \setkomavar*{subject}{\VAR{subject_prefix}}
77
+ \BLOCK{ endif }
78
+ \setkomavar{signature}{\SignatureBlock}
79
+ \BLOCK{ if has_back_address }
80
+ \setkomavar{backaddress}{%
81
+ \VAR{back_address_lines|join('\\\\\n')}
82
+ }
83
+ \BLOCK{ endif }
84
+ \BLOCK{ if reference_value }
85
+ \setkomavar{myref}{\VAR{reference_value}}
86
+ \BLOCK{ endif }
87
+ \BLOCK{ if not reference_fields_enabled }
88
+ \removereffields
89
+ \BLOCK{ endif }
90
+ \renewcommand*{\raggedsignature}{\VAR{signature_alignment_command}}
91
+
92
+ \begin{document}
93
+
94
+ \begin{letter}{%
95
+ \BLOCK{ if has_recipient_address }
96
+ \VAR{to_address_lines|join('\\\\\n ')}
97
+ \BLOCK{ else }
98
+ \VAR{to_name}
99
+ \BLOCK{ endif }
100
+ }
101
+
102
+ \opening{\VAR{opening_text}}
103
+
104
+ \VAR{mainmatter}
105
+
106
+ \VAR{backmatter}
107
+ \VAR{fragment_backmatter}
108
+
109
+ \BLOCK{ if has_closing }
110
+ \closing{\VAR{closing_text}}
111
+ \BLOCK{ endif }
112
+ \BLOCK{ if has_postscript }
113
+ \ps{PS: \VAR{postscript_text}}
114
+ \BLOCK{ endif }
115
+
116
+ \end{letter}
117
+ \BLOCK{ if not page_numbers }
118
+ \pagenumbering{gobble}
119
+ \thispagestyle{empty}
120
+ \pagestyle{empty}
121
+ \BLOCK{ endif }
122
+
123
+ \end{document}
@@ -0,0 +1,21 @@
1
+ # TeXSmith Snippet Template
2
+
3
+ The built-in `snippet` template renders Markdown fragments inside a decorated
4
+ `tikzpicture`, perfect for standalone notes, stickers, or screenshot-friendly
5
+ callouts. It reuses TeXSmith’s article preamble (fonts, callouts, keystrokes,
6
+ progress bars) so Markdown extensions behave the same way, but swaps the
7
+ document class for `standalone` and constrains the body to a configurable
8
+ minipage.
9
+
10
+ ```bash
11
+ texsmith snippet.md --template snippet \
12
+ --attribute width=11cm \
13
+ --attribute margin=7mm \
14
+ --attribute dogear=12mm \
15
+ --attribute dogear_enabled=false
16
+ ```
17
+
18
+ Override attributes via front matter or CLI `--attribute` flags to tweak the
19
+ inner width, padding, dog-ear size, or border visibility. Because the template
20
+ includes the shared callout definitions, admonitions look identical to the
21
+ `article` template inside the snippet frame.
@@ -0,0 +1,80 @@
1
+ """Snippet template integration for TeXSmith."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Mapping
6
+ from pathlib import Path
7
+ from typing import Any, ClassVar
8
+
9
+ from texsmith.core.templates import TemplateError, WrappableTemplate
10
+
11
+
12
+ _PACKAGE_ROOT = Path(__file__).parent.resolve()
13
+
14
+
15
+ class Template(WrappableTemplate):
16
+ """Expose the snippet template as a wrappable template instance."""
17
+
18
+ _CALLOUT_STYLES: ClassVar[set[str]] = {"fancy", "classic", "minimal"}
19
+ _EMOJI_MODES: ClassVar[set[str]] = {"artifact", "symbola", "color", "black", "twemoji"}
20
+
21
+ def __init__(self) -> None:
22
+ try:
23
+ super().__init__(_PACKAGE_ROOT)
24
+ except TemplateError as exc: # pragma: no cover - file system safeguard
25
+ raise TemplateError(f"Failed to initialise snippet template: {exc}") from exc
26
+
27
+ def prepare_context(
28
+ self,
29
+ latex_body: str,
30
+ *,
31
+ overrides: Mapping[str, Any] | None = None,
32
+ ) -> dict[str, Any]:
33
+ context = super().prepare_context(latex_body, overrides=overrides)
34
+ context["ts_extra_disable_hyperref"] = True
35
+
36
+ context["language"] = self._normalise_string(context.get("language"), "english")
37
+ context["width"] = self._normalise_dimension(context.get("width"), "12cm")
38
+ context["margin"] = self._normalise_dimension(context.get("margin"), "6mm")
39
+ context["dogear"] = self._normalise_dimension(context.get("dogear"), "10mm")
40
+ context["border"] = bool(context.get("border", True))
41
+ context["dogear_enabled"] = bool(context.get("dogear_enabled", True))
42
+ candidate_emoji = context.get("emoji")
43
+ if not candidate_emoji:
44
+ fonts_cfg = context.get("fonts")
45
+ if isinstance(fonts_cfg, Mapping):
46
+ candidate_emoji = fonts_cfg.get("emoji")
47
+ if not candidate_emoji:
48
+ press_cfg = context.get("press")
49
+ if isinstance(press_cfg, Mapping):
50
+ press_fonts = press_cfg.get("fonts")
51
+ if isinstance(press_fonts, Mapping):
52
+ candidate_emoji = press_fonts.get("emoji")
53
+ context["emoji"] = self._normalise_emoji_mode(candidate_emoji)
54
+ context.setdefault("preamble", "")
55
+ context.setdefault("latex_engine", "lualatex")
56
+ return context
57
+
58
+ def _normalise_string(self, value: Any, default: str) -> str:
59
+ if value is None:
60
+ return default
61
+ candidate = str(value).strip()
62
+ return candidate or default
63
+
64
+ def _normalise_dimension(self, value: Any, default: str) -> str:
65
+ if value is None:
66
+ return default
67
+ candidate = str(value).strip()
68
+ return candidate or default
69
+
70
+ def _normalise_emoji_mode(self, value: Any) -> str:
71
+ candidate = str(value).strip() if value is not None else ""
72
+ if not candidate:
73
+ return "black"
74
+ lowered = candidate.lower()
75
+ if lowered in self._EMOJI_MODES:
76
+ return lowered
77
+ return candidate
78
+
79
+
80
+ __all__ = ["Template"]