3 from PyQt4
.QtCore
import Qt
4 from PyQt4
.QtGui
import QFont
5 from PyQt4
.QtGui
import QSyntaxHighlighter
6 from PyQt4
.QtGui
import QTextCharFormat
8 class GenericSyntaxHighligher(QSyntaxHighlighter
):
10 def __init__(self
, doc
):
11 QSyntaxHighlighter
.__init
__(self
, doc
)
14 FINAL_STR
= '__FINAL__:'
15 def final(self
, pattern
=''):
16 '''Denotes that a pattern is the final pattern that should
17 be matched. If this pattern matches no other formats
18 will be applied, even if they would have matched.'''
19 return GenericSyntaxHighligher
.FINAL_STR
+ pattern
21 def create_rules(self
, *rules
):
23 raise Exception("create_rules requires an even "
24 "number of arguments.")
25 for idx
, rule
in enumerate(rules
):
27 formats
= rules
[idx
+1]
28 terminal
= rule
.startswith(self
.final())
30 rule
= rule
[len(self
.final()):]
31 regex
= re
.compile(rule
)
32 self
.__rules
.append((regex
, formats
, terminal
,))
34 def get_formats(self
, line
):
36 for regex
, fmts
, terminal
in self
.__rules
:
37 match
= regex
.match(line
)
39 matched
.append([match
, fmts
])
40 if terminal
: return matched
43 def mkformat(self
, fg
, bg
=None, bold
=False):
44 format
= QTextCharFormat()
45 if bold
: format
.setFontWeight(QFont
.Bold
)
46 format
.setForeground(fg
)
47 if bg
: format
.setBackground(bg
)
50 def highlightBlock(self
, qstr
):
51 ascii
= qstr
.toAscii().data()
53 formats
= self
.get_formats(ascii
)
54 if not formats
: return
55 for match
, fmts
in formats
:
58 groups
= match
.groups()
60 # No groups in the regex, assume this is a single rule
61 # that spans the entire line
63 self
.setFormat(0, len(ascii
), fmts
)
66 # Groups exist, rule is a tuple corresponding to group
67 for grpidx
, group
in enumerate(groups
):
69 if not group
: continue
70 # allow None as a no-op format
73 self
.setFormat(start
, start
+length
,
77 class DiffSyntaxHighlighter(GenericSyntaxHighligher
):
78 def __init__(self
, doc
,whitespace
=True):
79 GenericSyntaxHighligher
.__init
__(self
,doc
)
81 diffstat
= self
.mkformat(Qt
.blue
, bold
=True)
82 diffstat_add
= self
.mkformat(Qt
.darkGreen
, bold
=True)
83 diffstat_remove
= self
.mkformat(Qt
.red
, bold
=True)
85 diff_begin
= self
.mkformat(Qt
.darkCyan
, bold
=True)
86 diff_head
= self
.mkformat(Qt
.darkYellow
)
87 diff_add
= self
.mkformat(Qt
.darkGreen
)
88 diff_remove
= self
.mkformat(Qt
.red
)
91 bad_ws
= self
.mkformat(Qt
.black
, Qt
.red
)
93 # We specify the whitespace rule last so that it is
94 # applied after the diff addition/removal rules.
95 # The rules for the header
97 self
.final('^@@|^\+\+\+|^---'), diff_begin
,
98 self
.final('^diff --git'), diff_head
,
99 self
.final('^index \S+\.\.\S+'), diff_head
,
100 self
.final('^new file mode'), diff_head
,
101 self
.final('^\+'), diff_add
,
102 self
.final('^-'), diff_remove
,
104 '(.+\|.+?)(\d+)(.+?)([\+]*?)([-]*?)$',
105 (None, diffstat
, None, diffstat_add
, diffstat_remove
),
107 '(\s+\d+ files changed[^\d]*)'
108 '(:?\d+ insertions[^\d]*)'
109 '(:?\d+ deletions.*)$',
110 (diffstat
, diffstat_add
, diffstat_remove
),
113 self
.create_rules('(.+)(\s+)$', (None, bad_ws
,))
115 class LogSyntaxHighlighter(GenericSyntaxHighligher
):
116 def __init__(self
, doc
):
117 GenericSyntaxHighligher
.__init
__(self
,doc
)
119 black
= self
.mkformat(Qt
.black
, bold
=True)
120 blue
= self
.mkformat(Qt
.blue
, bold
=True)
121 dark_cyan
= self
.mkformat(Qt
.darkCyan
, bold
=True)
124 self
.final('^\w{3}\W+\w{3}\W+\d+\W+'
131 if __name__
== '__main__':
133 from PyQt4
import QtCore
, QtGui
134 class SyntaxTestDialog(QtGui
.QDialog
):
135 def __init__(self
, parent
):
136 QtGui
.QDialog
.__init
__(self
, parent
)
138 def setupUi(self
, dialog
):
139 dialog
.resize(QtCore
.QSize(QtCore
.QRect(0,0,720,512).size()).expandedTo(dialog
.minimumSizeHint()))
140 self
.vboxlayout
= QtGui
.QVBoxLayout(dialog
)
141 self
.vboxlayout
.setObjectName("vboxlayout")
142 self
.output_text
= QtGui
.QTextEdit(dialog
)
144 font
.setFamily("Monospace")
145 font
.setPointSize(13)
146 self
.output_text
.setFont(font
)
147 self
.output_text
.setAcceptDrops(False)
148 self
.vboxlayout
.addWidget(self
.output_text
)
149 DiffSyntaxHighlighter(self
.output_text
.document())
150 app
= QtGui
.QApplication(sys
.argv
)
151 dialog
= SyntaxTestDialog(app
.activeWindow())