mathfmt-tex 0.1.0__py3-none-win_amd64.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.
|
Binary file
|
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mathfmt-tex
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Classifier: Environment :: Console
|
|
5
|
+
Classifier: Intended Audience :: Science/Research
|
|
6
|
+
Classifier: Programming Language :: Rust
|
|
7
|
+
Classifier: Topic :: Text Processing :: Markup :: LaTeX
|
|
8
|
+
Summary: A filter that enforces math-notation conventions in LaTeX source
|
|
9
|
+
Keywords: latex,math,unicode,formatter,pre-commit
|
|
10
|
+
Requires-Python: >=3.8
|
|
11
|
+
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
12
|
+
Project-URL: Repository, https://github.com/jackruder/mathfmt
|
|
13
|
+
|
|
14
|
+
# mathfmt
|
|
15
|
+
|
|
16
|
+
`mathfmt` rewrites the mathematical notation inside LaTeX source so that one
|
|
17
|
+
symbol is spelled one way, the way your profile says. `\R`, `\mathbb{R}`,
|
|
18
|
+
`\symbb{R}` and `ℝ` are four spellings of one symbol; a run makes them one. It
|
|
19
|
+
is a filter: LaTeX in, the same LaTeX out, with only the recognized math tokens
|
|
20
|
+
changed and every other byte untouched.
|
|
21
|
+
|
|
22
|
+
It is not a formatter. Whitespace, line breaks and indentation are left to
|
|
23
|
+
`latexindent`, `tex-fmt` or `badness`, and `mathfmt` runs beside them. It has no
|
|
24
|
+
opinion about when it runs (a pre-commit hook, a CI check, an editor's
|
|
25
|
+
format-on-save, a one-off switch of a whole repository to ASCII for a venue
|
|
26
|
+
that cannot take Unicode) or about what compiles the result.
|
|
27
|
+
|
|
28
|
+
Status: version zero. Atomic symbols (named symbols, Greek letters, styled
|
|
29
|
+
letters and digits, zero-argument macros that stand for one of them) and
|
|
30
|
+
notations with arguments (`\KL{p}{q}` and `D_{\mathrm{KL}}(p \| q)`) convert
|
|
31
|
+
in both directions; a conversion can be compiled before and after and the
|
|
32
|
+
pages compared. See `docs/superpowers/specs/2026-11-05-mathfmt-design.md`.
|
|
33
|
+
|
|
34
|
+
## Install
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
uv tool install mathfmt-tex # or pipx / pip: a prebuilt binary, no Rust
|
|
38
|
+
cargo install --path . # any platform with a Rust toolchain
|
|
39
|
+
nix build # Linux and macOS; ./result/bin/mathfmt
|
|
40
|
+
nix profile install . # or add the flake's package to your configuration
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The Python package is named `mathfmt-tex` because `mathfmt` on PyPI is an
|
|
44
|
+
unrelated project; the command it installs is `mathfmt`. Its wheels hold the
|
|
45
|
+
compiled binary and nothing else, one per platform (Linux x86-64 and ARM,
|
|
46
|
+
glibc and musl; macOS Intel and Apple; Windows x64), built by
|
|
47
|
+
`.github/workflows/wheels.yml` on the GitHub mirror and published to PyPI
|
|
48
|
+
from a `v*` tag. `maturin build --release` in the dev shell builds one for
|
|
49
|
+
the machine at hand.
|
|
50
|
+
|
|
51
|
+
## Use
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
mathfmt [OPTIONS] [FILE...]
|
|
55
|
+
no FILE: read stdin, write stdout
|
|
56
|
+
-p, --profile NAME profile from the config (default: config's `profile`)
|
|
57
|
+
-c, --config PATH config file (default: nearest mathfmt.toml)
|
|
58
|
+
--macros FILE an extra definition source (repeatable)
|
|
59
|
+
--project FILEs are root documents: take every file each one
|
|
60
|
+
inputs (no FILE: --root, else the config's `root`)
|
|
61
|
+
--root FILE the root document of the FILEs: its preamble's
|
|
62
|
+
packages and definitions apply to them
|
|
63
|
+
-w, --write rewrite FILEs in place (atomic: temp file + rename)
|
|
64
|
+
--check exit 1 if any file would change; print their names
|
|
65
|
+
--diff print a unified diff per changed file
|
|
66
|
+
--emit KIND regions | tokens | atoms | symbols, as JSON lines
|
|
67
|
+
--verify compile before and after, compare the rendered pages
|
|
68
|
+
--engine PROGRAM the TeX engine --verify uses (default: the config's
|
|
69
|
+
`engine`, else what the root's preamble says,
|
|
70
|
+
else pdflatex)
|
|
71
|
+
--declare under --verify, add the lines of `mathfmt
|
|
72
|
+
declarations` to a document's preamble, both sides
|
|
73
|
+
--preamble FILE preamble for snippets under --verify
|
|
74
|
+
--dpi N resolution of the page comparison (default 100)
|
|
75
|
+
--keep DIR keep the --verify build trees
|
|
76
|
+
--format text|json diagnostics format (default text)
|
|
77
|
+
--strict warnings make the exit status 1
|
|
78
|
+
-j, --jobs N parallel files (default: available cores)
|
|
79
|
+
-q, --quiet no diagnostics on stderr
|
|
80
|
+
-v, --verbose also show informational diagnostics
|
|
81
|
+
|
|
82
|
+
mathfmt rename --from SPELLING --to SPELLING [same options] [FILE...]
|
|
83
|
+
mathfmt declarations [--project] [--root FILE] [--with MECHANISM] [FILE...]
|
|
84
|
+
mathfmt project [ROOT]
|
|
85
|
+
mathfmt table [--profile NAME]
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
```sh
|
|
89
|
+
mathfmt < draft.tex > out.tex
|
|
90
|
+
mathfmt --profile unicode --write sections/*.tex
|
|
91
|
+
mathfmt --check --diff main.tex sections/*.tex
|
|
92
|
+
mathfmt --emit symbols main.tex | jq -r .atom | sort | uniq -c
|
|
93
|
+
mathfmt rename --from 𝔉 --to ℱ --write sections/*.tex
|
|
94
|
+
mathfmt --verify --macros ddssm.sty main.tex sections/*.tex
|
|
95
|
+
mathfmt --project main.tex --write
|
|
96
|
+
mathfmt --project main.tex --verify --declare
|
|
97
|
+
mathfmt declarations --project main.tex >> preamble.tex
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Exit status: 0 clean; 1 `--check` found changes, `--strict` found warnings or
|
|
101
|
+
`--verify` found a difference; 2 usage, config or I/O error, or an original
|
|
102
|
+
that `--verify` could not compile (every other verdict is still printed).
|
|
103
|
+
Silent on success. With no FILE it reads stdin, so guard a shell expansion that may come
|
|
104
|
+
back empty; a pre-commit hook passes the files itself.
|
|
105
|
+
|
|
106
|
+
### A whole paper at once
|
|
107
|
+
|
|
108
|
+
A paper is a root file, the files it reads with `\input`, `\include`,
|
|
109
|
+
`\subfile` and `\import`, and a preamble that loads packages, some of them
|
|
110
|
+
local. Name the root and mathfmt reads that much itself, without running
|
|
111
|
+
TeX:
|
|
112
|
+
|
|
113
|
+
```sh
|
|
114
|
+
mathfmt project main.tex # what it found: files, packages, engine
|
|
115
|
+
mathfmt --project main.tex --check # every file the root inputs
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
or once, in `mathfmt.toml` beside the root:
|
|
119
|
+
|
|
120
|
+
```toml
|
|
121
|
+
root = "main.tex"
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
With a root, named either way, the definitions of its preamble and of the
|
|
125
|
+
local packages and classes it loads (`\usepackage{ddssm}` with a `ddssm.sty`
|
|
126
|
+
beside the root) are in force for every file, so a pre-commit hook that is
|
|
127
|
+
handed `sections/method.tex` alone still knows the paper's `\R`. `--project`
|
|
128
|
+
also takes the file list from the root: the root, then each file its body
|
|
129
|
+
inputs, in reading order. A package is read and never rewritten. The reader
|
|
130
|
+
does not evaluate conditionals, skips a file name built by a macro, and knows
|
|
131
|
+
a distributed package by its name only.
|
|
132
|
+
|
|
133
|
+
The preamble also says what the document is written for. Whether it loads
|
|
134
|
+
`unicode-math` decides the commands: a profile's commands for the math
|
|
135
|
+
alphabets become unicode-math's (`\symbf`, `\symbb`, `\symcal`) instead of
|
|
136
|
+
`\mathbf`, `\mathbb`, `\mathcal`, which that package typesets differently,
|
|
137
|
+
and a symbol whose amssymb name that package lacks or draws as another glyph
|
|
138
|
+
is written by unicode-math's own name (`\square` becomes `\mdlgwhtsquare`, ▸
|
|
139
|
+
becomes `\smallblacktriangleright`); read back, those names mean what
|
|
140
|
+
unicode-math draws. A lualatex document with fontspec and no unicode-math
|
|
141
|
+
keeps `\mathbf`. The root is `--root`, else the config's `root`, else, for a
|
|
142
|
+
file named on its own, the document itself, or the main document a subfile
|
|
143
|
+
names. `style_preset = "latex"` or `"unicode-math"` in a profile decides the
|
|
144
|
+
commands by hand; `--engine` or `engine` in the config names the program
|
|
145
|
+
`--verify` runs, which otherwise is lualatex for a preamble that loads
|
|
146
|
+
`unicode-math` or `fontspec`. Without a root, an engine other than pdflatex
|
|
147
|
+
is taken to mean unicode-math, which is what `--verify`'s own snippet
|
|
148
|
+
preamble for it loads.
|
|
149
|
+
|
|
150
|
+
When a root is known, a conversion that writes a command the preamble does
|
|
151
|
+
not provide (`\mathbbm` without bbm) gets a `package-not-loaded` warning.
|
|
152
|
+
With bbold or mathbbol loaded, lowercase and digit blackboard letters are
|
|
153
|
+
written with `\mathbb`, which those packages extend.
|
|
154
|
+
|
|
155
|
+
`mathfmt declarations` prints what the preamble must hold for the notation to
|
|
156
|
+
compile in either form: the packages the profile's commands come from that
|
|
157
|
+
the preamble does not load, and a meaning for the Unicode characters, each
|
|
158
|
+
declared as exactly what the profile spells it with commands.
|
|
159
|
+
|
|
160
|
+
```
|
|
161
|
+
$ mathfmt declarations --project main.tex
|
|
162
|
+
% mathfmt declarations: main.tex, profile unicode, unicode-math-input
|
|
163
|
+
% packages the notation's commands need and the preamble does not load
|
|
164
|
+
\usepackage{unicode-math-input}
|
|
165
|
+
% styled letters, as the profile spells them (…)
|
|
166
|
+
\umiDeclareMathChar{𝐱}{\mathbf{x}}
|
|
167
|
+
\umiDeclareMathChar{𝛔}{\boldsymbol{\sigma}}
|
|
168
|
+
\umiDeclareMathChar{𝟙}{\mathbbm{1}}
|
|
169
|
+
…
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
How a document reads Unicode is a choice (`--with`, or `unicode_input` in the
|
|
173
|
+
config):
|
|
174
|
+
|
|
175
|
+
| | |
|
|
176
|
+
|---|---|
|
|
177
|
+
| `unicode-math-input` | pdflatex with that package, which reads a character after `\big` or as a script where the kernel's mechanism does not. Every character is declared all the same: the package's own table lacks some symbols and reads others as something else (`√` as the radical). The default under pdflatex. |
|
|
178
|
+
| `kernel` | pdflatex with `\DeclareUnicodeCharacter` and no package. Every character the math uses is declared, inside `\ensuremath`, so it also works in text (mathfmt reads math only, so a character that appears only in text is not seen). `\big⟨` does not compile, and the primes cannot be declared at all: a declared `′` before a script is a double superscript. |
|
|
179
|
+
| `unicode-math` | lualatex or xelatex with unicode-math. The characters are native; nothing is declared. |
|
|
180
|
+
|
|
181
|
+
Without unicode-math, lualatex reads Unicode math through unicode-math-input
|
|
182
|
+
as pdflatex does.
|
|
183
|
+
|
|
184
|
+
### Proving a conversion is safe
|
|
185
|
+
|
|
186
|
+
The promise is the same PDF from different source, and `--verify` checks it
|
|
187
|
+
rather than arguing it: the original and the converted source are compiled
|
|
188
|
+
with the same engine, both PDFs are rasterized with `pdftoppm`, and the pages
|
|
189
|
+
are compared pixel for pixel. Text extraction cannot tell a bold `x` from a
|
|
190
|
+
plain one; pixels can. A FILE with `\documentclass` is a document and is
|
|
191
|
+
compiled as it is, under its own preamble, with the converted copies of the
|
|
192
|
+
other FILEs in place:
|
|
193
|
+
|
|
194
|
+
```
|
|
195
|
+
$ mathfmt --project main.tex --verify
|
|
196
|
+
broken: main.tex: the converted source does not compile
|
|
197
|
+
! LaTeX Error: Unicode character 𝐱 (U+1D431)
|
|
198
|
+
not set up for use with LaTeX.
|
|
199
|
+
the preamble does not read this character: `mathfmt declarations` prints
|
|
200
|
+
the lines it needs, and --verify --declare compiles with them
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
That is the honest answer for a pdflatex paper whose preamble does not read
|
|
204
|
+
Unicode math: it is not safe to convert yet. `--declare` answers the next
|
|
205
|
+
question without touching the paper: what would it render as with the lines
|
|
206
|
+
of `mathfmt declarations` in its preamble? They are added before
|
|
207
|
+
`\begin{document}` on both sides.
|
|
208
|
+
|
|
209
|
+
```
|
|
210
|
+
$ mathfmt --project main.tex --verify --declare
|
|
211
|
+
differs: main.tex: 1 of 14 pages
|
|
212
|
+
page 2: 3225 pixels in the box x=95..401 y=212..241
|
|
213
|
+
the extracted text is the same; the difference is in glyph shapes or positions
|
|
214
|
+
with 28 declaration lines added to the preamble on both sides
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
One page, and the reason is the paper's: it writes `\mathbf{\sigma_\theta}`,
|
|
218
|
+
which pdflatex draws plain, where its author meant all of it bold. mathfmt
|
|
219
|
+
reads it as meant: both profiles write it bold (`\boldsymbol{\sigma_\theta}`,
|
|
220
|
+
`𝛔_{𝛉}`), so the difference is a repair and the check has found a slip in
|
|
221
|
+
the paper. With those two occurrences written `\boldsymbol{\sigma_\theta}`
|
|
222
|
+
the verdict is `verified: main.tex (14 pages identical)`, in about eight
|
|
223
|
+
seconds for the seventeen files. A paper that wants pdflatex's plain reading
|
|
224
|
+
kept instead sets `bf_greek = "\\mathbf"` in its profile.
|
|
225
|
+
|
|
226
|
+
A FILE without `\documentclass` is a snippet and is wrapped in a preamble
|
|
227
|
+
(`--preamble FILE`, or a built-in one that loads the usual packages and
|
|
228
|
+
unicode-math-input and declares the styled letters the snippet uses to mean
|
|
229
|
+
what the profile spells them as). `--verify` needs the engine and
|
|
230
|
+
`pdftoppm` on PATH; the test suite runs it over every fixture and over the
|
|
231
|
+
small projects in `tests/projects/`, one of them under lualatex.
|
|
232
|
+
|
|
233
|
+
A project's `mathfmt.toml` names its root, the definition files whose macros
|
|
234
|
+
the tool reads beyond the root's, and the profiles it may emit; two profiles,
|
|
235
|
+
`unicode` and `ascii`, exist with defaults even when the file does not mention
|
|
236
|
+
them.
|
|
237
|
+
|
|
238
|
+
### Notations with arguments
|
|
239
|
+
|
|
240
|
+
A symbol with parameters has spellings too. Declare the notation once, with
|
|
241
|
+
every form the project has ever written, and let each profile pick the one it
|
|
242
|
+
emits:
|
|
243
|
+
|
|
244
|
+
```toml
|
|
245
|
+
[notations.KL]
|
|
246
|
+
macro = "\\KL{#1}{#2}"
|
|
247
|
+
expanded = "D_{\\mathrm{KL}}(#1 \\| #2)"
|
|
248
|
+
spaced = "D_{\\mathrm{KL}}(#1 \\,\\|\\, #2)"
|
|
249
|
+
|
|
250
|
+
[profiles.ascii.notations]
|
|
251
|
+
KL = "macro" # D_{\mathrm{KL}}(p \| q) → \KL{p}{q}
|
|
252
|
+
[profiles.unicode.notations]
|
|
253
|
+
KL = "expanded" # \KL{p}{q} → D_{\mathrm{KL}}(p ‖ q)
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
Matching is on the math tree modulo symbols, so `\|`, `\Vert` and `‖` are one
|
|
257
|
+
thing, `\mathbb{E}` in a form is the character `𝔼` in the source,
|
|
258
|
+
`D_\mathrm{KL}` is `D_{\mathrm{KL}}`, and a hole binds the shortest stretch
|
|
259
|
+
between the literals that is balanced in its delimiters:
|
|
260
|
+
`D_{\mathrm{KL}}(q_\phi(z \mid x) ‖ p(z))` becomes
|
|
261
|
+
`\KL{q_\phi(z \mid x)}{p(z)}`, with the holes converted and nested notations
|
|
262
|
+
handled inside them. The form a profile writes goes through the profile's
|
|
263
|
+
symbol spellings too, so one form serves both; a macro in it (`\R^{#1}`) is
|
|
264
|
+
written as it stands. Among forms that match, the one with the most tokens
|
|
265
|
+
wins, whichever notation it belongs to. A profile that names no form leaves
|
|
266
|
+
the notation as written; `--emit symbols` still counts it, form by form.
|
|
267
|
+
|
|
268
|
+
The matcher prefers no match to a doubtful one, and a notation it does not
|
|
269
|
+
match is left exactly as written:
|
|
270
|
+
|
|
271
|
+
- A form must begin and end with something literal. `#1 \cdot #2` is refused
|
|
272
|
+
by the config: a hole at the edge has no boundary.
|
|
273
|
+
- A stretch that holds a `%` comment or a brace that is never closed is not a
|
|
274
|
+
match. A rewrite would swallow what follows the one and run to the end of
|
|
275
|
+
the file through the other.
|
|
276
|
+
- A group standing alone is not its content: `P(A {\mid} B)` is not
|
|
277
|
+
`P(#1 \mid #2)`, because the braces make the bar an ordinary symbol. A
|
|
278
|
+
braced script operand or command argument is its content.
|
|
279
|
+
- A notation that is itself a script operand (`e^\KL{p}{q}`) is kept: what
|
|
280
|
+
the script takes there is the macro's business.
|
|
281
|
+
|
|
282
|
+
## What it does to a real paper
|
|
283
|
+
|
|
284
|
+
Run read-only over the eight `.tex` files of an ICML manuscript that defines
|
|
285
|
+
`\R`, `\E`, `\N` and friends in its style file:
|
|
286
|
+
|
|
287
|
+
```sh
|
|
288
|
+
mathfmt --check --diff --macros ddssm.sty main.tex sections/*.tex
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
| | |
|
|
292
|
+
|---|---|
|
|
293
|
+
| time for all eight files | about 25 ms |
|
|
294
|
+
| symbol occurrences rewritten | 679 |
|
|
295
|
+
| distinct symbols | 48 |
|
|
296
|
+
| warnings | 0 |
|
|
297
|
+
| style groups left as written | 0 |
|
|
298
|
+
|
|
299
|
+
The result taken through `--profile ascii` and back to `unicode` returns seven
|
|
300
|
+
of the eight files byte for byte. The eighth writes `\mathbf{\sigma_\theta}`,
|
|
301
|
+
which pdflatex renders as plain italic (its `\mathbf` ignores lowercase Greek);
|
|
302
|
+
mathfmt reads it literally as bold upright `𝛔_{𝛉}`, and the `ascii` profile
|
|
303
|
+
spells bold Greek with `\boldsymbol`, which reads back as bold italic `𝝈_{𝜽}`.
|
|
304
|
+
A profile with `bf_greek = "\\mathbf"` keeps pdflatex's reading and closes the
|
|
305
|
+
round trip; see "Known collapses" below. A line of the diff:
|
|
306
|
+
|
|
307
|
+
```diff
|
|
308
|
+
-Let \( \mathbf{x}_{1:T} = (\mathbf{x}_1, \dots, \mathbf{x}_T) \) with \( \mathbf{x}_t \in \mathbb{R}^D \)
|
|
309
|
+
+Let \( 𝐱_{1:T} = (𝐱_1, \dots, 𝐱_T) \) with \( 𝐱_t ∈ ℝ^D \)
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
The `ascii` profile on the same files makes 26 changes, every one a macro
|
|
313
|
+
inlined to its definition: `\N` to `\mathcal{N}`, `\E` to `\mathbb{E}`.
|
|
314
|
+
Collaborators who prefer the macros write a profile with
|
|
315
|
+
`spellings."ℝ" = "\\R"` and get them back.
|
|
316
|
+
|
|
317
|
+
## As a pre-commit hook
|
|
318
|
+
|
|
319
|
+
For collaborators without Rust, a local hook that installs the wheel into
|
|
320
|
+
pre-commit's own environment:
|
|
321
|
+
|
|
322
|
+
```yaml
|
|
323
|
+
repos:
|
|
324
|
+
- repo: local
|
|
325
|
+
hooks:
|
|
326
|
+
- id: mathfmt
|
|
327
|
+
name: mathfmt
|
|
328
|
+
entry: mathfmt
|
|
329
|
+
language: python
|
|
330
|
+
additional_dependencies: ["mathfmt-tex==0.1.0"]
|
|
331
|
+
args: ["--write"] # or ["--check"]: fail the commit, change nothing
|
|
332
|
+
files: \.(tex|sty)$
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
Before the package is on PyPI, `additional_dependencies` takes a wheel's
|
|
336
|
+
path or URL instead. With a Rust toolchain, the repository is a hook repo
|
|
337
|
+
itself, and pre-commit builds the binary with cargo on first use:
|
|
338
|
+
|
|
339
|
+
```yaml
|
|
340
|
+
repos:
|
|
341
|
+
- repo: ssh://forgejo@git.buttermilks.rocks/jack/mathfmt.git
|
|
342
|
+
rev: v0.1.0
|
|
343
|
+
hooks:
|
|
344
|
+
- id: mathfmt # rewrites staged .tex/.sty files to the profile
|
|
345
|
+
# - id: mathfmt-check # or: fail the commit, change nothing
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
`tests/pre-commit-e2e.sh` builds the wheel and runs the first form in a
|
|
349
|
+
scratch repository, twice: the first run rewrites and fails, as pre-commit
|
|
350
|
+
does when a hook changes a file, and the second passes.
|
|
351
|
+
|
|
352
|
+
## Known collapses
|
|
353
|
+
|
|
354
|
+
Places where the Unicode pivot loses a distinction, by design and
|
|
355
|
+
configurable:
|
|
356
|
+
|
|
357
|
+
- **cal and scr.** `\mathcal{F}` and `\mathscr{F}` both print as the one Unicode
|
|
358
|
+
script alphabet (`𝓕`); reading it back gives `\mathcal` unless the profile
|
|
359
|
+
sets `script_reads_as = "scr"`.
|
|
360
|
+
- **bf_greek.** The `ascii` profile prints a bold Greek letter as
|
|
361
|
+
`\boldsymbol{\alpha}` because pdflatex's `\mathbf` renders nothing bold for
|
|
362
|
+
Greek. Bold upright `𝛂` and bold italic `𝜶` therefore both become
|
|
363
|
+
`\boldsymbol{\alpha}` and come back as `𝜶`. Set `style_commands.bf_greek =
|
|
364
|
+
"\\mathbf"` for the literal reading.
|
|
365
|
+
- **ℑ and ℜ.** Unicode has one codepoint each for the fraktur I and R and for
|
|
366
|
+
the imaginary and real parts, so `\mathfrak{I}` and `\Im` are one atom. The
|
|
367
|
+
`ascii` profile spells it `\Im`; pdflatex draws `\mathfrak{I}` from eufm and
|
|
368
|
+
`\Im` from cmsy, and they look different. Set `spellings."frak:I" =
|
|
369
|
+
"\\mathfrak{I}"` (and `frak:R`) for a paper that means the letter.
|
|
370
|
+
|
|
371
|
+
- **The primes.** The characters `′`, `″` and `‴` are the superscript primes
|
|
372
|
+
that `'`, `''` and `'''` write, under unicode-math-input and unicode-math
|
|
373
|
+
alike, so every profile writes them that way; `\prime` is the unraised
|
|
374
|
+
glyph and is left alone, and `‵` has no command spelling.
|
|
375
|
+
- **`\emptyset` and `\varnothing`.** `\emptyset` (pdflatex's slashed zero) and `\varnothing`
|
|
376
|
+
(amssymb's slashed circle) are one codepoint, U+2205, whose glyph is the
|
|
377
|
+
circle. The `ascii` profile spells it `\varnothing`; set
|
|
378
|
+
`spellings."∅" = "\\emptyset"` for a paper that means the zero.
|
|
379
|
+
- **Shape under unicode-math.** With that package's default options the
|
|
380
|
+
shape of a bold or sans letter is the document's (`bold-style`,
|
|
381
|
+
`sans-style`), not the character's: a literal `𝛔`, a literal `𝝈` and
|
|
382
|
+
`\symbf{\sigma}` all draw the house bold sigma, and a literal `𝒙` draws
|
|
383
|
+
upright. The preset therefore spells `bf` as `\symbf` and `sf` as `\symsf`.
|
|
384
|
+
A letter whose shape contradicts the house style (`𝒙`, `𝘈`,
|
|
385
|
+
`\symbfup{\sigma}`, `\symbfit{x}`) changes when it crosses between a
|
|
386
|
+
character and a command. A document that sets `bold-style=literal` and
|
|
387
|
+
`sans-style=literal` wants `bf = "\\symbfup"`, `sf = "\\symsfup"` and
|
|
388
|
+
`bfsf = "\\symbfsfup"` in `style_commands`.
|
|
389
|
+
|
|
390
|
+
`\mathbb{1}` is not a collapse but a repair: amsfonts has no blackboard digits
|
|
391
|
+
and `\mathbb{1}` is the glyph ⊮, so the `bb_digit` key spells `𝟙` as
|
|
392
|
+
`\mathbbm{1}`. `--verify` reports each of these as a difference when a
|
|
393
|
+
conversion crosses one, which is how they were found.
|
|
394
|
+
|
|
395
|
+
## Developing
|
|
396
|
+
|
|
397
|
+
`cargo test --workspace` on a laptop; `tests/dev.sh cargo test --workspace`
|
|
398
|
+
anywhere else (it enters the dev shell and runs cargo offline against the
|
|
399
|
+
crates nix vendored from `Cargo.lock`). `CLAUDE.md` has the rest: the fixture
|
|
400
|
+
discipline, the tables, and the rules.
|
|
401
|
+
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
mathfmt_tex-0.1.0.data/scripts/mathfmt.exe,sha256=PtpWZ_lYgeDcJBGVU_rzxRbECI9zXT-w0DaMdw3XEAE,2613760
|
|
2
|
+
mathfmt_tex-0.1.0.dist-info/METADATA,sha256=mudFUfunUrQ5B54z0Uh64U9-qDRfuzg3EY4OyDD70NA,20087
|
|
3
|
+
mathfmt_tex-0.1.0.dist-info/WHEEL,sha256=Uvw7WSmy7Kj2FBk8Va4L_dq4MDW8X5Ynby-pOX3ZNS0,94
|
|
4
|
+
mathfmt_tex-0.1.0.dist-info/sboms/mathfmt.cyclonedx.json,sha256=Ae8_5L3JQVGmJXvTTyb3BAlzM4hJt45-CQetxmQ0xD0,50665
|
|
5
|
+
mathfmt_tex-0.1.0.dist-info/RECORD,,
|