Skip to content

Instantly share code, notes, and snippets.

@danielSanchezQ
Created April 10, 2012 17:12
Show Gist options
  • Select an option

  • Save danielSanchezQ/2352928 to your computer and use it in GitHub Desktop.

Select an option

Save danielSanchezQ/2352928 to your computer and use it in GitHub Desktop.

Revisions

  1. bakkal created this gist Apr 10, 2012.
    123 changes: 123 additions & 0 deletions gistfile1.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,123 @@
    class Python (QSyntaxHighlighter):
    """Syntax highlighter for the Python language.
    """
    # Python keywords
    keywords = [
    'and', 'as', 'assert', 'break', 'class',
    'continue', 'def', 'del', 'elif', 'else',
    'except', 'exec', 'finally', 'for', 'from',
    'global', 'if', 'import', 'in', 'is',
    'lambda', 'not', 'or', 'pass', 'print', 'raise',
    'return', 'try', 'while', 'with', 'yield', 'True',
    'False', 'None' ]

    # Python operators
    operators = [
    '=',
    # Comparison
    '==', '!=', '<', '<=', '>', '>=',
    # Arithmetic
    '\+', '-', '\*', '/', '//', '\%', '\*\*',
    # In-place
    '\+=', '-=', '\*=', '/=', '\%=',
    # Bitwise
    '\^', '\|', '\&', '\~', '>>', '<<' ]

    # Python braces
    braces = [
    '\{', '\}', '\(', '\)', '\[', '\]' ]
    def __init__(self, document):
    QSyntaxHighlighter.__init__(self, document)

    # Multi-line strings (expression, flag, style)
    # FIXME: The triple-quotes in these two lines will mess up the
    # syntax highlighting from this point onward
    self.tri_single = (QRegExp("'''"), 1, STYLES['string2'])
    self.tri_double = (QRegExp('"""'), 2, STYLES['string2'])

    rules = []
    rules += [(r'\b%s\b' % w, 0, STYLES['keyword'])
    for w in Python.keywords]
    rules += [(r'%s' % o, 0, STYLES['operator'])
    for o in Python.operators]
    rules += [(r'%s' % b, 0, STYLES['brace'])
    for b in Python.braces]
    rules += [
    # Double-quoted string, possibly containing escape sequences
    (r'"[^"\\]*(\\.[^"\\]*)*"', 0, STYLES['string']),
    # Single-quoted string, possibly containing escape sequences
    (r"'[^'\\]*(\\.[^'\\]*)*'", 0, STYLES['string']),
    # 'def' followed by an identifier
    (r'\bdef\b\s*(\w+)', 1, STYLES['defclass']),
    # 'class' followed by an identifier
    (r'\bclass\b\s*(\w+)', 1, STYLES['defclass']),
    # From '#' until a newline
    (r'#[^\n]*', 0, STYLES['comment']),
    # From #! to new line
    (r'#![^\n]*', 0, STYLES['pybang']) ]

    # Build a QRegExp for each pattern
    self.rules = [(QRegExp(pat), index, fmt)
    for (pat, index, fmt) in rules]

    def highlightBlock(self, text):
    """Apply syntax highlighting to the given block of text.
    """
    # Do other syntax formatting
    for expression, nth, format in self.rules:
    index = expression.indexIn(text, 0)

    while index >= 0:
    # We actually want the index of the nth match
    index = expression.pos(nth)
    length = expression.cap(nth).length()
    self.setFormat(index, length, format)
    index = expression.indexIn(text, index + length)

    self.setCurrentBlockState(0)

    # Do multi-line strings
    in_multiline = self.match_multiline(text, *self.tri_single)
    if not in_multiline:
    in_multiline = self.match_multiline(text, *self.tri_double)


    def match_multiline(self, text, delimiter, in_state, style):
    """Do highlighting of multi-line strings. ``delimiter`` should be a
    ``QRegExp`` for triple-single-quotes or triple-double-quotes, and
    ``in_state`` should be a unique integer to represent the corresponding
    state changes when inside those strings. Returns True if we're still
    inside a multi-line string when this function is finished. """
    # If inside triple-single quotes, start at 0
    if self.previousBlockState() == in_state:
    start = 0
    add = 0
    # Otherwise, look for the delimiter on this line
    else:
    start = delimiter.indexIn(text)
    # Move past this match
    add = delimiter.matchedLength()

    # As long as there's a delimiter match on this line...
    while start >= 0:
    # Look for the ending delimiter
    end = delimiter.indexIn(text, start + add)
    # Ending delimiter on this line?
    if end >= add:
    length = end - start + add + delimiter.matchedLength()
    self.setCurrentBlockState(0)
    # No; multi-line string
    else:
    self.setCurrentBlockState(in_state)
    length = text.length() - start + add
    # Apply formatting
    self.setFormat(start, length, style)
    # Look for the next match

    start = delimiter.indexIn(text, start + length)

    # Return True if still inside a multi-line string, False otherwise
    if self.currentBlockState() == in_state:
    return True
    else:
    return False