--- a/src/eric7/Plugins/WizardPlugins/PyRegExpWizard/PyRegExpWizardDialog.py Wed Jul 13 11:16:20 2022 +0200 +++ b/src/eric7/Plugins/WizardPlugins/PyRegExpWizard/PyRegExpWizardDialog.py Wed Jul 13 14:55:47 2022 +0200 @@ -14,8 +14,13 @@ from PyQt6.QtCore import pyqtSlot from PyQt6.QtGui import QClipboard, QTextCursor from PyQt6.QtWidgets import ( - QWidget, QDialog, QInputDialog, QApplication, QDialogButtonBox, - QVBoxLayout, QTableWidgetItem + QWidget, + QDialog, + QInputDialog, + QApplication, + QDialogButtonBox, + QVBoxLayout, + QTableWidgetItem, ) from EricWidgets import EricMessageBox, EricFileDialog @@ -33,16 +38,17 @@ """ Class implementing the Python re wizard dialog. """ + def __init__(self, parent=None, fromEric=True): """ Constructor - + @param parent parent widget (QWidget) @param fromEric flag indicating a call from within eric """ super().__init__(parent) self.setupUi(self) - + # initialize icons of the tool buttons self.commentButton.setIcon(UI.PixmapCache.getIcon("comment")) self.charButton.setIcon(UI.PixmapCache.getIcon("characters")) @@ -51,62 +57,59 @@ self.nonGroupButton.setIcon(UI.PixmapCache.getIcon("nongroup")) self.groupButton.setIcon(UI.PixmapCache.getIcon("group")) self.namedGroupButton.setIcon(UI.PixmapCache.getIcon("namedgroup")) - self.namedReferenceButton.setIcon( - UI.PixmapCache.getIcon("namedreference")) + self.namedReferenceButton.setIcon(UI.PixmapCache.getIcon("namedreference")) self.altnButton.setIcon(UI.PixmapCache.getIcon("altn")) self.beglineButton.setIcon(UI.PixmapCache.getIcon("begline")) self.endlineButton.setIcon(UI.PixmapCache.getIcon("endline")) - self.wordboundButton.setIcon( - UI.PixmapCache.getIcon("wordboundary")) - self.nonwordboundButton.setIcon( - UI.PixmapCache.getIcon("nonwordboundary")) - self.poslookaheadButton.setIcon( - UI.PixmapCache.getIcon("poslookahead")) - self.neglookaheadButton.setIcon( - UI.PixmapCache.getIcon("neglookahead")) - self.poslookbehindButton.setIcon( - UI.PixmapCache.getIcon("poslookbehind")) - self.neglookbehindButton.setIcon( - UI.PixmapCache.getIcon("neglookbehind")) + self.wordboundButton.setIcon(UI.PixmapCache.getIcon("wordboundary")) + self.nonwordboundButton.setIcon(UI.PixmapCache.getIcon("nonwordboundary")) + self.poslookaheadButton.setIcon(UI.PixmapCache.getIcon("poslookahead")) + self.neglookaheadButton.setIcon(UI.PixmapCache.getIcon("neglookahead")) + self.poslookbehindButton.setIcon(UI.PixmapCache.getIcon("poslookbehind")) + self.neglookbehindButton.setIcon(UI.PixmapCache.getIcon("neglookbehind")) self.undoButton.setIcon(UI.PixmapCache.getIcon("editUndo")) self.redoButton.setIcon(UI.PixmapCache.getIcon("editRedo")) - + self.namedGroups = re.compile(r"""\(?P<([^>]+)>""").findall - + self.saveButton = self.buttonBox.addButton( - self.tr("Save"), QDialogButtonBox.ButtonRole.ActionRole) - self.saveButton.setToolTip( - self.tr("Save the regular expression to a file")) + self.tr("Save"), QDialogButtonBox.ButtonRole.ActionRole + ) + self.saveButton.setToolTip(self.tr("Save the regular expression to a file")) self.loadButton = self.buttonBox.addButton( - self.tr("Load"), QDialogButtonBox.ButtonRole.ActionRole) - self.loadButton.setToolTip( - self.tr("Load a regular expression from a file")) + self.tr("Load"), QDialogButtonBox.ButtonRole.ActionRole + ) + self.loadButton.setToolTip(self.tr("Load a regular expression from a file")) self.validateButton = self.buttonBox.addButton( - self.tr("Validate"), QDialogButtonBox.ButtonRole.ActionRole) - self.validateButton.setToolTip( - self.tr("Validate the regular expression")) + self.tr("Validate"), QDialogButtonBox.ButtonRole.ActionRole + ) + self.validateButton.setToolTip(self.tr("Validate the regular expression")) self.executeButton = self.buttonBox.addButton( - self.tr("Execute"), QDialogButtonBox.ButtonRole.ActionRole) - self.executeButton.setToolTip( - self.tr("Execute the regular expression")) + self.tr("Execute"), QDialogButtonBox.ButtonRole.ActionRole + ) + self.executeButton.setToolTip(self.tr("Execute the regular expression")) self.nextButton = self.buttonBox.addButton( - self.tr("Next match"), QDialogButtonBox.ButtonRole.ActionRole) + self.tr("Next match"), QDialogButtonBox.ButtonRole.ActionRole + ) self.nextButton.setToolTip( - self.tr("Show the next match of the regular expression")) + self.tr("Show the next match of the regular expression") + ) self.nextButton.setEnabled(False) - + if fromEric: self.buttonBox.setStandardButtons( - QDialogButtonBox.StandardButton.Cancel | - QDialogButtonBox.StandardButton.Ok) + QDialogButtonBox.StandardButton.Cancel + | QDialogButtonBox.StandardButton.Ok + ) self.copyButton = None else: self.copyButton = self.buttonBox.addButton( - self.tr("Copy"), QDialogButtonBox.ButtonRole.ActionRole) + self.tr("Copy"), QDialogButtonBox.ButtonRole.ActionRole + ) self.copyButton.setToolTip( - self.tr("Copy the regular expression to the clipboard")) - self.buttonBox.setStandardButtons( - QDialogButtonBox.StandardButton.Close) + self.tr("Copy the regular expression to the clipboard") + ) + self.buttonBox.setStandardButtons(QDialogButtonBox.StandardButton.Close) self.variableLabel.hide() self.variableLineEdit.hide() self.variableLine.hide() @@ -116,7 +119,7 @@ def __insertString(self, s, steps=0): """ Private method to insert a string into line edit and move cursor. - + @param s string to be inserted into the regexp line edit (string) @param steps number of characters to move the cursor (integer). @@ -133,42 +136,42 @@ for _ in range(steps): tc.movePosition(act) self.regexpTextEdit.setTextCursor(tc) - + @pyqtSlot() def on_commentButton_clicked(self): """ Private slot to handle the comment toolbutton. """ self.__insertString("(?#)", -1) - + @pyqtSlot() def on_anycharButton_clicked(self): """ Private slot to handle the any character toolbutton. """ self.__insertString(".") - + @pyqtSlot() def on_nonGroupButton_clicked(self): """ Private slot to handle the non group toolbutton. """ self.__insertString("(?:)", -1) - + @pyqtSlot() def on_groupButton_clicked(self): """ Private slot to handle the group toolbutton. """ self.__insertString("()", -1) - + @pyqtSlot() def on_namedGroupButton_clicked(self): """ Private slot to handle the named group toolbutton. """ self.__insertString("(?P<>)", -2) - + @pyqtSlot() def on_namedReferenceButton_clicked(self): """ @@ -176,7 +179,7 @@ """ # determine cursor position as length into text length = self.regexpTextEdit.textCursor().position() - + # only present group names that occur before the # current cursor position regex = self.regexpTextEdit.toPlainText()[:length] @@ -185,121 +188,124 @@ EricMessageBox.information( self, self.tr("Named reference"), - self.tr("""No named groups have been defined yet.""")) + self.tr("""No named groups have been defined yet."""), + ) return - + groupName, ok = QInputDialog.getItem( self, self.tr("Named reference"), self.tr("Select group name:"), names, - 0, True) + 0, + True, + ) if ok and groupName: self.__insertString("(?P={0})".format(groupName)) - + @pyqtSlot() def on_altnButton_clicked(self): """ Private slot to handle the alternatives toolbutton. """ self.__insertString("(|)", -2) - + @pyqtSlot() def on_beglineButton_clicked(self): """ Private slot to handle the begin line toolbutton. """ self.__insertString("^") - + @pyqtSlot() def on_endlineButton_clicked(self): """ Private slot to handle the end line toolbutton. """ self.__insertString("$") - + @pyqtSlot() def on_wordboundButton_clicked(self): """ Private slot to handle the word boundary toolbutton. """ self.__insertString("\\b") - + @pyqtSlot() def on_nonwordboundButton_clicked(self): """ Private slot to handle the non word boundary toolbutton. """ self.__insertString("\\B") - + @pyqtSlot() def on_poslookaheadButton_clicked(self): """ Private slot to handle the positive lookahead toolbutton. """ self.__insertString("(?=)", -1) - + @pyqtSlot() def on_neglookaheadButton_clicked(self): """ Private slot to handle the negative lookahead toolbutton. """ self.__insertString("(?!)", -1) - + @pyqtSlot() def on_poslookbehindButton_clicked(self): """ Private slot to handle the positive lookbehind toolbutton. """ self.__insertString("(?<=)", -1) - + @pyqtSlot() def on_neglookbehindButton_clicked(self): """ Private slot to handle the negative lookbehind toolbutton. """ self.__insertString("(?<!)", -1) - + @pyqtSlot() def on_repeatButton_clicked(self): """ Private slot to handle the repeat toolbutton. """ from .PyRegExpWizardRepeatDialog import PyRegExpWizardRepeatDialog + dlg = PyRegExpWizardRepeatDialog(self) if dlg.exec() == QDialog.DialogCode.Accepted: self.__insertString(dlg.getRepeat()) - + @pyqtSlot() def on_charButton_clicked(self): """ Private slot to handle the characters toolbutton. """ - from .PyRegExpWizardCharactersDialog import ( - PyRegExpWizardCharactersDialog - ) + from .PyRegExpWizardCharactersDialog import PyRegExpWizardCharactersDialog + dlg = PyRegExpWizardCharactersDialog(self) if dlg.exec() == QDialog.DialogCode.Accepted: self.__insertString(dlg.getCharacters()) - + @pyqtSlot() def on_undoButton_clicked(self): """ Private slot to handle the undo action. """ self.regexpTextEdit.document().undo() - + @pyqtSlot() def on_redoButton_clicked(self): """ Private slot to handle the redo action. """ self.regexpTextEdit.document().redo() - + def on_buttonBox_clicked(self, button): """ Private slot called by a button of the button box clicked. - + @param button button that was clicked (QAbstractButton) """ if button == self.validateButton: @@ -314,7 +320,7 @@ self.on_nextButton_clicked() elif self.copyButton and button == self.copyButton: self.on_copyButton_clicked() - + @pyqtSlot() def on_saveButton_clicked(self): """ @@ -326,7 +332,8 @@ "", self.tr("RegExp Files (*.rx);;All Files (*)"), None, - EricFileDialog.DontConfirmOverwrite) + EricFileDialog.DontConfirmOverwrite, + ) if fname: fpath = pathlib.Path(fname) if not fpath.suffix: @@ -337,12 +344,14 @@ res = EricMessageBox.yesNo( self, self.tr("Save regular expression"), - self.tr("<p>The file <b>{0}</b> already exists." - " Overwrite it?</p>").format(fpath), - icon=EricMessageBox.Warning) + self.tr( + "<p>The file <b>{0}</b> already exists." " Overwrite it?</p>" + ).format(fpath), + icon=EricMessageBox.Warning, + ) if not res: return - + try: with fpath.open("w", encoding="utf-8") as f: f.write(self.regexpTextEdit.toPlainText()) @@ -350,10 +359,12 @@ EricMessageBox.information( self, self.tr("Save regular expression"), - self.tr("""<p>The regular expression could not""" - """ be saved.</p><p>Reason: {0}</p>""") - .format(str(err))) - + self.tr( + """<p>The regular expression could not""" + """ be saved.</p><p>Reason: {0}</p>""" + ).format(str(err)), + ) + @pyqtSlot() def on_loadButton_clicked(self): """ @@ -363,7 +374,8 @@ self, self.tr("Load regular expression"), "", - self.tr("RegExp Files (*.rx);;All Files (*)")) + self.tr("RegExp Files (*.rx);;All Files (*)"), + ) if fname: fname = Utilities.toNativeSeparators(fname) try: @@ -374,15 +386,17 @@ EricMessageBox.information( self, self.tr("Save regular expression"), - self.tr("""<p>The regular expression could not""" - """ be saved.</p><p>Reason: {0}</p>""") - .format(str(err))) + self.tr( + """<p>The regular expression could not""" + """ be saved.</p><p>Reason: {0}</p>""" + ).format(str(err)), + ) @pyqtSlot() def on_copyButton_clicked(self): """ Private slot to copy the regexp string into the clipboard. - + This slot is only available, if not called from within eric. """ escaped = self.regexpTextEdit.toPlainText() @@ -416,35 +430,39 @@ EricMessageBox.information( self, self.tr("Validation"), - self.tr("""The regular expression is valid.""")) + self.tr("""The regular expression is valid."""), + ) except re.error as e: EricMessageBox.critical( self, self.tr("Error"), - self.tr("""Invalid regular expression: {0}""") - .format(str(e))) + self.tr("""Invalid regular expression: {0}""").format(str(e)), + ) return except IndexError: EricMessageBox.critical( self, self.tr("Error"), - self.tr("""Invalid regular expression: missing""" - """ group name""")) + self.tr( + """Invalid regular expression: missing""" """ group name""" + ), + ) return else: EricMessageBox.critical( self, self.tr("Error"), - self.tr("""A regular expression must be given.""")) + self.tr("""A regular expression must be given."""), + ) @pyqtSlot() def on_executeButton_clicked(self, startpos=0): """ Private slot to execute the entered regexp on the test text. - + This slot will execute the entered regexp on the entered test data and will display the result in the table part of the dialog. - + @param startpos starting position for the regexp matching """ regex = self.regexpTextEdit.toPlainText() @@ -472,74 +490,72 @@ captures = 0 row = 0 OFFSET = 5 - + self.resultTable.setColumnCount(0) self.resultTable.setColumnCount(3) self.resultTable.setRowCount(0) self.resultTable.setRowCount(OFFSET) - self.resultTable.setItem( - row, 0, QTableWidgetItem(self.tr("Regexp"))) - self.resultTable.setItem( - row, 1, QTableWidgetItem(regex)) - + self.resultTable.setItem(row, 0, QTableWidgetItem(self.tr("Regexp"))) + self.resultTable.setItem(row, 1, QTableWidgetItem(regex)) + if matchobj is not None: offset = matchobj.start() self.lastMatchEnd = matchobj.end() self.nextButton.setEnabled(True) row += 1 self.resultTable.setItem( - row, 0, - QTableWidgetItem(self.tr("Offset"))) + row, 0, QTableWidgetItem(self.tr("Offset")) + ) self.resultTable.setItem( - row, 1, - QTableWidgetItem("{0:d}".format(matchobj.start(0)))) - - row += 1 - self.resultTable.setItem( - row, 0, - QTableWidgetItem(self.tr("Captures"))) - self.resultTable.setItem( - row, 1, - QTableWidgetItem("{0:d}".format(captures))) + row, 1, QTableWidgetItem("{0:d}".format(matchobj.start(0))) + ) + row += 1 self.resultTable.setItem( - row, 1, - QTableWidgetItem(self.tr("Text"))) + row, 0, QTableWidgetItem(self.tr("Captures")) + ) self.resultTable.setItem( - row, 2, - QTableWidgetItem(self.tr("Characters"))) - + row, 1, QTableWidgetItem("{0:d}".format(captures)) + ) row += 1 + self.resultTable.setItem(row, 1, QTableWidgetItem(self.tr("Text"))) self.resultTable.setItem( - row, 0, - QTableWidgetItem(self.tr("Match"))) + row, 2, QTableWidgetItem(self.tr("Characters")) + ) + + row += 1 + self.resultTable.setItem(row, 0, QTableWidgetItem(self.tr("Match"))) self.resultTable.setItem( - row, 1, - QTableWidgetItem(matchobj.group(0))) + row, 1, QTableWidgetItem(matchobj.group(0)) + ) self.resultTable.setItem( - row, 2, - QTableWidgetItem( - "{0:d}".format(len(matchobj.group(0))))) - + row, 2, QTableWidgetItem("{0:d}".format(len(matchobj.group(0)))) + ) + for i in range(1, captures + 1): if matchobj.group(i) is not None: row += 1 self.resultTable.insertRow(row) self.resultTable.setItem( - row, 0, - QTableWidgetItem( - self.tr("Capture #{0}").format(i))) + row, + 0, + QTableWidgetItem(self.tr("Capture #{0}").format(i)), + ) + self.resultTable.setItem( + row, 1, QTableWidgetItem(matchobj.group(i)) + ) self.resultTable.setItem( - row, 1, QTableWidgetItem(matchobj.group(i))) - self.resultTable.setItem( - row, 2, QTableWidgetItem( - "{0:d}".format(len(matchobj.group(i))))) - + row, + 2, + QTableWidgetItem( + "{0:d}".format(len(matchobj.group(i))) + ), + ) + # highlight the matched text tc = self.textTextEdit.textCursor() tc.setPosition(offset) - tc.setPosition(self.lastMatchEnd, - QTextCursor.MoveMode.KeepAnchor) + tc.setPosition(self.lastMatchEnd, QTextCursor.MoveMode.KeepAnchor) self.textTextEdit.setTextCursor(tc) else: self.nextButton.setEnabled(False) @@ -547,18 +563,18 @@ row += 1 if startpos > 0: self.resultTable.setItem( - row, 0, - QTableWidgetItem(self.tr("No more matches"))) + row, 0, QTableWidgetItem(self.tr("No more matches")) + ) else: self.resultTable.setItem( - row, 0, - QTableWidgetItem(self.tr("No matches"))) - + row, 0, QTableWidgetItem(self.tr("No matches")) + ) + # remove the highlight tc = self.textTextEdit.textCursor() tc.setPosition(0) self.textTextEdit.setTextCursor(tc) - + self.resultTable.resizeColumnsToContents() self.resultTable.resizeRowsToContents() self.resultTable.verticalHeader().hide() @@ -567,41 +583,43 @@ EricMessageBox.critical( self, self.tr("Error"), - self.tr("""Invalid regular expression: {0}""") - .format(str(e))) + self.tr("""Invalid regular expression: {0}""").format(str(e)), + ) return except IndexError: EricMessageBox.critical( self, self.tr("Error"), - self.tr("""Invalid regular expression: missing""" - """ group name""")) + self.tr( + """Invalid regular expression: missing""" """ group name""" + ), + ) return else: EricMessageBox.critical( self, self.tr("Error"), - self.tr("""A regular expression and a text must be""" - """ given.""")) - + self.tr("""A regular expression and a text must be""" """ given."""), + ) + @pyqtSlot() def on_nextButton_clicked(self): """ Private slot to find the next match. """ self.on_executeButton_clicked(self.lastMatchEnd) - + @pyqtSlot() def on_regexpTextEdit_textChanged(self): """ Private slot called when the regexp changes. """ self.nextButton.setEnabled(False) - + def getCode(self, indLevel, indString): """ Public method to get the source code. - + @param indLevel indentation level (int) @param indString string used for indentation (space or tab) (string) @return generated code (string) @@ -610,36 +628,37 @@ istring = indLevel * indString i1string = (indLevel + 1) * indString estring = os.linesep + indLevel * indString - + # now generate the code reVar = self.variableLineEdit.text() if not reVar: reVar = "regexp" - + regexp = self.regexpTextEdit.toPlainText() - + flags = [] if not self.caseSensitiveCheckBox.isChecked(): - flags.append('re.IGNORECASE') + flags.append("re.IGNORECASE") if self.multilineCheckBox.isChecked(): - flags.append('re.MULTILINE') + flags.append("re.MULTILINE") if self.dotallCheckBox.isChecked(): - flags.append('re.DOTALL') + flags.append("re.DOTALL") if self.verboseCheckBox.isChecked(): - flags.append('re.VERBOSE') + flags.append("re.VERBOSE") if self.unicodeCheckBox.isChecked(): - flags.append('re.ASCII') + flags.append("re.ASCII") flags = " | ".join(flags) - - code = '' + + code = "" if self.importCheckBox.isChecked(): - code += 'import re{0}{1}'.format(os.linesep, istring) - code += '{0} = re.compile('.format(reVar) + code += "import re{0}{1}".format(os.linesep, istring) + code += "{0} = re.compile(".format(reVar) code += '{0}{1}r"""{2}"""'.format( - os.linesep, i1string, regexp.replace('"', '\\"')) + os.linesep, i1string, regexp.replace('"', '\\"') + ) if flags: - code += ',{0}{1}{2}'.format(os.linesep, i1string, flags) - code += '{0}){0}'.format(estring) + code += ",{0}{1}{2}".format(os.linesep, i1string, flags) + code += "{0}){0}".format(estring) return code @@ -647,34 +666,35 @@ """ Class for the dialog variant. """ + def __init__(self, parent=None, fromEric=True): """ Constructor - + @param parent parent widget (QWidget) @param fromEric flag indicating a call from within eric """ super().__init__(parent) self.setModal(fromEric) self.setSizeGripEnabled(True) - + self.__layout = QVBoxLayout(self) self.__layout.setContentsMargins(0, 0, 0, 0) self.setLayout(self.__layout) - + self.cw = PyRegExpWizardWidget(self, fromEric) size = self.cw.size() self.__layout.addWidget(self.cw) self.resize(size) self.setWindowTitle(self.cw.windowTitle()) - + self.cw.buttonBox.accepted.connect(self.accept) self.cw.buttonBox.rejected.connect(self.reject) - + def getCode(self, indLevel, indString): """ Public method to get the source code. - + @param indLevel indentation level (int) @param indString string used for indentation (space or tab) (string) @return generated code (string) @@ -686,10 +706,11 @@ """ Main window class for the standalone dialog. """ + def __init__(self, parent=None): """ Constructor - + @param parent reference to the parent widget (QWidget) """ super().__init__(parent) @@ -698,9 +719,8 @@ self.setCentralWidget(self.cw) self.resize(size) self.setWindowTitle(self.cw.windowTitle()) - - self.setStyle( - Preferences.getUI("Style"), Preferences.getUI("StyleSheet")) - + + self.setStyle(Preferences.getUI("Style"), Preferences.getUI("StyleSheet")) + self.cw.buttonBox.accepted.connect(self.close) self.cw.buttonBox.rejected.connect(self.close)