##// END OF EJS Templates
Fully refactored subprocess handling on all platforms....
Fully refactored subprocess handling on all platforms. Now we have all process-related code in utils.process, which itself imports from platform-specific files as needed. On posix, we have reliable asynchronous delivery of stdout and stderr, and on win32 at least we have the basics that subprocess.py provides, since pexpect is not available. We also now support robust killing of subprocesses that may capture SIGINT: one SIGINT on our end is sent to the subprocess, but then we kill it, to prevent a rogue subprocess from hijacking the ipython console. Note that on posix, we now depend on pexpect, but we ship our own copy to users which we'll use if there's no system pexpect installed. UNC path handling for windows was implemented as a context manager called AvoidUNCPath.

File last commit:

r2894:d23d38e7
r2908:06dcbd43
Show More
pygments_highlighter.py
226 lines | 8.1 KiB | text/x-python | PythonLexer
/ IPython / frontend / qt / console / pygments_highlighter.py
epatters
Fixed imports and removed references to ETS/EPD
r2603 # System library imports.
epatters
Initial checkin of Qt frontend code.
r2602 from PyQt4 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
def get_tokens_unprocessed(self, text, stack=('root',)):
""" Split ``text`` into (tokentype, text) pairs.
Monkeypatched to store the final stack on the object itself.
"""
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:
if type(action) is _TokenType:
yield pos, action, m.group()
else:
for item in action(self, m):
yield item
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):
for key, value in kwds.iteritems():
setattr(self, key, value)
QtGui.QTextBlockUserData.__init__(self)
def __repr__(self):
attrs = ['syntax_stack']
kwds = ', '.join([ '%s=%r' % (attr, getattr(self, attr))
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)
epatters
IPythonWidget now supports styling the syntax highlighting.
r2728 self._document = QtGui.QTextDocument()
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
def highlightBlock(self, qstring):
""" Highlight a block of text.
"""
qstring = unicode(qstring)
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
epatters
Initial checkin of Qt frontend code.
r2602 for token, text in self._lexer.get_tokens(qstring):
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.
"""
if isinstance(style, basestring):
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):
""" Returns a QTextCharFormat for token by
"""
code, html = self._formatter._format_lines([(token, 'dummy')]).next()
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