oops: fixed git reset usage
[ugit.git] / ugit / syntax.py
blob0c3b74071842b0a1b2ababfb0b24e58929f09749
1 #!/usr/bin/python
2 import re
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)
12 self.__rules = []
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):
22 if len(rules) % 2:
23 raise Exception("create_rules requires an even "
24 "number of arguments.")
25 for idx, rule in enumerate(rules):
26 if idx % 2: continue
27 formats = rules[idx+1]
28 terminal = rule.startswith(self.final())
29 if terminal:
30 rule = rule[len(self.final()):]
31 regex = re.compile(rule)
32 self.__rules.append((regex, formats, terminal,))
34 def get_formats(self, line):
35 matched = []
36 for regex, fmts, terminal in self.__rules:
37 match = regex.match(line)
38 if match:
39 matched.append([match, fmts])
40 if terminal: return matched
41 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)
48 return format
50 def highlightBlock(self, qstr):
51 ascii = qstr.toAscii().data()
52 if not ascii: return
53 formats = self.get_formats(ascii)
54 if not formats: return
55 for match, fmts in formats:
56 start = match.start()
57 end = match.end()
58 groups = match.groups()
60 # No groups in the regex, assume this is a single rule
61 # that spans the entire line
62 if not groups:
63 self.setFormat(0, len(ascii), fmts)
64 continue
66 # Groups exist, rule is a tuple corresponding to group
67 for grpidx, group in enumerate(groups):
68 # allow empty matches
69 if not group: continue
70 # allow None as a no-op format
71 length = len(group)
72 if fmts[grpidx]:
73 self.setFormat(start, start+length,
74 fmts[grpidx])
75 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)
90 if whitespace:
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
96 self.create_rules(
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),
112 if whitespace:
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)
123 self.create_rules(
124 self.final('^\w{3}\W+\w{3}\W+\d+\W+'
125 '[:0-9]+\W+\d{4}$'),
126 dark_cyan,
127 '^([^:]+:)(.*)$',
128 (blue, black),
131 if __name__ == '__main__':
132 import sys
133 from PyQt4 import QtCore, QtGui
134 class SyntaxTestDialog(QtGui.QDialog):
135 def __init__(self, parent):
136 QtGui.QDialog.__init__(self, parent)
137 self.setupUi(self)
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)
143 font = QtGui.QFont()
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())
152 dialog.show()
153 dialog.exec_()