python-color-math 0.1.0__py3-none-any.whl → 0.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
color_math/__init__.py CHANGED
@@ -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
- __all__ = ["ColorMathOptions", "convert_text", "detect_format", "transform_document", "uncolor_text"]
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
+ ]
color_math/adapters.py CHANGED
@@ -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(text: str, format_name: str, undo: bool = False) -> str:
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(text: str, undo: bool) -> str:
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(text: str, undo: bool) -> str:
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(text: str, undo: bool) -> str:
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(text: str, undo: bool) -> str:
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))
@@ -0,0 +1,272 @@
1
+ """Shell autocompletion script generators for color-math."""
2
+
3
+ from __future__ import annotations
4
+
5
+ SHELLS = ["bash", "zsh", "fish", "powershell"]
6
+
7
+ THEME_CHOICES = "default catppuccin nord light"
8
+ PRESET_CHOICES = "all minimal extended"
9
+ FORMAT_CHOICES = "auto markdown jupyter anki tex"
10
+ SHELL_CHOICES = "bash zsh fish powershell"
11
+
12
+ ALL_FLAGS = [
13
+ "-h", "--help",
14
+ "-i", "--in-place",
15
+ "-w", "--write",
16
+ "-f", "--file",
17
+ "-o", "--output",
18
+ "-r", "--recursive",
19
+ "--exclude",
20
+ "--diff",
21
+ "--check",
22
+ "--dry-run",
23
+ "--json",
24
+ "--parse",
25
+ "--format",
26
+ "--theme",
27
+ "-c", "--color",
28
+ "--main-color",
29
+ "--show-colors", "--show-palette",
30
+ "--reset-colors", "--reset-palette",
31
+ "--reset-config",
32
+ "--init-config",
33
+ "--config",
34
+ "--preset",
35
+ "--taxonomy", "--no-taxonomy",
36
+ "--rainbow-delimiters", "--no-rainbow-delimiters",
37
+ "--variable-data-flow", "--no-variable-data-flow",
38
+ "--units", "--no-units",
39
+ "--differentials", "--no-differentials",
40
+ "--braket", "--no-braket",
41
+ "--dimensionless", "--no-dimensionless",
42
+ "--undo",
43
+ "--ui", "--gui",
44
+ "--tutorial",
45
+ "-V", "--version",
46
+ "-v", "--verbose",
47
+ "-q", "--quiet",
48
+ "--self-test",
49
+ "--update-generated",
50
+ "--generate-completion",
51
+ ]
52
+
53
+
54
+ def generate_bash() -> str:
55
+ opts = " ".join(ALL_FLAGS)
56
+ return f"""# Bash completion for color-math / python-color-math
57
+ _color_math_completion() {{
58
+ local cur prev
59
+ COMPREPLY=()
60
+ cur="${{COMP_WORDS[COMP_CWORD]}}"
61
+ prev="${{COMP_WORDS[COMP_CWORD-1]}}"
62
+
63
+ case "${{prev}}" in
64
+ --theme)
65
+ COMPREPLY=( $(compgen -W "{THEME_CHOICES}" -- "${{cur}}") )
66
+ return 0
67
+ ;;
68
+ --preset)
69
+ COMPREPLY=( $(compgen -W "{PRESET_CHOICES}" -- "${{cur}}") )
70
+ return 0
71
+ ;;
72
+ --format)
73
+ COMPREPLY=( $(compgen -W "{FORMAT_CHOICES}" -- "${{cur}}") )
74
+ return 0
75
+ ;;
76
+ --generate-completion)
77
+ COMPREPLY=( $(compgen -W "{SHELL_CHOICES}" -- "${{cur}}") )
78
+ return 0
79
+ ;;
80
+ -o|--output|--config|--init-config)
81
+ COMPREPLY=( $(compgen -f -- "${{cur}}") )
82
+ return 0
83
+ ;;
84
+ esac
85
+
86
+ if [[ "${{cur}}" == -* ]]; then
87
+ COMPREPLY=( $(compgen -W "{opts}" -- "${{cur}}") )
88
+ return 0
89
+ fi
90
+
91
+ COMPREPLY=( $(compgen -f -- "${{cur}}") )
92
+ }}
93
+
94
+ complete -F _color_math_completion color-math
95
+ complete -F _color_math_completion python-color-math
96
+ """
97
+
98
+
99
+ def generate_zsh() -> str:
100
+ return f"""#compdef color-math python-color-math
101
+ # Zsh completion for color-math / python-color-math
102
+
103
+ _color_math() {{
104
+ local -a themes presets formats shells
105
+ themes=({THEME_CHOICES})
106
+ presets=({PRESET_CHOICES})
107
+ formats=({FORMAT_CHOICES})
108
+ shells=({SHELL_CHOICES})
109
+
110
+ _arguments -s -S \\
111
+ '(-h --help)'{{-h,--help}}'[Show help message]' \\
112
+ '(-i --in-place -w --write)'{{-i,--in-place,-w,--write}}'[Write converted text back to file(s)]' \\
113
+ '(-f --file)'{{-f,--file}}'[Treat target explicitly as file]' \\
114
+ '(-o --output)'{{-o,--output}}'[Destination file]:file:_files' \\
115
+ '(-r --recursive)'{{-r,--recursive}}'[Recursively scan directories]' \\
116
+ '*--exclude[Glob pattern to exclude]:pattern:' \\
117
+ '--diff[Display syntax-colored unified diff]' \\
118
+ '--check[Linter/CI check mode]' \\
119
+ '--dry-run[Report files that would change]' \\
120
+ '--json[Output results in JSON format]' \\
121
+ '--parse[Inspect nested function AST]' \\
122
+ '--format[Input format]:format:($formats)' \\
123
+ '--theme[Curated theme preset]:theme:($themes)' \\
124
+ '*-c[Override color role]:color:' \\
125
+ '*--color[Override color role]:color:' \\
126
+ '--main-color[Override main function color]:hex:' \\
127
+ '(--show-colors --show-palette)'{{--show-colors,--show-palette}}'[Print active palette]' \\
128
+ '(--reset-colors --reset-palette)'{{--reset-colors,--reset-palette}}'[Restore factory defaults]' \\
129
+ '--reset-config[Reset local .colormath.json]' \\
130
+ '--init-config[Generate config template]:file:_files' \\
131
+ '--config[Custom config file]:file:_files' \\
132
+ '--preset[Feature preset]:preset:($presets)' \\
133
+ '--taxonomy[Enable taxonomy]' \\
134
+ '--no-taxonomy[Disable taxonomy]' \\
135
+ '--rainbow-delimiters[Enable rainbow delimiters]' \\
136
+ '--no-rainbow-delimiters[Disable rainbow delimiters]' \\
137
+ '--variable-data-flow[Enable variable data-flow]' \\
138
+ '--no-variable-data-flow[Disable variable data-flow]' \\
139
+ '--units[Enable unit disambiguation]' \\
140
+ '--no-units[Disable unit disambiguation]' \\
141
+ '--differentials[Enable differentials]' \\
142
+ '--no-differentials[Disable differentials]' \\
143
+ '--braket[Enable bra-ket notation]' \\
144
+ '--no-braket[Disable bra-ket notation]' \\
145
+ '--dimensionless[Enable dimensionless groups]' \\
146
+ '--no-dimensionless[Disable dimensionless groups]' \\
147
+ '--undo[Strip color wrappers back to plain LaTeX]' \\
148
+ '(--ui --gui)'{{--ui,--gui}}'[Open graphical window]' \\
149
+ '--tutorial[Launch terminal tutorial]' \\
150
+ '(-V --version)'{{-V,--version}}'[Show version]' \\
151
+ '(-v --verbose)'{{-v,--verbose}}'[Verbose progress]' \\
152
+ '(-q --quiet)'{{-q,--quiet}}'[Suppress output]' \\
153
+ '--self-test[Run self-test suite]' \\
154
+ '--generate-completion[Generate shell completion]:shell:($shells)' \\
155
+ '*:file:_files'
156
+ }}
157
+
158
+ compdef _color_math color-math python-color-math
159
+ """
160
+
161
+
162
+ def generate_fish() -> str:
163
+ return f"""# Fish completion for color-math / python-color-math
164
+
165
+ for cmd in color-math python-color-math
166
+ complete -c $cmd -s h -l help -d "Show help message"
167
+ complete -c $cmd -s w -s i -l write -l in-place -d "Write converted text back to file(s)"
168
+ complete -c $cmd -s f -l file -d "Treat target explicitly as file"
169
+ complete -c $cmd -s o -l output -F -d "Destination file"
170
+ complete -c $cmd -s r -l recursive -d "Recursively scan directories"
171
+ complete -c $cmd -l exclude -d "Glob pattern to exclude"
172
+ complete -c $cmd -l diff -d "Display syntax-colored unified diff"
173
+ complete -c $cmd -l check -d "Linter/CI check mode"
174
+ complete -c $cmd -l dry-run -d "Report files that would change"
175
+ complete -c $cmd -l json -d "Output results in JSON format"
176
+ complete -c $cmd -l parse -d "Inspect nested function AST"
177
+ complete -c $cmd -l format -x -a "{FORMAT_CHOICES}" -d "Input format"
178
+ complete -c $cmd -l theme -x -a "{THEME_CHOICES}" -d "Curated theme preset"
179
+ complete -c $cmd -s c -l color -d "Override color role"
180
+ complete -c $cmd -l main-color -d "Override main function color"
181
+ complete -c $cmd -l show-colors -l show-palette -d "Display active palette"
182
+ complete -c $cmd -l reset-colors -l reset-palette -d "Restore factory defaults"
183
+ complete -c $cmd -l reset-config -d "Reset local config"
184
+ complete -c $cmd -l init-config -F -d "Generate config template"
185
+ complete -c $cmd -l config -F -d "Custom config path"
186
+ complete -c $cmd -l preset -x -a "{PRESET_CHOICES}" -d "Feature preset"
187
+ complete -c $cmd -l taxonomy -d "Enable taxonomy"
188
+ complete -c $cmd -l no-taxonomy -d "Disable taxonomy"
189
+ complete -c $cmd -l rainbow-delimiters -d "Enable rainbow delimiters"
190
+ complete -c $cmd -l no-rainbow-delimiters -d "Disable rainbow delimiters"
191
+ complete -c $cmd -l variable-data-flow -d "Enable variable data-flow"
192
+ complete -c $cmd -l no-variable-data-flow -d "Disable variable data-flow"
193
+ complete -c $cmd -l units -d "Enable unit disambiguation"
194
+ complete -c $cmd -l no-units -d "Disable unit disambiguation"
195
+ complete -c $cmd -l differentials -d "Enable differentials"
196
+ complete -c $cmd -l no-differentials -d "Disable differentials"
197
+ complete -c $cmd -l braket -d "Enable bra-ket notation"
198
+ complete -c $cmd -l no-braket -d "Disable bra-ket notation"
199
+ complete -c $cmd -l dimensionless -d "Enable dimensionless groups"
200
+ complete -c $cmd -l no-dimensionless -d "Disable dimensionless groups"
201
+ complete -c $cmd -l undo -d "Strip color wrappers back to plain LaTeX"
202
+ complete -c $cmd -l ui -l gui -d "Open graphical window"
203
+ complete -c $cmd -l tutorial -d "Launch terminal tutorial"
204
+ complete -c $cmd -s V -l version -d "Show version"
205
+ complete -c $cmd -s v -l verbose -d "Verbose progress"
206
+ complete -c $cmd -s q -l quiet -d "Suppress output"
207
+ complete -c $cmd -l self-test -d "Run self-test suite"
208
+ complete -c $cmd -l generate-completion -x -a "{SHELL_CHOICES}" -d "Generate completion script"
209
+ end
210
+ """
211
+
212
+
213
+ def generate_powershell() -> str:
214
+ flag_list = "\n ".join(f'"{f}",' for f in ALL_FLAGS)
215
+ return f"""# PowerShell completion for color-math / python-color-math
216
+ Register-ArgumentCompleter -Native -CommandName color-math, python-color-math -ScriptBlock {{
217
+ param($wordToComplete, $commandAst, $cursorPosition)
218
+
219
+ $options = @(
220
+ {flag_list}
221
+ )
222
+
223
+ $elements = $commandAst.Elements
224
+ $prev = if ($elements.Count -gt 1) {{ $elements[$elements.Count - 1].Extent.Text }} else {{ "" }}
225
+
226
+ if ($prev -eq "--theme") {{
227
+ @("{THEME_CHOICES}".Split(" ")) | Where-Object {{ $_ -like "$wordToComplete*" }} | ForEach-Object {{
228
+ [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
229
+ }}
230
+ return
231
+ }}
232
+ if ($prev -eq "--preset") {{
233
+ @("{PRESET_CHOICES}".Split(" ")) | Where-Object {{ $_ -like "$wordToComplete*" }} | ForEach-Object {{
234
+ [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
235
+ }}
236
+ return
237
+ }}
238
+ if ($prev -eq "--format") {{
239
+ @("{FORMAT_CHOICES}".Split(" ")) | Where-Object {{ $_ -like "$wordToComplete*" }} | ForEach-Object {{
240
+ [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
241
+ }}
242
+ return
243
+ }}
244
+ if ($prev -eq "--generate-completion") {{
245
+ @("{SHELL_CHOICES}".Split(" ")) | Where-Object {{ $_ -like "$wordToComplete*" }} | ForEach-Object {{
246
+ [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
247
+ }}
248
+ return
249
+ }}
250
+
251
+ $options | Where-Object {{ $_ -like "$wordToComplete*" }} | ForEach-Object {{
252
+ [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterName', $_)
253
+ }}
254
+ }}
255
+ """
256
+
257
+
258
+ def get_completion_script(shell: str) -> str:
259
+ """Return the completion script for the requested shell."""
260
+ shell_lower = shell.strip().lower()
261
+ if shell_lower == "bash":
262
+ return generate_bash()
263
+ elif shell_lower == "zsh":
264
+ return generate_zsh()
265
+ elif shell_lower == "fish":
266
+ return generate_fish()
267
+ elif shell_lower == "powershell":
268
+ return generate_powershell()
269
+ raise ValueError(f"Unsupported shell: '{shell}'. Choose from: {', '.join(SHELLS)}")
270
+
271
+
272
+ generate_completion = get_completion_script