Show More
@@ -41,7 +41,7 class IPythonWidget(FrontendWidget): | |||||
41 | self._prompt_count = 0 |
|
41 | self._prompt_count = 0 | |
42 |
|
42 | |||
43 | # Set a default stylesheet. |
|
43 | # Set a default stylesheet. | |
44 |
self.reset_styl |
|
44 | self.reset_styling() | |
45 |
|
45 | |||
46 | #--------------------------------------------------------------------------- |
|
46 | #--------------------------------------------------------------------------- | |
47 | # 'FrontendWidget' interface |
|
47 | # 'FrontendWidget' interface | |
@@ -106,17 +106,35 class IPythonWidget(FrontendWidget): | |||||
106 | # 'IPythonWidget' interface |
|
106 | # 'IPythonWidget' interface | |
107 | #--------------------------------------------------------------------------- |
|
107 | #--------------------------------------------------------------------------- | |
108 |
|
108 | |||
109 |
def reset_styl |
|
109 | def reset_styling(self): | |
110 |
""" |
|
110 | """ Restores the default IPythonWidget styling. | |
111 | """ |
|
111 | """ | |
112 |
self.set_styl |
|
112 | self.set_styling(self.default_stylesheet, syntax_style='default') | |
113 |
|
113 | #self.set_styling(self.dark_stylesheet, syntax_style='monokai') | ||
114 | def set_style_sheet(self, stylesheet): |
|
114 | ||
115 | """ Sets the style sheet. |
|
115 | def set_styling(self, stylesheet, syntax_style=None): | |
|
116 | """ Sets the IPythonWidget styling. | |||
|
117 | ||||
|
118 | Parameters: | |||
|
119 | ----------- | |||
|
120 | stylesheet : str | |||
|
121 | A CSS stylesheet. The stylesheet can contain classes for: | |||
|
122 | 1. Qt: QPlainTextEdit, QFrame, QWidget, etc | |||
|
123 | 2. Pygments: .c, .k, .o, etc (see PygmentsHighlighter) | |||
|
124 | 3. IPython: .error, .in-prompt, .out-prompt, etc. | |||
|
125 | ||||
|
126 | syntax_style : str or None [default None] | |||
|
127 | If specified, use the Pygments style with given name. Otherwise, | |||
|
128 | the stylesheet is queried for Pygments style information. | |||
116 | """ |
|
129 | """ | |
117 | self.setStyleSheet(stylesheet) |
|
130 | self.setStyleSheet(stylesheet) | |
118 | self.document().setDefaultStyleSheet(stylesheet) |
|
131 | self.document().setDefaultStyleSheet(stylesheet) | |
119 |
|
132 | |||
|
133 | if syntax_style is None: | |||
|
134 | self._highlighter.set_style_sheet(stylesheet) | |||
|
135 | else: | |||
|
136 | self._highlighter.set_style(syntax_style) | |||
|
137 | ||||
120 |
|
138 | |||
121 | if __name__ == '__main__': |
|
139 | if __name__ == '__main__': | |
122 | from IPython.frontend.qt.kernelmanager import QtKernelManager |
|
140 | from IPython.frontend.qt.kernelmanager import QtKernelManager |
@@ -1,9 +1,9 | |||||
1 | # System library imports. |
|
1 | # System library imports. | |
2 | from PyQt4 import QtGui |
|
2 | from PyQt4 import QtGui | |
|
3 | from pygments.formatters.html import HtmlFormatter | |||
3 | from pygments.lexer import RegexLexer, _TokenType, Text, Error |
|
4 | from pygments.lexer import RegexLexer, _TokenType, Text, Error | |
4 | from pygments.lexers import PythonLexer |
|
5 | from pygments.lexers import PythonLexer | |
5 |
from pygments.styles |
|
6 | from pygments.styles import get_style_by_name | |
6 | from pygments.token import Comment |
|
|||
7 |
|
7 | |||
8 |
|
8 | |||
9 | def get_tokens_unprocessed(self, text, stack=('root',)): |
|
9 | def get_tokens_unprocessed(self, text, stack=('root',)): | |
@@ -87,20 +87,23 class PygmentsBlockUserData(QtGui.QTextBlockUserData): | |||||
87 | class PygmentsHighlighter(QtGui.QSyntaxHighlighter): |
|
87 | class PygmentsHighlighter(QtGui.QSyntaxHighlighter): | |
88 | """ Syntax highlighter that uses Pygments for parsing. """ |
|
88 | """ Syntax highlighter that uses Pygments for parsing. """ | |
89 |
|
89 | |||
|
90 | #--------------------------------------------------------------------------- | |||
|
91 | # 'QSyntaxHighlighter' interface | |||
|
92 | #--------------------------------------------------------------------------- | |||
|
93 | ||||
90 | def __init__(self, parent, lexer=None): |
|
94 | def __init__(self, parent, lexer=None): | |
91 | super(PygmentsHighlighter, self).__init__(parent) |
|
95 | super(PygmentsHighlighter, self).__init__(parent) | |
92 |
|
96 | |||
|
97 | self._document = QtGui.QTextDocument() | |||
|
98 | self._formatter = HtmlFormatter(nowrap=True) | |||
93 | self._lexer = lexer if lexer else PythonLexer() |
|
99 | self._lexer = lexer if lexer else PythonLexer() | |
94 |
self._style |
|
100 | self.set_style('default') | |
95 | # Caches for formats and brushes. |
|
|||
96 | self._brushes = {} |
|
|||
97 | self._formats = {} |
|
|||
98 |
|
101 | |||
99 | def highlightBlock(self, qstring): |
|
102 | def highlightBlock(self, qstring): | |
100 | """ Highlight a block of text. |
|
103 | """ Highlight a block of text. | |
101 | """ |
|
104 | """ | |
102 | qstring = unicode(qstring) |
|
105 | qstring = unicode(qstring) | |
103 |
prev_data = self.previous |
|
106 | prev_data = self.currentBlock().previous().userData() | |
104 |
|
107 | |||
105 | if prev_data is not None: |
|
108 | if prev_data is not None: | |
106 | self._lexer._saved_state_stack = prev_data.syntax_stack |
|
109 | self._lexer._saved_state_stack = prev_data.syntax_stack | |
@@ -123,18 +126,67 class PygmentsHighlighter(QtGui.QSyntaxHighlighter): | |||||
123 | # Clean up for the next go-round. |
|
126 | # Clean up for the next go-round. | |
124 | del self._lexer._saved_state_stack |
|
127 | del self._lexer._saved_state_stack | |
125 |
|
128 | |||
126 | def previous_block_data(self): |
|
129 | #--------------------------------------------------------------------------- | |
127 | """ Convenience method for returning the previous block's user data. |
|
130 | # 'PygmentsHighlighter' interface | |
|
131 | #--------------------------------------------------------------------------- | |||
|
132 | ||||
|
133 | def set_style(self, style): | |||
|
134 | """ Sets the style to the specified Pygments style. | |||
|
135 | """ | |||
|
136 | if isinstance(style, basestring): | |||
|
137 | style = get_style_by_name(style) | |||
|
138 | self._style = style | |||
|
139 | self._clear_caches() | |||
|
140 | ||||
|
141 | def set_style_sheet(self, stylesheet): | |||
|
142 | """ Sets a CSS stylesheet. The classes in the stylesheet should | |||
|
143 | correspond to those generated by: | |||
|
144 | ||||
|
145 | pygmentize -S <style> -f html | |||
|
146 | ||||
|
147 | Note that 'set_style' and 'set_style_sheet' completely override each | |||
|
148 | other, i.e. they cannot be used in conjunction. | |||
|
149 | """ | |||
|
150 | self._document.setDefaultStyleSheet(stylesheet) | |||
|
151 | self._style = None | |||
|
152 | self._clear_caches() | |||
|
153 | ||||
|
154 | #--------------------------------------------------------------------------- | |||
|
155 | # Protected interface | |||
|
156 | #--------------------------------------------------------------------------- | |||
|
157 | ||||
|
158 | def _clear_caches(self): | |||
|
159 | """ Clear caches for brushes and formats. | |||
128 | """ |
|
160 | """ | |
129 | return self.currentBlock().previous().userData() |
|
161 | self._brushes = {} | |
|
162 | self._formats = {} | |||
130 |
|
163 | |||
131 | def _get_format(self, token): |
|
164 | def _get_format(self, token): | |
132 | """ Returns a QTextCharFormat for token or None. |
|
165 | """ Returns a QTextCharFormat for token or None. | |
133 | """ |
|
166 | """ | |
134 | if token in self._formats: |
|
167 | if token in self._formats: | |
135 | return self._formats[token] |
|
168 | return self._formats[token] | |
|
169 | ||||
|
170 | if self._style is None: | |||
|
171 | result = self._get_format_from_document(token, self._document) | |||
|
172 | else: | |||
|
173 | result = self._get_format_from_style(token, self._style) | |||
|
174 | ||||
|
175 | self._formats[token] = result | |||
|
176 | return result | |||
|
177 | ||||
|
178 | def _get_format_from_document(self, token, document): | |||
|
179 | """ Returns a QTextCharFormat for token by | |||
|
180 | """ | |||
|
181 | code, html = self._formatter._format_lines([(token, 'dummy')]).next() | |||
|
182 | self._document.setHtml(html) | |||
|
183 | return QtGui.QTextCursor(self._document).charFormat() | |||
|
184 | ||||
|
185 | def _get_format_from_style(self, token, style): | |||
|
186 | """ Returns a QTextCharFormat for token by reading a Pygments style. | |||
|
187 | """ | |||
136 | result = None |
|
188 | result = None | |
137 |
for key, value in |
|
189 | for key, value in style.style_for_token(token).items(): | |
138 | if value: |
|
190 | if value: | |
139 | if result is None: |
|
191 | if result is None: | |
140 | result = QtGui.QTextCharFormat() |
|
192 | result = QtGui.QTextCharFormat() | |
@@ -155,13 +207,6 class PygmentsHighlighter(QtGui.QSyntaxHighlighter): | |||||
155 | result.setFontStyleHint(QtGui.QFont.Times) |
|
207 | result.setFontStyleHint(QtGui.QFont.Times) | |
156 | elif key == 'mono': |
|
208 | elif key == 'mono': | |
157 | result.setFontStyleHint(QtGui.QFont.TypeWriter) |
|
209 | result.setFontStyleHint(QtGui.QFont.TypeWriter) | |
158 | elif key == 'border': |
|
|||
159 | # Borders are normally used for errors. We can't do a border |
|
|||
160 | # so instead we do a wavy underline |
|
|||
161 | result.setUnderlineStyle( |
|
|||
162 | QtGui.QTextCharFormat.WaveUnderline) |
|
|||
163 | result.setUnderlineColor(self._get_color(value)) |
|
|||
164 | self._formats[token] = result |
|
|||
165 | return result |
|
210 | return result | |
166 |
|
211 | |||
167 | def _get_brush(self, color): |
|
212 | def _get_brush(self, color): |
General Comments 0
You need to be logged in to leave comments.
Login now