File indexing completed on 2024-06-23 04:28:04
0001 """ 0002 SPDX-FileCopyrightText: 2017 Eliakin Costa <eliakim170@gmail.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 """ 0006 # syntax.py: taken from https://wiki.python.org/moin/PyQt/Python%20syntax%20highlighting 0007 0008 0009 from PyQt5.QtCore import QRegExp 0010 from PyQt5.QtGui import QSyntaxHighlighter 0011 0012 0013 class PythonHighlighter (QSyntaxHighlighter): 0014 0015 """Syntax highlighter for the Python language. 0016 """ 0017 # Python keywords 0018 keywords = [ 0019 'and', 'assert', 'break', 'class', 'continue', 'def', 0020 'del', 'elif', 'else', 'except', 'exec', 'finally', 0021 'for', 'from', 'global', 'if', 'import', 'in', 0022 'is', 'lambda', 'not', 'or', 'pass', 'print', 0023 'raise', 'return', 'try', 'while', 'yield', 0024 'None', 'True', 'False', 0025 ] 0026 0027 # Python operators 0028 operators = [ 0029 '=', 0030 # Comparison 0031 '==', '!=', '<', '<=', '>', '>=', 0032 # Arithmetic 0033 '\+', '-', '\*', '/', '//', '\%', '\*\*', 0034 # In-place 0035 '\+=', '-=', '\*=', '/=', '\%=', 0036 # Bitwise 0037 '\^', '\|', '\&', '\~', '>>', '<<', 0038 ] 0039 0040 # Python braces 0041 braces = [ 0042 '\{', '\}', '\(', '\)', '\[', '\]', 0043 ] 0044 0045 def __init__(self, document, syntaxStyle): 0046 QSyntaxHighlighter.__init__(self, document) 0047 0048 self.syntaxStyle = syntaxStyle 0049 self.document = document 0050 0051 # Multi-line strings (expression, flag, style) 0052 # FIXME: The triple-quotes in these two lines will mess up the 0053 # syntax highlighting from this point onward 0054 self.tri_single = (QRegExp(r"""'''(?!")"""), 1, 'string2') 0055 self.tri_double = (QRegExp(r'''"""(?!')'''), 2, 'string2') 0056 0057 rules = [] 0058 0059 # Keyword, operator, and brace rules 0060 rules += [(r'\b%s\b' % w, 0, 'keyword') 0061 for w in PythonHighlighter.keywords] 0062 rules += [(r'%s' % o, 0, 'operator') 0063 for o in PythonHighlighter.operators] 0064 rules += [(r'%s' % b, 0, 'brace') 0065 for b in PythonHighlighter.braces] 0066 0067 # All other rules 0068 rules += [ 0069 # 'self' 0070 (r'\bself\b', 0, 'self'), 0071 0072 # Double-quoted string, possibly containing escape sequences 0073 (r'"[^"\\]*(\\.[^"\\]*)*"', 0, 'string'), 0074 # Single-quoted string, possibly containing escape sequences 0075 (r"'[^'\\]*(\\.[^'\\]*)*'", 0, 'string'), 0076 0077 # 'def' followed by an identifier 0078 (r'\bdef\b\s*(\w+)', 1, 'defclass'), 0079 # 'class' followed by an identifier 0080 (r'\bclass\b\s*(\w+)', 1, 'defclass'), 0081 0082 # From '#' until a newline 0083 (r'#[^\n]*', 0, 'comment'), 0084 0085 # Numeric literals 0086 (r'\b[+-]?[0-9]+[lL]?\b', 0, 'numbers'), 0087 (r'\b[+-]?0[xX][0-9A-Fa-f]+[lL]?\b', 0, 'numbers'), 0088 (r'\b[+-]?[0-9]+(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?\b', 0, 'numbers'), 0089 ] 0090 0091 # Build a QRegExp for each pattern 0092 self.rules = [(QRegExp(pat), index, identifier) 0093 for (pat, index, identifier) in rules] 0094 0095 def highlightBlock(self, text): 0096 """Apply syntax highlighting to the given block of text.""" 0097 # Do other syntax formatting 0098 for expression, nth, identifier in self.rules: 0099 index = expression.indexIn(text, 0) 0100 0101 while index >= 0: 0102 # We actually want the index of the nth match 0103 index = expression.pos(nth) 0104 length = len(expression.cap(nth)) 0105 self.setFormat(index, length, self.syntaxStyle[identifier]) 0106 index = expression.indexIn(text, index + length) 0107 0108 self.setCurrentBlockState(0) 0109 0110 # Do multi-line strings 0111 in_multiline = self.match_multiline(text, *self.tri_single) 0112 if not in_multiline: 0113 in_multiline = self.match_multiline(text, *self.tri_double) 0114 0115 def match_multiline(self, text, delimiter, in_state, style): 0116 """Do highlighting of multi-line strings. ``delimiter`` should be a 0117 ``QRegExp`` for triple-single-quotes or triple-double-quotes, and 0118 ``in_state`` should be a unique integer to represent the corresponding 0119 state changes when inside those strings. Returns True if we're still 0120 inside a multi-line string when this function is finished. 0121 """ 0122 # If inside triple-single quotes, start at 0 0123 if self.previousBlockState() == in_state: 0124 start = 0 0125 add = 0 0126 # Otherwise, look for the delimiter on this line 0127 else: 0128 start = delimiter.indexIn(text) 0129 # Move past this match 0130 add = delimiter.matchedLength() 0131 0132 # As long as there's a delimiter match on this line... 0133 while start >= 0: 0134 # Look for the ending delimiter 0135 end = delimiter.indexIn(text, start + add) 0136 # Ending delimiter on this line? 0137 if end >= add: 0138 length = end - start + add + delimiter.matchedLength() 0139 self.setCurrentBlockState(0) 0140 # No; multi-line string 0141 else: 0142 self.setCurrentBlockState(in_state) 0143 length = len(text) - start + add 0144 # Apply formatting 0145 self.setFormat(start, length, self.syntaxStyle[style]) 0146 # Look for the next match 0147 start = delimiter.indexIn(text, start + length) 0148 0149 # Return True if still inside a multi-line string, False otherwise 0150 if self.currentBlockState() == in_state: 0151 return True 0152 else: 0153 return False 0154 0155 def getSyntaxStyle(self): 0156 return self.syntaxStyle 0157 0158 def setSyntaxStyle(self, syntaxStyle): 0159 self.syntaxStyle = syntaxStyle