Improved regex, highlighting and HTML conversion of bold and italic text. Reverting to old syntax for italic.

This commit is contained in:
Veronica K. B. Olsen
2020-06-29 12:15:49 +02:00
parent c572eb0d16
commit ceadfe1e5c
5 changed files with 59 additions and 51 deletions
+3 -4
View File
@@ -37,10 +37,9 @@ class nwConst():
class nwRegEx(): class nwRegEx():
FMT_B = r"(?<![\w|\*|_|\\])([\*|_]{2})(?!\s|\*|_)(.+?)(?<![\s|\\])(\1)(?!\w)" FMT_I = r"(?<![\w\\])(_)(?![\s_])(.+?)(?<![\s\\])(\1)(?!\w)"
FMT_I = r"(?<![\w|\*|_|\\])([\*|_])(?!\s|\*|_)(.+?)(?<![\s|\\])(\1)(?!\w)" FMT_B = r"(?<![\w\\])([\*]{2})(?![\s\*])(.+?)(?<![\s\\])(\1)(?!\w)"
FMT_BI = r"(?<![\w|\*|\\])([\*]{3})(?!\s|\*)(.+?)(?<![\s|\\])(\1)(?!\w)" FMT_ST = r"(?<![\w\\])([~]{2})(?![\s~])(.+?)(?<![\s\\])(\1)(?!\w)"
FMT_ST = r"(?<![\w|~|\\])([~]{2})(?!\s|~)(.+?)(?<![\s|\\])(\1)(?!\w)"
# END Class nwRegEx # END Class nwRegEx
+1 -4
View File
@@ -107,6 +107,7 @@ class ToHtml(Tokenizer):
"""Reverse the html entities replacement on the markdown text. """Reverse the html entities replacement on the markdown text.
Otherwise, all the &something; bits will also be in there. Otherwise, all the &something; bits will also be in there.
""" """
Tokenizer.doPostProcessing(self)
if self.genMode == self.M_PREVIEW: if self.genMode == self.M_PREVIEW:
# Doesn't matter for preview as we don't use the markdown # Doesn't matter for preview as we don't use the markdown
return return
@@ -125,8 +126,6 @@ class ToHtml(Tokenizer):
self.FMT_B_E : "</b>", self.FMT_B_E : "</b>",
self.FMT_I_B : "<i>", self.FMT_I_B : "<i>",
self.FMT_I_E : "</i>", self.FMT_I_E : "</i>",
self.FMT_S_B : "<b><i>",
self.FMT_S_E : "</i></b>",
self.FMT_D_B : "<span style='text-decoration: line-through;'>", self.FMT_D_B : "<span style='text-decoration: line-through;'>",
self.FMT_D_E : "</span>", self.FMT_D_E : "</span>",
} }
@@ -136,8 +135,6 @@ class ToHtml(Tokenizer):
self.FMT_B_E : "</strong>", self.FMT_B_E : "</strong>",
self.FMT_I_B : "<em>", self.FMT_I_B : "<em>",
self.FMT_I_E : "</em>", self.FMT_I_E : "</em>",
self.FMT_S_B : "<strong><em>",
self.FMT_S_E : "</em></strong>",
self.FMT_D_B : "<del>", self.FMT_D_B : "<del>",
self.FMT_D_E : "</del>", self.FMT_D_E : "</del>",
} }
+15 -7
View File
@@ -44,10 +44,8 @@ class Tokenizer():
FMT_B_E = 2 # End bold FMT_B_E = 2 # End bold
FMT_I_B = 3 # Begin italics FMT_I_B = 3 # Begin italics
FMT_I_E = 4 # End italics FMT_I_E = 4 # End italics
FMT_S_B = 5 # Begin bold italic FMT_D_B = 5 # Begin strikeout
FMT_S_E = 6 # End bold italic FMT_D_E = 6 # End strikeout
FMT_D_B = 7 # Begin strikeout
FMT_D_E = 8 # End strikeout
T_EMPTY = 1 # Empty line (new paragraph) T_EMPTY = 1 # Empty line (new paragraph)
T_SYNOPSIS = 2 # Synopsis comment T_SYNOPSIS = 2 # Synopsis comment
@@ -269,7 +267,6 @@ class Tokenizer():
def doAutoReplace(self): def doAutoReplace(self):
"""Run through the user's auto-replace dictionary. """Run through the user's auto-replace dictionary.
""" """
if len(self.theProject.autoReplace) > 0: if len(self.theProject.autoReplace) > 0:
repDict = {} repDict = {}
for aKey, aVal in self.theProject.autoReplace.items(): for aKey, aVal in self.theProject.autoReplace.items():
@@ -280,8 +277,20 @@ class Tokenizer():
return return
def doPostProcessing(self): 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 return
def tokenizeText(self): def tokenizeText(self):
@@ -304,7 +313,6 @@ class Tokenizer():
rxFormats = [ rxFormats = [
(QRegularExpression(nwRegEx.FMT_I), [None, self.FMT_I_B, None, self.FMT_I_E]), (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_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]), (QRegularExpression(nwRegEx.FMT_ST), [None, self.FMT_D_B, None, self.FMT_D_E]),
] ]
+8
View File
@@ -34,6 +34,10 @@ from os import path, unlink, rmdir
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# =========================================================================== #
# Simple Word Counter
# =========================================================================== #
def countWords(theText): def countWords(theText):
"""Count words in a piece of text, skipping special syntax and """Count words in a piece of text, skipping special syntax and
comments. comments.
@@ -80,6 +84,10 @@ def countWords(theText):
return charCount, wordCount, paraCount return charCount, wordCount, paraCount
# =========================================================================== #
# Convert an Integer to a Word Number
# =========================================================================== #
def numberToWord(numVal, theLanguage): def numberToWord(numVal, theLanguage):
"""Wrapper for converting numbers to words for chapter headings. """Wrapper for converting numbers to words for chapter headings.
""" """
+32 -36
View File
@@ -107,7 +107,6 @@ class GuiDocHighlighter(QSyntaxHighlighter):
"header4h" : self._makeFormat(self.colHeadH, "bold", 1.2), "header4h" : self._makeFormat(self.colHeadH, "bold", 1.2),
"bold" : self._makeFormat(self.colEmph, "bold"), "bold" : self._makeFormat(self.colEmph, "bold"),
"italic" : self._makeFormat(self.colEmph, "italic"), "italic" : self._makeFormat(self.colEmph, "italic"),
"bolditalic" : self._makeFormat(self.colEmph, ("bold","italic")),
"strike" : self._makeFormat(self.colEmph, "strike"), "strike" : self._makeFormat(self.colEmph, "strike"),
"trailing" : self._makeFormat(self.colTrail, "background"), "trailing" : self._makeFormat(self.colTrail, "background"),
"nobreak" : 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 # Quoted Strings
if self.mainConf.highlightQuotes: if self.mainConf.highlightQuotes:
self.hRules.append(( 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 # Auto-Replace Tags
self.hRules.append(( self.hRules.append((
r"<(\S+?)>", { r"<(\S+?)>", {
@@ -302,10 +294,14 @@ class GuiDocHighlighter(QSyntaxHighlighter):
rxItt = rX.globalMatch(theText, 0) rxItt = rX.globalMatch(theText, 0)
while rxItt.hasNext(): while rxItt.hasNext():
rxMatch = rxItt.next() rxMatch = rxItt.next()
for xM in xFmt.keys(): for xM in xFmt:
xPos = rxMatch.capturedStart(xM) xPos = rxMatch.capturedStart(xM)
xLen = rxMatch.capturedLength(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: if self.theDict is None or not self.spellCheck:
return return
@@ -318,11 +314,11 @@ class GuiDocHighlighter(QSyntaxHighlighter):
continue continue
xPos = rxMatch.capturedStart(0) xPos = rxMatch.capturedStart(0)
xLen = rxMatch.capturedLength(0) xLen = rxMatch.capturedLength(0)
for x in range(xLen): for x in range(xPos, xPos+xLen):
spFmt = self.format(xPos+x) spFmt = self.format(x)
spFmt.setUnderlineColor(self.colSpell) spFmt.setUnderlineColor(self.colSpell)
spFmt.setUnderlineStyle(QTextCharFormat.SpellCheckUnderline) spFmt.setUnderlineStyle(QTextCharFormat.SpellCheckUnderline)
self.setFormat(xPos+x, 1, spFmt) self.setFormat(x, 1, spFmt)
return return