Files
LithosAnanake/docs/formal/fix-doxygen-unicode.py

148 lines
4.7 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
fix-doxygen-unicode.py — replace problematic Unicode characters in
Doxygen-generated LaTeX files with pdflatex-safe equivalents.
Run this on the doxygen/latex/ directory before calling pdflatex.
"""
import os, sys, re
REPLACEMENTS = [
# Math symbols
('≈', r'\ensuremath{\approx}'),
('≤', r'\ensuremath{\leq}'),
('≥', r'\ensuremath{\geq}'),
('≠', r'\ensuremath{\neq}'),
('±', r'\ensuremath{\pm}'),
('×', r'\ensuremath{\times}'),
('÷', r'\ensuremath{\div}'),
('∞', r'\ensuremath{\infty}'),
('∑', r'\ensuremath{\sum}'),
('∏', r'\ensuremath{\prod}'),
('∫', r'\ensuremath{\int}'),
('√', r'\ensuremath{\sqrt{\cdot}}'),
('∂', r'\ensuremath{\partial}'),
('∆', r'\ensuremath{\Delta}'),
('∇', r'\ensuremath{\nabla}'),
('∈', r'\ensuremath{\in}'),
('∉', r'\ensuremath{\notin}'),
('∩', r'\ensuremath{\cap}'),
('', r'\ensuremath{\cup}'),
('⊂', r'\ensuremath{\subset}'),
('⊃', r'\ensuremath{\supset}'),
('∀', r'\ensuremath{\forall}'),
('∃', r'\ensuremath{\exists}'),
('∧', r'\ensuremath{\wedge}'),
('', r'\ensuremath{\vee}'),
('¬', r'\ensuremath{\neg}'),
# Arrows
('←', r'\ensuremath{\leftarrow}'),
('→', r'\ensuremath{\rightarrow}'),
('↑', r'\ensuremath{\uparrow}'),
('↓', r'\ensuremath{\downarrow}'),
('↔', r'\ensuremath{\leftrightarrow}'),
('⇒', r'\ensuremath{\Rightarrow}'),
('⇐', r'\ensuremath{\Leftarrow}'),
('⇔', r'\ensuremath{\Leftrightarrow}'),
# Greek letters
('α', r'\ensuremath{\alpha}'),
('β', r'\ensuremath{\beta}'),
('γ', r'\ensuremath{\gamma}'),
('δ', r'\ensuremath{\delta}'),
('ε', r'\ensuremath{\varepsilon}'),
('θ', r'\ensuremath{\theta}'),
('λ', r'\ensuremath{\lambda}'),
('μ', r'\ensuremath{\mu}'),
('π', r'\ensuremath{\pi}'),
('σ', r'\ensuremath{\sigma}'),
('τ', r'\ensuremath{\tau}'),
('φ', r'\ensuremath{\phi}'),
('ω', r'\ensuremath{\omega}'),
('Δ', r'\ensuremath{\Delta}'),
('Σ', r'\ensuremath{\Sigma}'),
('Ω', r'\ensuremath{\Omega}'),
# Superscripts/subscripts
('⁻', r'\ensuremath{{}^{-}}'),
('⁺', r'\ensuremath{{}^{+}}'),
('²', r'\ensuremath{{}^{2}}'),
('³', r'\ensuremath{{}^{3}}'),
('⁰', r'\ensuremath{{}^{0}}'),
('¹', r'\ensuremath{{}^{1}}'),
# Box-drawing (from ASCII art in comments)
('├', r'\textbar{}'),
('│', r'\textbar{}'),
('└', r'`'),
('┌', r'.'),
('┐', r'.'),
('┘', r"'"),
('─', r'-'),
('═', r'='),
('║', r'\textbar{}'),
('╔', r'.'),
('╗', r'.'),
('╚', r'.'),
('╝', r'.'),
('╠', r'\textbar{}'),
('╣', r'\textbar{}'),
('╦', r'-'),
('╩', r'-'),
('╬', r'+'),
# Misc
('·', r'\ensuremath{\cdot}'),
('°', r'\ensuremath{{}^{\circ}}'),
('™', r'\texttrademark{}'),
('®', r'\textregistered{}'),
('©', r'\textcopyright{}'),
('…', r'\ldots{}'),
('', r'--'),
('—', r'---'),
('', r'`'), # left single quote
('', r"'"), # right single quote
('“', r'``'), # left double quote
('”', r"''"), # right double quote
]
def fix_line(line):
# Protect \doxynewunicodechar{CHAR}{...} and \newunicodechar{CHAR}{...}
# first arguments — these must stay as literal Unicode chars.
# Strategy: split on these patterns, fix only the non-protected parts.
import re
parts = re.split(r'(\\(?:doxy)?newunicodechar\{[^}]*\})', line)
result = []
for i, part in enumerate(parts):
if i % 2 == 1: # protected token — preserve as-is
result.append(part)
else:
for char, replacement in REPLACEMENTS:
part = part.replace(char, replacement)
result.append(part)
return ''.join(result)
def fix_file(path):
with open(path, encoding='utf-8', errors='replace') as f:
lines = f.readlines()
original = ''.join(lines)
fixed_lines = [fix_line(l) for l in lines]
content = ''.join(fixed_lines)
# Replace any remaining non-ASCII with ? placeholder
content = content.encode('ascii', errors='replace').decode('ascii')
if content != original:
with open(path, 'w', encoding='ascii') as f:
f.write(content)
return True
return False
def main():
latex_dir = sys.argv[1] if len(sys.argv) > 1 else '.'
fixed = 0
for root, _, files in os.walk(latex_dir):
for fname in files:
if fname.endswith('.tex') or fname.endswith('.sty'):
path = os.path.join(root, fname)
if fix_file(path):
fixed += 1
print(f"Fixed {fixed} files in {latex_dir}")
if __name__ == '__main__':
main()