66import keyword
77import re
88from dataclasses import dataclass , field
9+ from functools import lru_cache
910from typing import TYPE_CHECKING , Callable , Generator , Match , Pattern , Protocol
1011
12+ from .markup import Token , consume_tag
1113from .regex import RE_MARKUP
1214
1315if TYPE_CHECKING :
1618__all__ = [
1719 "Highlighter" ,
1820 "RegexHighlighter" ,
21+ "highlight_tim" ,
1922 "highlight_python" ,
2023]
2124
@@ -137,7 +140,7 @@ def _insert_style(matchobj: Match) -> str:
137140 return text
138141
139142 def __fancy_repr__ (self ) -> Generator [FancyYield , None , None ]:
140- """Yields some fancy looking repl text."""
143+ """Yields some fancy looking repr text."""
141144
142145 preview = self ("highlight_python()" ) + "\x1b [0m"
143146 pattern = self ._pattern .pattern
@@ -151,6 +154,72 @@ def __fancy_repr__(self) -> Generator[FancyYield, None, None]:
151154 yield ">"
152155
153156
157+ def highlight_tim (text : str , cache : bool = True ) -> str :
158+ """Highlights some TIM code."""
159+
160+ @lru_cache (1048 )
161+ def _highlight (txt : str ) -> str :
162+ output = ""
163+ cursor = 0
164+ active_tokens : list [Token ] = []
165+
166+ def _get_active_markup () -> str :
167+ active_markup = " " .join (tkn .markup for tkn in active_tokens )
168+
169+ if active_markup == "" :
170+ return ""
171+
172+ return f"[{ active_markup } ]"
173+
174+ for matchobj in RE_MARKUP .finditer (txt ):
175+ start , end = matchobj .span ()
176+
177+ if cursor < start :
178+ if cursor > 0 :
179+ output += "]"
180+
181+ output += _get_active_markup ()
182+ output += f"{ txt [cursor :start ]} [/]"
183+
184+ * _ , tags = matchobj .groups ()
185+
186+ output += "["
187+ for tag in tags .split ():
188+ token = consume_tag (tag )
189+ output += f"{ token .prettified_markup } "
190+
191+ if Token .is_clear (token ):
192+ active_tokens = [
193+ tkn for tkn in active_tokens if not token .targets (tkn )
194+ ]
195+
196+ else :
197+ active_tokens .append (token )
198+
199+ output = output .rstrip ()
200+ cursor = end
201+
202+ if cursor < len (txt ) - 1 :
203+ if cursor > 0 :
204+ output += "]"
205+
206+ output += _get_active_markup ()
207+ output += f"{ txt [cursor :]} "
208+
209+ if len (active_tokens ) > 0 :
210+ output += "[/]"
211+
212+ if output .count ("[" ) != output .count ("]" ):
213+ output += "]"
214+
215+ return output
216+
217+ if cache :
218+ return _highlight (text )
219+
220+ return _highlight .__wrapped__ (text )
221+
222+
154223_BUILTIN_NAMES = "|" .join (f"(?:{ item } )" for item in dir (builtins ))
155224_KEYWORD_NAMES = "|" .join (
156225 f"(?:{ keyw } )" for keyw in list (keyword .kwlist ) + ["builtin" , "function" , "module" ]
0 commit comments