Add converter support for the new formats

This commit is contained in:
Veronica Berglyd Olsen
2023-10-20 00:05:17 +02:00
parent 0115f1e343
commit ae1ed10f25
3 changed files with 107 additions and 16 deletions
+9
View File
@@ -131,6 +131,8 @@ class ToHtml(Tokenizer):
self.FMT_I_E: "</i>", self.FMT_I_E: "</i>",
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>",
self.FMT_U_B: "<u>",
self.FMT_U_E: "</u>",
} }
else: else:
htmlTags = { # HTML5 (for export) htmlTags = { # HTML5 (for export)
@@ -140,8 +142,15 @@ class ToHtml(Tokenizer):
self.FMT_I_E: "</em>", self.FMT_I_E: "</em>",
self.FMT_D_B: "<del>", self.FMT_D_B: "<del>",
self.FMT_D_E: "</del>", self.FMT_D_E: "</del>",
self.FMT_U_B: "<span style='text-decoration: underline;'>",
self.FMT_U_E: "</span>",
} }
htmlTags[self.FMT_SUP_B] = "<sup>"
htmlTags[self.FMT_SUP_E] = "</sup>"
htmlTags[self.FMT_SUB_B] = "<sub>"
htmlTags[self.FMT_SUB_E] = "</sub>"
if self._isNovel and self._genMode != self.M_PREVIEW: if self._isNovel and self._genMode != self.M_PREVIEW:
# For story files, we bump the titles one level up # For story files, we bump the titles one level up
h1Cl = " class='title'" h1Cl = " class='title'"
+20 -8
View File
@@ -38,12 +38,12 @@ class ToMarkdown(Tokenizer):
"""Core: Markdown Document Writer """Core: Markdown Document Writer
Extend the Tokenizer class to writer Markdown output. It supports Extend the Tokenizer class to writer Markdown output. It supports
both Standard Markdown and GitHub Flavour Markdown (Extended). The both Standard Markdown and Extended Markdown. The class also
class also supports concatenating novelWriter markup files. supports concatenating novelWriter markup files.
""" """
M_STD = 0 # Standard Markdown M_STD = 0 # Standard Markdown
M_GH = 1 # GitHub Markdown M_EXT = 1 # Extended Markdown
def __init__(self, project: NWProject) -> None: def __init__(self, project: NWProject) -> None:
super().__init__(project) super().__init__(project)
@@ -69,9 +69,9 @@ class ToMarkdown(Tokenizer):
self._genMode = self.M_STD self._genMode = self.M_STD
return return
def setGitHubMarkdown(self) -> None: def setExtendedMarkdown(self) -> None:
"""Set the converter to use GitHub Markdown formatting.""" """Set the converter to use Extended Markdown formatting."""
self._genMode = self.M_GH self._genMode = self.M_EXT
return return
## ##
@@ -85,7 +85,7 @@ class ToMarkdown(Tokenizer):
def doConvert(self) -> None: def doConvert(self) -> None:
"""Convert the list of text tokens into a Markdown document.""" """Convert the list of text tokens into a Markdown document."""
if self._genMode == self.M_STD: if self._genMode == self.M_STD:
# Standard # Standard Markdown
mdTags = { mdTags = {
self.FMT_B_B: "**", self.FMT_B_B: "**",
self.FMT_B_E: "**", self.FMT_B_E: "**",
@@ -93,9 +93,15 @@ class ToMarkdown(Tokenizer):
self.FMT_I_E: "_", self.FMT_I_E: "_",
self.FMT_D_B: "", self.FMT_D_B: "",
self.FMT_D_E: "", self.FMT_D_E: "",
self.FMT_U_B: "",
self.FMT_U_E: "",
self.FMT_SUP_B: "",
self.FMT_SUP_E: "",
self.FMT_SUB_B: "",
self.FMT_SUB_E: "",
} }
else: else:
# GitHub # Extended Markdown
mdTags = { mdTags = {
self.FMT_B_B: "**", self.FMT_B_B: "**",
self.FMT_B_E: "**", self.FMT_B_E: "**",
@@ -103,6 +109,12 @@ class ToMarkdown(Tokenizer):
self.FMT_I_E: "_", self.FMT_I_E: "_",
self.FMT_D_B: "~~", self.FMT_D_B: "~~",
self.FMT_D_E: "~~", self.FMT_D_E: "~~",
self.FMT_U_B: "",
self.FMT_U_E: "",
self.FMT_SUP_B: "^",
self.FMT_SUP_E: "^",
self.FMT_SUB_B: "~",
self.FMT_SUB_E: "~",
} }
self._result = "" self._result = ""
+78 -8
View File
@@ -82,11 +82,17 @@ TAG_STNM = _mkTag("text", "style-name")
X_BLD = 0x01 # Bold format X_BLD = 0x01 # Bold format
X_ITA = 0x02 # Italic format X_ITA = 0x02 # Italic format
X_DEL = 0x04 # Strikethrough format X_DEL = 0x04 # Strikethrough format
X_UND = 0x08 # Underline format
X_SUP = 0x10 # Superscript
X_SUB = 0x20 # Subscript
# Formatting Masks # Formatting Masks
M_BLD = ~X_BLD M_BLD = ~X_BLD
M_ITA = ~X_ITA M_ITA = ~X_ITA
M_DEL = ~X_DEL M_DEL = ~X_DEL
M_UND = ~X_UND
M_SUP = ~X_SUP
M_SUB = ~X_SUB
class ToOdt(Tokenizer): class ToOdt(Tokenizer):
@@ -386,12 +392,18 @@ class ToOdt(Tokenizer):
self._result = "" # Not used, but cleared just in case self._result = "" # Not used, but cleared just in case
odtTags = { odtTags = {
self.FMT_B_B: "_B", # Bold open format self.FMT_B_B: "B", # Bold open format
self.FMT_B_E: "b_", # Bold close format self.FMT_B_E: "b", # Bold close format
self.FMT_I_B: "I", # Italic open format self.FMT_I_B: "I", # Italic open format
self.FMT_I_E: "i", # Italic close format self.FMT_I_E: "i", # Italic close format
self.FMT_D_B: "_S", # Strikethrough open format self.FMT_D_B: "S", # Strikethrough open format
self.FMT_D_E: "s_", # Strikethrough close format self.FMT_D_E: "s", # Strikethrough close format
self.FMT_U_B: "U", # Underline open format
self.FMT_U_E: "u", # Underline close format
self.FMT_SUP_B: "P", # Superscript open format
self.FMT_SUP_E: "p", # Superscript close format
self.FMT_SUB_B: "D", # Subscript open format
self.FMT_SUB_E: "d", # Subscript close format
} }
fmt = [] fmt = []
@@ -480,7 +492,10 @@ class ToOdt(Tokenizer):
tFmt = " "*len(tText) tFmt = " "*len(tText)
for xPos, xLen, xFmt in tFormat: for xPos, xLen, xFmt in tFormat:
tFmt = tFmt[:xPos] + odtTags[xFmt] + tFmt[xPos+xLen:] if xFmt%2 == 0: # Even number: End
tFmt = tFmt[:xPos] + odtTags[xFmt].ljust(xLen, "_") + tFmt[xPos+xLen:]
else: # Odd number: Begin
tFmt = tFmt[:xPos] + odtTags[xFmt].rjust(xLen, "_") + tFmt[xPos+xLen:]
tTxt = tText.rstrip() tTxt = tText.rstrip()
tFmt = tFmt[:len(tTxt)] tFmt = tFmt[:len(tTxt)]
@@ -650,6 +665,18 @@ class ToOdt(Tokenizer):
xFmt |= X_DEL xFmt |= X_DEL
elif tFmt[i] == "s": elif tFmt[i] == "s":
xFmt &= M_DEL xFmt &= M_DEL
elif tFmt[i] == "U":
xFmt |= X_UND
elif tFmt[i] == "u":
xFmt &= M_UND
elif tFmt[i] == "P":
xFmt |= X_SUP
elif tFmt[i] == "p":
xFmt &= M_SUP
elif tFmt[i] == "D":
xFmt |= X_SUB
elif tFmt[i] == "d":
xFmt &= M_SUB
else: else:
pErr += 1 pErr += 1
@@ -713,6 +740,14 @@ class ToOdt(Tokenizer):
if hFmt & X_DEL: if hFmt & X_DEL:
newStyle.setStrikeStyle("solid") newStyle.setStrikeStyle("solid")
newStyle.setStrikeType("single") newStyle.setStrikeType("single")
if hFmt & X_UND:
newStyle.setUnderlineStyle("solid")
newStyle.setUnderlineWidth("auto")
newStyle.setUnderlineColour("font-color")
if hFmt & X_SUP:
newStyle.setTextPosition("super")
if hFmt & X_SUB:
newStyle.setTextPosition("sub")
self._autoText[hFmt] = (newName, newStyle) self._autoText[hFmt] = (newName, newStyle)
@@ -1256,16 +1291,23 @@ class ODTTextStyle:
""" """
VALID_WEIGHT = ["normal", "inherit", "bold"] VALID_WEIGHT = ["normal", "inherit", "bold"]
VALID_STYLE = ["normal", "inherit", "italic"] VALID_STYLE = ["normal", "inherit", "italic"]
VALID_POS = ["super", "sub"]
VALID_LSTYLE = ["none", "solid"] VALID_LSTYLE = ["none", "solid"]
VALID_LTYPE = ["none", "single", "double"] VALID_LTYPE = ["single", "double"]
VALID_LWIDTH = ["auto"]
VALID_LCOL = ["font-color"]
def __init__(self) -> None: def __init__(self) -> None:
# Text Attributes # Text Attributes
self._tAttr = { self._tAttr = {
"font-weight": ["fo", None], "font-weight": ["fo", None],
"font-style": ["fo", None], "font-style": ["fo", None],
"text-position": ["style", None],
"text-line-through-style": ["style", None], "text-line-through-style": ["style", None],
"text-line-through-type": ["style", None], "text-line-through-type": ["style", None],
"text-underline-style": ["style", None],
"text-underline-width": ["style", None],
"text-underline-color": ["style", None],
} }
return return
@@ -1287,6 +1329,13 @@ class ODTTextStyle:
self._tAttr["font-style"][1] = None self._tAttr["font-style"][1] = None
return return
def setTextPosition(self, value: str | None) -> None:
if value in self.VALID_POS:
self._tAttr["text-position"][1] = f"{value} 58%"
else:
self._tAttr["text-position"][1] = None
return
def setStrikeStyle(self, value: str | None) -> None: def setStrikeStyle(self, value: str | None) -> None:
if value in self.VALID_LSTYLE: if value in self.VALID_LSTYLE:
self._tAttr["text-line-through-style"][1] = value self._tAttr["text-line-through-style"][1] = value
@@ -1301,6 +1350,27 @@ class ODTTextStyle:
self._tAttr["text-line-through-type"][1] = None self._tAttr["text-line-through-type"][1] = None
return return
def setUnderlineStyle(self, value: str | None) -> None:
if value in self.VALID_LSTYLE:
self._tAttr["text-underline-style"][1] = value
else:
self._tAttr["text-underline-style"][1] = None
return
def setUnderlineWidth(self, value: str | None) -> None:
if value in self.VALID_LWIDTH:
self._tAttr["text-underline-width"][1] = value
else:
self._tAttr["text-underline-width"][1] = None
return
def setUnderlineColour(self, value: str | None) -> None:
if value in self.VALID_LCOL:
self._tAttr["text-underline-color"][1] = value
else:
self._tAttr["text-underline-color"][1] = None
return
## ##
# Methods # Methods
## ##