Add basic string search
This commit is contained in:
@@ -304,6 +304,34 @@ class DocDuplicator:
|
|||||||
# END Class DocDuplicator
|
# END Class DocDuplicator
|
||||||
|
|
||||||
|
|
||||||
|
class DocSearch:
|
||||||
|
|
||||||
|
def __init__(self, project: NWProject) -> None:
|
||||||
|
self._project = project
|
||||||
|
return
|
||||||
|
|
||||||
|
def iterSearch(self, search: str) -> Iterable[tuple[NWItem, list[tuple[int, int, str]]]]:
|
||||||
|
"""Iteratively search through documents in the project."""
|
||||||
|
num = len(search)
|
||||||
|
cap = min(num+100, 100)
|
||||||
|
storage = self._project.storage
|
||||||
|
for item in self._project.tree:
|
||||||
|
if item.isFileType():
|
||||||
|
text = storage.getDocument(item.itemHandle).readDocument() or ""
|
||||||
|
prev = 0
|
||||||
|
results = []
|
||||||
|
count = 0
|
||||||
|
while (pos := text.find(search, prev)) >= 0 and count < 100:
|
||||||
|
count += 1
|
||||||
|
context = text[pos:pos+cap].partition("\n")[0]
|
||||||
|
results.append((pos, num, context))
|
||||||
|
prev = pos + num
|
||||||
|
yield item, results
|
||||||
|
return
|
||||||
|
|
||||||
|
# END Class DocSearch
|
||||||
|
|
||||||
|
|
||||||
class ProjectBuilder:
|
class ProjectBuilder:
|
||||||
"""A class to build a new project from a set of user-defined
|
"""A class to build a new project from a set of user-defined
|
||||||
parameter provided by the New Project Wizard.
|
parameter provided by the New Project Wizard.
|
||||||
|
|||||||
@@ -25,10 +25,16 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from PyQt5.QtCore import pyqtSlot
|
||||||
from PyQt5.QtGui import QPalette
|
from PyQt5.QtGui import QPalette
|
||||||
from PyQt5.QtWidgets import QHBoxLayout, QLabel, QLineEdit, QTreeWidget, QVBoxLayout, QWidget
|
from PyQt5.QtWidgets import (
|
||||||
|
QHBoxLayout, QLabel, QLineEdit, QTreeWidget, QTreeWidgetItem, QVBoxLayout,
|
||||||
|
QWidget
|
||||||
|
)
|
||||||
|
|
||||||
from novelwriter import CONFIG, SHARED
|
from novelwriter import CONFIG, SHARED
|
||||||
|
from novelwriter.core.coretools import DocSearch
|
||||||
|
from novelwriter.core.item import NWItem
|
||||||
from novelwriter.extensions.modified import NIconToolButton
|
from novelwriter.extensions.modified import NIconToolButton
|
||||||
from novelwriter.gui.theme import STYLES_MIN_TOOLBUTTON
|
from novelwriter.gui.theme import STYLES_MIN_TOOLBUTTON
|
||||||
|
|
||||||
@@ -51,13 +57,14 @@ class GuiProjectSearch(QWidget):
|
|||||||
self.viewLabel.setContentsMargins(mPx, mPx, 0, mPx)
|
self.viewLabel.setContentsMargins(mPx, mPx, 0, mPx)
|
||||||
|
|
||||||
# Controls
|
# Controls
|
||||||
self.searchBox = QLineEdit(self)
|
self.searchText = QLineEdit(self)
|
||||||
self.searchBox.setPlaceholderText(self.tr("Search text ..."))
|
self.searchText.setPlaceholderText(self.tr("Search text ..."))
|
||||||
|
|
||||||
self.searchButton = NIconToolButton(self, iPx)
|
self.searchButton = NIconToolButton(self, iPx)
|
||||||
|
self.searchButton.clicked.connect(self._processSearch)
|
||||||
|
|
||||||
self.searchBar = QHBoxLayout()
|
self.searchBar = QHBoxLayout()
|
||||||
self.searchBar.addWidget(self.searchBox)
|
self.searchBar.addWidget(self.searchText)
|
||||||
self.searchBar.addWidget(self.searchButton)
|
self.searchBar.addWidget(self.searchButton)
|
||||||
|
|
||||||
# Search Result
|
# Search Result
|
||||||
@@ -96,4 +103,36 @@ class GuiProjectSearch(QWidget):
|
|||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
##
|
||||||
|
# Private Slots
|
||||||
|
##
|
||||||
|
|
||||||
|
@pyqtSlot()
|
||||||
|
def _processSearch(self) -> None:
|
||||||
|
"""Perform a search."""
|
||||||
|
self.searchResult.clear()
|
||||||
|
if text := self.searchText.text():
|
||||||
|
search = DocSearch(SHARED.project)
|
||||||
|
for item, results in search.iterSearch(text):
|
||||||
|
self._appendResultSet(item, results)
|
||||||
|
return
|
||||||
|
|
||||||
|
##
|
||||||
|
# Internal Functions
|
||||||
|
##
|
||||||
|
|
||||||
|
def _appendResultSet(self, item: NWItem, results: list[tuple[int, int, str]]) -> None:
|
||||||
|
"""Populate the result tree."""
|
||||||
|
if results:
|
||||||
|
tItem = QTreeWidgetItem()
|
||||||
|
tItem.setText(0, f"{item.itemName} ({len(results)})")
|
||||||
|
rItems = []
|
||||||
|
for start, end, context in results:
|
||||||
|
rItem = QTreeWidgetItem()
|
||||||
|
rItem.setText(0, context)
|
||||||
|
rItems.append(rItem)
|
||||||
|
tItem.addChildren(rItems)
|
||||||
|
self.searchResult.addTopLevelItem(tItem)
|
||||||
|
return
|
||||||
|
|
||||||
# END Class GuiProjectSearch
|
# END Class GuiProjectSearch
|
||||||
|
|||||||
Reference in New Issue
Block a user