python-color-math 0.1.0__tar.gz → 0.2.0__tar.gz
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.
- python_color_math-0.2.0/.pre-commit-hooks.yaml +15 -0
- python_color_math-0.2.0/MANIFEST.in +6 -0
- python_color_math-0.2.0/PKG-INFO +261 -0
- python_color_math-0.2.0/README.md +206 -0
- {python_color_math-0.1.0 → python_color_math-0.2.0}/color_math/__init__.py +10 -1
- {python_color_math-0.1.0 → python_color_math-0.2.0}/color_math/adapters.py +46 -17
- python_color_math-0.2.0/color_math/completions.py +272 -0
- python_color_math-0.2.0/color_math/config.py +679 -0
- {python_color_math-0.1.0 → python_color_math-0.2.0}/color_math/converters/block.py +21 -0
- {python_color_math-0.1.0 → python_color_math-0.2.0}/color_math/converters/generic.py +20 -14
- {python_color_math-0.1.0 → python_color_math-0.2.0}/color_math/converters/matrix.py +6 -0
- python_color_math-0.2.0/color_math/gui.py +528 -0
- python_color_math-0.2.0/color_math/main.py +855 -0
- {python_color_math-0.1.0 → python_color_math-0.2.0}/color_math/parsers/__init__.py +8 -0
- python_color_math-0.2.0/color_math/parsers/alignment.py +74 -0
- python_color_math-0.2.0/color_math/parsers/constants.py +130 -0
- {python_color_math-0.1.0 → python_color_math-0.2.0}/color_math/parsers/latex_spans.py +35 -2
- {python_color_math-0.1.0 → python_color_math-0.2.0}/color_math/parsers/math_parser.py +142 -14
- {python_color_math-0.1.0 → python_color_math-0.2.0}/color_math/parsers/taxonomy.py +84 -8
- python_color_math-0.2.0/color_math/parsers/variable_hash.py +222 -0
- python_color_math-0.2.0/color_math/py.typed +1 -0
- python_color_math-0.2.0/color_math/tutorial.py +183 -0
- {python_color_math-0.1.0 → python_color_math-0.2.0}/color_math/utils/latex_helpers.py +177 -0
- {python_color_math-0.1.0 → python_color_math-0.2.0}/pyproject.toml +18 -10
- python_color_math-0.2.0/python_color_math/__init__.py +17 -0
- python_color_math-0.2.0/python_color_math/__main__.py +4 -0
- python_color_math-0.2.0/python_color_math.egg-info/PKG-INFO +261 -0
- {python_color_math-0.1.0 → python_color_math-0.2.0}/python_color_math.egg-info/SOURCES.txt +13 -1
- {python_color_math-0.1.0 → python_color_math-0.2.0}/python_color_math.egg-info/entry_points.txt +1 -0
- python_color_math-0.2.0/python_color_math.egg-info/top_level.txt +2 -0
- python_color_math-0.2.0/tests/test_cli.py +344 -0
- {python_color_math-0.1.0 → python_color_math-0.2.0}/tests/test_features.py +140 -4
- python_color_math-0.2.0/tests/test_gui.py +133 -0
- python_color_math-0.1.0/PKG-INFO +0 -167
- python_color_math-0.1.0/README.md +0 -116
- python_color_math-0.1.0/color_math/config.py +0 -351
- python_color_math-0.1.0/color_math/main.py +0 -162
- python_color_math-0.1.0/color_math/parsers/variable_hash.py +0 -126
- python_color_math-0.1.0/python_color_math.egg-info/PKG-INFO +0 -167
- python_color_math-0.1.0/python_color_math.egg-info/top_level.txt +0 -1
- {python_color_math-0.1.0 → python_color_math-0.2.0}/LICENSE +0 -0
- {python_color_math-0.1.0 → python_color_math-0.2.0}/color_math/__main__.py +0 -0
- {python_color_math-0.1.0 → python_color_math-0.2.0}/color_math/converters/__init__.py +0 -0
- {python_color_math-0.1.0 → python_color_math-0.2.0}/color_math/converters/align.py +0 -0
- {python_color_math-0.1.0 → python_color_math-0.2.0}/color_math/converters/derivative.py +0 -0
- {python_color_math-0.1.0 → python_color_math-0.2.0}/color_math/converters/equation.py +0 -0
- {python_color_math-0.1.0 → python_color_math-0.2.0}/color_math/converters/integral.py +0 -0
- {python_color_math-0.1.0 → python_color_math-0.2.0}/color_math/converters/limit.py +0 -0
- {python_color_math-0.1.0 → python_color_math-0.2.0}/color_math/converters/semantic.py +0 -0
- {python_color_math-0.1.0 → python_color_math-0.2.0}/color_math/io.py +0 -0
- {python_color_math-0.1.0 → python_color_math-0.2.0}/color_math/parsers/braket.py +0 -0
- {python_color_math-0.1.0 → python_color_math-0.2.0}/color_math/parsers/delimiters.py +0 -0
- {python_color_math-0.1.0 → python_color_math-0.2.0}/color_math/parsers/differentials.py +0 -0
- {python_color_math-0.1.0 → python_color_math-0.2.0}/color_math/parsers/dimensionless.py +0 -0
- {python_color_math-0.1.0 → python_color_math-0.2.0}/color_math/parsers/markdown_scanner.py +0 -0
- {python_color_math-0.1.0 → python_color_math-0.2.0}/color_math/parsers/scanner.py +0 -0
- {python_color_math-0.1.0 → python_color_math-0.2.0}/color_math/parsers/units.py +0 -0
- {python_color_math-0.1.0 → python_color_math-0.2.0}/color_math/self_test.py +0 -0
- {python_color_math-0.1.0 → python_color_math-0.2.0}/color_math/undo.py +0 -0
- {python_color_math-0.1.0 → python_color_math-0.2.0}/color_math/utils/__init__.py +0 -0
- {python_color_math-0.1.0 → python_color_math-0.2.0}/color_math/utils/coloring.py +0 -0
- {python_color_math-0.1.0 → python_color_math-0.2.0}/color_math/utils/spans.py +0 -0
- {python_color_math-0.1.0 → python_color_math-0.2.0}/python_color_math.egg-info/dependency_links.txt +0 -0
- {python_color_math-0.1.0 → python_color_math-0.2.0}/setup.cfg +0 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
- id: color-math-check
|
|
2
|
+
name: color-math check (LaTeX math linter)
|
|
3
|
+
description: Verify that LaTeX math expressions in Markdown, LaTeX, and Jupyter notebooks are colored and cleanly formatted.
|
|
4
|
+
entry: color-math --check
|
|
5
|
+
language: python
|
|
6
|
+
types_or: [markdown, jupyter, tex]
|
|
7
|
+
require_serial: true
|
|
8
|
+
|
|
9
|
+
- id: color-math
|
|
10
|
+
name: color-math format
|
|
11
|
+
description: Automatically format and add semantic colors to LaTeX math expressions in Markdown, LaTeX, and Jupyter notebooks.
|
|
12
|
+
entry: color-math -w
|
|
13
|
+
language: python
|
|
14
|
+
types_or: [markdown, jupyter, tex]
|
|
15
|
+
require_serial: true
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: python-color-math
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: A fast, local semantic LaTeX colorizer for Markdown, Jupyter, and LaTeX math equations.
|
|
5
|
+
Author: Aditya
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2026 Aditya
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Project-URL: Homepage, https://github.com/36ty-blip/python-color-math
|
|
29
|
+
Project-URL: Documentation, https://github.com/36ty-blip/python-color-math#readme
|
|
30
|
+
Project-URL: Repository, https://github.com/36ty-blip/python-color-math
|
|
31
|
+
Project-URL: Issues, https://github.com/36ty-blip/python-color-math/issues
|
|
32
|
+
Project-URL: Changelog, https://github.com/36ty-blip/python-color-math/releases
|
|
33
|
+
Keywords: obsidian,latex,math,markdown,jupyter,colorizer,katex,mathjax,cli
|
|
34
|
+
Classifier: Development Status :: 4 - Beta
|
|
35
|
+
Classifier: Environment :: Console
|
|
36
|
+
Classifier: Intended Audience :: Developers
|
|
37
|
+
Classifier: Intended Audience :: Education
|
|
38
|
+
Classifier: Intended Audience :: Science/Research
|
|
39
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
40
|
+
Classifier: Operating System :: OS Independent
|
|
41
|
+
Classifier: Programming Language :: Python :: 3
|
|
42
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
43
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
44
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
45
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
46
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
47
|
+
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
48
|
+
Classifier: Topic :: Text Processing :: Markup
|
|
49
|
+
Classifier: Topic :: Text Processing :: Markup :: LaTeX
|
|
50
|
+
Classifier: Topic :: Text Processing :: Markup :: Markdown
|
|
51
|
+
Requires-Python: >=3.10
|
|
52
|
+
Description-Content-Type: text/markdown
|
|
53
|
+
License-File: LICENSE
|
|
54
|
+
Dynamic: license-file
|
|
55
|
+
|
|
56
|
+
# 🎨 Python Color Math
|
|
57
|
+
|
|
58
|
+
> Semantic color for LaTeX equations in Markdown, Jupyter notebooks, and native TeX documents — without handing your notation to a computer algebra system.
|
|
59
|
+
|
|
60
|
+
`python-color-math` parses mathematical expressions and inserts MathJax/KaTeX-compatible `\textcolor{...}{...}` wrappers. It operates completely locally, preserves existing LaTeX structure, and leaves prose, fenced code, TeX comments, and `\verb` payloads untouched.
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## 🌈 Before & After
|
|
65
|
+
|
|
66
|
+
**Input:**
|
|
67
|
+
```latex
|
|
68
|
+
$$ \frac{d}{dx} f(g(y)) = f'(g(y)) \cdot g'(y)y' $$
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**Output:**
|
|
72
|
+
```latex
|
|
73
|
+
$$ \frac{d}{dx}\textcolor{#7aa2f7}{f(g(y))} \textcolor{white}{=} \textcolor{#bb9af7}{f'(g(y))}\textcolor{white}{\cdot} \textcolor{#9ece6a}{g'(y)}\textcolor{#9ece6a}{y'} $$
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## 🚀 Quick Start
|
|
79
|
+
|
|
80
|
+
### Installation
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
pip install python-color-math
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
*(Or locally from cloned source: `pip install -e .`)*
|
|
87
|
+
|
|
88
|
+
> [!TIP]
|
|
89
|
+
> **Commands & PATH**:
|
|
90
|
+
> - Registers both the short **`color-math`** and full **`python-color-math`** commands.
|
|
91
|
+
> - If Python's `Scripts/` folder is not on your `PATH`, run directly via Python without touching environment variables:
|
|
92
|
+
> `python -m color_math [options]` *(or `python -m python_color_math`)*.
|
|
93
|
+
> - *Linux users*: Python's standard GUI library is available via `sudo apt install python3-tk`.
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## ⚡ Three Ways to Use
|
|
98
|
+
|
|
99
|
+
### 1. 🎓 Interactive Terminal Tutorial
|
|
100
|
+
New to Color Math? Take the 2-minute paced CLI tour with live examples:
|
|
101
|
+
```bash
|
|
102
|
+
color-math --tutorial
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### 2. 🖥️ Graphical Pop-up Window (GUI)
|
|
106
|
+
Prefer visual controls? Launch the native High-DPI pop-up window:
|
|
107
|
+
```bash
|
|
108
|
+
color-math --ui
|
|
109
|
+
# or:
|
|
110
|
+
color-math --gui
|
|
111
|
+
```
|
|
112
|
+
- **Preview vs Write Toggle**: Inspect diffs safely or write directly to disk.
|
|
113
|
+
- **Visual Color Picker**: Click color chips to select custom hex values.
|
|
114
|
+
- **Theme & Preset Selectors**: Switch curated palettes and engine toggles in 1 click.
|
|
115
|
+
- **1-Click Reset**: Restore factory Tokyo Night defaults anytime.
|
|
116
|
+
|
|
117
|
+
### 3. ⌨️ Fast Terminal Commands
|
|
118
|
+
```bash
|
|
119
|
+
# Safe preview in terminal (leaves notes unchanged)
|
|
120
|
+
color-math note.md
|
|
121
|
+
|
|
122
|
+
# Save changes directly back to the note
|
|
123
|
+
color-math note.md -w
|
|
124
|
+
|
|
125
|
+
# Process an entire folder recursively
|
|
126
|
+
color-math notes/ -r -w
|
|
127
|
+
|
|
128
|
+
# Color a raw LaTeX string directly
|
|
129
|
+
color-math "$$\frac{d}{dx} x^2 = 2x$$"
|
|
130
|
+
|
|
131
|
+
# Read and color from standard input pipeline
|
|
132
|
+
cat note.md | color-math -
|
|
133
|
+
|
|
134
|
+
# Inspect syntax-colored unified diff without touching disk
|
|
135
|
+
color-math note.md --diff
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## 📋 Cheat Sheet (Command Reference)
|
|
141
|
+
|
|
142
|
+
| Task | Command | Description |
|
|
143
|
+
| :--- | :--- | :--- |
|
|
144
|
+
| **Visual Window** | `color-math --ui` *(or `--gui`)* | Open interactive High-DPI GUI |
|
|
145
|
+
| **Interactive Tour** | `color-math --tutorial` | 2-minute interactive terminal guide |
|
|
146
|
+
| **Preview** | `color-math note.md` | Safe preview (leaves disk untouched) |
|
|
147
|
+
| **Save / Write** | `color-math note.md -w` *(or `-i`)* | Write changes in-place |
|
|
148
|
+
| **Batch Folder** | `color-math notes/ -r -w` | Recursively color directory |
|
|
149
|
+
| **Unified Diff** | `color-math note.md --diff` | Inspect exact line changes (colorized) |
|
|
150
|
+
| **Linter / CI Mode** | `color-math notes/ -r --check` | Exit `0` if clean, `1` if notes need coloring |
|
|
151
|
+
| **Machine JSON** | `color-math notes/ -r --check --json` | Structured JSON output for CI and pipelines |
|
|
152
|
+
| **Stdin Pipeline** | `cat note.md \| color-math -` | Read and color math from standard input |
|
|
153
|
+
| **Curated Themes** | `color-math note.md --theme catppuccin -w` | Select `default`, `catppuccin`, `nord`, or `light` |
|
|
154
|
+
| **Feature Preset** | `color-math note.md --preset minimal -w` | Presets: `all` (default), `minimal` |
|
|
155
|
+
| **Custom Colors** | `color-math note.md -c unit=#73daca -w` | Override any of 12 individual color roles |
|
|
156
|
+
| **Reset Palette** | `color-math --reset-colors` | Restore factory Tokyo Night palette |
|
|
157
|
+
| **Inspect Colors** | `color-math --show-colors` | Display palette, descriptions, & terminal swatches |
|
|
158
|
+
| **Undo / Strip** | `color-math note.md --undo -w` | Strip color wrappers back to plain LaTeX |
|
|
159
|
+
| **Export Config** | `color-math --init-config` | Generate a documented `.colormath.json` |
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## 🧠 Engine Features & Disambiguation
|
|
164
|
+
|
|
165
|
+
Control recognition features with `--preset {all,minimal}` (default: `all`) or individual flags:
|
|
166
|
+
|
|
167
|
+
- **Calculus Differentials (`--differentials`)**: Disambiguates `dx`, `dt`, `d\theta`, and derivatives (`\frac{d}{dx}`, `\frac{\partial \psi}{\partial t}`) while leaving standalone distance variables `$d$` untouched.
|
|
168
|
+
- **Physical Units (`--units`)**: Recognizes metric prefixes and unit compounds (`\mu m`, `m/s`, `kg`, `nm`).
|
|
169
|
+
- **Rainbow Delimiters (`--rainbow-delimiters`)**: Recursively colors nested brackets `()`, `[]`, `{}` by depth to eliminate delimiter blindness.
|
|
170
|
+
- **Quantum Bra-Ket (`--braket`)**: Dirac notation (`|\psi\rangle`, `\langle\phi|`, `\langle\phi|\psi\rangle`).
|
|
171
|
+
- **Dimensionless Groups (`--dimensionless`)**: Recognizes engineering numbers (`Re`, `Ma`, `Pr`, `Nu`).
|
|
172
|
+
- **Semantic Taxonomy (`--taxonomy`)**: Colors constants ($\pi, \hbar, \infty$), Greek parameters ($\alpha, \theta$), and standard functions ($\sin, \cos, \ln$).
|
|
173
|
+
- **Variable Data-Flow (`--variable-data-flow`)**: Deterministically hashes variable names to track variable flow across equations.
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## 📁 Supported File Formats
|
|
178
|
+
|
|
179
|
+
`python-color-math` automatically detects file formats by extension:
|
|
180
|
+
- **Markdown**: `.md`, `.markdown`, `.qmd` (Quarto)
|
|
181
|
+
- **Jupyter Notebooks**: `.ipynb` (transforms only Markdown cells)
|
|
182
|
+
- **Native LaTeX**: `.tex`, `.latex` (adds `\usepackage{xcolor}` compatibility)
|
|
183
|
+
- **Anki Flashcards**: `.tsv`, `.txt` (select via `--format anki`)
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## ↩️ Complete Reversibility (Undo)
|
|
188
|
+
|
|
189
|
+
Never worry about locking your documents into color wrappers:
|
|
190
|
+
```bash
|
|
191
|
+
# Preview what plain LaTeX would look like
|
|
192
|
+
color-math note.md --undo
|
|
193
|
+
|
|
194
|
+
# Restore plain LaTeX back to disk
|
|
195
|
+
color-math note.md --undo -w
|
|
196
|
+
|
|
197
|
+
# Strip colors from an entire vault
|
|
198
|
+
color-math notes/ -r --undo -w
|
|
199
|
+
```
|
|
200
|
+
*Undo cleanly removes generated `\textcolor{...}{...}` and compatible legacy `\color{...}{...}` wrappers.*
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## 🐚 Shell Autocompletion
|
|
205
|
+
|
|
206
|
+
Generate fast, native completions with full support for all flags, themes, presets, and file formats:
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
# Bash
|
|
210
|
+
color-math --generate-completion bash >> ~/.bash_completion
|
|
211
|
+
|
|
212
|
+
# Zsh
|
|
213
|
+
color-math --generate-completion zsh > ~/.zsh/completion/_color-math
|
|
214
|
+
|
|
215
|
+
# Fish
|
|
216
|
+
color-math --generate-completion fish > ~/.config/fish/completions/color-math.fish
|
|
217
|
+
|
|
218
|
+
# PowerShell
|
|
219
|
+
color-math --generate-completion powershell | Out-String | Invoke-Expression
|
|
220
|
+
# Or persist to your $PROFILE:
|
|
221
|
+
Add-Content $PROFILE "`ncolor-math --generate-completion powershell | Out-String | Invoke-Expression"
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## 🪝 Pre-commit Integration
|
|
227
|
+
|
|
228
|
+
Integrate `color-math` into your git workflow using [pre-commit](https://pre-commit.com):
|
|
229
|
+
|
|
230
|
+
```yaml
|
|
231
|
+
repos:
|
|
232
|
+
- repo: https://github.com/36ty-blip/color-math
|
|
233
|
+
rev: v0.2.0
|
|
234
|
+
hooks:
|
|
235
|
+
# Formatter: colorizes modified Markdown, LaTeX, and Jupyter files in-place
|
|
236
|
+
- id: color-math
|
|
237
|
+
# Linter: verifies math formatting without modifying files (fails if uncolored)
|
|
238
|
+
# - id: color-math-check
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## ⚙️ Configuration & Standards
|
|
244
|
+
|
|
245
|
+
`python-color-math` adheres to modern CLI standards ([clig.dev](https://clig.dev/)):
|
|
246
|
+
- **Config Hierarchy**: `--config <file>` > `./.colormath.json` (project local) > Global user config (`%APPDATA%\color-math\config.json` on Windows or `~/.config/color-math/config.json` on Linux/macOS) > Factory defaults.
|
|
247
|
+
- **Color Standards**: Honors `NO_COLOR` ([no-color.org](https://no-color.org)), `FORCE_COLOR`, and `TERM=dumb`.
|
|
248
|
+
- **CI / Pre-commit**: Combine `--check --json` for structured reporting in automated pipelines.
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## 🤝 Obsidian Companion Plugin
|
|
253
|
+
|
|
254
|
+
Looking for dynamic real-time equation coloring inside Obsidian without modifying notes on disk? Check out the sister plugin:
|
|
255
|
+
👉 [**Obsidian Color Math**](https://github.com/36ty-blip/obsidian-color-math) *(Pure TypeScript, runs natively on Obsidian Desktop & Mobile).*
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## 📄 License
|
|
260
|
+
|
|
261
|
+
Released under the [MIT License](LICENSE).
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
# 🎨 Python Color Math
|
|
2
|
+
|
|
3
|
+
> Semantic color for LaTeX equations in Markdown, Jupyter notebooks, and native TeX documents — without handing your notation to a computer algebra system.
|
|
4
|
+
|
|
5
|
+
`python-color-math` parses mathematical expressions and inserts MathJax/KaTeX-compatible `\textcolor{...}{...}` wrappers. It operates completely locally, preserves existing LaTeX structure, and leaves prose, fenced code, TeX comments, and `\verb` payloads untouched.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 🌈 Before & After
|
|
10
|
+
|
|
11
|
+
**Input:**
|
|
12
|
+
```latex
|
|
13
|
+
$$ \frac{d}{dx} f(g(y)) = f'(g(y)) \cdot g'(y)y' $$
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
**Output:**
|
|
17
|
+
```latex
|
|
18
|
+
$$ \frac{d}{dx}\textcolor{#7aa2f7}{f(g(y))} \textcolor{white}{=} \textcolor{#bb9af7}{f'(g(y))}\textcolor{white}{\cdot} \textcolor{#9ece6a}{g'(y)}\textcolor{#9ece6a}{y'} $$
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## 🚀 Quick Start
|
|
24
|
+
|
|
25
|
+
### Installation
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pip install python-color-math
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
*(Or locally from cloned source: `pip install -e .`)*
|
|
32
|
+
|
|
33
|
+
> [!TIP]
|
|
34
|
+
> **Commands & PATH**:
|
|
35
|
+
> - Registers both the short **`color-math`** and full **`python-color-math`** commands.
|
|
36
|
+
> - If Python's `Scripts/` folder is not on your `PATH`, run directly via Python without touching environment variables:
|
|
37
|
+
> `python -m color_math [options]` *(or `python -m python_color_math`)*.
|
|
38
|
+
> - *Linux users*: Python's standard GUI library is available via `sudo apt install python3-tk`.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## ⚡ Three Ways to Use
|
|
43
|
+
|
|
44
|
+
### 1. 🎓 Interactive Terminal Tutorial
|
|
45
|
+
New to Color Math? Take the 2-minute paced CLI tour with live examples:
|
|
46
|
+
```bash
|
|
47
|
+
color-math --tutorial
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### 2. 🖥️ Graphical Pop-up Window (GUI)
|
|
51
|
+
Prefer visual controls? Launch the native High-DPI pop-up window:
|
|
52
|
+
```bash
|
|
53
|
+
color-math --ui
|
|
54
|
+
# or:
|
|
55
|
+
color-math --gui
|
|
56
|
+
```
|
|
57
|
+
- **Preview vs Write Toggle**: Inspect diffs safely or write directly to disk.
|
|
58
|
+
- **Visual Color Picker**: Click color chips to select custom hex values.
|
|
59
|
+
- **Theme & Preset Selectors**: Switch curated palettes and engine toggles in 1 click.
|
|
60
|
+
- **1-Click Reset**: Restore factory Tokyo Night defaults anytime.
|
|
61
|
+
|
|
62
|
+
### 3. ⌨️ Fast Terminal Commands
|
|
63
|
+
```bash
|
|
64
|
+
# Safe preview in terminal (leaves notes unchanged)
|
|
65
|
+
color-math note.md
|
|
66
|
+
|
|
67
|
+
# Save changes directly back to the note
|
|
68
|
+
color-math note.md -w
|
|
69
|
+
|
|
70
|
+
# Process an entire folder recursively
|
|
71
|
+
color-math notes/ -r -w
|
|
72
|
+
|
|
73
|
+
# Color a raw LaTeX string directly
|
|
74
|
+
color-math "$$\frac{d}{dx} x^2 = 2x$$"
|
|
75
|
+
|
|
76
|
+
# Read and color from standard input pipeline
|
|
77
|
+
cat note.md | color-math -
|
|
78
|
+
|
|
79
|
+
# Inspect syntax-colored unified diff without touching disk
|
|
80
|
+
color-math note.md --diff
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## 📋 Cheat Sheet (Command Reference)
|
|
86
|
+
|
|
87
|
+
| Task | Command | Description |
|
|
88
|
+
| :--- | :--- | :--- |
|
|
89
|
+
| **Visual Window** | `color-math --ui` *(or `--gui`)* | Open interactive High-DPI GUI |
|
|
90
|
+
| **Interactive Tour** | `color-math --tutorial` | 2-minute interactive terminal guide |
|
|
91
|
+
| **Preview** | `color-math note.md` | Safe preview (leaves disk untouched) |
|
|
92
|
+
| **Save / Write** | `color-math note.md -w` *(or `-i`)* | Write changes in-place |
|
|
93
|
+
| **Batch Folder** | `color-math notes/ -r -w` | Recursively color directory |
|
|
94
|
+
| **Unified Diff** | `color-math note.md --diff` | Inspect exact line changes (colorized) |
|
|
95
|
+
| **Linter / CI Mode** | `color-math notes/ -r --check` | Exit `0` if clean, `1` if notes need coloring |
|
|
96
|
+
| **Machine JSON** | `color-math notes/ -r --check --json` | Structured JSON output for CI and pipelines |
|
|
97
|
+
| **Stdin Pipeline** | `cat note.md \| color-math -` | Read and color math from standard input |
|
|
98
|
+
| **Curated Themes** | `color-math note.md --theme catppuccin -w` | Select `default`, `catppuccin`, `nord`, or `light` |
|
|
99
|
+
| **Feature Preset** | `color-math note.md --preset minimal -w` | Presets: `all` (default), `minimal` |
|
|
100
|
+
| **Custom Colors** | `color-math note.md -c unit=#73daca -w` | Override any of 12 individual color roles |
|
|
101
|
+
| **Reset Palette** | `color-math --reset-colors` | Restore factory Tokyo Night palette |
|
|
102
|
+
| **Inspect Colors** | `color-math --show-colors` | Display palette, descriptions, & terminal swatches |
|
|
103
|
+
| **Undo / Strip** | `color-math note.md --undo -w` | Strip color wrappers back to plain LaTeX |
|
|
104
|
+
| **Export Config** | `color-math --init-config` | Generate a documented `.colormath.json` |
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## 🧠 Engine Features & Disambiguation
|
|
109
|
+
|
|
110
|
+
Control recognition features with `--preset {all,minimal}` (default: `all`) or individual flags:
|
|
111
|
+
|
|
112
|
+
- **Calculus Differentials (`--differentials`)**: Disambiguates `dx`, `dt`, `d\theta`, and derivatives (`\frac{d}{dx}`, `\frac{\partial \psi}{\partial t}`) while leaving standalone distance variables `$d$` untouched.
|
|
113
|
+
- **Physical Units (`--units`)**: Recognizes metric prefixes and unit compounds (`\mu m`, `m/s`, `kg`, `nm`).
|
|
114
|
+
- **Rainbow Delimiters (`--rainbow-delimiters`)**: Recursively colors nested brackets `()`, `[]`, `{}` by depth to eliminate delimiter blindness.
|
|
115
|
+
- **Quantum Bra-Ket (`--braket`)**: Dirac notation (`|\psi\rangle`, `\langle\phi|`, `\langle\phi|\psi\rangle`).
|
|
116
|
+
- **Dimensionless Groups (`--dimensionless`)**: Recognizes engineering numbers (`Re`, `Ma`, `Pr`, `Nu`).
|
|
117
|
+
- **Semantic Taxonomy (`--taxonomy`)**: Colors constants ($\pi, \hbar, \infty$), Greek parameters ($\alpha, \theta$), and standard functions ($\sin, \cos, \ln$).
|
|
118
|
+
- **Variable Data-Flow (`--variable-data-flow`)**: Deterministically hashes variable names to track variable flow across equations.
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## 📁 Supported File Formats
|
|
123
|
+
|
|
124
|
+
`python-color-math` automatically detects file formats by extension:
|
|
125
|
+
- **Markdown**: `.md`, `.markdown`, `.qmd` (Quarto)
|
|
126
|
+
- **Jupyter Notebooks**: `.ipynb` (transforms only Markdown cells)
|
|
127
|
+
- **Native LaTeX**: `.tex`, `.latex` (adds `\usepackage{xcolor}` compatibility)
|
|
128
|
+
- **Anki Flashcards**: `.tsv`, `.txt` (select via `--format anki`)
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## ↩️ Complete Reversibility (Undo)
|
|
133
|
+
|
|
134
|
+
Never worry about locking your documents into color wrappers:
|
|
135
|
+
```bash
|
|
136
|
+
# Preview what plain LaTeX would look like
|
|
137
|
+
color-math note.md --undo
|
|
138
|
+
|
|
139
|
+
# Restore plain LaTeX back to disk
|
|
140
|
+
color-math note.md --undo -w
|
|
141
|
+
|
|
142
|
+
# Strip colors from an entire vault
|
|
143
|
+
color-math notes/ -r --undo -w
|
|
144
|
+
```
|
|
145
|
+
*Undo cleanly removes generated `\textcolor{...}{...}` and compatible legacy `\color{...}{...}` wrappers.*
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## 🐚 Shell Autocompletion
|
|
150
|
+
|
|
151
|
+
Generate fast, native completions with full support for all flags, themes, presets, and file formats:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
# Bash
|
|
155
|
+
color-math --generate-completion bash >> ~/.bash_completion
|
|
156
|
+
|
|
157
|
+
# Zsh
|
|
158
|
+
color-math --generate-completion zsh > ~/.zsh/completion/_color-math
|
|
159
|
+
|
|
160
|
+
# Fish
|
|
161
|
+
color-math --generate-completion fish > ~/.config/fish/completions/color-math.fish
|
|
162
|
+
|
|
163
|
+
# PowerShell
|
|
164
|
+
color-math --generate-completion powershell | Out-String | Invoke-Expression
|
|
165
|
+
# Or persist to your $PROFILE:
|
|
166
|
+
Add-Content $PROFILE "`ncolor-math --generate-completion powershell | Out-String | Invoke-Expression"
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## 🪝 Pre-commit Integration
|
|
172
|
+
|
|
173
|
+
Integrate `color-math` into your git workflow using [pre-commit](https://pre-commit.com):
|
|
174
|
+
|
|
175
|
+
```yaml
|
|
176
|
+
repos:
|
|
177
|
+
- repo: https://github.com/36ty-blip/color-math
|
|
178
|
+
rev: v0.2.0
|
|
179
|
+
hooks:
|
|
180
|
+
# Formatter: colorizes modified Markdown, LaTeX, and Jupyter files in-place
|
|
181
|
+
- id: color-math
|
|
182
|
+
# Linter: verifies math formatting without modifying files (fails if uncolored)
|
|
183
|
+
# - id: color-math-check
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## ⚙️ Configuration & Standards
|
|
189
|
+
|
|
190
|
+
`python-color-math` adheres to modern CLI standards ([clig.dev](https://clig.dev/)):
|
|
191
|
+
- **Config Hierarchy**: `--config <file>` > `./.colormath.json` (project local) > Global user config (`%APPDATA%\color-math\config.json` on Windows or `~/.config/color-math/config.json` on Linux/macOS) > Factory defaults.
|
|
192
|
+
- **Color Standards**: Honors `NO_COLOR` ([no-color.org](https://no-color.org)), `FORCE_COLOR`, and `TERM=dumb`.
|
|
193
|
+
- **CI / Pre-commit**: Combine `--check --json` for structured reporting in automated pipelines.
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## 🤝 Obsidian Companion Plugin
|
|
198
|
+
|
|
199
|
+
Looking for dynamic real-time equation coloring inside Obsidian without modifying notes on disk? Check out the sister plugin:
|
|
200
|
+
👉 [**Obsidian Color Math**](https://github.com/36ty-blip/obsidian-color-math) *(Pure TypeScript, runs natively on Obsidian Desktop & Mobile).*
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## 📄 License
|
|
205
|
+
|
|
206
|
+
Released under the [MIT License](LICENSE).
|
|
@@ -5,4 +5,13 @@ from .config import ColorMathOptions
|
|
|
5
5
|
from .converters.block import convert_text
|
|
6
6
|
from .undo import uncolor_text
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
__version__ = "0.2.0"
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"__version__",
|
|
12
|
+
"ColorMathOptions",
|
|
13
|
+
"convert_text",
|
|
14
|
+
"detect_format",
|
|
15
|
+
"transform_document",
|
|
16
|
+
"uncolor_text",
|
|
17
|
+
]
|
|
@@ -6,6 +6,7 @@ import json
|
|
|
6
6
|
import re
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
|
|
9
|
+
from .config import ColorMathOptions
|
|
9
10
|
from .converters.block import convert_math_block, convert_text
|
|
10
11
|
from .undo import uncolor_fragment, uncolor_text
|
|
11
12
|
from .utils.latex_helpers import read_comment_end, read_verb_end
|
|
@@ -49,26 +50,42 @@ def detect_format(path: Path | None, requested: str = "auto") -> str:
|
|
|
49
50
|
return "markdown"
|
|
50
51
|
|
|
51
52
|
|
|
52
|
-
def transform_document(
|
|
53
|
+
def transform_document(
|
|
54
|
+
text: str,
|
|
55
|
+
format_name: str,
|
|
56
|
+
undo: bool = False,
|
|
57
|
+
palette: dict[str, str] | None = None,
|
|
58
|
+
options: ColorMathOptions | None = None,
|
|
59
|
+
) -> str:
|
|
53
60
|
if format_name == "markdown":
|
|
54
|
-
return uncolor_text(text) if undo else convert_text(text)
|
|
61
|
+
return uncolor_text(text) if undo else convert_text(text, palette=palette, options=options)
|
|
55
62
|
if format_name == "jupyter":
|
|
56
|
-
return _transform_notebook(text, undo)
|
|
63
|
+
return _transform_notebook(text, undo, palette=palette, options=options)
|
|
57
64
|
if format_name == "anki":
|
|
58
|
-
return _transform_delimited(text, ANKI_DELIMITERS, undo)
|
|
65
|
+
return _transform_delimited(text, ANKI_DELIMITERS, undo, palette=palette, options=options)
|
|
59
66
|
if format_name == "tex":
|
|
60
|
-
return _transform_tex(text, undo)
|
|
67
|
+
return _transform_tex(text, undo, palette=palette, options=options)
|
|
61
68
|
raise AdapterError(f"unsupported format: {format_name}")
|
|
62
69
|
|
|
63
70
|
|
|
64
|
-
def _transform_fragment(
|
|
71
|
+
def _transform_fragment(
|
|
72
|
+
text: str,
|
|
73
|
+
undo: bool,
|
|
74
|
+
palette: dict[str, str] | None = None,
|
|
75
|
+
options: ColorMathOptions | None = None,
|
|
76
|
+
) -> str:
|
|
65
77
|
if undo:
|
|
66
78
|
return uncolor_fragment(text)
|
|
67
|
-
converted = convert_math_block(f"$${text}$$")
|
|
79
|
+
converted = convert_math_block(f"$${text}$$", palette=palette, options=options)
|
|
68
80
|
return converted[2:-2]
|
|
69
81
|
|
|
70
82
|
|
|
71
|
-
def _transform_notebook(
|
|
83
|
+
def _transform_notebook(
|
|
84
|
+
text: str,
|
|
85
|
+
undo: bool,
|
|
86
|
+
palette: dict[str, str] | None = None,
|
|
87
|
+
options: ColorMathOptions | None = None,
|
|
88
|
+
) -> str:
|
|
72
89
|
try:
|
|
73
90
|
notebook = json.loads(text)
|
|
74
91
|
except json.JSONDecodeError as error:
|
|
@@ -89,7 +106,7 @@ def _transform_notebook(text: str, undo: bool) -> str:
|
|
|
89
106
|
else:
|
|
90
107
|
raise AdapterError(f"markdown cell {index + 1} has an invalid source")
|
|
91
108
|
|
|
92
|
-
converted = uncolor_text(joined) if undo else convert_text(joined)
|
|
109
|
+
converted = uncolor_text(joined) if undo else convert_text(joined, palette=palette, options=options)
|
|
93
110
|
if converted == joined:
|
|
94
111
|
continue
|
|
95
112
|
cell["source"] = (
|
|
@@ -145,6 +162,8 @@ def _transform_delimited(
|
|
|
145
162
|
text: str,
|
|
146
163
|
delimiters: tuple[tuple[str, str], ...],
|
|
147
164
|
undo: bool,
|
|
165
|
+
palette: dict[str, str] | None = None,
|
|
166
|
+
options: ColorMathOptions | None = None,
|
|
148
167
|
) -> str:
|
|
149
168
|
output: list[str] = []
|
|
150
169
|
index = 0
|
|
@@ -154,7 +173,7 @@ def _transform_delimited(
|
|
|
154
173
|
if end < 0:
|
|
155
174
|
break
|
|
156
175
|
output.append(text[index:start + len(opening)])
|
|
157
|
-
output.append(_transform_fragment(text[start + len(opening):end], undo))
|
|
176
|
+
output.append(_transform_fragment(text[start + len(opening):end], undo, palette=palette, options=options))
|
|
158
177
|
output.append(closing)
|
|
159
178
|
index = end + len(closing)
|
|
160
179
|
output.append(text[index:])
|
|
@@ -190,7 +209,12 @@ def _find_dollar(text: str, start: int, width: int) -> int:
|
|
|
190
209
|
return -1
|
|
191
210
|
|
|
192
211
|
|
|
193
|
-
def _transform_tex_math(
|
|
212
|
+
def _transform_tex_math(
|
|
213
|
+
text: str,
|
|
214
|
+
undo: bool,
|
|
215
|
+
palette: dict[str, str] | None = None,
|
|
216
|
+
options: ColorMathOptions | None = None,
|
|
217
|
+
) -> str:
|
|
194
218
|
output: list[str] = []
|
|
195
219
|
index = 0
|
|
196
220
|
while index < len(text):
|
|
@@ -220,7 +244,7 @@ def _transform_tex_math(text: str, undo: bool) -> str:
|
|
|
220
244
|
continue
|
|
221
245
|
if end_start >= 0 and name in MATH_ENVIRONMENTS:
|
|
222
246
|
end = end_start + len(closing)
|
|
223
|
-
output.append(_transform_fragment(text[index:end], undo))
|
|
247
|
+
output.append(_transform_fragment(text[index:end], undo, palette=palette, options=options))
|
|
224
248
|
index = end
|
|
225
249
|
continue
|
|
226
250
|
|
|
@@ -233,7 +257,7 @@ def _transform_tex_math(text: str, undo: bool) -> str:
|
|
|
233
257
|
end_start = _find_active(text, closing, index + len(opening))
|
|
234
258
|
if end_start >= 0:
|
|
235
259
|
output.append(opening)
|
|
236
|
-
output.append(_transform_fragment(text[index + len(opening):end_start], undo))
|
|
260
|
+
output.append(_transform_fragment(text[index + len(opening):end_start], undo, palette=palette, options=options))
|
|
237
261
|
output.append(closing)
|
|
238
262
|
index = end_start + len(closing)
|
|
239
263
|
continue
|
|
@@ -244,7 +268,7 @@ def _transform_tex_math(text: str, undo: bool) -> str:
|
|
|
244
268
|
if end_start >= 0:
|
|
245
269
|
delimiter = "$" * width
|
|
246
270
|
output.append(delimiter)
|
|
247
|
-
output.append(_transform_fragment(text[index + width:end_start], undo))
|
|
271
|
+
output.append(_transform_fragment(text[index + width:end_start], undo, palette=palette, options=options))
|
|
248
272
|
output.append(delimiter)
|
|
249
273
|
index = end_start + width
|
|
250
274
|
continue
|
|
@@ -282,7 +306,12 @@ def _native_support(text: str) -> str:
|
|
|
282
306
|
return translated[:insertion] + block + translated[insertion:]
|
|
283
307
|
|
|
284
308
|
|
|
285
|
-
def _transform_tex(
|
|
309
|
+
def _transform_tex(
|
|
310
|
+
text: str,
|
|
311
|
+
undo: bool,
|
|
312
|
+
palette: dict[str, str] | None = None,
|
|
313
|
+
options: ColorMathOptions | None = None,
|
|
314
|
+
) -> str:
|
|
286
315
|
if undo:
|
|
287
|
-
return _transform_tex_math(NATIVE_BLOCK_RE.sub("", text), True)
|
|
288
|
-
return _native_support(_transform_tex_math(text, False))
|
|
316
|
+
return _transform_tex_math(NATIVE_BLOCK_RE.sub("", text), True, palette=palette, options=options)
|
|
317
|
+
return _native_support(_transform_tex_math(text, False, palette=palette, options=options))
|