build123d/docs/build123d_lexer.py
2025-09-09 23:21:05 -04:00

75 lines
No EOL
2.3 KiB
Python

import inspect
import enum
import sys
import os
from pygments.lexers.python import PythonLexer
from pygments.token import Name
from sphinx.highlighting import lexers
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../src")))
import build123d
class Build123dLexer(PythonLexer):
"""
Python lexer extended with Build123d-specific highlighting.
Dynamically pulls symbols from build123d.__all__.
"""
EXTRA_SYMBOLS = set(getattr(build123d, "__all__", []))
EXTRA_CLASSES = {
n for n in EXTRA_SYMBOLS
if n[0].isupper()
}
EXTRA_CONSTANTS = {
n for n in EXTRA_SYMBOLS
if n.isupper() and not callable(getattr(build123d, n, None))
}
EXTRA_ENUMS = {
n for n in EXTRA_SYMBOLS
if inspect.isclass(getattr(build123d, n, None)) and issubclass(getattr(build123d, n), enum.Enum)
}
EXTRA_FUNCTIONS = EXTRA_SYMBOLS - EXTRA_CLASSES - EXTRA_CONSTANTS - EXTRA_ENUMS
def get_tokens_unprocessed(self, text):
"""
Yield tokens, highlighting Build123d symbols, including chained accesses.
"""
dot_chain = False
for index, token, value in super().get_tokens_unprocessed(text):
if value == ".":
dot_chain = True
yield index, token, value
continue
if dot_chain:
# In a chain, don't use top-level categories
if value[0].isupper():
yield index, Name.Class, value
elif value.isupper():
yield index, Name.Constant, value
else:
yield index, Name.Function, value
dot_chain = False
continue
# Top-level classification from __all__
if value in self.EXTRA_CLASSES:
yield index, Name.Class, value
elif value in self.EXTRA_FUNCTIONS:
yield index, Name.Function, value
elif value in self.EXTRA_CONSTANTS:
yield index, Name.Constant, value
elif value in self.EXTRA_ENUMS:
yield index, Name.Builtin, value
else:
yield index, token, value
def setup(app):
lexers["build123d"] = Build123dLexer()
return {"version": "0.1"}