E5Gui/E5GenericDiffHighlighter.py

changeset 4108
0059d2d09ab8
child 4109
809b8268183d
diff -r 501c964e20e7 -r 0059d2d09ab8 E5Gui/E5GenericDiffHighlighter.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/E5Gui/E5GenericDiffHighlighter.py	Sun Feb 08 19:12:05 2015 +0100
@@ -0,0 +1,159 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2015 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a syntax highlighter for diff outputs.
+"""
+
+from __future__ import unicode_literals
+
+import re
+
+from PyQt5.QtGui import QSyntaxHighlighter, QColor, QTextCharFormat, QFont
+
+import Preferences
+
+def TERMINAL(pattern):
+    """
+    Function to mark a pattern as the final one to search for.
+    
+    @param pattern pattern to be marked (string)
+    @param return marked pattern (string)
+    """
+    return "__TERMINAL__:{0}".format(pattern)
+
+# Cache the results of re.compile for performance reasons
+_REGEX_CACHE = {}
+
+class E5GenericDiffHighlighter(QSyntaxHighlighter):
+    """
+    Class implementing a generic diff highlighter.
+    """
+    def __init__(self, doc):
+        """
+        Constructor
+        
+        @param doc reference to the text document (QTextDocument)
+        """
+        super(E5GenericDiffHighlighter, self).__init__(doc)
+        
+        self.textColor = QColor(0, 0, 0)
+        self.addedColor = QColor(190, 237, 190)
+        self.removedColor = QColor(237, 190, 190)
+        self.replacedColor = QColor(190, 190, 237)
+        self.contextColor = QColor(255, 220, 168)
+        self.headerColor = QColor(190, 190, 237)
+        
+        self.normalFormat = self.makeFormat()
+        
+        self._rules = []
+        self.generateRules()
+    
+    def generateRules(self):
+        """
+        Public method to generate the rule set.
+        
+        Note: This method must me implemented by derived syntax
+        highlighters.
+        """
+        pass
+    
+    def createRules(self, *rules):
+        """
+        Public method to create the highlighting rules.
+        
+        @param rules set of highlighting rules (list of tuples of rule
+            pattern (string) and highlighting format (QTextCharFormat))
+        """
+        for idx, ruleFormat in enumerate(rules):
+            rule, formats = ruleFormat
+            terminal = rule.startswith(TERMINAL(''))
+            if terminal:
+                rule = rule[len(TERMINAL('')):]
+            try:
+                regex = _REGEX_CACHE[rule]
+            except KeyError:
+                regex = _REGEX_CACHE[rule] = re.compile(rule)
+            self._rules.append((regex, formats, terminal))
+    
+    def formats(self, line):
+        """
+        Public method to determine the highlighting formats for a line of
+        text.
+        
+        @param line text line to be highlighted (string)
+        @return list of matched highlighting rules (list of tuples of match
+            object and format (QTextCharFormat))
+        """
+        matched = []
+        for rx, formats, terminal in self._rules:
+            match = rx.match(line)
+            if not match:
+                continue
+            matched.append([match, formats])
+            if terminal:
+                return matched
+        
+        return matched
+    
+    def makeFormat(self, fg=None, bg=None, bold=False):
+        """
+        Public method to generate a format definition.
+        
+        @param fg foreground color (QColor)
+        @param bg background color (QColor)
+        @param bold flag indicating bold text (boolean)
+        @return format definiton (QTextCharFormat)
+        """
+        font = Preferences.getEditorOtherFonts("MonospacedFont")
+        format = QTextCharFormat()
+        format.setFontFamily(font.family())
+        format.setFontPointSize(font.pointSize())
+        
+        if fg:
+            format.setForeground(fg)
+        
+        if bg:
+            format.setBackground(bg)
+        
+        if bold:
+            format.setFontWeight(QFont.Bold)
+        
+        return format
+    
+    def highlightBlock(self, text):
+        """
+        Public method to highlight a block of text.
+        
+        @param text text to be highlighted (string)
+        """
+        formats = self.formats(text)
+        if not formats:
+            # nothing matched
+            self.setFormat(0, len(text), self.normalFormat)
+            return
+        
+        for match, format in formats:
+            start = match.start()
+            groups = match.groups()
+
+            # No groups in the regex, assume this is a single rule
+            # that spans the entire line
+            if not groups:
+                self.setFormat(0, len(text), format)
+                continue
+
+            # Groups exist, rule is a tuple corresponding to group
+            for groupIndex, group in enumerate(groups):
+                if not group:
+                    # empty match
+                    continue
+                
+                # allow None as a no-op format
+                length = len(group)
+                if format[groupIndex]:
+                    self.setFormat(start, start + length,
+                                   format[groupIndex])
+                start += length

eric ide

mercurial