Add tokenizer support for the new formats
This commit is contained in:
@@ -184,7 +184,7 @@ class NWBuildDocument:
|
|||||||
filtered = self._setupBuild(makeObj)
|
filtered = self._setupBuild(makeObj)
|
||||||
|
|
||||||
if extendedMd:
|
if extendedMd:
|
||||||
makeObj.setGitHubMarkdown()
|
makeObj.setExtendedMarkdown()
|
||||||
else:
|
else:
|
||||||
makeObj.setStandardMarkdown()
|
makeObj.setStandardMarkdown()
|
||||||
|
|
||||||
|
|||||||
@@ -43,15 +43,21 @@ from novelwriter.core.project import NWProject
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
ESCAPES = {
|
||||||
|
r"\*": "*",
|
||||||
|
r"\~": "~",
|
||||||
|
r"\_": "_",
|
||||||
|
r"\[": "[",
|
||||||
|
r"\]": "]",
|
||||||
|
r"\ ": "",
|
||||||
|
}
|
||||||
|
RX_ESC = re.compile("|".join([re.escape(k) for k in ESCAPES.keys()]), flags=re.DOTALL)
|
||||||
|
|
||||||
|
|
||||||
def stripEscape(text) -> str:
|
def stripEscape(text) -> str:
|
||||||
"""Helper function to strip escaped Markdown characters from
|
"""Strip escaped Markdown characters from paragraph text."""
|
||||||
paragraph text.
|
|
||||||
"""
|
|
||||||
if "\\" in text:
|
if "\\" in text:
|
||||||
# Checking first is slightly slower when there are escaped
|
return RX_ESC.sub(lambda x: ESCAPES[x.group(0)], text)
|
||||||
# characters in the text, but significantly faster when not
|
|
||||||
return text.replace(r"\*", "*").replace(r"\~", "~").replace(r"\_", "_")
|
|
||||||
return text
|
return text
|
||||||
|
|
||||||
|
|
||||||
@@ -65,12 +71,18 @@ class Tokenizer(ABC):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
# In-Text Format
|
# In-Text Format
|
||||||
FMT_B_B = 1 # Begin bold
|
FMT_B_B = 1 # Begin bold
|
||||||
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_D_B = 5 # Begin strikeout
|
FMT_D_B = 5 # Begin strikeout
|
||||||
FMT_D_E = 6 # End strikeout
|
FMT_D_E = 6 # End strikeout
|
||||||
|
FMT_U_B = 7 # Begin underline
|
||||||
|
FMT_U_E = 8 # End underline
|
||||||
|
FMT_SUP_B = 9 # Begin superscript
|
||||||
|
FMT_SUP_E = 10 # End superscript
|
||||||
|
FMT_SUB_B = 11 # Begin subscript
|
||||||
|
FMT_SUB_E = 12 # End subscript
|
||||||
|
|
||||||
# Block Type
|
# Block Type
|
||||||
T_EMPTY = 1 # Empty line (new paragraph)
|
T_EMPTY = 1 # Empty line (new paragraph)
|
||||||
@@ -392,6 +404,12 @@ class Tokenizer(ABC):
|
|||||||
(QRegularExpression(nwRegEx.FMT_EI), [None, self.FMT_I_B, None, self.FMT_I_E]),
|
(QRegularExpression(nwRegEx.FMT_EI), [None, self.FMT_I_B, None, self.FMT_I_E]),
|
||||||
(QRegularExpression(nwRegEx.FMT_EB), [None, self.FMT_B_B, None, self.FMT_B_E]),
|
(QRegularExpression(nwRegEx.FMT_EB), [None, self.FMT_B_B, None, self.FMT_B_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]),
|
||||||
|
(QRegularExpression(nwRegEx.INL_EI), [None, self.FMT_I_B, None, self.FMT_I_E]),
|
||||||
|
(QRegularExpression(nwRegEx.INL_EB), [None, self.FMT_B_B, None, self.FMT_B_E]),
|
||||||
|
(QRegularExpression(nwRegEx.INL_ST), [None, self.FMT_D_B, None, self.FMT_D_E]),
|
||||||
|
(QRegularExpression(nwRegEx.INL_UN), [None, self.FMT_U_B, None, self.FMT_U_E]),
|
||||||
|
(QRegularExpression(nwRegEx.INL_UP), [None, self.FMT_SUP_B, None, self.FMT_SUP_E]),
|
||||||
|
(QRegularExpression(nwRegEx.INL_DN), [None, self.FMT_SUB_B, None, self.FMT_SUB_E]),
|
||||||
]
|
]
|
||||||
|
|
||||||
self._tokens = []
|
self._tokens = []
|
||||||
@@ -423,6 +441,9 @@ class Tokenizer(ABC):
|
|||||||
|
|
||||||
if aLine[0] == "[":
|
if aLine[0] == "[":
|
||||||
# Parse special formatting line
|
# Parse special formatting line
|
||||||
|
# This must be a separate if statement, as it may not
|
||||||
|
# reach a continue statement and must thefore proceed to
|
||||||
|
# check other formats.
|
||||||
|
|
||||||
if sLine in ("[NEWPAGE]", "[NEW PAGE]"):
|
if sLine in ("[NEWPAGE]", "[NEW PAGE]"):
|
||||||
breakNext = True
|
breakNext = True
|
||||||
@@ -446,7 +467,7 @@ class Tokenizer(ABC):
|
|||||||
]
|
]
|
||||||
continue
|
continue
|
||||||
|
|
||||||
elif aLine[0] == "%":
|
if aLine[0] == "%":
|
||||||
cLine = aLine[1:].lstrip()
|
cLine = aLine[1:].lstrip()
|
||||||
synTag = cLine[:9].lower()
|
synTag = cLine[:9].lower()
|
||||||
if synTag == "synopsis:":
|
if synTag == "synopsis:":
|
||||||
@@ -567,15 +588,15 @@ class Tokenizer(ABC):
|
|||||||
|
|
||||||
# Otherwise we use RegEx to find formatting tags within a line of text
|
# Otherwise we use RegEx to find formatting tags within a line of text
|
||||||
fmtPos = []
|
fmtPos = []
|
||||||
for theRX, theKeys in rxFormats:
|
for regEx, keys in rxFormats:
|
||||||
rxThis = theRX.globalMatch(aLine, 0)
|
rxThis = regEx.globalMatch(aLine, 0)
|
||||||
while rxThis.hasNext():
|
while rxThis.hasNext():
|
||||||
rxMatch = rxThis.next()
|
rxMatch = rxThis.next()
|
||||||
for n in range(1, len(theKeys)):
|
for n in range(1, len(keys)):
|
||||||
if theKeys[n] is not None:
|
if keys[n] is not None:
|
||||||
xPos = rxMatch.capturedStart(n)
|
xPos = rxMatch.capturedStart(n)
|
||||||
xLen = rxMatch.capturedLength(n)
|
xLen = rxMatch.capturedLength(n)
|
||||||
fmtPos.append([xPos, xLen, theKeys[n]])
|
fmtPos.append([xPos, xLen, keys[n]])
|
||||||
|
|
||||||
# Save the line as is, but append the array of formatting locations
|
# Save the line as is, but append the array of formatting locations
|
||||||
# sorted by position
|
# sorted by position
|
||||||
|
|||||||
@@ -81,8 +81,8 @@ def testCoreToMarkdown_ConvertFormat(mockGUI):
|
|||||||
# Paragraphs
|
# Paragraphs
|
||||||
# ==========
|
# ==========
|
||||||
|
|
||||||
# Text for GitHub Markdown
|
# Text for Extended Markdown
|
||||||
theMD.setGitHubMarkdown()
|
theMD.setExtendedMarkdown()
|
||||||
theMD._text = "Some **nested bold and _italic_ and ~~strikethrough~~ text** here\n"
|
theMD._text = "Some **nested bold and _italic_ and ~~strikethrough~~ text** here\n"
|
||||||
theMD.tokenizeText()
|
theMD.tokenizeText()
|
||||||
theMD.doConvert()
|
theMD.doConvert()
|
||||||
|
|||||||
Reference in New Issue
Block a user