##// END OF EJS Templates
Merge pull request #7660 from minrk/overlayHackHack...
Merge pull request #7660 from minrk/overlayHackHack Reverse hscrollbar min-height hack on OS X

File last commit:

r18720:8f21962e
r20353:2f6a0eff merge
Show More
pygments_highlighter.py
232 lines | 8.5 KiB | text/x-python | PythonLexer
/ IPython / qt / console / pygments_highlighter.py
epatters
Fixed imports and removed references to ETS/EPD
r2603 # System library imports.
Evan Patterson
Paved the way for PySide support....
r3304 from IPython.external.qt import QtGui
epatters
IPythonWidget now supports styling the syntax highlighting.
r2728 from pygments.formatters.html import HtmlFormatter
epatters
Initial checkin of Qt frontend code.
r2602 from pygments.lexer import RegexLexer, _TokenType, Text, Error
epatters
* IPythonWidget now has IPython-style prompts that are futher stylabla via CSS...
r2715 from pygments.lexers import PythonLexer
epatters
IPythonWidget now supports styling the syntax highlighting.
r2728 from pygments.styles import get_style_by_name
epatters
Initial checkin of Qt frontend code.
r2602
Thomas Kluyver
Replace references to unicode and basestring
r13353 # Local imports
from IPython.utils.py3compat import string_types
epatters
Initial checkin of Qt frontend code.
r2602
def get_tokens_unprocessed(self, text, stack=('root',)):
""" Split ``text`` into (tokentype, text) pairs.
Monkeypatched to store the final stack on the object itself.
Thomas Kluyver
Add some explanation about the pygments monkeypatch
r18720
The `text` parameter this gets passed is only the current line, so to
highlight things like multiline strings correctly, we need to retrieve
the state from the previous line (this is done in PygmentsHighlighter,
below), and use it to continue processing the current line.
epatters
Initial checkin of Qt frontend code.
r2602 """
pos = 0
tokendefs = self._tokens
epatters
Fixed imports and removed references to ETS/EPD
r2603 if hasattr(self, '_saved_state_stack'):
statestack = list(self._saved_state_stack)
epatters
Initial checkin of Qt frontend code.
r2602 else:
statestack = list(stack)
statetokens = tokendefs[statestack[-1]]
while 1:
for rexmatch, action, new_state in statetokens:
m = rexmatch(text, pos)
if m:
Carlos Cordoba
Update pygments monkeypatch for compatibility with Pygments 2.0...
r18719 if action is not None:
if type(action) is _TokenType:
yield pos, action, m.group()
else:
for item in action(self, m):
yield item
epatters
Initial checkin of Qt frontend code.
r2602 pos = m.end()
if new_state is not None:
# state transition
if isinstance(new_state, tuple):
for state in new_state:
if state == '#pop':
statestack.pop()
elif state == '#push':
statestack.append(statestack[-1])
else:
statestack.append(state)
elif isinstance(new_state, int):
# pop
del statestack[new_state:]
elif new_state == '#push':
statestack.append(statestack[-1])
else:
assert False, "wrong state def: %r" % new_state
statetokens = tokendefs[statestack[-1]]
break
else:
try:
if text[pos] == '\n':
# at EOL, reset state to "root"
pos += 1
statestack = ['root']
statetokens = tokendefs['root']
yield pos, Text, u'\n'
continue
yield pos, Error, text[pos]
pos += 1
except IndexError:
break
epatters
Fixed imports and removed references to ETS/EPD
r2603 self._saved_state_stack = list(statestack)
epatters
Initial checkin of Qt frontend code.
r2602
# Monkeypatch!
RegexLexer.get_tokens_unprocessed = get_tokens_unprocessed
epatters
* Fleshed out IPythonWidget's style control....
r2725 class PygmentsBlockUserData(QtGui.QTextBlockUserData):
epatters
Initial checkin of Qt frontend code.
r2602 """ Storage for the user data associated with each line.
"""
syntax_stack = ('root',)
def __init__(self, **kwds):
Thomas Kluyver
Fix references to dict.iteritems and dict.itervalues
r13361 for key, value in kwds.items():
epatters
Initial checkin of Qt frontend code.
r2602 setattr(self, key, value)
QtGui.QTextBlockUserData.__init__(self)
def __repr__(self):
attrs = ['syntax_stack']
Bernardo B. Marques
remove all trailling spaces
r4872 kwds = ', '.join([ '%s=%r' % (attr, getattr(self, attr))
epatters
Initial checkin of Qt frontend code.
r2602 for attr in attrs ])
epatters
* Fleshed out IPythonWidget's style control....
r2725 return 'PygmentsBlockUserData(%s)' % kwds
epatters
Initial checkin of Qt frontend code.
r2602
class PygmentsHighlighter(QtGui.QSyntaxHighlighter):
""" Syntax highlighter that uses Pygments for parsing. """
epatters
IPythonWidget now supports styling the syntax highlighting.
r2728 #---------------------------------------------------------------------------
# 'QSyntaxHighlighter' interface
#---------------------------------------------------------------------------
epatters
Initial checkin of Qt frontend code.
r2602 def __init__(self, parent, lexer=None):
super(PygmentsHighlighter, self).__init__(parent)
MinRK
use self._document = self.document()...
r10082 self._document = self.document()
epatters
IPythonWidget now supports styling the syntax highlighting.
r2728 self._formatter = HtmlFormatter(nowrap=True)
epatters
Initial checkin of Qt frontend code.
r2602 self._lexer = lexer if lexer else PythonLexer()
epatters
IPythonWidget now supports styling the syntax highlighting.
r2728 self.set_style('default')
epatters
Initial checkin of Qt frontend code.
r2602
Evan Patterson
Paved the way for PySide support....
r3304 def highlightBlock(self, string):
epatters
Initial checkin of Qt frontend code.
r2602 """ Highlight a block of text.
"""
epatters
IPythonWidget now supports styling the syntax highlighting.
r2728 prev_data = self.currentBlock().previous().userData()
epatters
Initial checkin of Qt frontend code.
r2602 if prev_data is not None:
epatters
Fixed imports and removed references to ETS/EPD
r2603 self._lexer._saved_state_stack = prev_data.syntax_stack
elif hasattr(self._lexer, '_saved_state_stack'):
del self._lexer._saved_state_stack
epatters
Initial checkin of Qt frontend code.
r2602
# Lex the text using Pygments
epatters
First cut at a generic bracket matcher for Q[Plain]TextEdits.
r2894 index = 0
Evan Patterson
Paved the way for PySide support....
r3304 for token, text in self._lexer.get_tokens(string):
epatters
First cut at a generic bracket matcher for Q[Plain]TextEdits.
r2894 length = len(text)
self.setFormat(index, length, self._get_format(token))
index += length
epatters
Initial checkin of Qt frontend code.
r2602
epatters
Fixed imports and removed references to ETS/EPD
r2603 if hasattr(self._lexer, '_saved_state_stack'):
epatters
* Fleshed out IPythonWidget's style control....
r2725 data = PygmentsBlockUserData(
syntax_stack=self._lexer._saved_state_stack)
epatters
Initial checkin of Qt frontend code.
r2602 self.currentBlock().setUserData(data)
# Clean up for the next go-round.
epatters
Fixed imports and removed references to ETS/EPD
r2603 del self._lexer._saved_state_stack
epatters
Initial checkin of Qt frontend code.
r2602
epatters
IPythonWidget now supports styling the syntax highlighting.
r2728 #---------------------------------------------------------------------------
# 'PygmentsHighlighter' interface
#---------------------------------------------------------------------------
def set_style(self, style):
""" Sets the style to the specified Pygments style.
"""
Thomas Kluyver
Replace references to unicode and basestring
r13353 if isinstance(style, string_types):
epatters
IPythonWidget now supports styling the syntax highlighting.
r2728 style = get_style_by_name(style)
self._style = style
self._clear_caches()
def set_style_sheet(self, stylesheet):
""" Sets a CSS stylesheet. The classes in the stylesheet should
correspond to those generated by:
pygmentize -S <style> -f html
Note that 'set_style' and 'set_style_sheet' completely override each
other, i.e. they cannot be used in conjunction.
"""
self._document.setDefaultStyleSheet(stylesheet)
self._style = None
self._clear_caches()
#---------------------------------------------------------------------------
# Protected interface
#---------------------------------------------------------------------------
def _clear_caches(self):
""" Clear caches for brushes and formats.
epatters
Initial checkin of Qt frontend code.
r2602 """
epatters
IPythonWidget now supports styling the syntax highlighting.
r2728 self._brushes = {}
self._formats = {}
epatters
Initial checkin of Qt frontend code.
r2602
def _get_format(self, token):
""" Returns a QTextCharFormat for token or None.
"""
if token in self._formats:
return self._formats[token]
epatters
IPythonWidget now supports styling the syntax highlighting.
r2728
if self._style is None:
result = self._get_format_from_document(token, self._document)
else:
result = self._get_format_from_style(token, self._style)
self._formats[token] = result
return result
def _get_format_from_document(self, token, document):
Bernardo B. Marques
remove all trailling spaces
r4872 """ Returns a QTextCharFormat for token by
epatters
IPythonWidget now supports styling the syntax highlighting.
r2728 """
Bradley M. Froehle
Apply 2to3 `next` fix....
r7847 code, html = next(self._formatter._format_lines([(token, u'dummy')]))
epatters
IPythonWidget now supports styling the syntax highlighting.
r2728 self._document.setHtml(html)
return QtGui.QTextCursor(self._document).charFormat()
def _get_format_from_style(self, token, style):
""" Returns a QTextCharFormat for token by reading a Pygments style.
"""
epatters
First cut at a generic bracket matcher for Q[Plain]TextEdits.
r2894 result = QtGui.QTextCharFormat()
epatters
IPythonWidget now supports styling the syntax highlighting.
r2728 for key, value in style.style_for_token(token).items():
epatters
Initial checkin of Qt frontend code.
r2602 if value:
if key == 'color':
result.setForeground(self._get_brush(value))
elif key == 'bgcolor':
result.setBackground(self._get_brush(value))
elif key == 'bold':
result.setFontWeight(QtGui.QFont.Bold)
elif key == 'italic':
result.setFontItalic(True)
elif key == 'underline':
result.setUnderlineStyle(
QtGui.QTextCharFormat.SingleUnderline)
elif key == 'sans':
result.setFontStyleHint(QtGui.QFont.SansSerif)
elif key == 'roman':
result.setFontStyleHint(QtGui.QFont.Times)
elif key == 'mono':
result.setFontStyleHint(QtGui.QFont.TypeWriter)
return result
def _get_brush(self, color):
""" Returns a brush for the color.
"""
result = self._brushes.get(color)
if result is None:
qcolor = self._get_color(color)
result = QtGui.QBrush(qcolor)
self._brushes[color] = result
return result
def _get_color(self, color):
epatters
* Fleshed out IPythonWidget's style control....
r2725 """ Returns a QColor built from a Pygments color string.
"""
epatters
Initial checkin of Qt frontend code.
r2602 qcolor = QtGui.QColor()
epatters
* IPythonWidget now has IPython-style prompts that are futher stylabla via CSS...
r2715 qcolor.setRgb(int(color[:2], base=16),
epatters
Initial checkin of Qt frontend code.
r2602 int(color[2:4], base=16),
int(color[4:6], base=16))
return qcolor