From 03cb6ccb2b0f08d3c503621230ab2704754a2158 Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Tue, 2 Apr 2024 22:51:04 +0200 Subject: [PATCH 1/2] Let project search start with selected text (#1789) --- novelwriter/core/coretools.py | 3 +-- novelwriter/gui/doceditor.py | 28 +++++++++++++++++----------- novelwriter/gui/search.py | 5 ++++- novelwriter/guimain.py | 4 +++- 4 files changed, 25 insertions(+), 15 deletions(-) diff --git a/novelwriter/core/coretools.py b/novelwriter/core/coretools.py index f6558600..b8fc5ba1 100644 --- a/novelwriter/core/coretools.py +++ b/novelwriter/core/coretools.py @@ -382,8 +382,7 @@ class DocSearch: escaped += f"\\{c}" search = escaped if self._words: - search = search if search.startswith("\\b") else f"\\b{search}" - search = search if search.endswith("\\b") else f"{search}\\b" + search = f"(?:^|\\b){search}(?:$|\\b)" return search # END Class DocSearch diff --git a/novelwriter/gui/doceditor.py b/novelwriter/gui/doceditor.py index d695f041..fbf4f224 100644 --- a/novelwriter/gui/doceditor.py +++ b/novelwriter/gui/doceditor.py @@ -596,6 +596,15 @@ class GuiDocEditor(QPlainTextEdit): text = text.replace(nwUnicode.U_PSEP, "\n") # Paragraph separators return text + def getSelectedText(self) -> str: + """Get currently selected text.""" + if (cursor := self.textCursor()).hasSelection(): + text = cursor.selectedText() + text = text.replace(nwUnicode.U_LSEP, "\n") # Line separators + text = text.replace(nwUnicode.U_PSEP, "\n") # Paragraph separators + return text + return "" + def getCursorPosition(self) -> int: """Find the cursor position in the document. If the editor has a selection, return the position of the end of the selection. @@ -642,12 +651,13 @@ class GuiDocEditor(QPlainTextEdit): logger.debug("Cursor moved to line %d", line) return - def setCursorSelection(self, selStart: int, selLength: int) -> None: + def setCursorSelection(self, start: int, length: int) -> None: """Make a text selection.""" - cursor = self.textCursor() - cursor.setPosition(selStart, QTextCursor.MoveMode.MoveAnchor) - cursor.setPosition(selStart + selLength, QTextCursor.MoveMode.KeepAnchor) - self.setTextCursor(cursor) + if start >= 0 and length > 0: + cursor = self.textCursor() + cursor.setPosition(start, QTextCursor.MoveMode.MoveAnchor) + cursor.setPosition(start + length, QTextCursor.MoveMode.KeepAnchor) + self.setTextCursor(cursor) return ## @@ -1280,11 +1290,7 @@ class GuiDocEditor(QPlainTextEdit): def beginSearch(self) -> None: """Set the selected text as the search text.""" - cursor = self.textCursor() - if cursor.hasSelection(): - self.docSearch.setSearchText(cursor.selectedText()) - else: - self.docSearch.setSearchText(None) + self.docSearch.setSearchText(self.getSelectedText() or None) resS, _ = self.findAllOccurences() self.docSearch.setResultCount(None, len(resS)) return @@ -2226,7 +2232,7 @@ class BackgroundWordCounter(QRunnable): """ self._isRunning = True if self._forSelection: - text = self._docEditor.textCursor().selectedText() + text = self._docEditor.getSelectedText() else: text = self._docEditor.getText() diff --git a/novelwriter/gui/search.py b/novelwriter/gui/search.py index 0394c26e..769689ee 100644 --- a/novelwriter/gui/search.py +++ b/novelwriter/gui/search.py @@ -192,10 +192,13 @@ class GuiProjectSearch(QWidget): ) return - def beginSearch(self) -> None: + def beginSearch(self, text: str = "") -> None: """Focus the search box and select its text, if any.""" self.searchText.setFocus() self.searchText.selectAll() + if text: + self.searchText.setText(text.partition("\n")[0]) + self.searchText.selectAll() return def closeProjectTasks(self) -> None: diff --git a/novelwriter/guimain.py b/novelwriter/guimain.py index 3a336577..14f9a494 100644 --- a/novelwriter/guimain.py +++ b/novelwriter/guimain.py @@ -1168,7 +1168,9 @@ class GuiMain(QMainWindow): elif view == nwView.SEARCH: self.mainStack.setCurrentWidget(self.splitMain) self.projStack.setCurrentWidget(self.projSearch) - self.projSearch.beginSearch() + self.projSearch.beginSearch( + self.docEditor.getSelectedText() if self.docEditor.anyFocus() else "" + ) elif view == nwView.OUTLINE: self.mainStack.setCurrentWidget(self.outlineView) return From c0fd1f1466cd4e6b391bde93704fb6f7a9f5349f Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Tue, 2 Apr 2024 22:53:21 +0200 Subject: [PATCH 2/2] Update tests --- tests/test_core/test_core_coretools.py | 5 +---- tests/test_gui/test_gui_search.py | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/tests/test_core/test_core_coretools.py b/tests/test_core/test_core_coretools.py index b3178ef6..7c68bb7d 100644 --- a/tests/test_core/test_core_coretools.py +++ b/tests/test_core/test_core_coretools.py @@ -439,10 +439,7 @@ def testCoreTools_DocSearch(monkeypatch, mockGUI, fncPath, mockRnd, ipsumText): # Whole Words search.setWholeWords(True) search.setUserRegEx(True) - assert search._buildPattern("Hi") == r"\bHi\b" - assert search._buildPattern(r"\bHi") == r"\bHi\b" - assert search._buildPattern(r"Hi\b") == r"\bHi\b" - assert search._buildPattern(r"\bHi\b") == r"\bHi\b" + assert search._buildPattern("Hi") == r"(?:^|\b)Hi(?:$|\b)" search.setWholeWords(False) search.setUserRegEx(False) diff --git a/tests/test_gui/test_gui_search.py b/tests/test_gui/test_gui_search.py index bd8ed4be..1bd3d359 100644 --- a/tests/test_gui/test_gui_search.py +++ b/tests/test_gui/test_gui_search.py @@ -117,7 +117,7 @@ def testGuiDocSearch_Main(qtbot, monkeypatch, nwGUI, prjLipsum): # RegEx search.toggleRegEx.setChecked(True) - search.searchText.setText("(dolor|dolorem)") + search.beginSearch("(dolor|dolorem)") search.searchAction.activate(QAction.ActionEvent.Trigger) assert search.searchResult.topLevelItemCount() == 10 assert totalCount() == 34