python-color-math 0.2.17__tar.gz → 0.2.19__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.
Files changed (80) hide show
  1. {python_color_math-0.2.17/python_color_math.egg-info → python_color_math-0.2.19}/PKG-INFO +1 -1
  2. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/__init__.py +12 -2
  3. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/config.py +131 -22
  4. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/ipython.py +49 -18
  5. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/main.py +30 -0
  6. {python_color_math-0.2.17 → python_color_math-0.2.19}/pyproject.toml +1 -1
  7. {python_color_math-0.2.17 → python_color_math-0.2.19/python_color_math.egg-info}/PKG-INFO +1 -1
  8. {python_color_math-0.2.17 → python_color_math-0.2.19}/.pre-commit-hooks.yaml +0 -0
  9. {python_color_math-0.2.17 → python_color_math-0.2.19}/LICENSE +0 -0
  10. {python_color_math-0.2.17 → python_color_math-0.2.19}/MANIFEST.in +0 -0
  11. {python_color_math-0.2.17 → python_color_math-0.2.19}/README.md +0 -0
  12. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/__main__.py +0 -0
  13. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/adapters.py +0 -0
  14. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/colormath.default.json +0 -0
  15. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/completions.py +0 -0
  16. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/converters/__init__.py +0 -0
  17. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/converters/align.py +0 -0
  18. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/converters/block.py +0 -0
  19. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/converters/derivative.py +0 -0
  20. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/converters/equation.py +0 -0
  21. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/converters/generic.py +0 -0
  22. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/converters/integral.py +0 -0
  23. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/converters/limit.py +0 -0
  24. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/converters/matrix.py +0 -0
  25. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/converters/semantic.py +0 -0
  26. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/converters/unicode_converter.py +0 -0
  27. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/custom_definitions.py +0 -0
  28. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/gui.py +0 -0
  29. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/io.py +0 -0
  30. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/jupyter.py +0 -0
  31. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/mcp.py +0 -0
  32. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/mcp_server.py +0 -0
  33. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/parsers/__init__.py +0 -0
  34. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/parsers/alignment.py +0 -0
  35. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/parsers/braket.py +0 -0
  36. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/parsers/constants.py +0 -0
  37. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/parsers/delimiters.py +0 -0
  38. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/parsers/differentials.py +0 -0
  39. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/parsers/dimensionless.py +0 -0
  40. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/parsers/frontmatter.py +0 -0
  41. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/parsers/latex_spans.py +0 -0
  42. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/parsers/markdown_scanner.py +0 -0
  43. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/parsers/math_parser.py +0 -0
  44. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/parsers/physics.py +0 -0
  45. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/parsers/scanner.py +0 -0
  46. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/parsers/taxonomy.py +0 -0
  47. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/parsers/units.py +0 -0
  48. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/parsers/variable_hash.py +0 -0
  49. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/py.typed +0 -0
  50. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/self_test.py +0 -0
  51. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/tutorial.py +0 -0
  52. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/undo.py +0 -0
  53. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/unicode.py +0 -0
  54. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/utils/__init__.py +0 -0
  55. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/utils/coloring.py +0 -0
  56. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/utils/latex_helpers.py +0 -0
  57. {python_color_math-0.2.17 → python_color_math-0.2.19}/color_math/utils/spans.py +0 -0
  58. {python_color_math-0.2.17 → python_color_math-0.2.19}/python_color_math/__init__.py +0 -0
  59. {python_color_math-0.2.17 → python_color_math-0.2.19}/python_color_math/__main__.py +0 -0
  60. {python_color_math-0.2.17 → python_color_math-0.2.19}/python_color_math.egg-info/SOURCES.txt +0 -0
  61. {python_color_math-0.2.17 → python_color_math-0.2.19}/python_color_math.egg-info/dependency_links.txt +0 -0
  62. {python_color_math-0.2.17 → python_color_math-0.2.19}/python_color_math.egg-info/entry_points.txt +0 -0
  63. {python_color_math-0.2.17 → python_color_math-0.2.19}/python_color_math.egg-info/requires.txt +0 -0
  64. {python_color_math-0.2.17 → python_color_math-0.2.19}/python_color_math.egg-info/top_level.txt +0 -0
  65. {python_color_math-0.2.17 → python_color_math-0.2.19}/setup.cfg +0 -0
  66. {python_color_math-0.2.17 → python_color_math-0.2.19}/tests/test_adversarial.py +0 -0
  67. {python_color_math-0.2.17 → python_color_math-0.2.19}/tests/test_cli.py +0 -0
  68. {python_color_math-0.2.17 → python_color_math-0.2.19}/tests/test_config_tolerance.py +0 -0
  69. {python_color_math-0.2.17 → python_color_math-0.2.19}/tests/test_custom_definitions.py +0 -0
  70. {python_color_math-0.2.17 → python_color_math-0.2.19}/tests/test_extreme_adversarial.py +0 -0
  71. {python_color_math-0.2.17 → python_color_math-0.2.19}/tests/test_features.py +0 -0
  72. {python_color_math-0.2.17 → python_color_math-0.2.19}/tests/test_frontmatter.py +0 -0
  73. {python_color_math-0.2.17 → python_color_math-0.2.19}/tests/test_fuzz.py +0 -0
  74. {python_color_math-0.2.17 → python_color_math-0.2.19}/tests/test_gui.py +0 -0
  75. {python_color_math-0.2.17 → python_color_math-0.2.19}/tests/test_ipython.py +0 -0
  76. {python_color_math-0.2.17 → python_color_math-0.2.19}/tests/test_mcp_hardcore.py +0 -0
  77. {python_color_math-0.2.17 → python_color_math-0.2.19}/tests/test_mcp_server.py +0 -0
  78. {python_color_math-0.2.17 → python_color_math-0.2.19}/tests/test_physics.py +0 -0
  79. {python_color_math-0.2.17 → python_color_math-0.2.19}/tests/test_unicode.py +0 -0
  80. {python_color_math-0.2.17 → python_color_math-0.2.19}/tests/test_unicode_converter.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-color-math
3
- Version: 0.2.17
3
+ Version: 0.2.19
4
4
  Summary: A fast, local semantic LaTeX colorizer for Markdown, Jupyter, and LaTeX math equations.
5
5
  Author: Aditya
6
6
  License: MIT License
@@ -1,13 +1,19 @@
1
1
  """Public helpers for converting Obsidian LaTeX color markup."""
2
2
 
3
3
  from .adapters import detect_format, transform_document
4
- from .config import ColorMathOptions
4
+ from .config import (
5
+ ColorMathOptions,
6
+ find_config_path,
7
+ get_venv_config_path,
8
+ init_config,
9
+ open_config_folder,
10
+ )
5
11
  from .converters.block import convert_text
6
12
  from .undo import uncolor_text
7
13
 
8
14
  from .ipython import ColorMath, colormath, load_ipython_extension, unload_ipython_extension
9
15
 
10
- __version__ = "0.2.17"
16
+ __version__ = "0.2.19"
11
17
 
12
18
  __all__ = [
13
19
  "__version__",
@@ -16,7 +22,11 @@ __all__ = [
16
22
  "colormath",
17
23
  "convert_text",
18
24
  "detect_format",
25
+ "find_config_path",
26
+ "get_venv_config_path",
27
+ "init_config",
19
28
  "load_ipython_extension",
29
+ "open_config_folder",
20
30
  "transform_document",
21
31
  "uncolor_text",
22
32
  "unload_ipython_extension",
@@ -714,22 +714,137 @@ def default_config_dict() -> dict[str, object]:
714
714
  }
715
715
 
716
716
 
717
- def get_global_config_path() -> Path | None:
718
- """Return platform-appropriate XDG / AppData user configuration path."""
719
- if sys.platform == "win32":
720
- app_data = os.environ.get("APPDATA")
721
- if app_data:
722
- return Path(app_data) / "color-math" / "config.json"
723
- else:
724
- xdg_config = os.environ.get("XDG_CONFIG_HOME")
725
- if xdg_config:
726
- return Path(xdg_config) / "color-math" / "config.json"
727
- home = os.environ.get("HOME")
728
- if home:
729
- return Path(home) / ".config" / "color-math" / "config.json"
717
+ def get_user_home_config_path() -> Path:
718
+ """Return platform-standard user-level config path (~/.config/color-math/config.json)."""
719
+ xdg_config = os.environ.get("XDG_CONFIG_HOME")
720
+ if xdg_config:
721
+ return Path(xdg_config) / "color-math" / "config.json"
722
+ return Path.home() / ".config" / "color-math" / "config.json"
723
+
724
+
725
+ def get_global_config_path() -> Path:
726
+ """Backward-compatible alias for user home configuration path."""
727
+ return get_user_home_config_path()
728
+
729
+
730
+ def find_project_config_path(start_dir: Path | None = None) -> Path | None:
731
+ """Search for .colormath.json in start_dir and walk up parent directories."""
732
+ curr = (start_dir or Path.cwd()).resolve()
733
+ for parent in [curr, *curr.parents]:
734
+ candidate = parent / ".colormath.json"
735
+ if candidate.exists() and candidate.is_file():
736
+ return candidate
737
+ if (parent / ".git").exists():
738
+ break
730
739
  return None
731
740
 
732
741
 
742
+ def get_venv_config_path() -> Path | None:
743
+ """Return path to .colormath.json inside active virtual environment, if any."""
744
+ if sys.prefix != sys.base_prefix or "VIRTUAL_ENV" in os.environ:
745
+ venv_root = Path(os.environ.get("VIRTUAL_ENV", sys.prefix))
746
+ return venv_root / ".colormath.json"
747
+ return None
748
+
749
+
750
+ def find_config_path(start_dir: Path | None = None) -> tuple[Path | None, str]:
751
+ """Resolve active configuration path in order of precedence:
752
+ 1. Project hierarchy (.colormath.json in current or parent dirs)
753
+ 2. Active virtual environment (.colormath.json in sys.prefix or $VIRTUAL_ENV)
754
+ 3. User home config (~/.config/color-math/config.json)
755
+
756
+ Returns (path_or_none, scope_name).
757
+ """
758
+ proj = find_project_config_path(start_dir)
759
+ if proj is not None:
760
+ return proj, "project"
761
+
762
+ venv_cfg = get_venv_config_path()
763
+ if venv_cfg is not None and venv_cfg.exists():
764
+ return venv_cfg, "venv"
765
+
766
+ home_cfg = get_user_home_config_path()
767
+ if home_cfg.exists():
768
+ return home_cfg, "home"
769
+
770
+ return None, "default"
771
+
772
+
773
+ def init_config(scope: str = "project", target_dir: Path | None = None) -> Path:
774
+ """Initialize a new .colormath.json configuration file.
775
+
776
+ Scopes:
777
+ - 'project': in target_dir or current working directory (isolated per project)
778
+ - 'venv': inside the active virtual environment (.venv)
779
+ - 'home': in user home (~/.config/color-math/config.json)
780
+ """
781
+ if scope == "venv":
782
+ venv_cfg = get_venv_config_path()
783
+ if venv_cfg is None:
784
+ raise RuntimeError("No active virtual environment detected to initialize config in.")
785
+ path = venv_cfg
786
+ elif scope == "home":
787
+ path = get_user_home_config_path()
788
+ else: # project
789
+ directory = (target_dir or Path.cwd()).resolve()
790
+ path = directory / ".colormath.json"
791
+
792
+ path.parent.mkdir(parents=True, exist_ok=True)
793
+ save_default_config(path)
794
+ return path
795
+
796
+
797
+ def ensure_global_config_exists() -> Path | None:
798
+ """Legacy helper maintained for backward compatibility."""
799
+ path = get_user_home_config_path()
800
+ if not path.exists():
801
+ try:
802
+ path.parent.mkdir(parents=True, exist_ok=True)
803
+ save_default_config(path)
804
+ except OSError:
805
+ pass
806
+ return path
807
+
808
+
809
+ def open_config_folder(path: Path | None = None, scope: str = "project") -> tuple[bool, Path]:
810
+ """Open the configuration file or folder in the operating system's default application."""
811
+ target = path
812
+ if target is None:
813
+ found, _ = find_config_path()
814
+ if found is not None:
815
+ target = found
816
+ else:
817
+ target = init_config(scope=scope)
818
+
819
+ if not target.exists():
820
+ try:
821
+ target.parent.mkdir(parents=True, exist_ok=True)
822
+ save_default_config(target)
823
+ except OSError:
824
+ pass
825
+
826
+ try:
827
+ if sys.platform == "win32":
828
+ os.startfile(target)
829
+ return True, target
830
+ elif sys.platform == "darwin":
831
+ import subprocess
832
+ subprocess.run(["open", str(target)], check=False)
833
+ return True, target
834
+ else:
835
+ import subprocess
836
+ subprocess.run(["xdg-open", str(target)], check=False)
837
+ return True, target
838
+ except Exception:
839
+ try:
840
+ if sys.platform == "win32":
841
+ os.startfile(target.parent)
842
+ return True, target.parent
843
+ except Exception:
844
+ pass
845
+ return False, target
846
+
847
+
733
848
  DEFAULT_UNICODE_CONFIG: dict[str, object] = {
734
849
  "greek_style": "plane1",
735
850
  "convert_definite_integrals": False,
@@ -766,8 +881,8 @@ def load_config(
766
881
  path: Path | None = None,
767
882
  ) -> tuple[dict[str, str], ColorMathOptions, dict[str, object]]:
768
883
  """
769
- Load configuration from path, local '.colormath.json', or global user config.
770
- Fault-tolerant: If the user file contains JSON syntax errors or invalid types,
884
+ Load configuration from path, project hierarchy, active venv, or user home.
885
+ Fault-tolerant: If the file contains JSON syntax errors or invalid types,
771
886
  a warning is emitted and it safely falls back to factory defaults without crashing.
772
887
  Returns (palette_dict, ColorMathOptions, unicode_config_dict).
773
888
  """
@@ -777,13 +892,7 @@ def load_config(
777
892
 
778
893
  target = path
779
894
  if target is None:
780
- local_candidate = Path(".colormath.json")
781
- if local_candidate.exists():
782
- target = local_candidate
783
- else:
784
- global_candidate = get_global_config_path()
785
- if global_candidate and global_candidate.exists():
786
- target = global_candidate
895
+ target, _ = find_config_path()
787
896
 
788
897
  if target is None or not target.exists():
789
898
  return palette, options, unicode_config
@@ -14,8 +14,11 @@ from .adapters import transform_document
14
14
  from .config import (
15
15
  ColorMathOptions,
16
16
  THEMES,
17
+ find_config_path,
18
+ get_venv_config_path,
19
+ init_config,
17
20
  load_config,
18
- get_global_config_path,
21
+ open_config_folder,
19
22
  save_default_config,
20
23
  )
21
24
  from .converters.block import convert_math_block, convert_text
@@ -178,35 +181,63 @@ if HAS_IPYTHON:
178
181
 
179
182
  @line_magic("color_math_config")
180
183
  def color_math_config(self, line: str) -> None:
181
- """Inspect or initialize Color Math configuration.
184
+ """Inspect, create, or open Color Math configuration.
182
185
 
183
186
  Usage:
184
- %color_math_config
185
- %color_math_config --init
186
- %color_math_config --reload
187
+ %color_math_config - Show current active config and scope
188
+ %color_math_config init - Create .colormath.json in current project
189
+ %color_math_config init --venv - Create .colormath.json inside active .venv
190
+ %color_math_config open - Open the active config file in editor
191
+ %color_math_config reload - Reload config from disk
187
192
  """
188
- raw = line.strip().lower()
189
- if "--init" in raw:
190
- target = Path(".colormath.json")
191
- save_default_config(target)
192
- print(f"Color Math: Created config template at '{target.resolve()}'.")
193
- self._palette, self._options, _ = load_config(target)
193
+ parts = line.strip().split()
194
+ subcmd = parts[0].lower() if parts else ""
195
+
196
+ if subcmd in ("init", "--init"):
197
+ scope = "venv" if "--venv" in parts else "project"
198
+ try:
199
+ target = init_config(scope=scope)
200
+ print(f"Color Math: Created {scope} configuration at '{target}'.")
201
+ self._palette, self._options, _ = load_config(target)
202
+ except Exception as err:
203
+ print(f"Color Math error: {err}")
194
204
  return
195
- if "--reload" in raw:
205
+
206
+ if subcmd in ("open", "--open", "explore", "folder", "edit"):
207
+ scope = "venv" if "--venv" in parts else "project"
208
+ success, target = open_config_folder(scope=scope)
209
+ if success:
210
+ print(f"Color Math: Opened '{target}'.")
211
+ else:
212
+ print(f"Color Math: Configuration file is at '{target}'.")
213
+ return
214
+
215
+ if subcmd in ("reload", "--reload"):
196
216
  self._palette, self._options, _ = load_config()
197
- print("Color Math: Configuration reloaded.")
217
+ print("Color Math: Configuration reloaded from disk.")
198
218
  return
199
219
 
200
- local_path = Path(".colormath.json")
201
- global_path = get_global_config_path()
220
+ active_path, scope = find_config_path()
202
221
  print("Color Math Configuration:")
203
- print(f" Local config: {local_path.resolve()} ({'exists' if local_path.exists() else 'not found'})")
204
- if global_path:
205
- print(f" Global config: {global_path} ({'exists' if global_path.exists() else 'not found'})")
222
+ if active_path:
223
+ print(f" Active Config: {active_path} (scope: {scope})")
224
+ else:
225
+ print(" Active Config: Built-in defaults (zero disk pollution)")
226
+
227
+ venv_cfg = get_venv_config_path()
228
+ if venv_cfg:
229
+ status = "configured" if venv_cfg.exists() else "no config in venv"
230
+ print(f" Virtual Env: {venv_cfg.parent.name} ({status})")
231
+
206
232
  print(f" Variables: {'ENABLED' if self._options.variable_data_flow else 'DISABLED'}")
207
233
  print(f" Taxonomy: {'ENABLED' if self._options.enable_taxonomy else 'DISABLED'}")
208
234
  print(f" Delimiters: {'ENABLED' if self._options.rainbow_delimiters else 'DISABLED'}")
209
235
  print(f" Auto-display: {'ENABLED' if self._auto_hook_active else 'DISABLED'}")
236
+ print("\nCommands:")
237
+ print(" %color_math_config init - Create project-level .colormath.json")
238
+ print(" %color_math_config init --venv - Create .colormath.json inside current .venv")
239
+ print(" %color_math_config open - Open active config in your editor")
240
+ print(" %color_math_config reload - Reload settings from disk")
210
241
 
211
242
  @line_magic("color_math_auto")
212
243
  def color_math_auto(self, line: str) -> None:
@@ -227,6 +227,16 @@ def build_parser() -> argparse.ArgumentParser:
227
227
  const=".colormath.json",
228
228
  help="Generate a .colormath.json config template (optional target path).",
229
229
  )
230
+ style_group.add_argument(
231
+ "--init-venv",
232
+ action="store_true",
233
+ help="Generate a .colormath.json inside the active virtual environment (.venv).",
234
+ )
235
+ style_group.add_argument(
236
+ "--open-config",
237
+ action="store_true",
238
+ help="Open configuration file in default editor/file manager.",
239
+ )
230
240
  style_group.add_argument(
231
241
  "--config",
232
242
  type=Path,
@@ -584,12 +594,32 @@ def _main_impl(argv: list[str] | None = None) -> int:
584
594
  sys.stdout.write("Reset runtime color palette to factory defaults (Tokyo Night).\n")
585
595
  return 0
586
596
 
597
+ if args.init_venv:
598
+ from .config import init_config
599
+ try:
600
+ cfg_path = init_config(scope="venv")
601
+ sys.stdout.write(f"Created virtual environment configuration: {cfg_path}\n")
602
+ except Exception as err:
603
+ sys.stderr.write(f"color-math error: {err}\n")
604
+ return 1
605
+ return 0
606
+
587
607
  if args.init_config:
608
+ from .config import init_config
588
609
  cfg_path = Path(args.init_config)
589
610
  save_default_config(cfg_path)
590
611
  sys.stdout.write(f"Created configuration file: {cfg_path}\n")
591
612
  return 0
592
613
 
614
+ if args.open_config:
615
+ from .config import open_config_folder
616
+ success, path = open_config_folder(args.config)
617
+ if success:
618
+ sys.stdout.write(f"Opened configuration: {path}\n")
619
+ else:
620
+ sys.stdout.write(f"Configuration file located at: {path}\n")
621
+ return 0
622
+
593
623
  # 3. Load base configuration & theme
594
624
  palette, config_options, unicode_config = load_config(args.config)
595
625
  if args.theme:
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "python-color-math"
7
- version = "0.2.17"
7
+ version = "0.2.19"
8
8
  description = "A fast, local semantic LaTeX colorizer for Markdown, Jupyter, and LaTeX math equations."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-color-math
3
- Version: 0.2.17
3
+ Version: 0.2.19
4
4
  Summary: A fast, local semantic LaTeX colorizer for Markdown, Jupyter, and LaTeX math equations.
5
5
  Author: Aditya
6
6
  License: MIT License