diff --git a/.github/workflows/syntax.yml b/.github/workflows/syntax.yml index 560dd7dc..a0b56ce1 100644 --- a/.github/workflows/syntax.yml +++ b/.github/workflows/syntax.yml @@ -4,9 +4,11 @@ on: push: branches: - main + - patch pull_request: branches: - main + - patch jobs: checkSyntax: diff --git a/.github/workflows/test_linux.yml b/.github/workflows/test_linux.yml index 5699d8a8..caf147ef 100644 --- a/.github/workflows/test_linux.yml +++ b/.github/workflows/test_linux.yml @@ -4,9 +4,11 @@ on: push: branches: - main + - patch pull_request: branches: - main + - patch jobs: testLinux: diff --git a/.github/workflows/test_mac.yml b/.github/workflows/test_mac.yml index c9b4497c..a011b51e 100644 --- a/.github/workflows/test_mac.yml +++ b/.github/workflows/test_mac.yml @@ -4,9 +4,11 @@ on: push: branches: - main + - patch pull_request: branches: - main + - patch jobs: testMac: diff --git a/.github/workflows/test_win.yml b/.github/workflows/test_win.yml index 85a0fda6..b41ccbf5 100644 --- a/.github/workflows/test_win.yml +++ b/.github/workflows/test_win.yml @@ -4,9 +4,11 @@ on: push: branches: - main + - patch pull_request: branches: - main + - patch jobs: testWin: diff --git a/novelwriter/gui/doceditor.py b/novelwriter/gui/doceditor.py index b1760be4..4d35c978 100644 --- a/novelwriter/gui/doceditor.py +++ b/novelwriter/gui/doceditor.py @@ -1436,10 +1436,16 @@ class GuiDocEditor(QTextEdit): theCursor.setPosition(0) self.setTextCursor(theCursor) - while self.find(searchFor, findOpt): + # Search up to a maximum of 1000, and make sure certain special + # searches like a regex search for .* turns into an infinite loop + while self.find(searchFor, findOpt) and len(resE) <= 1000: theCursor = self.textCursor() - resS.append(theCursor.selectionStart()) - resE.append(theCursor.selectionEnd()) + if theCursor.hasSelection(): + resS.append(theCursor.selectionStart()) + resE.append(theCursor.selectionEnd()) + else: + logger.warning("The search returned an empty result") + break if hasSelection: theCursor.setPosition(origA, QTextCursor.MoveAnchor) @@ -2410,7 +2416,7 @@ class GuiDocEditSearch(QFrame): """Set the count values for the current search. """ currRes = "?" if currRes is None else currRes - resCount = "?" if resCount is None else resCount + resCount = "?" if resCount is None else "1000+" if resCount > 1000 else resCount minWidth = self.theTheme.getTextWidth(f"{resCount}//{resCount}", self.boxFont) self.resultLabel.setText(f"{currRes}/{resCount}") self.resultLabel.setMinimumWidth(minWidth) diff --git a/tests/test_gui/test_gui_doceditor.py b/tests/test_gui/test_gui_doceditor.py index 241acd24..8057ca41 100644 --- a/tests/test_gui/test_gui_doceditor.py +++ b/tests/test_gui/test_gui_doceditor.py @@ -1286,13 +1286,13 @@ def testGuiEditor_Search(qtbot, monkeypatch, nwGUI, nwLipsum): monkeypatch.setattr(GuiDocEditor, "hasFocus", lambda *a: True) nwGUI.theProject.projTree.setSeed(42) - assert nwGUI.openProject(nwLipsum) - assert nwGUI.openDocument("4c4f28287af27") + assert nwGUI.openProject(nwLipsum) is True + assert nwGUI.openDocument("4c4f28287af27") is True origText = nwGUI.docEditor.getText() qtbot.wait(stepDelay) # Select the Word "est" - assert nwGUI.docEditor.setCursorPosition(630) + nwGUI.docEditor.setCursorPosition(630) nwGUI.docEditor._makeSelection(QTextCursor.WordUnderCursor) theCursor = nwGUI.docEditor.textCursor() assert theCursor.selectedText() == "est" @@ -1331,7 +1331,7 @@ def testGuiEditor_Search(qtbot, monkeypatch, nwGUI, nwLipsum): assert nwGUI.docEditor.docSearch.isVisible() is True # Search for non-existing - assert nwGUI.docEditor.setCursorPosition(0) + nwGUI.docEditor.setCursorPosition(0) assert nwGUI.docEditor.docSearch.setSearchText("abcdef") qtbot.mouseClick(nwGUI.docEditor.docSearch.searchButton, Qt.LeftButton, delay=keyDelay) assert nwGUI.docEditor.getCursorPosition() < 3 # No result @@ -1342,11 +1342,18 @@ def testGuiEditor_Search(qtbot, monkeypatch, nwGUI, nwLipsum): assert nwGUI.docEditor.docSearch.isRegEx is True # Set invalid RegEx - assert nwGUI.docEditor.setCursorPosition(0) + nwGUI.docEditor.setCursorPosition(0) assert nwGUI.docEditor.docSearch.setSearchText(r"\bSus[") qtbot.mouseClick(nwGUI.docEditor.docSearch.searchButton, Qt.LeftButton, delay=keyDelay) assert nwGUI.docEditor.getCursorPosition() < 3 # No result + # Set dangerous RegEx (issue #1015) + # If this doesn't get caught, the app will hang + nwGUI.docEditor.setCursorPosition(0) + assert nwGUI.docEditor.docSearch.setSearchText(r".*") + qtbot.mouseClick(nwGUI.docEditor.docSearch.searchButton, Qt.LeftButton, delay=keyDelay) + assert abs(nwGUI.docEditor.getCursorPosition() - 14) < 3 + # Set valid RegEx assert nwGUI.docEditor.docSearch.setSearchText(r"\bSus") qtbot.mouseClick(nwGUI.docEditor.docSearch.searchButton, Qt.LeftButton, delay=keyDelay)