From ceadfe1e5c51df02e386e0875c7998df4faf7719 Mon Sep 17 00:00:00 2001 From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com> Date: Mon, 29 Jun 2020 12:15:49 +0200 Subject: [PATCH] Improved regex, highlighting and HTML conversion of bold and italic text. Reverting to old syntax for italic. --- nw/constants/constants.py | 7 ++-- nw/core/tohtml.py | 5 +-- nw/core/tokenizer.py | 22 +++++++++---- nw/core/tools.py | 8 +++++ nw/gui/dochighlight.py | 68 ++++++++++++++++++--------------------- 5 files changed, 59 insertions(+), 51 deletions(-) diff --git a/nw/constants/constants.py b/nw/constants/constants.py index 18443c1d..d78cd5c6 100644 --- a/nw/constants/constants.py +++ b/nw/constants/constants.py @@ -37,10 +37,9 @@ class nwConst(): class nwRegEx(): - FMT_B = r"(?", self.FMT_I_B : "", self.FMT_I_E : "", - self.FMT_S_B : "", - self.FMT_S_E : "", self.FMT_D_B : "", self.FMT_D_E : "", } @@ -136,8 +135,6 @@ class ToHtml(Tokenizer): self.FMT_B_E : "", self.FMT_I_B : "", self.FMT_I_E : "", - self.FMT_S_B : "", - self.FMT_S_E : "", self.FMT_D_B : "", self.FMT_D_E : "", } diff --git a/nw/core/tokenizer.py b/nw/core/tokenizer.py index 09345e09..eba1ab65 100644 --- a/nw/core/tokenizer.py +++ b/nw/core/tokenizer.py @@ -44,10 +44,8 @@ class Tokenizer(): FMT_B_E = 2 # End bold FMT_I_B = 3 # Begin italics FMT_I_E = 4 # End italics - FMT_S_B = 5 # Begin bold italic - FMT_S_E = 6 # End bold italic - FMT_D_B = 7 # Begin strikeout - FMT_D_E = 8 # End strikeout + FMT_D_B = 5 # Begin strikeout + FMT_D_E = 6 # End strikeout T_EMPTY = 1 # Empty line (new paragraph) T_SYNOPSIS = 2 # Synopsis comment @@ -269,7 +267,6 @@ class Tokenizer(): def doAutoReplace(self): """Run through the user's auto-replace dictionary. """ - if len(self.theProject.autoReplace) > 0: repDict = {} for aKey, aVal in self.theProject.autoReplace.items(): @@ -280,8 +277,20 @@ class Tokenizer(): return def doPostProcessing(self): - """Do some postprocessing. Overloaded by subclasses. + """Do some postprocessing. Overloaded by subclasses. This just + does the standard escaped characters. """ + escapeDict = { + "\*" : "*", + "\~" : "~", + "\_" : "_", + } + escReplace = re.compile( + "|".join([re.escape(k) for k in escapeDict.keys()]), flags=re.DOTALL + ) + self.theResult = escReplace.sub( + lambda x: escapeDict[x.group(0)], self.theResult + ) return def tokenizeText(self): @@ -304,7 +313,6 @@ class Tokenizer(): rxFormats = [ (QRegularExpression(nwRegEx.FMT_I), [None, self.FMT_I_B, None, self.FMT_I_E]), (QRegularExpression(nwRegEx.FMT_B), [None, self.FMT_B_B, None, self.FMT_B_E]), - (QRegularExpression(nwRegEx.FMT_BI), [None, self.FMT_S_B, None, self.FMT_S_E]), (QRegularExpression(nwRegEx.FMT_ST), [None, self.FMT_D_B, None, self.FMT_D_E]), ] diff --git a/nw/core/tools.py b/nw/core/tools.py index 8115105d..5c352fe7 100644 --- a/nw/core/tools.py +++ b/nw/core/tools.py @@ -34,6 +34,10 @@ from os import path, unlink, rmdir logger = logging.getLogger(__name__) +# =========================================================================== # +# Simple Word Counter +# =========================================================================== # + def countWords(theText): """Count words in a piece of text, skipping special syntax and comments. @@ -80,6 +84,10 @@ def countWords(theText): return charCount, wordCount, paraCount +# =========================================================================== # +# Convert an Integer to a Word Number +# =========================================================================== # + def numberToWord(numVal, theLanguage): """Wrapper for converting numbers to words for chapter headings. """ diff --git a/nw/gui/dochighlight.py b/nw/gui/dochighlight.py index 4acc0e7a..deb646b2 100644 --- a/nw/gui/dochighlight.py +++ b/nw/gui/dochighlight.py @@ -107,7 +107,6 @@ class GuiDocHighlighter(QSyntaxHighlighter): "header4h" : self._makeFormat(self.colHeadH, "bold", 1.2), "bold" : self._makeFormat(self.colEmph, "bold"), "italic" : self._makeFormat(self.colEmph, "italic"), - "bolditalic" : self._makeFormat(self.colEmph, ("bold","italic")), "strike" : self._makeFormat(self.colEmph, "strike"), "trailing" : self._makeFormat(self.colTrail, "background"), "nobreak" : self._makeFormat(self.colTrail, "background"), @@ -137,36 +136,6 @@ class GuiDocHighlighter(QSyntaxHighlighter): } )) - # Markdown - self.hRules.append(( - nwRegEx.FMT_I, { - 1 : self.hStyles["hidden"], - 2 : self.hStyles["italic"], - 3 : self.hStyles["hidden"], - } - )) - self.hRules.append(( - nwRegEx.FMT_B, { - 1 : self.hStyles["hidden"], - 2 : self.hStyles["bold"], - 3 : self.hStyles["hidden"], - } - )) - self.hRules.append(( - nwRegEx.FMT_BI, { - 1 : self.hStyles["hidden"], - 2 : self.hStyles["bolditalic"], - 3 : self.hStyles["hidden"], - } - )) - self.hRules.append(( - nwRegEx.FMT_ST, { - 1 : self.hStyles["hidden"], - 2 : self.hStyles["strike"], - 3 : self.hStyles["hidden"], - } - )) - # Quoted Strings if self.mainConf.highlightQuotes: self.hRules.append(( @@ -185,6 +154,29 @@ class GuiDocHighlighter(QSyntaxHighlighter): } )) + # Markdown + self.hRules.append(( + nwRegEx.FMT_I, { + 1 : self.hStyles["hidden"], + 2 : self.hStyles["italic"], + 3 : self.hStyles["hidden"], + } + )) + self.hRules.append(( + nwRegEx.FMT_B, { + 1 : self.hStyles["hidden"], + 2 : self.hStyles["bold"], + 3 : self.hStyles["hidden"], + } + )) + self.hRules.append(( + nwRegEx.FMT_ST, { + 1 : self.hStyles["hidden"], + 2 : self.hStyles["strike"], + 3 : self.hStyles["hidden"], + } + )) + # Auto-Replace Tags self.hRules.append(( r"<(\S+?)>", { @@ -302,10 +294,14 @@ class GuiDocHighlighter(QSyntaxHighlighter): rxItt = rX.globalMatch(theText, 0) while rxItt.hasNext(): rxMatch = rxItt.next() - for xM in xFmt.keys(): + for xM in xFmt: xPos = rxMatch.capturedStart(xM) xLen = rxMatch.capturedLength(xM) - self.setFormat(xPos, xLen, xFmt[xM]) + for x in range(xPos, xPos+xLen): + spFmt = self.format(x) + if spFmt != self.hStyles["hidden"]: + spFmt.merge(xFmt[xM]) + self.setFormat(x, 1, spFmt) if self.theDict is None or not self.spellCheck: return @@ -318,11 +314,11 @@ class GuiDocHighlighter(QSyntaxHighlighter): continue xPos = rxMatch.capturedStart(0) xLen = rxMatch.capturedLength(0) - for x in range(xLen): - spFmt = self.format(xPos+x) + for x in range(xPos, xPos+xLen): + spFmt = self.format(x) spFmt.setUnderlineColor(self.colSpell) spFmt.setUnderlineStyle(QTextCharFormat.SpellCheckUnderline) - self.setFormat(xPos+x, 1, spFmt) + self.setFormat(x, 1, spFmt) return