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
@@ -5,6 +5,7 @@
% Begin Meta
@POV: Jane
@Char: Jane, John
@Location: Earth
% End Meta
Some text here would look good as well, and maybe some "dialogue"?
@@ -1,3 +1,5 @@
# Earth
@tag: Earth
Third planet from the sun, fairly dense, and with lots of people on it.
+23
View File
@@ -101,3 +101,26 @@ Start: 2019-05-30 18:26:01 End: 2019-05-30 18:27:56 Words: 0
Start: 2019-05-30 18:28:00 End: 2019-05-30 18:30:22 Words: 0
Start: 2019-05-30 18:42:16 End: 2019-05-30 18:43:10 Words: 0
Start: 2019-05-30 18:43:24 End: 2019-05-30 18:43:31 Words: 0
Start: 2019-05-30 18:48:54 End: 2019-05-30 18:49:19 Words: 0
Start: 2019-05-30 18:49:23 End: 2019-05-30 18:49:53 Words: 0
Start: 2019-05-30 18:51:06 End: 2019-05-30 19:02:40 Words: 0
Start: 2019-05-30 19:07:17 End: 2019-05-30 19:07:26 Words: 0
Start: 2019-05-30 19:17:16 End: 2019-05-30 19:17:39 Words: 0
Start: 2019-05-30 19:17:44 End: 2019-05-30 19:17:55 Words: 0
Start: 2019-05-30 19:18:44 End: 2019-05-30 19:19:15 Words: 0
Start: 2019-05-30 19:19:20 End: 2019-05-30 19:19:47 Words: 0
Start: 2019-05-30 19:21:41 End: 2019-05-30 19:21:44 Words: 0
Start: 2019-05-30 19:24:00 End: 2019-05-30 19:24:03 Words: 0
Start: 2019-05-30 19:24:45 End: 2019-05-30 19:26:48 Words: 0
Start: 2019-05-30 19:28:23 End: 2019-05-30 19:32:41 Words: 0
Start: 2019-05-30 19:32:57 End: 2019-05-30 19:33:18 Words: 0
Start: 2019-05-30 19:33:22 End: 2019-05-30 19:33:39 Words: 0
Start: 2019-05-30 19:34:08 End: 2019-05-30 19:34:31 Words: 0
Start: 2019-05-30 19:34:43 End: 2019-05-30 19:34:45 Words: 0
Start: 2019-05-30 19:34:58 End: 2019-05-30 19:36:33 Words: 0
Start: 2019-05-30 19:36:38 End: 2019-05-30 19:36:47 Words: 0
Start: 2019-05-30 19:43:30 End: 2019-05-30 19:43:35 Words: 0
Start: 2019-05-30 19:43:42 End: 2019-05-30 19:43:49 Words: 0
Start: 2019-05-30 19:45:34 End: 2019-05-30 19:45:59 Words: 0
Start: 2019-05-30 19:53:25 End: 2019-05-30 19:55:00 Words: 0
Start: 2019-05-30 19:55:21 End: 2019-05-30 19:56:16 Words: 0
+3 -3
View File
@@ -1,5 +1,5 @@
<?xml version='1.0' encoding='utf-8'?>
<novelWriterXML appVersion="0.1.4" fileVersion="1.0" timeStamp="2019-05-30 18:43:31">
<novelWriterXML appVersion="0.1.4" fileVersion="1.0" timeStamp="2019-05-30 19:56:16">
<project>
<name>Sample Project</name>
<title>Sample Project</title>
@@ -76,7 +76,7 @@
<charCount>656</charCount>
<wordCount>121</wordCount>
<paraCount>5</paraCount>
<cursorPos>729</cursorPos>
<cursorPos>105</cursorPos>
</item>
<item handle="bc0cbd2a407f3" order="2" parent="e7ded148d6e4a">
<name>New File</name>
@@ -145,7 +145,7 @@
<charCount>76</charCount>
<wordCount>15</wordCount>
<paraCount>1</paraCount>
<cursorPos>0</cursorPos>
<cursorPos>20</cursorPos>
</item>
<item handle="98acd8c76c93a" order="3" parent="None">
<name>Trash</name>