eric7/E5Gui/EricGenericDiffHighlighter.py

branch
eric7
changeset 8356
68ec9c3d4de5
parent 8318
962bce857696
equal deleted inserted replaced
8355:8a7677a63c8d 8356:68ec9c3d4de5
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2015 - 2021 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing a syntax highlighter for diff outputs.
8 """
9
10 import re
11
12 from PyQt6.QtGui import QSyntaxHighlighter, QTextCharFormat, QFont
13
14 import Preferences
15
16
17 def TERMINAL(pattern):
18 """
19 Function to mark a pattern as the final one to search for.
20
21 @param pattern pattern to be marked (string)
22 @return marked pattern (string)
23 """
24 return "__TERMINAL__:{0}".format(pattern)
25
26 # Cache the results of re.compile for performance reasons
27 _REGEX_CACHE = {}
28
29
30 class EricGenericDiffHighlighter(QSyntaxHighlighter):
31 """
32 Class implementing a generic diff highlighter.
33 """
34 def __init__(self, doc):
35 """
36 Constructor
37
38 @param doc reference to the text document (QTextDocument)
39 """
40 super().__init__(doc)
41
42 self.regenerateRules()
43
44 def __initColours(self):
45 """
46 Private method to initialize the highlighter colours.
47 """
48 self.textColor = Preferences.getDiffColour("TextColor")
49 self.addedColor = Preferences.getDiffColour("AddedColor")
50 self.removedColor = Preferences.getDiffColour("RemovedColor")
51 self.replacedColor = Preferences.getDiffColour("ReplacedColor")
52 self.contextColor = Preferences.getDiffColour("ContextColor")
53 self.headerColor = Preferences.getDiffColour("HeaderColor")
54 self.whitespaceColor = Preferences.getDiffColour("BadWhitespaceColor")
55
56 def createRules(self, *rules):
57 """
58 Public method to create the highlighting rules.
59
60 @param rules set of highlighting rules (list of tuples of rule
61 pattern (string) and highlighting format (QTextCharFormat))
62 """
63 for _idx, ruleFormat in enumerate(rules):
64 rule, formats = ruleFormat
65 terminal = rule.startswith(TERMINAL(''))
66 if terminal:
67 rule = rule[len(TERMINAL('')):]
68 try:
69 regex = _REGEX_CACHE[rule]
70 except KeyError:
71 regex = _REGEX_CACHE[rule] = re.compile(rule)
72 self._rules.append((regex, formats, terminal))
73
74 def formats(self, line):
75 """
76 Public method to determine the highlighting formats for a line of
77 text.
78
79 @param line text line to be highlighted (string)
80 @return list of matched highlighting rules (list of tuples of match
81 object and format (QTextCharFormat))
82 """
83 matched = []
84 for rx, formats, terminal in self._rules:
85 match = rx.match(line)
86 if not match:
87 continue
88 matched.append([match, formats])
89 if terminal:
90 return matched
91
92 return matched
93
94 def makeFormat(self, fg=None, bg=None, bold=False):
95 """
96 Public method to generate a format definition.
97
98 @param fg foreground color (QColor)
99 @param bg background color (QColor)
100 @param bold flag indicating bold text (boolean)
101 @return format definiton (QTextCharFormat)
102 """
103 font = Preferences.getEditorOtherFonts("MonospacedFont")
104 charFormat = QTextCharFormat()
105 charFormat.setFontFamilies([font.family()])
106 charFormat.setFontPointSize(font.pointSize())
107
108 if fg:
109 charFormat.setForeground(fg)
110
111 if bg:
112 charFormat.setBackground(bg)
113
114 if bold:
115 charFormat.setFontWeight(QFont.Weight.Bold)
116
117 return charFormat
118
119 def highlightBlock(self, text):
120 """
121 Public method to highlight a block of text.
122
123 @param text text to be highlighted (string)
124 """
125 formats = self.formats(text)
126 if not formats:
127 # nothing matched
128 self.setFormat(0, len(text), self.normalFormat)
129 return
130
131 for match, formatStr in formats:
132 start = match.start()
133 groups = match.groups()
134
135 # No groups in the regex, assume this is a single rule
136 # that spans the entire line
137 if not groups:
138 self.setFormat(0, len(text), formatStr)
139 continue
140
141 # Groups exist, rule is a tuple corresponding to group
142 for groupIndex, group in enumerate(groups):
143 if not group:
144 # empty match
145 continue
146
147 # allow None as a no-op format
148 length = len(group)
149 if formatStr[groupIndex]:
150 self.setFormat(start, start + length,
151 formatStr[groupIndex])
152 start += length
153
154 def regenerateRules(self):
155 """
156 Public method to initialize or regenerate the syntax highlighter rules.
157 """
158 self.normalFormat = self.makeFormat()
159
160 self.__initColours()
161
162 self._rules = []
163 self.generateRules()
164
165 def generateRules(self):
166 """
167 Public method to generate the rule set.
168
169 Note: This method must me implemented by derived syntax
170 highlighters.
171 """
172 pass

eric ide

mercurial