Coverage for app/venv/lib/python3.14/site-packages/weblate/checks/utils.py: 29%
53 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 07:15 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 07:15 +0000
1# Copyright © Michal Čihař <michal@weblate.org>
2#
3# SPDX-License-Identifier: GPL-3.0-or-later
5from __future__ import annotations
7from typing import TYPE_CHECKING
9from weblate.checks.models import CHECKS
11if TYPE_CHECKING: 11 ↛ 12line 11 didn't jump to line 12 because the condition on line 11 was never true
12 from collections.abc import Generator
14 from weblate.trans.models import Unit
17def highlight_pygments(source: str, unit: Unit) -> Generator[tuple[int, int, str]]:
18 """
19 Highlight syntax characters using pygments.
21 This is not really a full syntax highlighting, we're only interested in
22 non-translatable strings.
23 """
24 from pygments.lexers.markup import RstLexer
25 from pygments.token import Token
27 if "rst-text" in unit.all_flags:
28 lexer = RstLexer(stripnl=False)
29 start = 0
30 for token, text in lexer.get_tokens(source):
31 if token == Token.Literal.String:
32 if text[0] == "`" and text != "`_":
33 yield ((start, start + 1, "`"))
34 else:
35 yield ((start, start + len(text), text))
36 elif token == Token.Literal.String.Interpol:
37 yield ((start, start + len(text), text))
38 elif token == Token.Generic.Strong:
39 end = start + len(text)
40 yield (start, start + 2, "**")
41 yield (end - 2, end, "**")
42 elif token == Token.Generic.Emph:
43 end = start + len(text)
44 yield (start, start + 1, "*")
45 yield (end - 1, end, "*")
46 start += len(text)
49def highlight_string(
50 source: str, unit: Unit, *, highlight_syntax: bool = False
51) -> list[tuple[int, int, str]]:
52 """Return highlights for a string."""
53 if unit is None: 53 ↛ 54line 53 didn't jump to line 54 because the condition on line 53 was never true
54 return []
55 highlights = []
56 for check in CHECKS:
57 if not CHECKS[check].target:
58 continue
59 highlights.extend(CHECKS[check].check_highlight(source, unit))
61 if highlight_syntax: 61 ↛ 62line 61 didn't jump to line 62 because the condition on line 61 was never true
62 highlights.extend(highlight_pygments(source, unit))
64 # Remove empty strings
65 highlights = [highlight for highlight in highlights if highlight[2]]
67 # Sort by order in string, longest first
68 highlights.sort(key=lambda item: (item[0], -item[1]))
70 # Remove overlapping ones
71 for hl_idx in range(len(highlights)): 71 ↛ 72line 71 didn't jump to line 72 because the loop on line 71 never started
72 if hl_idx >= len(highlights):
73 break
74 elref = highlights[hl_idx]
75 hl_idx_next = hl_idx + 1
76 while hl_idx_next < len(highlights):
77 eltest = highlights[hl_idx_next]
78 if eltest[0] >= elref[0] and eltest[1] <= elref[1]:
79 # Elements overlap, remove inner one
80 highlights.pop(hl_idx_next)
81 # Do not increment index here as we've removed the current element
82 elif eltest[0] > elref[1]:
83 # This is not an overlapping element
84 break
85 else:
86 # Increase index to test
87 hl_idx_next += 1
89 return highlights