Rewritten index storage using classes instead

This commit is contained in:
Veronica Berglyd Olsen
2022-05-28 18:48:31 +02:00
parent 44926a4e9a
commit b5b0074411
+225 -1
View File
@@ -35,7 +35,7 @@ from novelwriter.error import logException
from novelwriter.constants import nwFiles, nwKeyWords, nwUnicode
from novelwriter.core.document import NWDoc
from novelwriter.common import (
isHandle, isTitleTag, isItemClass, isItemLayout, jsonEncode
checkInt, isHandle, isTitleTag, isItemClass, isItemLayout, jsonEncode
)
logger = logging.getLogger(__name__)
@@ -59,6 +59,9 @@ class NWIndex():
self._fileIndex = {}
self._fileMeta = {}
self._tags = {}
self._items = {}
# TimeStamps
self._timeNovel = 0
self._timeNotes = 0
@@ -84,6 +87,10 @@ class NWIndex():
self._timeNovel = 0
self._timeNotes = 0
self._timeIndex = 0
self._tags = {}
self._items = {}
return
def deleteHandle(self, tHandle):
@@ -194,6 +201,18 @@ class NWIndex():
logger.verbose("Index saved in %.3f ms", (time() - tStart)*1000)
indexFile = os.path.join(self.theProject.projMeta, "tagsIndex2.json")
tStart = time()
itemsIndex = {}
for item in self._items.values():
item.packData(itemsIndex)
with open(indexFile, mode="w+", encoding="utf-8") as outFile:
outFile.write(jsonEncode(itemsIndex, nmax=3))
logger.verbose("Index saved in %.3f ms", (time() - tStart)*1000)
return True
##
@@ -219,6 +238,11 @@ class NWIndex():
cC, wC, pC = countWords(theText)
self._fileMeta[tHandle] = ["H0", cC, wC, pC]
self._items[tHandle] = IndexItem(tHandle, theItem)
theItem.setCharCount(cC)
theItem.setWordCount(wC)
theItem.setParaCount(pC)
# If the file's meta data is missing, or the file is out of the
# main project, we don't index the content
if theItem.itemLayout == nwItemLayout.NO_LAYOUT:
@@ -338,6 +362,10 @@ class NWIndex():
# first header level is recorded in the file meta index
self._fileMeta[tHandle][0] = hDepth
tItem = self._items[tHandle]
tItem.updateLevel(hDepth)
tItem.addHeading(IndexHeading(sTitle, hDepth, hText))
return True
def _indexPage(self, tHandle, itemLayout):
@@ -364,6 +392,8 @@ class NWIndex():
self._fileIndex[tHandle][sTitle]["cCount"] = cC
self._fileIndex[tHandle][sTitle]["wCount"] = wC
self._fileIndex[tHandle][sTitle]["pCount"] = pC
if tHandle in self._items:
self._items[tHandle].setHeadingCounts(sTitle, cC, wC, pC)
return
def _indexSynopsis(self, tHandle, theText, nTitle):
@@ -373,6 +403,8 @@ class NWIndex():
if tHandle in self._fileIndex:
if sTitle in self._fileIndex[tHandle]:
self._fileIndex[tHandle][sTitle]["synopsis"] = theText
if tHandle in self._items:
self._items[tHandle].setHeadingSynopsis(sTitle, theText)
return
def _indexKeyword(self, tHandle, aLine, nLine, nTitle, itemClass):
@@ -391,6 +423,8 @@ class NWIndex():
sTitle = f"T{nTitle:06d}"
if theBits[0] == nwKeyWords.TAG_KEY:
self._tagIndex[theBits[1]] = [nLine, tHandle, itemClass.name, sTitle]
if tHandle in self._items:
self._items[tHandle].setHeadingTag(sTitle, theBits[1])
else:
if tHandle not in self._refIndex:
@@ -399,6 +433,8 @@ class NWIndex():
self._refIndex[tHandle][sTitle] = []
for aVal in theBits[1:]:
self._refIndex[tHandle][sTitle].append([nLine, theBits[0], aVal])
if tHandle in self._items:
self._items[tHandle].addHeadingReferences(sTitle, theBits[1:], theBits[0])
return
@@ -892,3 +928,191 @@ def countWords(theText):
prevEmpty = not countPara
return charCount, wordCount, paraCount
class IndexItem:
DEF_HKEY = "T000000"
def __init__(self, tHandle, tItem):
self._handle = tHandle
self._item = tItem
self._level = "H0"
self._headings = {}
# Add a placeholder heading
self._headings[self.DEF_HKEY] = IndexHeading(self.DEF_HKEY)
return
##
# Properties
##
@property
def level(self):
return self._level
##
# Setters
##
def setLevel(self, level):
if level in H_VALID:
self._level = level
else:
self._level = "H0"
return
def updateLevel(self, level):
"""Set the level only if it is H0.
"""
if level in H_VALID and self._level == "H0":
self._level = level
else:
self._level = "H0"
return
def addHeading(self, tHeading):
if "T000000" in self._headings:
self._headings.pop("T000000")
self._headings[tHeading.key] = tHeading
return
def setHeadingCounts(self, sTitle, charCount, wordCount, paraCount):
if sTitle in self._headings:
self._headings[sTitle].setCounts(charCount, wordCount, paraCount)
return
def setHeadingSynopsis(self, sTitle, synopText):
if sTitle in self._headings:
self._headings[sTitle].setSynopsis(synopText)
return
def setHeadingTag(self, sTitle, tagKey):
if sTitle in self._headings:
self._headings[sTitle].setTag(tagKey)
return
def addHeadingReferences(self, sTitle, tagKeys, refType):
if sTitle in self._headings:
for tagKey in tagKeys:
self._headings[sTitle].addReference(tagKey, refType)
return
##
# Data Methods
##
def packData(self, container):
"""Pack the indexed item's data into an existing dictionary.
"""
container[self._handle] = {
"firstLevel": self._level,
}
container[self._handle]["headings"] = {
key: value.packData() for key, value in self._headings.items()
}
container[self._handle]["references"] = {
key: value.packReferences() for key, value in self._headings.items()
}
return
# END Class IndexItem
class IndexHeading:
def __init__(self, key, level="H0", title=""):
self._key = key
self._level = level
self._title = title
self._charCount = 0
self._wordCount = 0
self._paraCount = 0
self._synopsis = ""
self._tag = ""
self._refs = {}
return
##
# Properties
##
@property
def key(self):
return self._key
##
# Setters
##
def setLevel(self, level):
if level in H_VALID:
self._level = level
else:
self._level = "H0"
return
def setCounts(self, charCount, wordCount, paraCount):
self._charCount = max(0, checkInt(charCount, 0))
self._wordCount = max(0, checkInt(wordCount, 0))
self._paraCount = max(0, checkInt(paraCount, 0))
return
def setSynopsis(self, synopText):
self._synopsis = str(synopText)
return
def setTag(self, tagKey):
self._tag = str(tagKey)
return
def addReference(self, tagKey, refType):
"""Add a record of a reference tag, and what keyword types it is
associated with.
"""
if tagKey not in self._refs:
self._refs[tagKey] = set()
self._refs[tagKey].add(refType)
return
##
# Data Methods
##
def packData(self):
"""Pack the values into a dictionary for saving to cache.
"""
return {
"level": self._level,
"title": self._title,
"tag": self._tag,
"cCount": self._charCount,
"wCount": self._wordCount,
"pCount": self._paraCount,
"synopsis": self._synopsis,
}
def packReferences(self):
return {key: list(value) for key, value in self._refs.items()}
def unpackData(self, data):
"""Unpack a title entry
"""
self._setLevel(data.get("level", "H0"))
self._title = str(data.get("title", ""))
self._tag = str(data.get("tag", ""))
self.setCounts(
data.get("cCount", 0),
data.get("wCount", 0),
data.get("pCount", 0),
)
self._synopsis = str(data.get("synopsis", ""))
return
# END Class IndexHeading