Added a generic syntax highlighter for diff outputs.

Sun, 08 Feb 2015 19:12:05 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Sun, 08 Feb 2015 19:12:05 +0100
changeset 4108
0059d2d09ab8
parent 4107
501c964e20e7
child 4109
809b8268183d

Added a generic syntax highlighter for diff outputs.

APIs/Python3/eric6.api file | annotate | diff | comparison | revisions
APIs/Python3/eric6.bas file | annotate | diff | comparison | revisions
Documentation/Help/source.qch file | annotate | diff | comparison | revisions
Documentation/Help/source.qhp file | annotate | diff | comparison | revisions
Documentation/Source/eric6.E5Gui.E5GenericDiffHighlighter.html file | annotate | diff | comparison | revisions
Documentation/Source/index-eric6.E5Gui.html file | annotate | diff | comparison | revisions
E5Gui/E5GenericDiffHighlighter.py file | annotate | diff | comparison | revisions
eric6.e4p file | annotate | diff | comparison | revisions
--- a/APIs/Python3/eric6.api	Sun Feb 08 16:16:32 2015 +0100
+++ b/APIs/Python3/eric6.api	Sun Feb 08 19:12:05 2015 +0100
@@ -1236,6 +1236,14 @@
 eric6.E5Gui.E5FileDialog.getOpenFileNamesAndFilter?4(parent=None, caption="", directory="", filter="", initialFilter="", options=QFileDialog.Options())
 eric6.E5Gui.E5FileDialog.getSaveFileName?4(parent=None, caption="", directory="", filter="", options=QFileDialog.Options())
 eric6.E5Gui.E5FileDialog.getSaveFileNameAndFilter?4(parent=None, caption="", directory="", filter="", initialFilter="", options=QFileDialog.Options())
+eric6.E5Gui.E5GenericDiffHighlighter.E5GenericDiffHighlighter.createRules?4(*rules)
+eric6.E5Gui.E5GenericDiffHighlighter.E5GenericDiffHighlighter.formats?4(line)
+eric6.E5Gui.E5GenericDiffHighlighter.E5GenericDiffHighlighter.generateRules?4()
+eric6.E5Gui.E5GenericDiffHighlighter.E5GenericDiffHighlighter.highlightBlock?4(text)
+eric6.E5Gui.E5GenericDiffHighlighter.E5GenericDiffHighlighter.makeFormat?4(fg=None, bg=None, bold=False)
+eric6.E5Gui.E5GenericDiffHighlighter.E5GenericDiffHighlighter?1(doc)
+eric6.E5Gui.E5GenericDiffHighlighter.TERMINAL?4(pattern)
+eric6.E5Gui.E5GenericDiffHighlighter._REGEX_CACHE?8
 eric6.E5Gui.E5Led.E5ClickableLed.clicked?7
 eric6.E5Gui.E5Led.E5ClickableLed.middleClicked?7
 eric6.E5Gui.E5Led.E5ClickableLed.mouseReleaseEvent?4(evt)
--- a/APIs/Python3/eric6.bas	Sun Feb 08 16:16:32 2015 +0100
+++ b/APIs/Python3/eric6.bas	Sun Feb 08 19:12:05 2015 +0100
@@ -60,7 +60,7 @@
 ChangeBookmarkCommand QUndoCommand
 ChatWidget QWidget Ui_ChatWidget
 ChromeImporter BookmarksImporter
-Class ClbrBase
+Class ClbrBaseClasses.Class VisibilityMixin
 ClassItem UMLItem
 ClassModel UMLModel
 ClbrBase _ClbrBase
@@ -145,6 +145,7 @@
 E5FileCompleter QCompleter
 E5Ftp ftplib.FTP
 E5FtpProxyError ftplib.Error
+E5GenericDiffHighlighter QSyntaxHighlighter
 E5GraphicsView QGraphicsView
 E5HorizontalToolBox E5TabWidget
 E5Led QWidget
Binary file Documentation/Help/source.qch has changed
--- a/Documentation/Help/source.qhp	Sun Feb 08 16:16:32 2015 +0100
+++ b/Documentation/Help/source.qhp	Sun Feb 08 19:12:05 2015 +0100
@@ -122,6 +122,7 @@
             <section title="eric6.E5Gui.E5ErrorMessage" ref="eric6.E5Gui.E5ErrorMessage.html" />
             <section title="eric6.E5Gui.E5ErrorMessageFilterDialog" ref="eric6.E5Gui.E5ErrorMessageFilterDialog.html" />
             <section title="eric6.E5Gui.E5FileDialog" ref="eric6.E5Gui.E5FileDialog.html" />
+            <section title="eric6.E5Gui.E5GenericDiffHighlighter" ref="eric6.E5Gui.E5GenericDiffHighlighter.html" />
             <section title="eric6.E5Gui.E5Led" ref="eric6.E5Gui.E5Led.html" />
             <section title="eric6.E5Gui.E5LineEdit" ref="eric6.E5Gui.E5LineEdit.html" />
             <section title="eric6.E5Gui.E5LineEditButton" ref="eric6.E5Gui.E5LineEditButton.html" />
@@ -3551,6 +3552,14 @@
       <keyword name="E5Ftp.setProxyAuthentication" id="E5Ftp.setProxyAuthentication" ref="eric6.E5Network.E5Ftp.html#E5Ftp.setProxyAuthentication" />
       <keyword name="E5FtpProxyError" id="E5FtpProxyError" ref="eric6.E5Network.E5Ftp.html#E5FtpProxyError" />
       <keyword name="E5FtpProxyType" id="E5FtpProxyType" ref="eric6.E5Network.E5Ftp.html#E5FtpProxyType" />
+      <keyword name="E5GenericDiffHighlighter" id="E5GenericDiffHighlighter" ref="eric6.E5Gui.E5GenericDiffHighlighter.html#E5GenericDiffHighlighter" />
+      <keyword name="E5GenericDiffHighlighter (Constructor)" id="E5GenericDiffHighlighter (Constructor)" ref="eric6.E5Gui.E5GenericDiffHighlighter.html#E5GenericDiffHighlighter.__init__" />
+      <keyword name="E5GenericDiffHighlighter (Module)" id="E5GenericDiffHighlighter (Module)" ref="eric6.E5Gui.E5GenericDiffHighlighter.html" />
+      <keyword name="E5GenericDiffHighlighter.createRules" id="E5GenericDiffHighlighter.createRules" ref="eric6.E5Gui.E5GenericDiffHighlighter.html#E5GenericDiffHighlighter.createRules" />
+      <keyword name="E5GenericDiffHighlighter.formats" id="E5GenericDiffHighlighter.formats" ref="eric6.E5Gui.E5GenericDiffHighlighter.html#E5GenericDiffHighlighter.formats" />
+      <keyword name="E5GenericDiffHighlighter.generateRules" id="E5GenericDiffHighlighter.generateRules" ref="eric6.E5Gui.E5GenericDiffHighlighter.html#E5GenericDiffHighlighter.generateRules" />
+      <keyword name="E5GenericDiffHighlighter.highlightBlock" id="E5GenericDiffHighlighter.highlightBlock" ref="eric6.E5Gui.E5GenericDiffHighlighter.html#E5GenericDiffHighlighter.highlightBlock" />
+      <keyword name="E5GenericDiffHighlighter.makeFormat" id="E5GenericDiffHighlighter.makeFormat" ref="eric6.E5Gui.E5GenericDiffHighlighter.html#E5GenericDiffHighlighter.makeFormat" />
       <keyword name="E5Graphics (Package)" id="E5Graphics (Package)" ref="index-eric6.E5Graphics.html" />
       <keyword name="E5GraphicsView" id="E5GraphicsView" ref="eric6.E5Graphics.E5GraphicsView.html#E5GraphicsView" />
       <keyword name="E5GraphicsView (Constructor)" id="E5GraphicsView (Constructor)" ref="eric6.E5Graphics.E5GraphicsView.html#E5GraphicsView.__init__" />
@@ -11386,6 +11395,7 @@
       <keyword name="SyntaxCheckerPlugin.serviceErrorJavaScript" id="SyntaxCheckerPlugin.serviceErrorJavaScript" ref="eric6.Plugins.PluginSyntaxChecker.html#SyntaxCheckerPlugin.serviceErrorJavaScript" />
       <keyword name="SyntaxCheckerPlugin.serviceErrorPy2" id="SyntaxCheckerPlugin.serviceErrorPy2" ref="eric6.Plugins.PluginSyntaxChecker.html#SyntaxCheckerPlugin.serviceErrorPy2" />
       <keyword name="SyntaxCheckerPlugin.serviceErrorPy3" id="SyntaxCheckerPlugin.serviceErrorPy3" ref="eric6.Plugins.PluginSyntaxChecker.html#SyntaxCheckerPlugin.serviceErrorPy3" />
+      <keyword name="TERMINAL" id="TERMINAL" ref="eric6.E5Gui.E5GenericDiffHighlighter.html#TERMINAL" />
       <keyword name="TRPreviewer" id="TRPreviewer" ref="eric6.Tools.TRPreviewer.html#TRPreviewer" />
       <keyword name="TRPreviewer (Constructor)" id="TRPreviewer (Constructor)" ref="eric6.Tools.TRPreviewer.html#TRPreviewer.__init__" />
       <keyword name="TRPreviewer (Module)" id="TRPreviewer (Module)" ref="eric6.Tools.TRPreviewer.html" />
@@ -13705,6 +13715,7 @@
       <file>eric6.E5Gui.E5ErrorMessage.html</file>
       <file>eric6.E5Gui.E5ErrorMessageFilterDialog.html</file>
       <file>eric6.E5Gui.E5FileDialog.html</file>
+      <file>eric6.E5Gui.E5GenericDiffHighlighter.html</file>
       <file>eric6.E5Gui.E5Led.html</file>
       <file>eric6.E5Gui.E5LineEdit.html</file>
       <file>eric6.E5Gui.E5LineEditButton.html</file>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Documentation/Source/eric6.E5Gui.E5GenericDiffHighlighter.html	Sun Feb 08 19:12:05 2015 +0100
@@ -0,0 +1,182 @@
+<!DOCTYPE html>
+<html><head>
+<title>eric6.E5Gui.E5GenericDiffHighlighter</title>
+<meta charset="UTF-8">
+<style>
+body {
+    background: #EDECE6;
+    margin: 0em 1em 10em 1em;
+    color: black;
+}
+
+h1 { color: white; background: #85774A; }
+h2 { color: white; background: #85774A; }
+h3 { color: white; background: #9D936E; }
+h4 { color: white; background: #9D936E; }
+    
+a { color: #BA6D36; }
+
+</style>
+</head>
+<body><a NAME="top" ID="top"></a>
+<h1>eric6.E5Gui.E5GenericDiffHighlighter</h1>
+<p>
+Module implementing a syntax highlighter for diff outputs.
+</p>
+<h3>Global Attributes</h3>
+<table>
+<tr><td>_REGEX_CACHE</td></tr>
+</table>
+<h3>Classes</h3>
+<table>
+<tr>
+<td><a href="#E5GenericDiffHighlighter">E5GenericDiffHighlighter</a></td>
+<td>Class implementing a generic diff highlighter.</td>
+</tr>
+</table>
+<h3>Functions</h3>
+<table>
+<tr>
+<td><a href="#TERMINAL">TERMINAL</a></td>
+<td>Function to mark a pattern as the final one to search for.</td>
+</tr>
+</table>
+<hr /><hr />
+<a NAME="E5GenericDiffHighlighter" ID="E5GenericDiffHighlighter"></a>
+<h2>E5GenericDiffHighlighter</h2>
+<p>
+    Class implementing a generic diff highlighter.
+</p>
+<h3>Derived from</h3>
+QSyntaxHighlighter
+<h3>Class Attributes</h3>
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Class Methods</h3>
+<table>
+<tr><td>None</td></tr>
+</table>
+<h3>Methods</h3>
+<table>
+<tr>
+<td><a href="#E5GenericDiffHighlighter.__init__">E5GenericDiffHighlighter</a></td>
+<td>Constructor</td>
+</tr><tr>
+<td><a href="#E5GenericDiffHighlighter.createRules">createRules</a></td>
+<td>Public method to create the highlighting rules.</td>
+</tr><tr>
+<td><a href="#E5GenericDiffHighlighter.formats">formats</a></td>
+<td>Public method to determine the highlighting formats for a line of text.</td>
+</tr><tr>
+<td><a href="#E5GenericDiffHighlighter.generateRules">generateRules</a></td>
+<td>Public method to generate the rule set.</td>
+</tr><tr>
+<td><a href="#E5GenericDiffHighlighter.highlightBlock">highlightBlock</a></td>
+<td>Public method to highlight a block of text.</td>
+</tr><tr>
+<td><a href="#E5GenericDiffHighlighter.makeFormat">makeFormat</a></td>
+<td>Public method to generate a format definition.</td>
+</tr>
+</table>
+<h3>Static Methods</h3>
+<table>
+<tr><td>None</td></tr>
+</table>
+<a NAME="E5GenericDiffHighlighter.__init__" ID="E5GenericDiffHighlighter.__init__"></a>
+<h4>E5GenericDiffHighlighter (Constructor)</h4>
+<b>E5GenericDiffHighlighter</b>(<i>doc</i>)
+<p>
+        Constructor
+</p><dl>
+<dt><i>doc</i></dt>
+<dd>
+reference to the text document (QTextDocument)
+</dd>
+</dl><a NAME="E5GenericDiffHighlighter.createRules" ID="E5GenericDiffHighlighter.createRules"></a>
+<h4>E5GenericDiffHighlighter.createRules</h4>
+<b>createRules</b>(<i>*rules</i>)
+<p>
+        Public method to create the highlighting rules.
+</p><dl>
+<dt><i>rules</i></dt>
+<dd>
+set of highlighting rules (list of tuples of rule
+            pattern (string) and highlighting format (QTextCharFormat))
+</dd>
+</dl><a NAME="E5GenericDiffHighlighter.formats" ID="E5GenericDiffHighlighter.formats"></a>
+<h4>E5GenericDiffHighlighter.formats</h4>
+<b>formats</b>(<i>line</i>)
+<p>
+        Public method to determine the highlighting formats for a line of
+        text.
+</p><dl>
+<dt><i>line</i></dt>
+<dd>
+text line to be highlighted (string)
+</dd>
+</dl><dl>
+<dt>Returns:</dt>
+<dd>
+list of matched highlighting rules (list of tuples of match
+            object and format (QTextCharFormat))
+</dd>
+</dl><a NAME="E5GenericDiffHighlighter.generateRules" ID="E5GenericDiffHighlighter.generateRules"></a>
+<h4>E5GenericDiffHighlighter.generateRules</h4>
+<b>generateRules</b>(<i></i>)
+<p>
+        Public method to generate the rule set.
+</p><p>
+        Note: This method must me implemented by derived syntax
+        highlighters.
+</p><a NAME="E5GenericDiffHighlighter.highlightBlock" ID="E5GenericDiffHighlighter.highlightBlock"></a>
+<h4>E5GenericDiffHighlighter.highlightBlock</h4>
+<b>highlightBlock</b>(<i>text</i>)
+<p>
+        Public method to highlight a block of text.
+</p><dl>
+<dt><i>text</i></dt>
+<dd>
+text to be highlighted (string)
+</dd>
+</dl><a NAME="E5GenericDiffHighlighter.makeFormat" ID="E5GenericDiffHighlighter.makeFormat"></a>
+<h4>E5GenericDiffHighlighter.makeFormat</h4>
+<b>makeFormat</b>(<i>fg=None, bg=None, bold=False</i>)
+<p>
+        Public method to generate a format definition.
+</p><dl>
+<dt><i>fg</i></dt>
+<dd>
+foreground color (QColor)
+</dd><dt><i>bg</i></dt>
+<dd>
+background color (QColor)
+</dd><dt><i>bold</i></dt>
+<dd>
+flag indicating bold text (boolean)
+</dd>
+</dl><dl>
+<dt>Returns:</dt>
+<dd>
+format definiton (QTextCharFormat)
+</dd>
+</dl>
+<div align="right"><a href="#top">Up</a></div>
+<hr /><hr />
+<a NAME="TERMINAL" ID="TERMINAL"></a>
+<h2>TERMINAL</h2>
+<b>TERMINAL</b>(<i>pattern</i>)
+<p>
+    Function to mark a pattern as the final one to search for.
+</p><dl>
+<dt><i>pattern</i></dt>
+<dd>
+pattern to be marked (string)
+</dd><dt><i>return</i></dt>
+<dd>
+marked pattern (string)
+</dd>
+</dl>
+<div align="right"><a href="#top">Up</a></div>
+<hr />
+</body></html>
\ No newline at end of file
--- a/Documentation/Source/index-eric6.E5Gui.html	Sun Feb 08 16:16:32 2015 +0100
+++ b/Documentation/Source/index-eric6.E5Gui.html	Sun Feb 08 19:12:05 2015 +0100
@@ -54,6 +54,9 @@
 <td><a href="eric6.E5Gui.E5FileDialog.html">E5FileDialog</a></td>
 <td>Module implementing alternative functions for the QFileDialog static methods to cope with distributor's usage of KDE wrapper dialogs for Qt file dialogs.</td>
 </tr><tr>
+<td><a href="eric6.E5Gui.E5GenericDiffHighlighter.html">E5GenericDiffHighlighter</a></td>
+<td>Module implementing a syntax highlighter for diff outputs.</td>
+</tr><tr>
 <td><a href="eric6.E5Gui.E5Led.html">E5Led</a></td>
 <td>Module implementing a LED widget.</td>
 </tr><tr>
--- /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
--- a/eric6.e4p	Sun Feb 08 16:16:32 2015 +0100
+++ b/eric6.e4p	Sun Feb 08 19:12:05 2015 +0100
@@ -1154,6 +1154,7 @@
     <Source>E5Gui/E5StringListEditWidget.py</Source>
     <Source>Preferences/ConfigurationPages/LogViewerPage.py</Source>
     <Source>Preferences/ConfigurationPages/MimeTypesPage.py</Source>
+    <Source>E5Gui/E5GenericDiffHighlighter.py</Source>
   </Sources>
   <Forms>
     <Form>PyUnit/UnittestDialog.ui</Form>

eric ide

mercurial