Connected the syntax highlicghter to the index. It now shows valid keywords and values

This commit is contained in:
Veronica K. B. Olsen
2019-05-30 19:57:02 +02:00
parent b526b0f5d9
commit a2d0f937ae
8 changed files with 196 additions and 92 deletions
+23 -19
View File
@@ -34,11 +34,12 @@ class GuiDocEditor(QTextEdit):
logger.debug("Initialising DocEditor ...")
# Class Variables
self.mainConf = nw.CONFIG
self.theParent = theParent
self.docChanged = False
self.pwlFile = None
self.spellCheck = False
self.mainConf = nw.CONFIG
self.theParent = theParent
self.docChanged = False
self.pwlFile = None
self.spellCheck = False
self.theDocument = theParent.theDocument
# Document Variables
self.charCount = 0
@@ -54,9 +55,9 @@ class GuiDocEditor(QTextEdit):
self.typApos = self.mainConf.fmtApostrophe
# Core Elements
self.theDoc = self.document()
self.theQDoc = self.document()
self.theDict = enchant.Dict(self.mainConf.spellLanguage)
self.hLight = GuiDocHighlighter(self.theDoc, self.theParent.theTheme)
self.hLight = GuiDocHighlighter(self.theQDoc, self.theParent)
self.hLight.setDict(self.theDict)
# Context Menu
@@ -71,8 +72,8 @@ class GuiDocEditor(QTextEdit):
self.clearEditor()
self.initEditor()
self.theDoc.setDocumentMargin(0)
self.theDoc.contentsChange.connect(self._docChange)
self.theQDoc.setDocumentMargin(0)
self.theQDoc.contentsChange.connect(self._docChange)
# Custom Shortcuts
QShortcut(QKeySequence("Ctrl+."), self, context=Qt.WidgetShortcut, activated=self._openSpellContext)
@@ -109,7 +110,18 @@ class GuiDocEditor(QTextEdit):
theOpt.setTabStopDistance(self.mainConf.tabWidth)
if self.mainConf.doJustify:
theOpt.setAlignment(Qt.AlignJustify)
self.theDoc.setDefaultTextOption(theOpt)
self.theQDoc.setDefaultTextOption(theOpt)
return True
def loadText(self, tHandle):
self.hLight.setHandle(tHandle)
self.setPlainText(self.theDocument.openDocument(tHandle))
self.setCursorPosition(self.theDocument.theItem.cursorPos)
self.lastEdit = time()
self._runCounter()
self.wcTimer.start()
self.setDocumentChanged(False)
self.setReadOnly(False)
return True
##
@@ -121,14 +133,6 @@ class GuiDocEditor(QTextEdit):
self.theParent.statusBar.setDocumentStatus(self.docChanged)
return self.docChanged
def setText(self, theText):
self.setPlainText(theText)
self.lastEdit = time()
self._runCounter()
self.wcTimer.start()
self.setDocumentChanged(False)
return True
def getText(self):
theText = self.toPlainText()
return theText
@@ -296,7 +300,7 @@ class GuiDocEditor(QTextEdit):
if not self.wcTimer.isActive():
self.wcTimer.start()
if self.mainConf.doReplace and not self.hasSelection:
self._docAutoReplace(self.theDoc.findBlock(thePos))
self._docAutoReplace(self.theQDoc.findBlock(thePos))
# logger.verbose("Doc change signal took %.3f µs" % ((time()-self.lastEdit)*1e6))
return
+84 -38
View File
@@ -20,14 +20,17 @@ logger = logging.getLogger(__name__)
class GuiDocHighlighter(QSyntaxHighlighter):
def __init__(self, theDoc, theTheme):
def __init__(self, theDoc, theParent):
QSyntaxHighlighter.__init__(self, theDoc)
logger.debug("Initialising DocHighlighter ...")
self.mainConf = nw.CONFIG
self.theDoc = theDoc
self.theTheme = theTheme
self.theParent = theParent
self.theTheme = theParent.theTheme
self.theIndex = theParent.theIndex
self.theDict = None
self.theHandle = None
self.spellCheck = False
self.hRules = []
@@ -90,12 +93,12 @@ class GuiDocHighlighter(QSyntaxHighlighter):
))
# Keyword/Value
self.hRules.append((
r"^(@.+?)\s*:\s*(.+?)$", {
1 : self.hStyles["keyword"],
2 : self.hStyles["value"],
}
))
# self.hRules.append((
# r"^(@.+?)\s*:\s*(.+?)$", {
# 1 : self.hStyles["keyword"],
# 2 : self.hStyles["value"],
# }
# ))
# Comments
self.hRules.append((
@@ -152,6 +155,10 @@ class GuiDocHighlighter(QSyntaxHighlighter):
return
##
# Setters
##
def setDict(self, theDict):
self.theDict = theDict
return True
@@ -160,6 +167,75 @@ class GuiDocHighlighter(QSyntaxHighlighter):
self.spellCheck = theMode
return True
def setHandle(self, theHandle):
self.theHandle = theHandle
return True
##
# Highlight Block
##
def highlightBlock(self, theText):
if self.theHandle is None:
self.setCurrentBlockState(0)
return
if theText.startswith("@"):
# Highlighting of keywords and commands
tItem = self.theParent.theProject.getItem(self.theHandle)
isValid, theBits, thePos = self.theIndex.scanThis(theText)
isGood = self.theIndex.checkThese(theBits, tItem)
if isValid:
for n in range(len(theBits)):
xPos = thePos[n]
xLen = len(theBits[n])
if isGood[n]:
if n == 0:
self.setFormat(xPos, xLen, self.hStyles["keyword"])
else:
self.setFormat(xPos, xLen, self.hStyles["value"])
else:
kwFmt = self.format(xPos)
kwFmt.setUnderlineColor(self.colSpell)
kwFmt.setUnderlineStyle(QTextCharFormat.SpellCheckUnderline)
self.setFormat(xPos, xLen, kwFmt)
else:
# Other text just uses regex
for rX, xFmt in self.rules:
rxItt = rX.globalMatch(theText, 0)
while rxItt.hasNext():
rxMatch = rxItt.next()
for xM in xFmt.keys():
xPos = rxMatch.capturedStart(xM)
xLen = rxMatch.capturedLength(xM)
self.setFormat(xPos, xLen, xFmt[xM])
self.setCurrentBlockState(0)
if self.theDict is None or not self.spellCheck or theText.startswith("@"):
return
rxSpell = self.spellRx.globalMatch(theText.replace("_"," "), 0)
while rxSpell.hasNext():
rxMatch = rxSpell.next()
if not self.theDict.check(rxMatch.captured(0)):
if rxMatch.captured(0) == rxMatch.captured(0).upper():
continue
xPos = rxMatch.capturedStart(0)
xLen = rxMatch.capturedLength(0)
spFmt = self.format(xPos)
spFmt.setUnderlineColor(self.colSpell)
spFmt.setUnderlineStyle(QTextCharFormat.SpellCheckUnderline)
self.setFormat(xPos, xLen, spFmt)
return
##
# Internal Functions
##
def _makeFormat(self, fmtCol=None, fmtStyle=None, fmtSize=None):
theFormat = QTextCharFormat()
@@ -181,34 +257,4 @@ class GuiDocHighlighter(QSyntaxHighlighter):
return theFormat
def highlightBlock(self, theText):
for rX, xFmt in self.rules:
rxItt = rX.globalMatch(theText, 0)
while rxItt.hasNext():
rxMatch = rxItt.next()
for xM in xFmt.keys():
xPos = rxMatch.capturedStart(xM)
xLen = rxMatch.capturedLength(xM)
self.setFormat(xPos, xLen, xFmt[xM])
self.setCurrentBlockState(0)
if self.theDict is None or not self.spellCheck or theText.startswith("@"):
return
rxSpell = self.spellRx.globalMatch(theText.replace("_"," "), 0)
while rxSpell.hasNext():
rxMatch = rxSpell.next()
if not self.theDict.check(rxMatch.captured(0)):
if rxMatch.captured(0) == rxMatch.captured(0).upper(): continue
xPos = rxMatch.capturedStart(0)
xLen = rxMatch.capturedLength(0)
spFmt = self.format(xPos)
spFmt.setUnderlineColor(self.colSpell)
spFmt.setUnderlineStyle(QTextCharFormat.SpellCheckUnderline)
self.setFormat(xPos, xLen, spFmt)
return
# END Class DocHighlighter
+8 -10
View File
@@ -53,7 +53,7 @@ class GuiMain(QMainWindow):
self.theTheme = Theme()
self.theProject = NWProject(self)
self.theDocument = NWDoc(self.theProject, self)
self.tagIndex = NWIndex(self.theProject, self)
self.theIndex = NWIndex(self.theProject, self)
self.hasProject = False
self.resize(*self.mainConf.winGeometry)
@@ -212,7 +212,7 @@ class GuiMain(QMainWindow):
if saveOK:
self.theProject.closeProject()
self.tagIndex.clearIndex()
self.theIndex.clearIndex()
self.clearGUI()
self.hasProject = False
@@ -236,7 +236,7 @@ class GuiMain(QMainWindow):
return False
# Load the tag index
self.tagIndex.loadIndex()
self.theIndex.loadIndex()
# Update GUI
self._setWindowTitle(self.theProject.projName)
@@ -268,7 +268,7 @@ class GuiMain(QMainWindow):
self.treeView.saveTreeOrder()
self.theProject.saveProject()
self.tagIndex.saveIndex()
self.theIndex.saveIndex()
self.mainMenu.updateRecentProjects()
return True
@@ -286,9 +286,7 @@ class GuiMain(QMainWindow):
def openDocument(self, tHandle):
self.closeDocument()
self.docEditor.setText(self.theDocument.openDocument(tHandle))
self.docEditor.setReadOnly(False)
self.docEditor.setCursorPosition(self.theDocument.theItem.cursorPos)
self.docEditor.loadText(tHandle)
self.docEditor.changeWidth()
self.docEditor.setFocus()
self.theProject.setLastEdited(tHandle)
@@ -305,7 +303,7 @@ class GuiMain(QMainWindow):
theItem.setCursorPos(cursPos)
self.theDocument.saveDocument(docText)
self.docEditor.setDocumentChanged(False)
self.tagIndex.scanText(theItem.itemHandle, docText)
self.theIndex.scanText(theItem.itemHandle, docText)
return True
def viewDocument(self, tHandle=None):
@@ -385,7 +383,7 @@ class GuiMain(QMainWindow):
logger.debug("Rebuilding indices ...")
self.treeView.saveTreeOrder()
self.tagIndex.clearIndex()
self.theIndex.clearIndex()
nItems = len(self.theProject.treeOrder)
dlgProg = QProgressDialog("Scanning files ...", "Cancel", 0, nItems, self)
@@ -419,7 +417,7 @@ class GuiMain(QMainWindow):
self.treeView.projectWordCount()
# Build tag index
self.tagIndex.scanText(tHandle, theText)
self.theIndex.scanText(tHandle, theText)
time.sleep(0.05)
nDone += 1
+52 -22
View File
@@ -36,24 +36,25 @@ logger = logging.getLogger(__name__)
class NWIndex():
TAG_KEY = "@tag"
POV_KEY = "@pov"
CHAR_KEY = "@char"
PLOT_KEY = "@plot"
TIME_KEY = "@time"
WORLD_KEY = "@location"
OBJECT_KEY = "@object"
CUSTOM_KEY = "@custom"
TAG_KEY = "@tag"
POV_KEY = "@pov"
CHAR_KEY = "@char"
PLOT_KEY = "@plot"
TIME_KEY = "@time"
WORLD_KEY = "@location"
OBJECT_KEY = "@object"
CUSTOM_KEY = "@custom"
NOTE_KEYS = [PLOT_KEY, POV_KEY, CHAR_KEY, WORLD_KEY, TIME_KEY, OBJECT_KEY, CUSTOM_KEY]
VALID_CLASS = {
nwItemClass.NOVEL : [],
nwItemClass.PLOT : [PLOT_KEY],
nwItemClass.CHARACTER : [POV_KEY, CHAR_KEY],
nwItemClass.WORLD : [WORLD_KEY],
nwItemClass.TIMELINE : [TIME_KEY],
nwItemClass.OBJECT : [OBJECT_KEY],
nwItemClass.CUSTOM : [CUSTOM_KEY],
NOTE_KEYS = [TAG_KEY]
NOVEL_KEYS = [PLOT_KEY, POV_KEY, CHAR_KEY, WORLD_KEY, TIME_KEY, OBJECT_KEY, CUSTOM_KEY]
TAG_CLASS = {
POV_KEY : nwItemClass.CHARACTER,
CHAR_KEY : nwItemClass.CHARACTER,
PLOT_KEY : nwItemClass.PLOT,
TIME_KEY : nwItemClass.TIMELINE,
WORLD_KEY : nwItemClass.WORLD,
OBJECT_KEY : nwItemClass.OBJECT,
CUSTOM_KEY : nwItemClass.CUSTOM,
}
def __init__(self, theProject, theParent):
@@ -137,7 +138,8 @@ class NWIndex():
theItem = self.theProject.getItem(tHandle)
if theItem is None: return False
if theItem.itemType != nwItemType.FILE: return False
itemClass = theItem.itemClass
itemClass = theItem.itemClass
itemLayout = theItem.itemLayout
logger.debug("Indexing item with handle %s" % tHandle)
@@ -162,7 +164,7 @@ class NWIndex():
if nChar == 0: continue
if aLine[0] == "#":
if isNovel:
self.indexTitle(tHandle, aLine, nLine)
self.indexTitle(tHandle, aLine, nLine, itemLayout)
elif aLine[0] == "@":
if isNovel:
self.indexNoteRef(tHandle, aLine, nLine)
@@ -171,7 +173,7 @@ class NWIndex():
return True
def indexTitle(self, tHandle, aLine, nLine):
def indexTitle(self, tHandle, aLine, nLine, itemLayout):
if aLine.startswith("# "):
hDepth = 1
@@ -189,7 +191,7 @@ class NWIndex():
return False
if hText != "":
self.novelIndex[tHandle].append([nLine, hDepth, hText])
self.novelIndex[tHandle].append([nLine, hDepth, hText, itemLayout.name])
return True
@@ -200,7 +202,7 @@ class NWIndex():
return False
theKey = theBits[0]
if theKey in self.NOTE_KEYS:
if theKey in self.NOVEL_KEYS:
for aVal in theBits[1:]:
self.noteIndex[tHandle].append([nLine, theKey, aVal])
@@ -254,4 +256,32 @@ class NWIndex():
return True, theBits, thePos
def checkThese(self, theBits, tItem):
theBits = [aBit.lower() for aBit in theBits]
nBits = len(theBits)
isGood = [False]*nBits
if nBits == 0:
return []
# If we have a tag, the first value is always OK, rest is ignored
if theBits[0] == self.TAG_KEY and nBits > 1:
isGood[0] = True
isGood[1] = True
return isGood
# If we're still here, we better check the references
if tItem.itemClass == nwItemClass.NOVEL:
isGood[0] = theBits[0] in self.NOVEL_KEYS
else:
isGood[0] = theBits[0] in self.NOTE_KEYS
if not isGood[0] or nBits == 1:
return isGood
for n in range(1,nBits):
if theBits[n] in self.tagIndex:
isGood[n] = self.TAG_CLASS[theBits[0]].name == self.tagIndex[theBits[n]][2]
return isGood
# END Class NWIndex