core: make getcwd() fail-safe
[git-cola.git] / cola / widgets / highlighter.py
blobff82f1499a9fc2a1fe3c1e8d536ae1950f2f99de
1 from __future__ import division, absolute_import, unicode_literals
3 from qtpy import QtCore
4 from qtpy import QtGui
5 from qtpy import QtWidgets
7 have_pygments = True
8 try:
9 from pygments.styles import get_style_by_name
10 from pygments import lex
11 from pygments.util import ClassNotFound
12 from pygments.lexers import get_lexer_for_filename
13 except ImportError:
14 have_pygments = False
17 def highlight_document(edit, filename):
18 if not have_pygments:
19 return
20 doc = edit.document()
21 try:
22 lexer = get_lexer_for_filename(filename, stripnl=False)
23 except ClassNotFound:
24 return
26 style = get_style_by_name('default')
28 font = doc.defaultFont()
29 base_format = QtGui.QTextCharFormat()
30 base_format.setFont(font)
31 token_formats = {}
33 window = edit.window()
34 if hasattr(window, 'processEvents'):
35 processEvents = window.processEvents
36 else:
37 processEvents = QtCore.QCoreApplication.processEvents
39 def get_token_format(token):
40 if token in token_formats:
41 return token_formats[token]
43 if token.parent:
44 parent_format = get_token_format(token.parent)
45 else:
46 parent_format = base_format
48 fmt = QtGui.QTextCharFormat(parent_format)
49 font = fmt.font()
50 if style.styles_token(token):
51 tstyle = style.style_for_token(token)
52 if tstyle['color']:
53 fmt.setForeground(QtGui.QColor('#' + tstyle['color']))
54 if tstyle['bold']:
55 font.setWeight(QtGui.QFont.Bold)
56 if tstyle['italic']:
57 font.setItalic(True)
58 if tstyle['underline']:
59 fmt.setFontUnderline(True)
60 if tstyle['bgcolor']:
61 fmt.setBackground(QtGui.QColor('#' + tstyle['bgcolor']))
62 token_formats[token] = fmt
63 return fmt
65 text = doc.toPlainText()
67 block_count = 0
68 block = doc.firstBlock()
69 assert isinstance(block, QtGui.QTextBlock)
70 block_pos = 0
71 block_len = block.length()
72 block_formats = []
74 for token, ttext in lex(text, lexer):
75 format_len = len(ttext)
76 fmt = get_token_format(token)
77 while format_len > 0:
78 format_range = QtGui.QTextLayout.FormatRange()
79 format_range.start = block_pos
80 format_range.length = min(format_len, block_len)
81 format_range.format = fmt
82 block_formats.append(format_range)
83 block_len -= format_range.length
84 format_len -= format_range.length
85 block_pos += format_range.length
86 if block_len == 0:
87 block.layout().setAdditionalFormats(block_formats)
88 doc.markContentsDirty(block.position(), block.length())
89 block = block.next() # pylint: disable=next-method-called
90 block_pos = 0
91 block_len = block.length()
92 block_formats = []
94 block_count += 1
95 if block_count % 100 == 0:
96 processEvents()
99 if __name__ == '__main__':
100 app = QtWidgets.QApplication([])
102 python = QtWidgets.QPlainTextEdit()
103 f = open(__file__, 'r')
104 python.setPlainText(f.read())
105 f.close()
107 python.setWindowTitle('python')
108 python.show()
109 highlight_document(python, __file__)
111 app.exec_()