from typing import Optional from src.ui.bigtext.highlight import Highlight from src.ui.bigtext.highlighted_range import HighlightedRange from src.ui.bigtext.line import Line from PySide6.QtGui import QBrush, QColor from typing import List import re class HighlightRegex(Highlight): def __init__(self, query: str, ignore_case: bool, is_regex: bool, hit_background_color: str = "None", line_background_color: str = "None", active: bool = True): self.active = active self.query = query self.ignore_case = ignore_case self.is_regex = is_regex self.regex = self._get_regex() self.hit_background_color = hit_background_color self.line_background_color = line_background_color self._brush_hit = self.brush(self.hit_background_color) self._brush_line = self.brush(self.line_background_color) def _get_regex(self): flags = re.IGNORECASE if self.ignore_case else 0 if self.is_regex: return re.compile(self.query, flags=flags) else: return re.compile(re.escape(self.query), flags=flags) def is_active(self) -> bool: return self.active def set_active(self, active: bool): self.active = active def set_query(self, query: str) -> None: self.query = query self.regex = self._get_regex() def set_hit_background_color(self, color: str): self.hit_background_color = color def set_line_background_color(self, color: str): self.line_background_color = color def set_is_regex(self, is_regex: bool): self.is_regex = is_regex def set_is_ignore_case(self, ignore_case: bool): self.ignore_case = ignore_case def compute_highlight(self, line: Line) -> Optional[List[HighlightedRange]]: result = [] if len(self.query) == 0: # query is empty - this would result in many hits and is quite expensive # This happens with the highlighter we use for the selected text and maybe for the current filter query. return result # print("execute regex: %s in %s" % (self.regex, line.line())) match_iter = re.finditer(self.regex, line.line()) for match in match_iter: # print("%s" % match) # if the regex has groups then skip the first, it represents the whole match, # but we only want to highlight the groups first_group = 1 if len(match.groups()) > 0 else 0 for i in range(first_group, len(match.groups()) + 1): start_column = line.char_to_column(match.start(i)) end_column = line.char_to_column(match.end(i)) # print(f"highlight: {start_column}:{end_column} - {match.group(i)}") result.append(HighlightedRange( start_column, end_column - start_column, highlight_full_line=True, brush=self._brush_hit, brush_full_line=self._brush_line )) return result def hit_background_brush(self): return self.brush(self.hit_background_color) @staticmethod def brush(color: str) -> QBrush: if re.match("^[0-9a-f]{6}$", color, flags=re.IGNORECASE): red = int(color[0:2], 16) green = int(color[2:4], 16) blue = int(color[4:6], 16) return QBrush(QColor(red, green, blue)) if re.match("^[0-9a-f]{8}$", color, flags=re.IGNORECASE): red = int(color[0:2], 16) green = int(color[2:4], 16) blue = int(color[4:6], 16) alpha = int(color[6:8], 16) return QBrush(QColor(red, green, blue, alpha)) return QBrush()