Wed, 05 Jan 2011 15:46:19 +0100
Updated Pygments to version 1.4.0.
# -*- coding: utf-8 -*- # Copyright (c) 2008 - 2011 Detlev Offenbach <detlev@die-offenbachs.de> # """ Module implementing a custom lexer using pygments. """ from pygments.token import Token from pygments.lexers import guess_lexer_for_filename, guess_lexer, find_lexer_class from pygments.util import ClassNotFound from PyQt4.QtGui import QColor, QFont from QScintilla.Lexers.LexerContainer import LexerContainer import Utilities PYGMENTS_DEFAULT, \ PYGMENTS_COMMENT, \ PYGMENTS_PREPROCESSOR, \ PYGMENTS_KEYWORD, \ PYGMENTS_PSEUDOKEYWORD, \ PYGMENTS_TYPEKEYWORD, \ PYGMENTS_OPERATOR, \ PYGMENTS_WORD, \ PYGMENTS_BUILTIN, \ PYGMENTS_FUNCTION, \ PYGMENTS_CLASS, \ PYGMENTS_NAMESPACE, \ PYGMENTS_EXCEPTION, \ PYGMENTS_VARIABLE, \ PYGMENTS_CONSTANT, \ PYGMENTS_LABEL, \ PYGMENTS_ENTITY, \ PYGMENTS_ATTRIBUTE, \ PYGMENTS_TAG, \ PYGMENTS_DECORATOR, \ PYGMENTS_STRING, \ PYGMENTS_DOCSTRING, \ PYGMENTS_SCALAR, \ PYGMENTS_ESCAPE, \ PYGMENTS_REGEX, \ PYGMENTS_SYMBOL, \ PYGMENTS_OTHER, \ PYGMENTS_NUMBER, \ PYGMENTS_HEADING, \ PYGMENTS_SUBHEADING, \ PYGMENTS_DELETED, \ PYGMENTS_INSERTED = list(range(32)) # 32 to 39 are reserved for QScintilla internal styles PYGMENTS_GENERIC_ERROR, \ PYGMENTS_EMPHASIZE, \ PYGMENTS_STRONG, \ PYGMENTS_PROMPT, \ PYGMENTS_OUTPUT, \ PYGMENTS_TRACEBACK, \ PYGMENTS_ERROR, \ PYGMENTS_MULTILINECOMMENT, \ PYGMENTS_PROPERTY, \ PYGMENTS_CHAR, \ PYGMENTS_HEREDOC, \ PYGMENTS_PUNCTUATION = list(range(40, 52)) #-----------------------------------------------------------------------------# TOKEN_MAP = { Token.Comment: PYGMENTS_COMMENT, Token.Comment.Preproc: PYGMENTS_PREPROCESSOR, Token.Comment.Multiline: PYGMENTS_MULTILINECOMMENT, Token.Comment.Single: PYGMENTS_COMMENT, Token.Comment.Special: PYGMENTS_COMMENT, Token.Keyword: PYGMENTS_KEYWORD, Token.Keyword.Pseudo: PYGMENTS_PSEUDOKEYWORD, Token.Keyword.Type: PYGMENTS_TYPEKEYWORD, Token.Keyword.Namespace: PYGMENTS_KEYWORD, Token.Operator: PYGMENTS_OPERATOR, Token.Operator.Word: PYGMENTS_WORD, Token.Name: PYGMENTS_DEFAULT, Token.Name.Builtin: PYGMENTS_BUILTIN, Token.Name.Builtin.Pseudo: PYGMENTS_BUILTIN, Token.Name.Function: PYGMENTS_FUNCTION, Token.Name.Class: PYGMENTS_CLASS, Token.Name.Namespace: PYGMENTS_NAMESPACE, Token.Name.Exception: PYGMENTS_EXCEPTION, Token.Name.Variable: PYGMENTS_VARIABLE, Token.Name.Variable.Class: PYGMENTS_VARIABLE, Token.Name.Variable.Global: PYGMENTS_VARIABLE, Token.Name.Variable.Instance: PYGMENTS_VARIABLE, Token.Name.Constant: PYGMENTS_CONSTANT, Token.Name.Label: PYGMENTS_LABEL, Token.Name.Entity: PYGMENTS_ENTITY, Token.Name.Attribute: PYGMENTS_ATTRIBUTE, Token.Name.Tag: PYGMENTS_TAG, Token.Name.Decorator: PYGMENTS_DECORATOR, Token.Name.Property: PYGMENTS_PROPERTY, Token.String: PYGMENTS_STRING, Token.String.Char: PYGMENTS_CHAR, Token.String.Doc: PYGMENTS_DOCSTRING, Token.String.Interpol: PYGMENTS_SCALAR, Token.String.Escape: PYGMENTS_ESCAPE, Token.String.Regex: PYGMENTS_REGEX, Token.String.Symbol: PYGMENTS_SYMBOL, Token.String.Other: PYGMENTS_OTHER, Token.String.Heredoc: PYGMENTS_HEREDOC, Token.Number: PYGMENTS_NUMBER, Token.Number.Float: PYGMENTS_NUMBER, Token.Number.Hex: PYGMENTS_NUMBER, Token.Number.Integer: PYGMENTS_NUMBER, Token.Number.Integer.Long: PYGMENTS_NUMBER, Token.Number.Oct: PYGMENTS_NUMBER, Token.Punctuation: PYGMENTS_PUNCTUATION, Token.Generic.Heading: PYGMENTS_HEADING, Token.Generic.Subheading: PYGMENTS_SUBHEADING, Token.Generic.Deleted: PYGMENTS_DELETED, Token.Generic.Inserted: PYGMENTS_INSERTED, Token.Generic.Error: PYGMENTS_GENERIC_ERROR, Token.Generic.Emph: PYGMENTS_EMPHASIZE, Token.Generic.Strong: PYGMENTS_STRONG, Token.Generic.Prompt: PYGMENTS_PROMPT, Token.Generic.Output: PYGMENTS_OUTPUT, Token.Generic.Traceback: PYGMENTS_TRACEBACK, Token.Error: PYGMENTS_ERROR, } #-----------------------------------------------------------------------------# class LexerPygments(LexerContainer): """ Class implementing a custom lexer using pygments. """ def __init__(self, parent = None, name = ""): """ Constructor @param parent parent widget of this lexer @keyparam name name of the pygments lexer to use (string) """ LexerContainer.__init__(self, parent) self.__pygmentsName = name self.descriptions = { PYGMENTS_DEFAULT : self.trUtf8("Default"), PYGMENTS_COMMENT : self.trUtf8("Comment"), PYGMENTS_PREPROCESSOR : self.trUtf8("Preprocessor"), PYGMENTS_KEYWORD : self.trUtf8("Keyword"), PYGMENTS_PSEUDOKEYWORD : self.trUtf8("Pseudo Keyword"), PYGMENTS_TYPEKEYWORD : self.trUtf8("Type Keyword"), PYGMENTS_OPERATOR : self.trUtf8("Operator"), PYGMENTS_WORD : self.trUtf8("Word"), PYGMENTS_BUILTIN : self.trUtf8("Builtin"), PYGMENTS_FUNCTION : self.trUtf8("Function or method name"), PYGMENTS_CLASS : self.trUtf8("Class name"), PYGMENTS_NAMESPACE : self.trUtf8("Namespace"), PYGMENTS_EXCEPTION : self.trUtf8("Exception"), PYGMENTS_VARIABLE : self.trUtf8("Identifier"), PYGMENTS_CONSTANT : self.trUtf8("Constant"), PYGMENTS_LABEL : self.trUtf8("Label"), PYGMENTS_ENTITY : self.trUtf8("Entity"), PYGMENTS_ATTRIBUTE : self.trUtf8("Attribute"), PYGMENTS_TAG : self.trUtf8("Tag"), PYGMENTS_DECORATOR : self.trUtf8("Decorator"), PYGMENTS_STRING : self.trUtf8("String"), PYGMENTS_DOCSTRING : self.trUtf8("Documentation string"), PYGMENTS_SCALAR : self.trUtf8("Scalar"), PYGMENTS_ESCAPE : self.trUtf8("Escape"), PYGMENTS_REGEX : self.trUtf8("Regular expression"), PYGMENTS_SYMBOL : self.trUtf8("Symbol"), PYGMENTS_OTHER : self.trUtf8("Other string"), PYGMENTS_NUMBER : self.trUtf8("Number"), PYGMENTS_HEADING : self.trUtf8("Heading"), PYGMENTS_SUBHEADING : self.trUtf8("Subheading"), PYGMENTS_DELETED : self.trUtf8("Deleted"), PYGMENTS_INSERTED : self.trUtf8("Inserted"), PYGMENTS_GENERIC_ERROR : self.trUtf8("Generic error"), PYGMENTS_EMPHASIZE : self.trUtf8("Emphasized text"), PYGMENTS_STRONG : self.trUtf8("Strong text"), PYGMENTS_PROMPT : self.trUtf8("Prompt"), PYGMENTS_OUTPUT : self.trUtf8("Output"), PYGMENTS_TRACEBACK : self.trUtf8("Traceback"), PYGMENTS_ERROR : self.trUtf8("Error"), PYGMENTS_MULTILINECOMMENT : self.trUtf8("Comment block"), PYGMENTS_PROPERTY : self.trUtf8("Property"), PYGMENTS_CHAR : self.trUtf8("Character"), PYGMENTS_HEREDOC : self.trUtf8("Here document"), PYGMENTS_PUNCTUATION : self.trUtf8("Punctuation"), } self.defaultColors = { PYGMENTS_DEFAULT : QColor("#000000"), PYGMENTS_COMMENT : QColor("#408080"), PYGMENTS_PREPROCESSOR : QColor("#BC7A00"), PYGMENTS_KEYWORD : QColor("#008000"), PYGMENTS_PSEUDOKEYWORD : QColor("#008000"), PYGMENTS_TYPEKEYWORD : QColor("#B00040"), PYGMENTS_OPERATOR : QColor("#666666"), PYGMENTS_WORD : QColor("#AA22FF"), PYGMENTS_BUILTIN : QColor("#008000"), PYGMENTS_FUNCTION : QColor("#0000FF"), PYGMENTS_CLASS : QColor("#0000FF"), PYGMENTS_NAMESPACE : QColor("#0000FF"), PYGMENTS_EXCEPTION : QColor("#D2413A"), PYGMENTS_VARIABLE : QColor("#19177C"), PYGMENTS_CONSTANT : QColor("#880000"), PYGMENTS_LABEL : QColor("#A0A000"), PYGMENTS_ENTITY : QColor("#999999"), PYGMENTS_ATTRIBUTE : QColor("#7D9029"), PYGMENTS_TAG : QColor("#008000"), PYGMENTS_DECORATOR : QColor("#AA22FF"), PYGMENTS_STRING : QColor("#BA2121"), PYGMENTS_DOCSTRING : QColor("#BA2121"), PYGMENTS_SCALAR : QColor("#BB6688"), PYGMENTS_ESCAPE : QColor("#BB6622"), PYGMENTS_REGEX : QColor("#BB6688"), PYGMENTS_SYMBOL : QColor("#19177C"), PYGMENTS_OTHER : QColor("#008000"), PYGMENTS_NUMBER : QColor("#666666"), PYGMENTS_HEADING : QColor("#000080"), PYGMENTS_SUBHEADING : QColor("#800080"), PYGMENTS_DELETED : QColor("#A00000"), PYGMENTS_INSERTED : QColor("#00A000"), PYGMENTS_GENERIC_ERROR : QColor("#FF0000"), PYGMENTS_PROMPT : QColor("#000080"), PYGMENTS_OUTPUT : QColor("#808080"), PYGMENTS_TRACEBACK : QColor("#0040D0"), PYGMENTS_MULTILINECOMMENT : QColor("#007F00"), PYGMENTS_PROPERTY : QColor("#00A0E0"), PYGMENTS_CHAR : QColor("#7F007F"), PYGMENTS_HEREDOC : QColor("#7F007F"), PYGMENTS_PUNCTUATION : QColor("#000000"), } self.defaultPapers = { PYGMENTS_ERROR : QColor("#FF0000"), PYGMENTS_MULTILINECOMMENT : QColor("#A8FFA8"), PYGMENTS_HEREDOC : QColor("#DDD0DD"), } self.defaultEolFill = { PYGMENTS_ERROR : True, PYGMENTS_MULTILINECOMMENT : True, PYGMENTS_HEREDOC : True, } def language(self): """ Public method returning the language of the lexer. @return language of the lexer (string) """ return "Guessed" def description(self, style): """ Public method returning the descriptions of the styles supported by the lexer. @param style style number (integer) @return description for the style (string) """ try: return self.descriptions[style] except KeyError: return "" def defaultColor(self, style): """ Public method to get the default foreground color for a style. @param style style number (integer) @return foreground color (QColor) """ try: return self.defaultColors[style] except KeyError: return LexerContainer.defaultColor(self, style) def defaultPaper(self, style): """ Public method to get the default background color for a style. @param style style number (integer) @return background color (QColor) """ try: return self.defaultPapers[style] except KeyError: return LexerContainer.defaultPaper(self, style) def defaultFont(self, style): """ Public method to get the default font for a style. @param style style number (integer) @return font (QFont) """ if style in [PYGMENTS_COMMENT, PYGMENTS_PREPROCESSOR, PYGMENTS_MULTILINECOMMENT]: if Utilities.isWindowsPlatform(): f = QFont("Comic Sans MS", 9) else: f = QFont("Bitstream Vera Serif", 9) if style == PYGMENTS_PREPROCESSOR: f.setItalic(True) return f if style in [PYGMENTS_STRING, PYGMENTS_CHAR]: if Utilities.isWindowsPlatform(): return QFont("Comic Sans MS", 10) else: return QFont("Bitstream Vera Serif", 10) if style in [PYGMENTS_KEYWORD, PYGMENTS_OPERATOR, PYGMENTS_WORD, PYGMENTS_BUILTIN, PYGMENTS_ATTRIBUTE, PYGMENTS_FUNCTION, PYGMENTS_CLASS, PYGMENTS_NAMESPACE, PYGMENTS_EXCEPTION, PYGMENTS_ENTITY, PYGMENTS_TAG, PYGMENTS_SCALAR, PYGMENTS_ESCAPE, PYGMENTS_HEADING, PYGMENTS_SUBHEADING, PYGMENTS_STRONG, PYGMENTS_PROMPT]: f = LexerContainer.defaultFont(self, style) f.setBold(True) return f if style in [PYGMENTS_DOCSTRING, PYGMENTS_EMPHASIZE]: f = LexerContainer.defaultFont(self, style) f.setItalic(True) return f return LexerContainer.defaultFont(self, style) def defaultEolFill(self, style): """ Public method to get the default fill to eol flag. @param style style number (integer) @return fill to eol flag (boolean) """ try: return self.defaultEolFill[style] except KeyError: return LexerContainer.defaultEolFill(self, style) def styleBitsNeeded(self): """ Public method to get the number of style bits needed by the lexer. @return number of style bits needed (integer) """ return 6 def __guessLexer(self, text): """ Private method to guess a pygments lexer. @param text text to base guessing on (string) @return reference to the guessed lexer (pygments.lexer) """ lexer = None if self.__pygmentsName: lexerClass = find_lexer_class(self.__pygmentsName) if lexerClass is not None: lexer = lexerClass() elif text: # step 1: guess based on filename and text if self.editor is not None: fn = self.editor.getFileName() try: lexer = guess_lexer_for_filename(fn, text) except ClassNotFound: pass # step 2: guess on text only if lexer is None: try: lexer = guess_lexer(text) except ClassNotFound: pass return lexer def canStyle(self): """ Public method to check, if the lexer is able to style the text. @return flag indicating the lexer capability (boolean) """ if self.editor is None: return True text = self.editor.text() self.__lexer = self.__guessLexer(text) return self.__lexer is not None def name(self): """ Public method to get the name of the pygments lexer. @return name of the pygments lexer (string) """ if self.__lexer is None: return "" else: return self.__lexer.name def styleText(self, start, end): """ Public method to perform the styling. @param start position of first character to be styled (integer) @param end position of last character to be styled (integer) """ text = self.editor.text()[:end + 1] self.__lexer = self.__guessLexer(text) cpos = 0 self.editor.startStyling(cpos, 0x3f) if self.__lexer is None: self.editor.setStyling(len(text), PYGMENTS_DEFAULT) else: eolLen = len(self.editor.getLineSeparator()) for token, txt in self.__lexer.get_tokens(text): style = TOKEN_MAP.get(token, PYGMENTS_DEFAULT) tlen = len(txt.encode('utf-8')) if eolLen > 1: tlen += txt.count('\n') if tlen: self.editor.setStyling(tlen, style) cpos += tlen self.editor.startStyling(cpos, 0x3f) def isCommentStyle(self, style): """ Public method to check, if a style is a comment style. @return flag indicating a comment style (boolean) """ return style in [PYGMENTS_COMMENT] def isStringStyle(self, style): """ Public method to check, if a style is a string style. @return flag indicating a string style (boolean) """ return style in [PYGMENTS_STRING, PYGMENTS_DOCSTRING, PYGMENTS_OTHER, PYGMENTS_HEADING, PYGMENTS_SUBHEADING, PYGMENTS_EMPHASIZE, PYGMENTS_STRONG] def defaultKeywords(self, kwSet): """ Public method to get the default keywords. @param kwSet number of the keyword set (integer) @return string giving the keywords (string) or None """ return None