Source code for openalea.oalab.editor.highlight

# -*- python -*-
#
#       OpenAlea.OALab: Multi-Paradigm GUI
#
#       Copyright 2013 INRIA - CIRAD - INRA
#
#       File author(s): Julien Coste <julien.coste@inria.fr>
#
#       File contributor(s):
#
#       Distributed under the Cecill-C License.
#       See accompanying file LICENSE.txt or copy at
#           http://www.cecill.info/licences/Licence_CeCILL-C_V1-en.html
#
#       OpenAlea WebSite : http://openalea.gforge.inria.fr
#
###############################################################################
__revision__ = ""

from openalea.vpltk.qt import QtGui
from pygments.formatters.html import HtmlFormatter
from pygments.lexers import guess_lexer_for_filename, PythonLexer
from pygments.styles import get_style_by_name


[docs]class Highlighter(QtGui.QSyntaxHighlighter): def __init__(self, parent, lexer=None): super(Highlighter, self).__init__(parent) self._document = self.document() self._formatter = HtmlFormatter() self._lexer = lexer if lexer else PythonLexer() self.set_style('default')
[docs] def highlightBlock(self, string): """ Highlight a block of text. """ prev_data = self.currentBlock().previous().userData() if prev_data is not None: self._lexer._saved_state_stack = prev_data.syntax_stack elif hasattr(self._lexer, '_saved_state_stack'): del self._lexer._saved_state_stack # Lex the text using Pygments index = 0 for token, text in self._lexer.get_tokens(string): length = len(text) self.setFormat(index, length, self._get_format(token)) index += length if hasattr(self._lexer, '_saved_state_stack'): data = PygmentsBlockUserData( syntax_stack=self._lexer._saved_state_stack) self.currentBlock().setUserData(data) # Clean up for the next go-round. del self._lexer._saved_state_stack
[docs] 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()
[docs] 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. """ self._brushes = {} self._formats = {} def _get_format(self, token): """ Returns a QTextCharFormat for token or None. """ if token in self._formats: return self._formats[token] 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 = next(self._formatter._format_lines([(token, u'dummy')])) 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. """ result = QtGui.QTextCharFormat() for key, value in style.style_for_token(token).items(): 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): """ Returns a QColor built from a Pygments color string. """ qcolor = QtGui.QColor() qcolor.setRgb(int(color[:2], base=16), int(color[2:4], base=16), int(color[4:6], base=16)) return qcolor
[docs]class PygmentsBlockUserData(QtGui.QTextBlockUserData): """ 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]) return 'PygmentsBlockUserData(%s)' % kwds
[docs]class GenericHighlighter(Highlighter): def __init__(self, parent, lexer=None, filename="a.txt"): super(GenericHighlighter, self).__init__(parent=parent, lexer=lexer) self._document = self.document() self._formatter = HtmlFormatter() self._lexer = guess_lexer_for_filename(filename, "") print(self._lexer) self.set_style('default')