From 01e1ab3f68e613eebc7a0361a5d840bb38be6c6e Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Mon, 27 Jul 2020 20:09:39 +0200 Subject: [PATCH] Found a better way to validate a search/replace when using RegEx --- nw/gui/doceditor.py | 66 ++++++++++++++++++++++++++++++++------------- 1 file changed, 47 insertions(+), 19 deletions(-) diff --git a/nw/gui/doceditor.py b/nw/gui/doceditor.py index 59bb9374..91c1aa51 100644 --- a/nw/gui/doceditor.py +++ b/nw/gui/doceditor.py @@ -79,6 +79,7 @@ class GuiDocEditor(QTextEdit): self.wordCount = 0 self.paraCount = 0 self.lastEdit = 0 + self.lastFind = None self.bigDoc = False self.doReplace = False self.nonWord = "\"'" @@ -89,7 +90,7 @@ class GuiDocEditor(QTextEdit): self.typSQOpen = self.mainConf.fmtSingleQuotes[0] self.typSQClose = self.mainConf.fmtSingleQuotes[1] - # Core Elements + # Core Elements and Signals self.qDocument = self.document() self.qDocument.contentsChange.connect(self._docChange) @@ -685,6 +686,7 @@ class GuiDocEditor(QTextEdit): triggers the syntax highlighter. """ self.lastEdit = time() + self.lastFind = None if not self.docChanged: self.setDocumentChanged(True) if not self.wcTimer.isActive(): @@ -1170,19 +1172,21 @@ class GuiDocEditor(QTextEdit): """ theCursor = self.textCursor() if theCursor.hasSelection(): - selText = theCursor.selectedText() + self.docSearch.setSearchText(theCursor.selectedText()) else: - selText = "" - self.docSearch.setSearchText(selText) + self.docSearch.setSearchText(None) self.updateDocMargins() return def _beginReplace(self): - """Opens the replace line of the search bar and sets the replace - text. + """Opens the replace line of the search bar and sets the find + text if a selection has been made, and resets the replace text. """ - self._beginSearch() + theCursor = self.textCursor() + if theCursor.hasSelection(): + self.docSearch.setSearchText(theCursor.selectedText()) self.docSearch.setReplaceText("") + self.updateDocMargins() return def _findNext(self, isBackward=False): @@ -1215,7 +1219,11 @@ class GuiDocEditor(QTextEdit): QTextCursor.End if isBackward else QTextCursor.Start ) self.setTextCursor(theCursor) - self.find(searchFor, findOpt) + wasFound = self.find(searchFor, findOpt) + + if wasFound: + theCursor = self.textCursor() + self.lastFind = (theCursor.selectionStart(), theCursor.selectionEnd()) return @@ -1225,32 +1233,49 @@ class GuiDocEditor(QTextEdit): next automatically when done. """ if not self.docSearch.isVisible(): + # The search tool is not active, so we activate it. self._beginSearch() return theCursor = self.textCursor() if not theCursor.hasSelection(): + # We have no text selected at all, so just make this a + # regular find next call. self._findNext() return + if self.lastFind is None and theCursor.hasSelection(): + # If we have a selection but no search, it may have been the + # text we triggered the search with, in which case we search + # again from the beginning of that selection to make sure we + # have a valid result. + sPos = theCursor.selectionStart() + theCursor.clearSelection() + theCursor.setPosition(sPos) + self.setTextCursor(theCursor) + self._findNext() + theCursor = self.textCursor() + + if self.lastFind is None: + # In case the above didn't find a result, we give up here. + return + searchFor = self.docSearch.getSearchText() replWith = self.docSearch.getReplaceText() selText = theCursor.selectedText() - if searchFor.strip() == "": - return - if self.docSearch.doMatchCap: replWith = transferCase(selText, replWith) - # Double check that we have a real match in case this is called - # on a regular word selection and not on a search match - if not self.docSearch.isCaseSense: - isMatch = searchFor.lower() == selText.lower() - else: - isMatch = searchFor == selText + # Make sure the selected text was selected by an actual find + # call, and not the user. + try: + isResult = self.lastFind[0] == theCursor.selectionStart() + isResult &= self.lastFind[1] == theCursor.selectionEnd() + except: + isResult = False - if isMatch: + if isResult: theCursor.beginEditBlock() theCursor.removeSelectedText() theCursor.insertText(replWith) @@ -1260,6 +1285,8 @@ class GuiDocEditor(QTextEdit): logger.verbose("Replaced occurrence of '%s' with '%s' on line %d" % ( searchFor, replWith, theCursor.blockNumber() )) + else: + logger.error("The selected text is not a search result, skipping replace") self._findNext() @@ -1530,7 +1557,8 @@ class GuiDocEditSearch(QFrame): """ if not self.isVisible(): self.setVisible(True) - self.searchBox.setText(theText) + if theText is not None: + self.searchBox.setText(theText) self.searchBox.setFocus() if self.isRegEx: self._alertSearchValid(True)