Get rid of QRegExp

It is not available in PyQt6 and we anyway use the python re module
everywhere else
This commit is contained in:
Kovid Goyal 2021-11-19 19:36:18 +05:30
parent 93f3ef821b
commit 3bff1f494f
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
2 changed files with 95 additions and 96 deletions

View File

@ -5,10 +5,10 @@ __copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
__license__ = 'GPL v3' __license__ = 'GPL v3'
import json, os, traceback import json, os, traceback, re
from qt.core import (Qt, QDialog, QDialogButtonBox, QSyntaxHighlighter, QFont, from qt.core import (Qt, QDialog, QDialogButtonBox, QSyntaxHighlighter, QFont,
QRegExp, QApplication, QTextCharFormat, QColor, QCursor, QApplication, QTextCharFormat, QColor, QCursor,
QIcon, QSize, QPalette, QLineEdit, QByteArray, QFontInfo, QIcon, QSize, QPalette, QLineEdit, QByteArray, QFontInfo,
QFontDatabase, QVBoxLayout, QTableWidget, QTableWidgetItem, QFontDatabase, QVBoxLayout, QTableWidget, QTableWidgetItem,
QComboBox, QAbstractItemView, QTextOption, QFontMetrics) QComboBox, QAbstractItemView, QTextOption, QFontMetrics)
@ -42,9 +42,6 @@ class ParenPosition:
class TemplateHighlighter(QSyntaxHighlighter): class TemplateHighlighter(QSyntaxHighlighter):
Config = {}
Rules = []
Formats = {}
BN_FACTOR = 1000 BN_FACTOR = 1000
KEYWORDS = ["program", 'if', 'then', 'else', 'elif', 'fi', 'for', 'rof', KEYWORDS = ["program", 'if', 'then', 'else', 'elif', 'fi', 'for', 'rof',
@ -52,44 +49,44 @@ class TemplateHighlighter(QSyntaxHighlighter):
def __init__(self, parent=None, builtin_functions=None): def __init__(self, parent=None, builtin_functions=None):
super().__init__(parent) super().__init__(parent)
self.initializeFormats() self.initializeFormats()
self.initialize_rules(builtin_functions)
TemplateHighlighter.Rules.append((QRegExp(
r"\b[a-zA-Z]\w*\b(?!\(|\s+\()"
r"|\$+#?[a-zA-Z]\w*"),
"identifier"))
TemplateHighlighter.Rules.append((QRegExp(
"|".join([r"\b%s\b" % keyword for keyword in self.KEYWORDS])),
"keyword"))
TemplateHighlighter.Rules.append((QRegExp(
"|".join([r"\b%s\b" % builtin for builtin in
(builtin_functions if builtin_functions else
formatter_functions().get_builtins())])),
"builtin"))
TemplateHighlighter.Rules.append((QRegExp(
r"\b[+-]?[0-9]+[lL]?\b"
r"|\b[+-]?0[xX][0-9A-Fa-f]+[lL]?\b"
r"|\b[+-]?[0-9]+(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?\b"),
"number"))
stringRe = QRegExp(r"""(?:[^:]'[^']*'|"[^"]*")""")
stringRe.setMinimal(True)
TemplateHighlighter.Rules.append((stringRe, "string"))
lparenRe = QRegExp(r'\(')
lparenRe.setMinimal(True)
TemplateHighlighter.Rules.append((lparenRe, "lparen"))
rparenRe = QRegExp(r'\)')
rparenRe.setMinimal(True)
TemplateHighlighter.Rules.append((rparenRe, "rparen"))
self.regenerate_paren_positions() self.regenerate_paren_positions()
self.highlighted_paren = False self.highlighted_paren = False
def initialize_rules(self, builtin_functions):
r = []
def a(a, b):
r.append((re.compile(a), b))
a(
r"\b[a-zA-Z]\w*\b(?!\(|\s+\()"
r"|\$+#?[a-zA-Z]\w*",
"identifier")
a(
"|".join([r"\b%s\b" % keyword for keyword in self.KEYWORDS]),
"keyword")
a(
"|".join([r"\b%s\b" % builtin for builtin in
(builtin_functions if builtin_functions else
formatter_functions().get_builtins())]),
"builtin")
a(
r"\b[+-]?[0-9]+[lL]?\b"
r"|\b[+-]?0[xX][0-9A-Fa-f]+[lL]?\b"
r"|\b[+-]?[0-9]+(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?\b",
"number")
a(r"""(?:[^:]'[^']*'|"[^"]*")""", "string")
a(r'\(', "lparen")
a(r'\)', "rparen")
self.Rules = tuple(r)
def initializeFormats(self): def initializeFormats(self):
font_name = gprefs.get('gpm_template_editor_font', None) font_name = gprefs.get('gpm_template_editor_font', None)
size = gprefs['gpm_template_editor_font_size'] size = gprefs['gpm_template_editor_font_size']
@ -98,7 +95,7 @@ class TemplateHighlighter(QSyntaxHighlighter):
font.setFixedPitch(True) font.setFixedPitch(True)
font.setPointSize(size) font.setPointSize(size)
font_name = font.family() font_name = font.family()
Config = self.Config Config = self.Config = {}
Config["fontfamily"] = font_name Config["fontfamily"] = font_name
pal = QApplication.instance().palette() pal = QApplication.instance().palette()
for name, color, bold, italic in ( for name, color, bold, italic in (
@ -118,6 +115,7 @@ class TemplateHighlighter(QSyntaxHighlighter):
baseFormat.setFontFamily(Config["fontfamily"]) baseFormat.setFontFamily(Config["fontfamily"])
Config["fontsize"] = size Config["fontsize"] = size
baseFormat.setFontPointSize(Config["fontsize"]) baseFormat.setFontPointSize(Config["fontsize"])
self.Formats = {}
for name in ("normal", "keyword", "builtin", "comment", "identifier", for name in ("normal", "keyword", "builtin", "comment", "identifier",
"string", "number", "lparen", "rparen"): "string", "number", "lparen", "rparen"):
@ -146,17 +144,15 @@ class TemplateHighlighter(QSyntaxHighlighter):
self.setFormat(0, textLength, self.Formats["comment"]) self.setFormat(0, textLength, self.Formats["comment"])
return return
for regex, format_ in TemplateHighlighter.Rules: for regex, format_ in self.Rules:
i = regex.indexIn(text) for m in regex.finditer(text):
while i >= 0: i, length = m.start(), m.end() - m.start()
length = regex.matchedLength()
if format_ in ['lparen', 'rparen']: if format_ in ['lparen', 'rparen']:
pp = self.find_paren(bn, i) pp = self.find_paren(bn, i)
if pp and pp.highlight: if pp and pp.highlight:
self.setFormat(i, length, self.Formats[format_]) self.setFormat(i, length, self.Formats[format_])
else: else:
self.setFormat(i, length, self.Formats[format_]) self.setFormat(i, length, self.Formats[format_])
i = regex.indexIn(text, i + length)
if self.generate_paren_positions: if self.generate_paren_positions:
t = str(text) t = str(text)
@ -178,7 +174,7 @@ class TemplateHighlighter(QSyntaxHighlighter):
i = len(t) i = len(t)
else: else:
i = i + j i = i + j
elif c in ['(', ')']: elif c in ('(', ')'):
pp = ParenPosition(bn, i, c) pp = ParenPosition(bn, i, c)
self.paren_positions.append(pp) self.paren_positions.append(pp)
self.paren_pos_map[bn*self.BN_FACTOR+i] = pp self.paren_pos_map[bn*self.BN_FACTOR+i] = pp
@ -186,7 +182,7 @@ class TemplateHighlighter(QSyntaxHighlighter):
def rehighlight(self): def rehighlight(self):
QApplication.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor)) QApplication.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor))
QSyntaxHighlighter.rehighlight(self) super().rehighlight()
QApplication.restoreOverrideCursor() QApplication.restoreOverrideCursor()
def check_cursor_pos(self, chr_, block, pos_in_block): def check_cursor_pos(self, chr_, block, pos_in_block):
@ -196,7 +192,7 @@ class TemplateHighlighter(QSyntaxHighlighter):
if pp.block == block and pp.pos == pos_in_block: if pp.block == block and pp.pos == pos_in_block:
found_pp = i found_pp = i
if chr_ not in ['(', ')']: if chr_ not in ('(', ')'):
if self.highlighted_paren: if self.highlighted_paren:
self.rehighlight() self.rehighlight()
self.highlighted_paren = False self.highlighted_paren = False
@ -887,7 +883,8 @@ class EmbeddedTemplateDialog(TemplateDialog):
if __name__ == '__main__': if __name__ == '__main__':
app = QApplication([]) from calibre.gui2 import Application
app = Application([])
from calibre.ebooks.metadata.book.base import field_metadata from calibre.ebooks.metadata.book.base import field_metadata
d = TemplateDialog(None, '{title}', fm=field_metadata) d = TemplateDialog(None, '{title}', fm=field_metadata)
d.exec_() d.exec_()

View File

@ -8,7 +8,7 @@ import re, os
from qt.core import (QIcon, QFont, QLabel, QListWidget, QAction, QEvent, from qt.core import (QIcon, QFont, QLabel, QListWidget, QAction, QEvent,
QListWidgetItem, QTextCharFormat, QApplication, QSyntaxHighlighter, QListWidgetItem, QTextCharFormat, QApplication, QSyntaxHighlighter,
QCursor, QColor, QWidget, QPixmap, QSplitterHandle, QToolButton, QCursor, QColor, QWidget, QPixmap, QSplitterHandle, QToolButton,
Qt, pyqtSignal, QRegExp, QSize, QSplitter, QPainter, QPageSize, QPrinter, Qt, pyqtSignal, QSize, QSplitter, QPainter, QPageSize, QPrinter,
QLineEdit, QComboBox, QPen, QGraphicsScene, QMenu, QStringListModel, QKeySequence, QLineEdit, QComboBox, QPen, QGraphicsScene, QMenu, QStringListModel, QKeySequence,
QCompleter, QTimer, QRect, QGraphicsView, QPagedPaintDevice, QPalette, QClipboard) QCompleter, QTimer, QRect, QGraphicsView, QPagedPaintDevice, QPalette, QClipboard)
@ -810,7 +810,7 @@ class EncodingComboBox(QComboBox): # {{{
class PythonHighlighter(QSyntaxHighlighter): # {{{ class PythonHighlighter(QSyntaxHighlighter): # {{{
Rules = [] Rules = ()
Formats = {} Formats = {}
KEYWORDS = ["and", "as", "assert", "break", "class", "continue", "def", KEYWORDS = ["and", "as", "assert", "break", "class", "continue", "def",
@ -834,34 +834,41 @@ class PythonHighlighter(QSyntaxHighlighter): # {{{
def __init__(self, parent=None): def __init__(self, parent=None):
super().__init__(parent) super().__init__(parent)
if not self.Rules:
self.initialize_class_members()
self.initializeFormats() @classmethod
def initialize_class_members(cls):
cls.initializeFormats()
r = []
PythonHighlighter.Rules.append((QRegExp( def a(a, b):
"|".join([r"\b%s\b" % keyword for keyword in self.KEYWORDS])), r.append((a, b))
"keyword"))
PythonHighlighter.Rules.append((QRegExp( a(re.compile(
"|".join([r"\b%s\b" % builtin for builtin in self.BUILTINS])), "|".join([r"\b%s\b" % keyword for keyword in cls.KEYWORDS])),
"builtin")) "keyword")
PythonHighlighter.Rules.append((QRegExp( a(re.compile(
"|".join([r"\b%s\b" % builtin for builtin in cls.BUILTINS])),
"builtin")
a(re.compile(
"|".join([r"\b%s\b" % constant "|".join([r"\b%s\b" % constant
for constant in self.CONSTANTS])), "constant")) for constant in cls.CONSTANTS])), "constant")
PythonHighlighter.Rules.append((QRegExp( a(re.compile(
r"\b[+-]?[0-9]+[lL]?\b" r"\b[+-]?[0-9]+[lL]?\b"
r"|\b[+-]?0[xX][0-9A-Fa-f]+[lL]?\b" r"|\b[+-]?0[xX][0-9A-Fa-f]+[lL]?\b"
r"|\b[+-]?[0-9]+(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?\b"), r"|\b[+-]?[0-9]+(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?\b"),
"number")) "number")
PythonHighlighter.Rules.append((QRegExp( a(re.compile(
r"\bPyQt5\b|\bQt?[A-Z][a-z]\w+\b"), "pyqt")) r"\bPyQt5\b|\bQt?[A-Z][a-z]\w+\b"), "pyqt")
PythonHighlighter.Rules.append((QRegExp(r"\b@\w+\b"), "decorator")) a(re.compile(r"\b@\w+\b"), "decorator")
stringRe = QRegExp(r"""(?:'[^']*'|"[^"]*")""") stringRe = re.compile(r"""(?:'[^']*?'|"[^"]*?")""")
stringRe.setMinimal(True) a(stringRe, "string")
PythonHighlighter.Rules.append((stringRe, "string")) cls.stringRe = re.compile(r"""(:?"["]".*?"["]"|'''.*?''')""")
self.stringRe = QRegExp(r"""(:?"["]".*"["]"|'''.*''')""") a(cls.stringRe, "string")
self.stringRe.setMinimal(True) cls.tripleSingleRe = re.compile(r"""'''(?!")""")
PythonHighlighter.Rules.append((self.stringRe, "string")) cls.tripleDoubleRe = re.compile(r'''"""(?!')''')
self.tripleSingleRe = QRegExp(r"""'''(?!")""") cls.Rules = tuple(r)
self.tripleDoubleRe = QRegExp(r'''"""(?!')''')
@classmethod @classmethod
def initializeFormats(cls): def initializeFormats(cls):
@ -896,36 +903,31 @@ class PythonHighlighter(QSyntaxHighlighter): # {{{
prevState = self.previousBlockState() prevState = self.previousBlockState()
self.setFormat(0, textLength, self.setFormat(0, textLength,
PythonHighlighter.Formats["normal"]) self.Formats["normal"])
if text.startswith("Traceback") or text.startswith("Error: "): if text.startswith("Traceback") or text.startswith("Error: "):
self.setCurrentBlockState(ERROR) self.setCurrentBlockState(ERROR)
self.setFormat(0, textLength, self.setFormat(0, textLength,
PythonHighlighter.Formats["error"]) self.Formats["error"])
return return
if prevState == ERROR and \ if prevState == ERROR and \
not (text.startswith('>>>') or text.startswith("#")): not (text.startswith('>>>') or text.startswith("#")):
self.setCurrentBlockState(ERROR) self.setCurrentBlockState(ERROR)
self.setFormat(0, textLength, self.setFormat(0, textLength,
PythonHighlighter.Formats["error"]) self.Formats["error"])
return return
for regex, format in PythonHighlighter.Rules: for regex, fmt in PythonHighlighter.Rules:
i = regex.indexIn(text) for m in regex.finditer(text):
while i >= 0: self.setFormat(m.start(), m.end() - m.start(), self.Formats[fmt])
length = regex.matchedLength()
self.setFormat(i, length,
PythonHighlighter.Formats[format])
i = regex.indexIn(text, i + length)
# Slow but good quality highlighting for comments. For more # Slow but good quality highlighting for comments. For more
# speed, comment this out and add the following to __init__: # speed, comment this out and add the following to __init__:
# PythonHighlighter.Rules.append((QRegExp(r"#.*"), "comment")) # PythonHighlighter.Rules.append((re.compile(r"#.*"), "comment"))
if not text: if not text:
pass pass
elif text[0] == "#": elif text[0] == "#":
self.setFormat(0, len(text), self.setFormat(0, len(text), self.Formats["comment"])
PythonHighlighter.Formats["comment"])
else: else:
stack = [] stack = []
for i, c in enumerate(text): for i, c in enumerate(text):
@ -935,33 +937,33 @@ class PythonHighlighter(QSyntaxHighlighter): # {{{
else: else:
stack.append(c) stack.append(c)
elif c == "#" and len(stack) == 0: elif c == "#" and len(stack) == 0:
self.setFormat(i, len(text), self.setFormat(i, len(text), self.Formats["comment"])
PythonHighlighter.Formats["comment"])
break break
self.setCurrentBlockState(NORMAL) self.setCurrentBlockState(NORMAL)
if self.stringRe.indexIn(text) != -1: if self.stringRe.search(text) is not None:
return return
# This is fooled by triple quotes inside single quoted strings # This is fooled by triple quotes inside single quoted strings
for i, state in ((self.tripleSingleRe.indexIn(text), for m, state in (
TRIPLESINGLE), (self.tripleSingleRe.search(text), TRIPLESINGLE),
(self.tripleDoubleRe.indexIn(text), (self.tripleDoubleRe.search(text), TRIPLEDOUBLE)
TRIPLEDOUBLE)): ):
i = -1 if m is None else m.start()
if self.previousBlockState() == state: if self.previousBlockState() == state:
if i == -1: if i == -1:
i = len(text) i = len(text)
self.setCurrentBlockState(state) self.setCurrentBlockState(state)
self.setFormat(0, i + 3, self.setFormat(0, i + 3,
PythonHighlighter.Formats["string"]) self.Formats["string"])
elif i > -1: elif i > -1:
self.setCurrentBlockState(state) self.setCurrentBlockState(state)
self.setFormat(i, len(text), self.setFormat(i, len(text),
PythonHighlighter.Formats["string"]) self.Formats["string"])
def rehighlight(self): def rehighlight(self):
QApplication.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor)) QApplication.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor))
QSyntaxHighlighter.rehighlight(self) super().rehighlight()
QApplication.restoreOverrideCursor() QApplication.restoreOverrideCursor()
# }}} # }}}