From 3bff1f494f983f25560ff4060f9f51fd638437ac Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Fri, 19 Nov 2021 19:36:18 +0530 Subject: [PATCH] Get rid of QRegExp It is not available in PyQt6 and we anyway use the python re module everywhere else --- src/calibre/gui2/dialogs/template_dialog.py | 95 ++++++++++---------- src/calibre/gui2/widgets.py | 96 +++++++++++---------- 2 files changed, 95 insertions(+), 96 deletions(-) diff --git a/src/calibre/gui2/dialogs/template_dialog.py b/src/calibre/gui2/dialogs/template_dialog.py index e21da7b281..469c8e58bd 100644 --- a/src/calibre/gui2/dialogs/template_dialog.py +++ b/src/calibre/gui2/dialogs/template_dialog.py @@ -5,10 +5,10 @@ __copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net' __docformat__ = 'restructuredtext en' __license__ = 'GPL v3' -import json, os, traceback +import json, os, traceback, re from qt.core import (Qt, QDialog, QDialogButtonBox, QSyntaxHighlighter, QFont, - QRegExp, QApplication, QTextCharFormat, QColor, QCursor, + QApplication, QTextCharFormat, QColor, QCursor, QIcon, QSize, QPalette, QLineEdit, QByteArray, QFontInfo, QFontDatabase, QVBoxLayout, QTableWidget, QTableWidgetItem, QComboBox, QAbstractItemView, QTextOption, QFontMetrics) @@ -42,9 +42,6 @@ class ParenPosition: class TemplateHighlighter(QSyntaxHighlighter): - Config = {} - Rules = [] - Formats = {} BN_FACTOR = 1000 KEYWORDS = ["program", 'if', 'then', 'else', 'elif', 'fi', 'for', 'rof', @@ -52,44 +49,44 @@ class TemplateHighlighter(QSyntaxHighlighter): def __init__(self, parent=None, builtin_functions=None): super().__init__(parent) - self.initializeFormats() - - 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.initialize_rules(builtin_functions) self.regenerate_paren_positions() 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): font_name = gprefs.get('gpm_template_editor_font', None) size = gprefs['gpm_template_editor_font_size'] @@ -98,7 +95,7 @@ class TemplateHighlighter(QSyntaxHighlighter): font.setFixedPitch(True) font.setPointSize(size) font_name = font.family() - Config = self.Config + Config = self.Config = {} Config["fontfamily"] = font_name pal = QApplication.instance().palette() for name, color, bold, italic in ( @@ -118,6 +115,7 @@ class TemplateHighlighter(QSyntaxHighlighter): baseFormat.setFontFamily(Config["fontfamily"]) Config["fontsize"] = size baseFormat.setFontPointSize(Config["fontsize"]) + self.Formats = {} for name in ("normal", "keyword", "builtin", "comment", "identifier", "string", "number", "lparen", "rparen"): @@ -146,17 +144,15 @@ class TemplateHighlighter(QSyntaxHighlighter): self.setFormat(0, textLength, self.Formats["comment"]) return - for regex, format_ in TemplateHighlighter.Rules: - i = regex.indexIn(text) - while i >= 0: - length = regex.matchedLength() + for regex, format_ in self.Rules: + for m in regex.finditer(text): + i, length = m.start(), m.end() - m.start() if format_ in ['lparen', 'rparen']: pp = self.find_paren(bn, i) if pp and pp.highlight: self.setFormat(i, length, self.Formats[format_]) else: self.setFormat(i, length, self.Formats[format_]) - i = regex.indexIn(text, i + length) if self.generate_paren_positions: t = str(text) @@ -178,7 +174,7 @@ class TemplateHighlighter(QSyntaxHighlighter): i = len(t) else: i = i + j - elif c in ['(', ')']: + elif c in ('(', ')'): pp = ParenPosition(bn, i, c) self.paren_positions.append(pp) self.paren_pos_map[bn*self.BN_FACTOR+i] = pp @@ -186,7 +182,7 @@ class TemplateHighlighter(QSyntaxHighlighter): def rehighlight(self): QApplication.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor)) - QSyntaxHighlighter.rehighlight(self) + super().rehighlight() QApplication.restoreOverrideCursor() 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: found_pp = i - if chr_ not in ['(', ')']: + if chr_ not in ('(', ')'): if self.highlighted_paren: self.rehighlight() self.highlighted_paren = False @@ -887,7 +883,8 @@ class EmbeddedTemplateDialog(TemplateDialog): if __name__ == '__main__': - app = QApplication([]) + from calibre.gui2 import Application + app = Application([]) from calibre.ebooks.metadata.book.base import field_metadata d = TemplateDialog(None, '{title}', fm=field_metadata) d.exec_() diff --git a/src/calibre/gui2/widgets.py b/src/calibre/gui2/widgets.py index 102069751c..41e849fea3 100644 --- a/src/calibre/gui2/widgets.py +++ b/src/calibre/gui2/widgets.py @@ -8,7 +8,7 @@ import re, os from qt.core import (QIcon, QFont, QLabel, QListWidget, QAction, QEvent, QListWidgetItem, QTextCharFormat, QApplication, QSyntaxHighlighter, 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, QCompleter, QTimer, QRect, QGraphicsView, QPagedPaintDevice, QPalette, QClipboard) @@ -810,7 +810,7 @@ class EncodingComboBox(QComboBox): # {{{ class PythonHighlighter(QSyntaxHighlighter): # {{{ - Rules = [] + Rules = () Formats = {} KEYWORDS = ["and", "as", "assert", "break", "class", "continue", "def", @@ -834,34 +834,41 @@ class PythonHighlighter(QSyntaxHighlighter): # {{{ def __init__(self, parent=None): 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( - "|".join([r"\b%s\b" % keyword for keyword in self.KEYWORDS])), - "keyword")) - PythonHighlighter.Rules.append((QRegExp( - "|".join([r"\b%s\b" % builtin for builtin in self.BUILTINS])), - "builtin")) - PythonHighlighter.Rules.append((QRegExp( + def a(a, b): + r.append((a, b)) + + a(re.compile( + "|".join([r"\b%s\b" % keyword for keyword in cls.KEYWORDS])), + "keyword") + a(re.compile( + "|".join([r"\b%s\b" % builtin for builtin in cls.BUILTINS])), + "builtin") + a(re.compile( "|".join([r"\b%s\b" % constant - for constant in self.CONSTANTS])), "constant")) - PythonHighlighter.Rules.append((QRegExp( + for constant in cls.CONSTANTS])), "constant") + a(re.compile( 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")) - PythonHighlighter.Rules.append((QRegExp( - r"\bPyQt5\b|\bQt?[A-Z][a-z]\w+\b"), "pyqt")) - PythonHighlighter.Rules.append((QRegExp(r"\b@\w+\b"), "decorator")) - stringRe = QRegExp(r"""(?:'[^']*'|"[^"]*")""") - stringRe.setMinimal(True) - PythonHighlighter.Rules.append((stringRe, "string")) - self.stringRe = QRegExp(r"""(:?"["]".*"["]"|'''.*''')""") - self.stringRe.setMinimal(True) - PythonHighlighter.Rules.append((self.stringRe, "string")) - self.tripleSingleRe = QRegExp(r"""'''(?!")""") - self.tripleDoubleRe = QRegExp(r'''"""(?!')''') + "number") + a(re.compile( + r"\bPyQt5\b|\bQt?[A-Z][a-z]\w+\b"), "pyqt") + a(re.compile(r"\b@\w+\b"), "decorator") + stringRe = re.compile(r"""(?:'[^']*?'|"[^"]*?")""") + a(stringRe, "string") + cls.stringRe = re.compile(r"""(:?"["]".*?"["]"|'''.*?''')""") + a(cls.stringRe, "string") + cls.tripleSingleRe = re.compile(r"""'''(?!")""") + cls.tripleDoubleRe = re.compile(r'''"""(?!')''') + cls.Rules = tuple(r) @classmethod def initializeFormats(cls): @@ -896,36 +903,31 @@ class PythonHighlighter(QSyntaxHighlighter): # {{{ prevState = self.previousBlockState() self.setFormat(0, textLength, - PythonHighlighter.Formats["normal"]) + self.Formats["normal"]) if text.startswith("Traceback") or text.startswith("Error: "): self.setCurrentBlockState(ERROR) self.setFormat(0, textLength, - PythonHighlighter.Formats["error"]) + self.Formats["error"]) return if prevState == ERROR and \ not (text.startswith('>>>') or text.startswith("#")): self.setCurrentBlockState(ERROR) self.setFormat(0, textLength, - PythonHighlighter.Formats["error"]) + self.Formats["error"]) return - for regex, format in PythonHighlighter.Rules: - i = regex.indexIn(text) - while i >= 0: - length = regex.matchedLength() - self.setFormat(i, length, - PythonHighlighter.Formats[format]) - i = regex.indexIn(text, i + length) + for regex, fmt in PythonHighlighter.Rules: + for m in regex.finditer(text): + self.setFormat(m.start(), m.end() - m.start(), self.Formats[fmt]) # Slow but good quality highlighting for comments. For more # 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: pass elif text[0] == "#": - self.setFormat(0, len(text), - PythonHighlighter.Formats["comment"]) + self.setFormat(0, len(text), self.Formats["comment"]) else: stack = [] for i, c in enumerate(text): @@ -935,33 +937,33 @@ class PythonHighlighter(QSyntaxHighlighter): # {{{ else: stack.append(c) elif c == "#" and len(stack) == 0: - self.setFormat(i, len(text), - PythonHighlighter.Formats["comment"]) + self.setFormat(i, len(text), self.Formats["comment"]) break self.setCurrentBlockState(NORMAL) - if self.stringRe.indexIn(text) != -1: + if self.stringRe.search(text) is not None: return # This is fooled by triple quotes inside single quoted strings - for i, state in ((self.tripleSingleRe.indexIn(text), - TRIPLESINGLE), - (self.tripleDoubleRe.indexIn(text), - TRIPLEDOUBLE)): + for m, state in ( + (self.tripleSingleRe.search(text), TRIPLESINGLE), + (self.tripleDoubleRe.search(text), TRIPLEDOUBLE) + ): + i = -1 if m is None else m.start() if self.previousBlockState() == state: if i == -1: i = len(text) self.setCurrentBlockState(state) self.setFormat(0, i + 3, - PythonHighlighter.Formats["string"]) + self.Formats["string"]) elif i > -1: self.setCurrentBlockState(state) self.setFormat(i, len(text), - PythonHighlighter.Formats["string"]) + self.Formats["string"]) def rehighlight(self): QApplication.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor)) - QSyntaxHighlighter.rehighlight(self) + super().rehighlight() QApplication.restoreOverrideCursor() # }}}