|
8 | 8 |
|
9 | 9 | DEBUG = False |
10 | 10 |
|
| 11 | +# Adding a tag to a line takes time proportional to the number of tags |
| 12 | +# already in the line, so only the beginning of a line is colorized; |
| 13 | +# the rest is usually not visible anyway (gh-103089). |
| 14 | +MAX_COLORIZED_LINE = 2000 |
| 15 | + |
11 | 16 |
|
12 | 17 | def any(name, alternates): |
13 | 18 | "Return a named group pattern matching list of alternates." |
@@ -344,16 +349,39 @@ def _add_tags_in_section(self, chars, head): |
344 | 349 | `chars` is a string with the text to parse and to which |
345 | 350 | highlighting is to be applied. |
346 | 351 |
|
347 | | - `head` is the index in the text widget where the text is found. |
| 352 | + `head` is the index in the text widget where the text is found. |
348 | 353 | """ |
349 | | - for m in self.prog.finditer(chars): |
| 354 | + # Positions are relative to the start of the current line, so that |
| 355 | + # Tk does not resolve them through the previous lines. |
| 356 | + line = int(head.split('.')[0]) |
| 357 | + line_start = 0 # Offset of the current line in chars. |
| 358 | + tags = [] |
| 359 | + pos = 0 |
| 360 | + while True: |
| 361 | + m = self.prog.search(chars, pos) |
| 362 | + if m is None: |
| 363 | + break |
350 | 364 | for name, matched_text in matched_named_groups(m): |
351 | 365 | a, b = m.span(name) |
352 | | - self._add_tag(a, b, head, name) |
| 366 | + tags.append((a - line_start, b - line_start, head, name)) |
353 | 367 | if matched_text in ("def", "class"): |
354 | 368 | if m1 := self.idprog.match(chars, b): |
355 | 369 | a, b = m1.span(1) |
356 | | - self._add_tag(a, b, head, "DEFINITION") |
| 370 | + tags.append((a - line_start, b - line_start, |
| 371 | + head, "DEFINITION")) |
| 372 | + pos = m.end() |
| 373 | + if '\n' in m[0]: |
| 374 | + line += m[0].count('\n') |
| 375 | + line_start = m.start() + m[0].rindex('\n') + 1 |
| 376 | + head = f"{line}.0" |
| 377 | + elif pos - line_start >= MAX_COLORIZED_LINE: |
| 378 | + # The rest of a long line is not colorized. |
| 379 | + pos = chars.find('\n', pos) |
| 380 | + if pos < 0: |
| 381 | + break |
| 382 | + # Adding a tag is faster if there are no tags after it. |
| 383 | + for args in reversed(tags): |
| 384 | + self._add_tag(*args) |
357 | 385 |
|
358 | 386 | def removecolors(self): |
359 | 387 | "Remove all colorizing tags." |
|
0 commit comments