Add highlight text shortcode (#1715)
This commit is contained in:
+3
-1
@@ -58,9 +58,11 @@ Some of the assets bundled with novelWriter were adapted from the following sour
|
||||
|
||||
## Fonts
|
||||
|
||||
The font used for the main novelWriter logo, mimetype and text banners is:
|
||||
The font used for the main novelWriter logo, mimetype and text banners is Pridi. Other fonts are
|
||||
used on buttons and icons.
|
||||
|
||||
* Pridi by Cadson Demak (Open Font License, Version 1.1)
|
||||
* Source Sans Pro by Paul D. Hunt (SIL Open Font License)
|
||||
|
||||
## Special Mentions
|
||||
|
||||
|
||||
@@ -179,15 +179,20 @@ A syntax theme ``.conf`` file consists of the following settings:
|
||||
errorline = 0, 0, 0
|
||||
replacetag = 0, 0, 0
|
||||
modifier = 0, 0, 0
|
||||
texthighlight = 255, 255, 255, 128
|
||||
|
||||
In the Main section, you must define at least the ``name`` setting. The Syntax colour values are
|
||||
RGB numbers of the format ``r, g, b`` where each is an integer from to 255. Omitted values default
|
||||
to black, except ``background`` which defaults to white,
|
||||
RGB(A) numbers of the format ``r, g, b, a`` where each is an integer from to 255. The fourth value
|
||||
is the alpha channel, which can be omitted.
|
||||
|
||||
Omitted syntax colours default to black, except ``background`` which defaults to white, and
|
||||
``texthighlight`` which defaults to grey.
|
||||
|
||||
.. versionadded:: 2.2
|
||||
The `shortcode` syntax colour entry was added, so you need to update your custom themes if you
|
||||
made any before version 2.2.
|
||||
The `shortcode` syntax colour entry was added.
|
||||
|
||||
.. versionadded:: 2.3
|
||||
The `optional` syntax colour entry was added, so you need to update your custom themes if you
|
||||
made any before version 2.3.
|
||||
The `optional` syntax colour entry was added.
|
||||
|
||||
.. versionadded:: 2.4
|
||||
The `texthighlight` syntax colour entry was added.
|
||||
|
||||
@@ -53,6 +53,7 @@ fmt_bold = nw_tb-bold.svg
|
||||
fmt_bold-md = nw_tb-bold-md.svg
|
||||
fmt_italic = nw_tb-italic.svg
|
||||
fmt_italic-md = nw_tb-italic-md.svg
|
||||
fmt_mark = nw_tb-mark.svg
|
||||
fmt_strike = nw_tb-strike.svg
|
||||
fmt_strike-md = nw_tb-strike-md.svg
|
||||
fmt_subscript = nw_tb-subscript.svg
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24" height="24" version="1.1" viewBox="0 0 6.35 6.35" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x=".26458" y=".79375" width="5.8208" height="4.7625" fill="#ffff84" fill-opacity=".8" stroke-linecap="round" stroke-width=".1354"/>
|
||||
<path d="m1.3229 5.2917v-4.2333h0.98087l0.6397 1.8829q0.060924 0.18829 0.11576 0.38957 0.054831 0.19479 0.11576 0.38957h0.024369q0.060924-0.19479 0.10966-0.38957 0.054831-0.20128 0.11576-0.38957l0.62752-1.8829h0.97478v4.2333h-0.81638v-1.5518q0-0.15583 0.012185-0.34412 0.012185-0.18829 0.030462-0.37658 0.018277-0.19479 0.036554-0.37658 0.018277-0.18829 0.036554-0.34412h-0.02437l-0.3229 1.0064-0.56659 1.6167h-0.49348l-0.56659-1.6167-0.3168-1.0064h-0.024369q0.018277 0.15583 0.036554 0.34412 0.018277 0.1818 0.036554 0.37658 0.018277 0.18829 0.030462 0.37658 0.012185 0.18829 0.012185 0.34412v1.5518z" fill="#808080" stroke-linecap="round" stroke-width=".11793"/>
|
||||
<path d="m4.9555 5.5562v-0.43195h0.54619v-3.8986h-0.54619v-0.43195h1.1299v4.7624z" fill="#69c" stroke-width="1.1186"/>
|
||||
<path d="m0.26458 5.5562v-4.7624h1.1299v0.43195h-0.54083v3.8986h0.54083v0.43195z" fill="#69c" stroke-width="1.1186"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -53,6 +53,7 @@ fmt_bold = nw_tb-bold.svg
|
||||
fmt_bold-md = nw_tb-bold-md.svg
|
||||
fmt_italic = nw_tb-italic.svg
|
||||
fmt_italic-md = nw_tb-italic-md.svg
|
||||
fmt_mark = nw_tb-mark.svg
|
||||
fmt_strike = nw_tb-strike.svg
|
||||
fmt_strike-md = nw_tb-strike-md.svg
|
||||
fmt_subscript = nw_tb-subscript.svg
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24" height="24" version="1.1" viewBox="0 0 6.35 6.35" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x=".26458" y=".79375" width="5.8208" height="4.7625" fill="#ad8700" fill-opacity=".8" stroke-linecap="round" stroke-width=".1354"/>
|
||||
<path d="m1.3229 5.2917v-4.2333h0.98087l0.6397 1.8829q0.060924 0.18829 0.11576 0.38957 0.054831 0.19479 0.11576 0.38957h0.024369q0.060924-0.19479 0.10966-0.38957 0.054831-0.20128 0.11576-0.38957l0.62752-1.8829h0.97478v4.2333h-0.81638v-1.5518q0-0.15583 0.012185-0.34412 0.012185-0.18829 0.030462-0.37658 0.018277-0.19479 0.036554-0.37658 0.018277-0.18829 0.036554-0.34412h-0.02437l-0.3229 1.0064-0.56659 1.6167h-0.49348l-0.56659-1.6167-0.3168-1.0064h-0.024369q0.018277 0.15583 0.036554 0.34412 0.018277 0.1818 0.036554 0.37658 0.018277 0.18829 0.030462 0.37658 0.012185 0.18829 0.012185 0.34412v1.5518z" fill-opacity=".78039" stroke-linecap="round" stroke-width=".11793"/>
|
||||
<path d="m4.9555 5.5562v-0.43195h0.54619v-3.8986h-0.54619v-0.43195h1.1299v4.7624z" fill="#4271ae" stroke-width="1.1186"/>
|
||||
<path d="m0.26458 5.5562v-4.7624h1.1299v0.43195h-0.54083v3.8986h0.54083v0.43195z" fill="#4271ae" stroke-width="1.1186"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -25,3 +25,4 @@ spellcheckline = 200, 46, 0
|
||||
errorline = 46, 200, 0
|
||||
replacetag = 0, 184, 46
|
||||
modifier = 200, 120, 0
|
||||
texthighlight = 136, 200, 0, 96
|
||||
|
||||
@@ -25,3 +25,4 @@ spellcheckline = 200, 0, 0
|
||||
errorline = 0, 150, 0
|
||||
replacetag = 0, 150, 0
|
||||
modifier = 150, 110, 30
|
||||
texthighlight = 150, 150, 0, 96
|
||||
|
||||
@@ -25,3 +25,4 @@ spellcheckline = 200, 46, 0
|
||||
errorline = 46, 200, 0
|
||||
replacetag = 225, 225, 225
|
||||
modifier = 225, 225, 225
|
||||
texthighlight = 255, 255, 255, 64
|
||||
|
||||
@@ -25,3 +25,4 @@ spellcheckline = 200, 0, 0
|
||||
errorline = 0, 150, 0
|
||||
replacetag = 0, 0, 0
|
||||
modifier = 0, 0, 0
|
||||
texthighlight = 0, 0, 0, 64
|
||||
|
||||
@@ -45,3 +45,4 @@ spellcheckline = 222, 61, 58
|
||||
errorline = 8, 145, 106
|
||||
replacetag = 42, 162, 152
|
||||
modifier = 224, 175, 5
|
||||
texthighlight = 218, 170, 1, 96
|
||||
|
||||
@@ -45,3 +45,4 @@ spellcheckline = 247, 140, 108
|
||||
errorline = 173, 219, 103
|
||||
replacetag = 127, 219, 202
|
||||
modifier = 236, 196, 141
|
||||
texthighlight = 255, 235, 149, 96
|
||||
|
||||
@@ -25,3 +25,4 @@ spellcheckline = 203, 75, 22
|
||||
errorline = 220, 50, 47
|
||||
replacetag = 133, 153, 0
|
||||
modifier = 181, 137, 0
|
||||
texthighlight = 181, 137, 0, 96
|
||||
|
||||
@@ -25,3 +25,4 @@ spellcheckline = 203, 75, 22
|
||||
errorline = 220, 50, 47
|
||||
replacetag = 133, 153, 0
|
||||
modifier = 181, 137, 0
|
||||
texthighlight = 181, 137, 0, 96
|
||||
|
||||
@@ -45,3 +45,4 @@ spellcheckline = 240, 40, 41
|
||||
errorline = 113, 140, 0
|
||||
replacetag = 62, 153, 159
|
||||
modifier = 245, 135, 31
|
||||
texthighlight = 234, 183, 0, 96
|
||||
|
||||
@@ -45,3 +45,4 @@ spellcheckline = 204, 102, 102
|
||||
errorline = 181, 189, 104
|
||||
replacetag = 138, 190, 183
|
||||
modifier = 222, 147, 95
|
||||
texthighlight = 240, 198, 116, 96
|
||||
|
||||
@@ -45,3 +45,4 @@ spellcheckline = 255, 157, 164
|
||||
errorline = 209, 241, 169
|
||||
replacetag = 153, 255, 255
|
||||
modifier = 255, 197, 143
|
||||
texthighlight = 255, 238, 173, 96
|
||||
|
||||
@@ -45,3 +45,4 @@ spellcheckline = 213, 78, 83
|
||||
errorline = 185, 202, 74
|
||||
replacetag = 112, 192, 177
|
||||
modifier = 231, 140, 69
|
||||
texthighlight = 231, 197, 71, 128
|
||||
|
||||
@@ -45,3 +45,4 @@ spellcheckline = 242, 119, 122
|
||||
errorline = 153, 204, 153
|
||||
replacetag = 102, 204, 204
|
||||
modifier = 249, 145, 57
|
||||
texthighlight = 255, 204, 102, 96
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
<h3>Contributors</h3>
|
||||
|
||||
<p>
|
||||
<b>Concept:</b> Marian Lückhof (<a href="https://github.com/Number042">@Number042</a>)<br>
|
||||
<b>Internationalisation:</b> Bruno Meneguello (<a href="https://github.com/bkmeneguello">@bkmeneguello</a>)<br>
|
||||
<b>Setup and Packaging:</b> Rachel Powers (<a href="https://github.com/Ryex">@Ryex</a>)
|
||||
• <b>Concept:</b> Marian Lückhof (<a href="https://github.com/Number042">@Number042</a>)<br>
|
||||
• <b>Internationalisation:</b> Bruno Meneguello (<a href="https://github.com/bkmeneguello">@bkmeneguello</a>)<br>
|
||||
• <b>Setup and Packaging:</b> Rachel Powers (<a href="https://github.com/Ryex">@Ryex</a>)
|
||||
</p>
|
||||
<p>For other contributions, see the project's
|
||||
<a href="https://github.com/vkbo/novelWriter/graphs/contributors">Contributors</a> page.</p>
|
||||
@@ -24,20 +24,20 @@
|
||||
<p>The default language is English (UK) with English (US) as an option. These are the original
|
||||
translators for the languages currently available:</p>
|
||||
<p>
|
||||
<b>Dutch:</b> Martijn van der Kleijn (<a href="https://github.com/mvdkleijn">@mvdkleijn</a>)<br>
|
||||
<b>French:</b> Jan Lüdke (<a href="https://github.com/jyhelle">@jyhelle</a>)<br>
|
||||
<b>German:</b> Myian (<a href="https://github.com/heymyian">@heymyian</a>)<br>
|
||||
<b>Italian:</b> Riccardo Mangili<br>
|
||||
<b>Japanese:</b> hebekeg (<a href="https://github.com/hebekeg">@hebekeg</a>)<br>
|
||||
<b>Latin American Spanish:</b> Tommy Marplatt (<a href="https://github.com/tmarplatt">@tmarplatt</a>)<br>
|
||||
<b>Norwegian:</b> Veronica Berglyd Olsen (<a href="https://github.com/vkbo">@vkbo</a>)<br>
|
||||
<b>Portuguese:</b> Bruno Meneguello (<a href="https://github.com/bkmeneguello">@bkmeneguello</a>)<br>
|
||||
<b>Simplified Chinese:</b> Qianzhi Long (<a href="https://github.com/longqzh">@longqzh</a>)
|
||||
• <b>Dutch:</b> Martijn van der Kleijn (<a href="https://github.com/mvdkleijn">@mvdkleijn</a>)<br>
|
||||
• <b>French:</b> Jan Lüdke (<a href="https://github.com/jyhelle">@jyhelle</a>)<br>
|
||||
• <b>German:</b> Myian (<a href="https://github.com/heymyian">@heymyian</a>)<br>
|
||||
• <b>Italian:</b> Riccardo Mangili<br>
|
||||
• <b>Japanese:</b> hebekeg (<a href="https://github.com/hebekeg">@hebekeg</a>)<br>
|
||||
• <b>Latin American Spanish:</b> Tommy Marplatt (<a href="https://github.com/tmarplatt">@tmarplatt</a>)<br>
|
||||
• <b>Norwegian:</b> Veronica Berglyd Olsen (<a href="https://github.com/vkbo">@vkbo</a>)<br>
|
||||
• <b>Portuguese:</b> Bruno Meneguello (<a href="https://github.com/bkmeneguello">@bkmeneguello</a>)<br>
|
||||
• <b>Simplified Chinese:</b> Qianzhi Long (<a href="https://github.com/longqzh">@longqzh</a>)
|
||||
</p>
|
||||
|
||||
<p>Additional larger translation contributions:</p>
|
||||
<p>
|
||||
<b>French:</b> Albert Aribaud (<a href="https://github.com/aaribaud">@aaribaud</a>)
|
||||
• <b>French:</b> Albert Aribaud (<a href="https://github.com/aaribaud">@aaribaud</a>)
|
||||
</p>
|
||||
|
||||
<p>Translations are managed on <a href="https://crowdin.com/project/novelwriter">Crowdin</a>, and
|
||||
@@ -47,27 +47,29 @@ more contributions are listed on the project's <a href="https://crowdin.com/proj
|
||||
|
||||
<p>The following libraries are dependencies of novelWriter:</p>
|
||||
<p>
|
||||
<a href="https://www.qt.io">Qt5</a> by Qt Company<br>
|
||||
<a href="https://www.riverbankcomputing.com/software/pyqt">PyQt5</a> by Riverbank Computing<br>
|
||||
<a href="https://abiword.github.io/enchant">Enchant</a> by Dom Lachowicz<br>
|
||||
<a href="https://pyenchant.github.io/pyenchant">PyEnchant</a> by Dimitri Merejkowsky
|
||||
• <a href="https://www.qt.io">Qt5</a> by Qt Company<br>
|
||||
• <a href="https://www.riverbankcomputing.com/software/pyqt">PyQt5</a> by Riverbank Computing<br>
|
||||
• <a href="https://abiword.github.io/enchant">Enchant</a> by Dom Lachowicz<br>
|
||||
• <a href="https://pyenchant.github.io/pyenchant">PyEnchant</a> by Dimitri Merejkowsky
|
||||
</p>
|
||||
|
||||
<h3>Assets</h3>
|
||||
|
||||
<p>Some of the assets bundled with novelWriter were adapted from the following sources:</p>
|
||||
<p>
|
||||
<a href="https://github.com/stephenhutchings/typicons.font">Typicons</a> icons by Stephen Hutchings (CC BY-SA 4.0)<br>
|
||||
<a href="https://github.com/chriskempson/base16">Tomorrow</a> syntax themes by Chris Kempson (MIT License)<br>
|
||||
<a href="https://github.com/sdras/night-owl-vscode-theme">Owl</a> syntax themes by Sarah Drasner (MIT License)<br>
|
||||
<a href="https://github.com/altercation/solarized">Solarized</a> themes by Ethan Schoonover (MIT License)
|
||||
• <a href="https://github.com/stephenhutchings/typicons.font">Typicons</a> icons by Stephen Hutchings (CC BY-SA 4.0)<br>
|
||||
• <a href="https://github.com/chriskempson/base16">Tomorrow</a> syntax themes by Chris Kempson (MIT License)<br>
|
||||
• <a href="https://github.com/sdras/night-owl-vscode-theme">Owl</a> syntax themes by Sarah Drasner (MIT License)<br>
|
||||
• <a href="https://github.com/altercation/solarized">Solarized</a> themes by Ethan Schoonover (MIT License)
|
||||
</p>
|
||||
|
||||
<h3>Fonts</h3>
|
||||
|
||||
<p>The font used for the main novelWriter logo, mimetype and text banners is:</p>
|
||||
<p>The font used for the main novelWriter logo, mimetype and text banners is Pridi. Other fonts are
|
||||
used on buttons and icons.</p>
|
||||
<p>
|
||||
Pridi by Cadson Demak (Open Font License, Version 1.1)
|
||||
• Pridi by Cadson Demak (Open Font License, Version 1.1)<br>
|
||||
• Source Sans Pro by Paul D. Hunt (SIL Open Font License)
|
||||
</p>
|
||||
|
||||
<h3>Special Mentions</h3>
|
||||
|
||||
@@ -67,7 +67,7 @@ class nwRegEx:
|
||||
FMT_EI = r"(?<![\w\\])(_)(?![\s_])(.+?)(?<![\s\\])(\1)(?!\w)"
|
||||
FMT_EB = r"(?<![\w\\])([\*]{2})(?![\s\*])(.+?)(?<![\s\\])(\1)(?!\w)"
|
||||
FMT_ST = r"(?<![\w\\])([~]{2})(?![\s~])(.+?)(?<![\s\\])(\1)(?!\w)"
|
||||
FMT_SC = r"(?i)(?<!\\)(\[[\/\!]?(?:i|b|s|u|sup|sub)\])"
|
||||
FMT_SC = r"(?i)(?<!\\)(\[[\/\!]?(?:i|b|s|u|m|sup|sub)\])"
|
||||
FMT_SV = r"(?<!\\)(\[(?i)(?:fn|footnote):)(.+?)(?<!\\)(\])"
|
||||
|
||||
# Pre-Compiled RegEx
|
||||
@@ -86,6 +86,8 @@ class nwShortcode:
|
||||
STRIKE_C = "[/s]"
|
||||
ULINE_O = "[u]"
|
||||
ULINE_C = "[/u]"
|
||||
MARK_O = "[m]"
|
||||
MARK_C = "[/m]"
|
||||
SUP_O = "[sup]"
|
||||
SUP_C = "[/sup]"
|
||||
SUB_O = "[sub]"
|
||||
|
||||
@@ -133,6 +133,8 @@ class ToHtml(Tokenizer):
|
||||
self.FMT_D_E: "</span>",
|
||||
self.FMT_U_B: "<u>",
|
||||
self.FMT_U_E: "</u>",
|
||||
self.FMT_M_B: "<mark>",
|
||||
self.FMT_M_E: "</mark>",
|
||||
}
|
||||
else:
|
||||
htmlTags = { # HTML5 (for export)
|
||||
@@ -144,6 +146,8 @@ class ToHtml(Tokenizer):
|
||||
self.FMT_D_E: "</del>",
|
||||
self.FMT_U_B: "<span style='text-decoration: underline;'>",
|
||||
self.FMT_U_E: "</span>",
|
||||
self.FMT_M_B: "<mark>",
|
||||
self.FMT_M_E: "</mark>",
|
||||
}
|
||||
|
||||
htmlTags[self.FMT_SUP_B] = "<sup>"
|
||||
|
||||
@@ -74,10 +74,12 @@ class Tokenizer(ABC):
|
||||
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
|
||||
FMT_M_B = 9 # Begin mark
|
||||
FMT_M_E = 10 # End mark
|
||||
FMT_SUP_B = 11 # Begin superscript
|
||||
FMT_SUP_E = 12 # End superscript
|
||||
FMT_SUB_B = 13 # Begin subscript
|
||||
FMT_SUB_E = 14 # End subscript
|
||||
|
||||
# Block Type
|
||||
T_EMPTY = 1 # Empty line (new paragraph)
|
||||
@@ -187,6 +189,7 @@ class Tokenizer(ABC):
|
||||
nwShortcode.BOLD_O: self.FMT_B_B, nwShortcode.BOLD_C: self.FMT_B_E,
|
||||
nwShortcode.STRIKE_O: self.FMT_D_B, nwShortcode.STRIKE_C: self.FMT_D_E,
|
||||
nwShortcode.ULINE_O: self.FMT_U_B, nwShortcode.ULINE_C: self.FMT_U_E,
|
||||
nwShortcode.MARK_O: self.FMT_M_B, nwShortcode.MARK_C: self.FMT_M_E,
|
||||
nwShortcode.SUP_O: self.FMT_SUP_B, nwShortcode.SUP_C: self.FMT_SUP_E,
|
||||
nwShortcode.SUB_O: self.FMT_SUB_B, nwShortcode.SUB_C: self.FMT_SUB_E,
|
||||
}
|
||||
|
||||
@@ -95,6 +95,8 @@ class ToMarkdown(Tokenizer):
|
||||
self.FMT_D_E: "",
|
||||
self.FMT_U_B: "",
|
||||
self.FMT_U_E: "",
|
||||
self.FMT_M_B: "",
|
||||
self.FMT_M_E: "",
|
||||
self.FMT_SUP_B: "",
|
||||
self.FMT_SUP_E: "",
|
||||
self.FMT_SUB_B: "",
|
||||
@@ -111,6 +113,8 @@ class ToMarkdown(Tokenizer):
|
||||
self.FMT_D_E: "~~",
|
||||
self.FMT_U_B: "",
|
||||
self.FMT_U_E: "",
|
||||
self.FMT_M_B: "==",
|
||||
self.FMT_M_E: "==",
|
||||
self.FMT_SUP_B: "^",
|
||||
self.FMT_SUP_E: "^",
|
||||
self.FMT_SUB_B: "~",
|
||||
|
||||
@@ -84,14 +84,16 @@ X_BLD = 0x01 # Bold format
|
||||
X_ITA = 0x02 # Italic format
|
||||
X_DEL = 0x04 # Strikethrough format
|
||||
X_UND = 0x08 # Underline format
|
||||
X_SUP = 0x10 # Superscript
|
||||
X_SUB = 0x20 # Subscript
|
||||
X_MRK = 0x10 # Marked format
|
||||
X_SUP = 0x20 # Superscript
|
||||
X_SUB = 0x40 # Subscript
|
||||
|
||||
# Formatting Masks
|
||||
M_BLD = ~X_BLD
|
||||
M_ITA = ~X_ITA
|
||||
M_DEL = ~X_DEL
|
||||
M_UND = ~X_UND
|
||||
M_MRK = ~X_MRK
|
||||
M_SUP = ~X_SUP
|
||||
M_SUB = ~X_SUB
|
||||
|
||||
@@ -189,6 +191,7 @@ class ToOdt(Tokenizer):
|
||||
self._opaHead34 = None
|
||||
self._colMetaTx = None
|
||||
self._opaMetaTx = None
|
||||
self._markText = "#ffffa6"
|
||||
|
||||
return
|
||||
|
||||
@@ -643,6 +646,10 @@ class ToOdt(Tokenizer):
|
||||
xFmt |= X_UND
|
||||
elif fFmt == self.FMT_U_E:
|
||||
xFmt &= M_UND
|
||||
elif fFmt == self.FMT_M_B:
|
||||
xFmt |= X_MRK
|
||||
elif fFmt == self.FMT_M_E:
|
||||
xFmt &= M_MRK
|
||||
elif fFmt == self.FMT_SUP_B:
|
||||
xFmt |= X_SUP
|
||||
elif fFmt == self.FMT_SUP_E:
|
||||
@@ -710,6 +717,8 @@ class ToOdt(Tokenizer):
|
||||
newStyle.setUnderlineStyle("solid")
|
||||
newStyle.setUnderlineWidth("auto")
|
||||
newStyle.setUnderlineColour("font-color")
|
||||
if hFmt & X_MRK:
|
||||
newStyle.setBackgroundColor(self._markText)
|
||||
if hFmt & X_SUP:
|
||||
newStyle.setTextPosition("super")
|
||||
if hFmt & X_SUB:
|
||||
@@ -1279,6 +1288,7 @@ class ODTTextStyle:
|
||||
self._tAttr = {
|
||||
"font-weight": ["fo", None],
|
||||
"font-style": ["fo", None],
|
||||
"background-color": ["fo", None],
|
||||
"text-position": ["style", None],
|
||||
"text-line-through-style": ["style", None],
|
||||
"text-line-through-type": ["style", None],
|
||||
@@ -1306,6 +1316,13 @@ class ODTTextStyle:
|
||||
self._tAttr["font-style"][1] = None
|
||||
return
|
||||
|
||||
def setBackgroundColor(self, value: str | None) -> None:
|
||||
if value and len(value) == 7 and value[0] == "#":
|
||||
self._tAttr["background-color"][1] = value
|
||||
else:
|
||||
self._tAttr["background-color"][1] = None
|
||||
return
|
||||
|
||||
def setTextPosition(self, value: str | None) -> None:
|
||||
if value in self.VALID_POS:
|
||||
self._tAttr["text-position"][1] = f"{value} 58%"
|
||||
|
||||
+3
-2
@@ -124,8 +124,9 @@ class nwDocAction(Enum):
|
||||
SC_BOLD = 31
|
||||
SC_STRIKE = 32
|
||||
SC_ULINE = 33
|
||||
SC_SUP = 34
|
||||
SC_SUB = 35
|
||||
SC_MARK = 34
|
||||
SC_SUP = 35
|
||||
SC_SUB = 36
|
||||
|
||||
# END Enum nwDocAction
|
||||
|
||||
|
||||
@@ -769,6 +769,8 @@ class GuiDocEditor(QPlainTextEdit):
|
||||
self._wrapSelection(nwShortcode.STRIKE_O, nwShortcode.STRIKE_C)
|
||||
elif action == nwDocAction.SC_ULINE:
|
||||
self._wrapSelection(nwShortcode.ULINE_O, nwShortcode.ULINE_C)
|
||||
elif action == nwDocAction.SC_MARK:
|
||||
self._wrapSelection(nwShortcode.MARK_O, nwShortcode.MARK_C)
|
||||
elif action == nwDocAction.SC_SUP:
|
||||
self._wrapSelection(nwShortcode.SUP_O, nwShortcode.SUP_C)
|
||||
elif action == nwDocAction.SC_SUB:
|
||||
@@ -2313,6 +2315,13 @@ class GuiDocToolBar(QWidget):
|
||||
lambda: self.requestDocAction.emit(nwDocAction.SC_ULINE)
|
||||
)
|
||||
|
||||
self.tbMark = QToolButton(self)
|
||||
self.tbMark.setIconSize(iconSize)
|
||||
self.tbMark.setToolTip(self.tr("Shortcode Highlight"))
|
||||
self.tbMark.clicked.connect(
|
||||
lambda: self.requestDocAction.emit(nwDocAction.SC_MARK)
|
||||
)
|
||||
|
||||
self.tbSuperscript = QToolButton(self)
|
||||
self.tbSuperscript.setIconSize(iconSize)
|
||||
self.tbSuperscript.setToolTip(self.tr("Shortcode Superscript"))
|
||||
@@ -2339,6 +2348,7 @@ class GuiDocToolBar(QWidget):
|
||||
self.outerBox.addWidget(self.tbItalic)
|
||||
self.outerBox.addWidget(self.tbStrike)
|
||||
self.outerBox.addWidget(self.tbUnderline)
|
||||
self.outerBox.addWidget(self.tbMark)
|
||||
self.outerBox.addWidget(self.tbSuperscript)
|
||||
self.outerBox.addWidget(self.tbSubscript)
|
||||
self.outerBox.setContentsMargins(cM, cM, cM, cM)
|
||||
@@ -2369,6 +2379,7 @@ class GuiDocToolBar(QWidget):
|
||||
self.tbItalic.setIcon(SHARED.theme.getIcon("fmt_italic"))
|
||||
self.tbStrike.setIcon(SHARED.theme.getIcon("fmt_strike"))
|
||||
self.tbUnderline.setIcon(SHARED.theme.getIcon("fmt_underline"))
|
||||
self.tbMark.setIcon(SHARED.theme.getIcon("fmt_mark"))
|
||||
self.tbSuperscript.setIcon(SHARED.theme.getIcon("fmt_superscript"))
|
||||
self.tbSubscript.setIcon(SHARED.theme.getIcon("fmt_subscript"))
|
||||
|
||||
|
||||
@@ -466,48 +466,30 @@ class GuiDocViewer(QTextBrowser):
|
||||
colText = SHARED.theme.colText
|
||||
colHead = SHARED.theme.colHead
|
||||
colVals = SHARED.theme.colVal
|
||||
colEmph = SHARED.theme.colEmph
|
||||
colMark = SHARED.theme.colMark
|
||||
colKeys = SHARED.theme.colKey
|
||||
colHide = SHARED.theme.colHidden
|
||||
colMods = SHARED.theme.colMod
|
||||
colOpts = SHARED.theme.colOpt
|
||||
styleSheet = (
|
||||
"body {{"
|
||||
" color: rgb({tColR}, {tColG}, {tColB});"
|
||||
"}}\n"
|
||||
"h1, h2, h3, h4 {{"
|
||||
" color: rgb({hColR}, {hColG}, {hColB});"
|
||||
"}}\n"
|
||||
"a {{"
|
||||
" color: rgb({aColR}, {aColG}, {aColB});"
|
||||
"}}\n"
|
||||
"mark {{"
|
||||
" color: rgb({eColR}, {eColG}, {eColB});"
|
||||
"}}\n"
|
||||
".tags {{"
|
||||
" color: rgb({kColR}, {kColG}, {kColB});"
|
||||
"}}\n"
|
||||
".optional {{"
|
||||
" color: rgb({oColR}, {oColG}, {oColB});"
|
||||
"}}\n"
|
||||
".comment {{"
|
||||
" color: rgb({cColR}, {cColG}, {cColB});"
|
||||
"}}\n"
|
||||
".synopsis {{"
|
||||
" color: rgb({mColR}, {mColG}, {mColB});"
|
||||
"}}\n"
|
||||
".title {{"
|
||||
" text-align: center;"
|
||||
"}}\n"
|
||||
"body {{color: rgb({rT}, {gT}, {bT});}}\n"
|
||||
"h1, h2, h3, h4 {{color: rgb({rH}, {gH}, {bH});}}\n"
|
||||
"a {{color: rgb({rA}, {gA}, {bA});}}\n"
|
||||
"mark {{background-color: rgba({rE}, {gE}, {bE}, {aE});}}\n"
|
||||
".tags {{color: rgb({rK}, {gK}, {bK});}}\n"
|
||||
".optional {{color: rgb({rO}, {gO}, {bO});}}\n"
|
||||
".comment {{color: rgb({rC}, {gC}, {bC});}}\n"
|
||||
".synopsis {{color: rgb({rM}, {gM}, {bM});}}\n"
|
||||
".title {{text-align: center;}}\n"
|
||||
).format(
|
||||
tColR=colText.red(), tColG=colText.green(), tColB=colText.blue(),
|
||||
hColR=colHead.red(), hColG=colHead.green(), hColB=colHead.blue(),
|
||||
aColR=colVals.red(), aColG=colVals.green(), aColB=colVals.blue(),
|
||||
eColR=colEmph.red(), eColG=colEmph.green(), eColB=colEmph.blue(),
|
||||
kColR=colKeys.red(), kColG=colKeys.green(), kColB=colKeys.blue(),
|
||||
cColR=colHide.red(), cColG=colHide.green(), cColB=colHide.blue(),
|
||||
mColR=colMods.red(), mColG=colMods.green(), mColB=colMods.blue(),
|
||||
oColR=colOpts.red(), oColG=colOpts.green(), oColB=colOpts.blue(),
|
||||
rT=colText.red(), gT=colText.green(), bT=colText.blue(),
|
||||
rH=colHead.red(), gH=colHead.green(), bH=colHead.blue(),
|
||||
rA=colVals.red(), gA=colVals.green(), bA=colVals.blue(),
|
||||
rE=colMark.red(), gE=colMark.green(), bE=colMark.blue(), aE=colMark.alpha(),
|
||||
rK=colKeys.red(), gK=colKeys.green(), bK=colKeys.blue(),
|
||||
rC=colHide.red(), gC=colHide.green(), bC=colHide.blue(),
|
||||
rM=colMods.red(), gM=colMods.green(), bM=colMods.blue(),
|
||||
rO=colOpts.red(), gO=colOpts.green(), bO=colOpts.blue(),
|
||||
)
|
||||
self.document().setDefaultStyleSheet(styleSheet)
|
||||
|
||||
|
||||
@@ -672,6 +672,12 @@ class GuiMainMenu(QMenuBar):
|
||||
lambda: self.requestDocAction.emit(nwDocAction.SC_ULINE)
|
||||
)
|
||||
|
||||
# Shortcode Mark
|
||||
self.aScMark = self.mShortcodes.addAction(self.tr("Highlight"))
|
||||
self.aScMark.triggered.connect(
|
||||
lambda: self.requestDocAction.emit(nwDocAction.SC_MARK)
|
||||
)
|
||||
|
||||
# Shortcode Superscript
|
||||
self.aScSuper = self.mShortcodes.addAction(self.tr("Superscript"))
|
||||
self.aScSuper.triggered.connect(
|
||||
|
||||
@@ -106,6 +106,7 @@ class GuiTheme:
|
||||
self.colError = QColor(0, 0, 0)
|
||||
self.colRepTag = QColor(0, 0, 0)
|
||||
self.colMod = QColor(0, 0, 0)
|
||||
self.colMark = QColor(255, 255, 255, 128)
|
||||
|
||||
# Class Setup
|
||||
# ===========
|
||||
@@ -329,6 +330,7 @@ class GuiTheme:
|
||||
self.colError = self._parseColour(confParser, cnfSec, "errorline")
|
||||
self.colRepTag = self._parseColour(confParser, cnfSec, "replacetag")
|
||||
self.colMod = self._parseColour(confParser, cnfSec, "modifier")
|
||||
self.colMark = self._parseColour(confParser, cnfSec, "texthighlight")
|
||||
|
||||
return True
|
||||
|
||||
@@ -448,8 +450,8 @@ class GuiIcons:
|
||||
"search_regex", "search_word",
|
||||
|
||||
# Format Icons
|
||||
"fmt_bold", "fmt_bold-md", "fmt_italic", "fmt_italic-md", "fmt_strike", "fmt_strike-md",
|
||||
"fmt_subscript", "fmt_superscript", "fmt_underline",
|
||||
"fmt_bold", "fmt_bold-md", "fmt_italic", "fmt_italic-md", "fmt_mark", "fmt_strike",
|
||||
"fmt_strike-md", "fmt_subscript", "fmt_superscript", "fmt_underline",
|
||||
|
||||
# General Button Icons
|
||||
"add", "add_document", "backward", "bookmark", "browse", "checked", "close", "cross",
|
||||
|
||||
@@ -768,6 +768,8 @@ class _PreviewWidget(QTextBrowser):
|
||||
html = html.replace("\t", "!!tab!!")
|
||||
html = html.replace("<del>", "<span style='text-decoration: line-through;'>")
|
||||
html = html.replace("</del>", "</span>")
|
||||
html = html.replace("<mark>", "<span style='background-color: #ffffa6;'>")
|
||||
html = html.replace("</mark>", "</span>")
|
||||
self.setHtml(html)
|
||||
qApp.processEvents()
|
||||
while self.find("!!tab!!"):
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
%%~name: Making a Scene
|
||||
%%~path: 6a2d6d5f4f401/636b6aa9b697b
|
||||
%%~kind: NOVEL/DOCUMENT
|
||||
%%~hash: d7920fe95fb48140278ae160fe7c3c1ce530072c
|
||||
%%~date: Unknown/2023-10-20 22:57:56
|
||||
%%~hash: e1c58699b05b512306a534da70c2952aafc60e8b
|
||||
%%~date: Unknown/2024-02-25 16:33:40
|
||||
### Making a Scene
|
||||
|
||||
@pov: Jane
|
||||
@@ -13,7 +13,7 @@ A scene is defined by a level three heading, like the one at the top of this pag
|
||||
|
||||
Each paragraph in the scene is separated by a blank line. The text supports minimal formatting, like **bold**, _italic_ and **_bold italic_**. You can also ~~strike through~~ text. There is **some support for _nested_ emphasis**, but there are some known limitations. If the syntax highlighter doesn’t show it correctly, the export tool will not either.
|
||||
|
||||
For special formatting aside from standard emphasis, you can use “shortcodes”. Here we have super[sup]script[/sup] and sub[sub]script[/sub], and [b]part[/b]ial bold too, which ends in the middle of a word. The shortcodes also support [u]underline[/u].
|
||||
For special formatting aside from standard emphasis, you can use “shortcodes”. Here we have super[sup]script[/sup] and sub[sub]script[/sub], and [b]part[/b]ial bold too, which ends in the middle of a word. The shortcodes also support [u]underline[/u], and you can [m]highlight text as well[/m].
|
||||
|
||||
In addition, the editor supports automatic formatting of “quotes”, both double and ‘single’. Depending on the syntax highlighter settings and colour theme, these can be in different colours. “You can of course use **bold** and _italic_ text inside of quotes too.”
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<novelWriterXML appVersion="2.3b1" hexVersion="0x020300b1" fileVersion="1.5" fileRevision="2" timeStamp="2024-02-15 22:37:50">
|
||||
<project id="e2be99af-f9bf-4403-857a-c3d1ac25abea" saveCount="1681" autoCount="263" editTime="82755">
|
||||
<novelWriterXML appVersion="2.4a0" hexVersion="0x020400a0" fileVersion="1.5" fileRevision="2" timeStamp="2024-02-25 16:33:49">
|
||||
<project id="e2be99af-f9bf-4403-857a-c3d1ac25abea" saveCount="1690" autoCount="264" editTime="83277">
|
||||
<name>Sample Project</name>
|
||||
<author>Jane Smith</author>
|
||||
</project>
|
||||
@@ -35,7 +35,7 @@
|
||||
<entry key="i56be10" count="1" red="117" green="0" blue="175">Main</entry>
|
||||
</importance>
|
||||
</settings>
|
||||
<content items="31" novelWords="991" notesWords="416">
|
||||
<content items="31" novelWords="998" notesWords="416">
|
||||
<item handle="7031beac91f75" parent="None" root="7031beac91f75" order="0" type="ROOT" class="NOVEL">
|
||||
<meta expanded="yes" />
|
||||
<name status="sc24b8f" import="ia857f0">Novel</name>
|
||||
@@ -57,7 +57,7 @@
|
||||
<name status="sf24ce6" import="ia857f0" active="yes">Chapter One</name>
|
||||
</item>
|
||||
<item handle="636b6aa9b697b" parent="6a2d6d5f4f401" root="7031beac91f75" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
|
||||
<meta expanded="no" heading="H3" charCount="2901" wordCount="513" paraCount="15" cursorPos="66" />
|
||||
<meta expanded="no" heading="H3" charCount="2937" wordCount="520" paraCount="15" cursorPos="1465" />
|
||||
<name status="s90e6c9" import="ia857f0" active="yes">Making a Scene</name>
|
||||
</item>
|
||||
<item handle="bc0cbd2a407f3" parent="6a2d6d5f4f401" root="7031beac91f75" order="1" type="FILE" class="NOVEL" layout="DOCUMENT">
|
||||
|
||||
@@ -29,8 +29,8 @@ from novelwriter.core.project import NWProject
|
||||
|
||||
|
||||
@pytest.mark.core
|
||||
def testCoreToHtml_ConvertFormat(mockGUI):
|
||||
"""Test the tokenizer and converter chain using the ToHtml class."""
|
||||
def testCoreToHtml_ConvertHeaders(mockGUI):
|
||||
"""Test header formats in the ToHtml class."""
|
||||
project = NWProject()
|
||||
html = ToHtml(project)
|
||||
|
||||
@@ -129,6 +129,19 @@ def testCoreToHtml_ConvertFormat(mockGUI):
|
||||
html.doConvert()
|
||||
assert html.result == "<h2><a name='T0001'></a>Heading Two</h2>\n"
|
||||
|
||||
# END Test testCoreToHtml_ConvertHeaders
|
||||
|
||||
|
||||
@pytest.mark.core
|
||||
def testCoreToHtml_ConvertParagraphs(mockGUI):
|
||||
"""Test paragraph formats in the ToHtml class."""
|
||||
project = NWProject()
|
||||
html = ToHtml(project)
|
||||
|
||||
html._isNovel = True
|
||||
html._isNote = False
|
||||
html._isFirst = True
|
||||
|
||||
# Paragraphs
|
||||
# ==========
|
||||
|
||||
@@ -141,6 +154,19 @@ def testCoreToHtml_ConvertFormat(mockGUI):
|
||||
"<del>strikethrough</del> text</strong> here</p>\n"
|
||||
)
|
||||
|
||||
# Shortcodes
|
||||
html._text = (
|
||||
"Some [b]bold[/b], [i]italic[/i], [s]strike[/s], [u]underline[/u], [m]mark[/m], "
|
||||
"super[sup]script[/sup], sub[sub]script[/sub] here\n"
|
||||
)
|
||||
html.tokenizeText()
|
||||
html.doConvert()
|
||||
assert html.result == (
|
||||
"<p>Some <strong>bold</strong>, <em>italic</em>, <del>strike</del>, "
|
||||
"<span style='text-decoration: underline;'>underline</span>, <mark>mark</mark>, "
|
||||
"super<sup>script</sup>, sub<sub>script</sub> here</p>\n"
|
||||
)
|
||||
|
||||
# Text w/Hard Break
|
||||
html._text = "Line one \nLine two \nLine three\n"
|
||||
html.tokenizeText()
|
||||
@@ -206,17 +232,13 @@ def testCoreToHtml_ConvertFormat(mockGUI):
|
||||
html.tokenizeText()
|
||||
html.doConvert()
|
||||
assert html.result == (
|
||||
"<h2>"
|
||||
"<a name='T0001'></a>Chapter</h2>\n"
|
||||
"<p style='margin-bottom: 0;'>"
|
||||
"<span class='tags'>Point of View:</span> <a href='#tag_Bod'>Bod</a>"
|
||||
"</p>\n"
|
||||
"<p style='margin-bottom: 0; margin-top: 0;'>"
|
||||
"<span class='tags'>Plot:</span> <a href='#tag_Main'>Main</a>"
|
||||
"</p>\n"
|
||||
"<p style='margin-top: 0;'>"
|
||||
"<span class='tags'>Locations:</span> <a href='#tag_Europe'>Europe</a>"
|
||||
"</p>\n"
|
||||
"<h1 style='page-break-before: always;'>Chapter</h1>\n"
|
||||
"<p style='margin-bottom: 0;'><span class='tags'>Point of View:</span> "
|
||||
"<a href='#tag_Bod'>Bod</a></p>\n"
|
||||
"<p style='margin-bottom: 0; margin-top: 0;'><span class='tags'>Plot:</span> "
|
||||
"<a href='#tag_Main'>Main</a></p>\n"
|
||||
"<p style='margin-top: 0;'><span class='tags'>Locations:</span> "
|
||||
"<a href='#tag_Europe'>Europe</a></p>\n"
|
||||
)
|
||||
|
||||
# Preview Mode
|
||||
@@ -234,7 +256,7 @@ def testCoreToHtml_ConvertFormat(mockGUI):
|
||||
"text</b> here</p>\n"
|
||||
)
|
||||
|
||||
# END Test testCoreToHtml_ConvertFormat
|
||||
# END Test testCoreToHtml_ConvertParagraphs
|
||||
|
||||
|
||||
@pytest.mark.core
|
||||
|
||||
@@ -638,6 +638,11 @@ def testCoreToken_ExtractFormats(mockGUI):
|
||||
assert text == "Text with underline in it."
|
||||
assert fmt == [(10, tokens.FMT_U_B), (19, tokens.FMT_U_E)]
|
||||
|
||||
# Plain mark
|
||||
text, fmt = tokens._extractFormats("Text with [m]highlight[/m] in it.")
|
||||
assert text == "Text with highlight in it."
|
||||
assert fmt == [(10, tokens.FMT_M_B), (19, tokens.FMT_M_E)]
|
||||
|
||||
# Plain superscript
|
||||
text, fmt = tokens._extractFormats("Text with super[sup]script[/sup] in it.")
|
||||
assert text == "Text with superscript in it."
|
||||
|
||||
@@ -29,16 +29,11 @@ from novelwriter.core.project import NWProject
|
||||
|
||||
|
||||
@pytest.mark.core
|
||||
def testCoreToMarkdown_ConvertFormat(mockGUI):
|
||||
"""Test the tokenizer and converter chain using the ToMarkdown
|
||||
class.
|
||||
"""
|
||||
def testCoreToMarkdown_ConvertHeaders(mockGUI):
|
||||
"""Test header formats in the ToMarkdown class."""
|
||||
project = NWProject()
|
||||
toMD = ToMarkdown(project)
|
||||
|
||||
# Headers
|
||||
# =======
|
||||
|
||||
toMD._isNovel = True
|
||||
toMD._isNote = False
|
||||
toMD._isFirst = True
|
||||
@@ -79,8 +74,18 @@ def testCoreToMarkdown_ConvertFormat(mockGUI):
|
||||
toMD.doConvert()
|
||||
assert toMD.result == "## Prologue\n\n"
|
||||
|
||||
# Paragraphs
|
||||
# ==========
|
||||
# END Test testCoreToMarkdown_ConvertHeaders
|
||||
|
||||
|
||||
@pytest.mark.core
|
||||
def testCoreToMarkdown_ConvertParagraphs(mockGUI):
|
||||
"""Test paragraph formats in the ToMarkdown class."""
|
||||
project = NWProject()
|
||||
toMD = ToMarkdown(project)
|
||||
|
||||
toMD._isNovel = True
|
||||
toMD._isNote = False
|
||||
toMD._isFirst = True
|
||||
|
||||
# Text for Extended Markdown
|
||||
toMD.setExtendedMarkdown()
|
||||
@@ -100,6 +105,31 @@ def testCoreToMarkdown_ConvertFormat(mockGUI):
|
||||
"Some **nested bold and _italic_ and strikethrough text** here\n\n"
|
||||
)
|
||||
|
||||
# Shortcodes for Extended Markdown
|
||||
toMD.setExtendedMarkdown()
|
||||
toMD._text = (
|
||||
"Some [b]bold[/b], [i]italic[/i], [s]strike[/s], [u]underline[/u], [m]mark[/m], "
|
||||
"super[sup]script[/sup], sub[sub]script[/sub] here\n"
|
||||
)
|
||||
toMD.tokenizeText()
|
||||
toMD.doConvert()
|
||||
assert toMD.result == (
|
||||
"Some **bold**, _italic_, ~~strike~~, underline, ==mark==, "
|
||||
"super^script^, sub~script~ here\n\n"
|
||||
)
|
||||
|
||||
# Shortcodes for Standard Markdown
|
||||
toMD.setStandardMarkdown()
|
||||
toMD._text = (
|
||||
"Some [b]bold[/b], [i]italic[/i], [s]strike[/s], [u]underline[/u], [m]mark[/m], "
|
||||
"super[sup]script[/sup], sub[sub]script[/sub] here\n"
|
||||
)
|
||||
toMD.tokenizeText()
|
||||
toMD.doConvert()
|
||||
assert toMD.result == (
|
||||
"Some **bold**, _italic_, strike, underline, mark, superscript, subscript here\n\n"
|
||||
)
|
||||
|
||||
# Text w/Hard Break
|
||||
toMD._text = "Line one \nLine two \nLine three\n"
|
||||
toMD.tokenizeText()
|
||||
@@ -160,7 +190,7 @@ def testCoreToMarkdown_ConvertFormat(mockGUI):
|
||||
"**Locations:** Europe\n\n"
|
||||
)
|
||||
|
||||
# END Test testCoreToMarkdown_ConvertFormat
|
||||
# END Test testCoreToMarkdown_ConvertParagraphs
|
||||
|
||||
|
||||
@pytest.mark.core
|
||||
|
||||
@@ -237,22 +237,12 @@ def testCoreToOdt_TextFormatting(mockGUI):
|
||||
|
||||
|
||||
@pytest.mark.core
|
||||
def testCoreToOdt_Convert(mockGUI):
|
||||
def testCoreToOdt_ConvertHeaders(mockGUI):
|
||||
"""Test the converter of the ToOdt class."""
|
||||
project = NWProject()
|
||||
odt = ToOdt(project, isFlat=True)
|
||||
|
||||
odt._isNovel = True
|
||||
|
||||
def getStyle(styleName):
|
||||
for aSet in odt._autoPara.values():
|
||||
if aSet[0] == styleName:
|
||||
return aSet[1]
|
||||
return None
|
||||
|
||||
# Headers
|
||||
# =======
|
||||
|
||||
# Header 1
|
||||
odt._text = "# Title\n"
|
||||
odt.tokenizeText()
|
||||
@@ -331,8 +321,21 @@ def testCoreToOdt_Convert(mockGUI):
|
||||
'</office:text>'
|
||||
)
|
||||
|
||||
# Paragraphs
|
||||
# ==========
|
||||
# END Test testCoreToOdt_ConvertHeaders
|
||||
|
||||
|
||||
@pytest.mark.core
|
||||
def testCoreToOdt_ConvertParagraphs(mockGUI):
|
||||
"""Test the converter of the ToOdt class."""
|
||||
project = NWProject()
|
||||
odt = ToOdt(project, isFlat=True)
|
||||
odt._isNovel = True
|
||||
|
||||
def getStyle(styleName):
|
||||
for aSet in odt._autoPara.values():
|
||||
if aSet[0] == styleName:
|
||||
return aSet[1]
|
||||
return None
|
||||
|
||||
# Nested Markdown Text
|
||||
odt._text = "Some ~~nested **bold** and _italics_ text~~ text."
|
||||
@@ -372,7 +375,7 @@ def testCoreToOdt_Convert(mockGUI):
|
||||
'</office:text>'
|
||||
)
|
||||
|
||||
# Nested Shortcode Text, Super/Subscript
|
||||
# Shortcode Text, Super/Subscript
|
||||
odt._text = "Some super[sup]script[/sup] and sub[sub]script[/sub] text."
|
||||
odt.tokenizeText()
|
||||
odt.initDocument()
|
||||
@@ -387,6 +390,21 @@ def testCoreToOdt_Convert(mockGUI):
|
||||
'</office:text>'
|
||||
)
|
||||
|
||||
# Shortcode Text, Underline/Highlight
|
||||
odt._text = "Some [u]underlined and [m]highlighted[/m][/u] text."
|
||||
odt.tokenizeText()
|
||||
odt.initDocument()
|
||||
odt.doConvert()
|
||||
odt.closeDocument()
|
||||
assert odt.errData == []
|
||||
assert xmlToText(odt._xText) == (
|
||||
'<office:text>'
|
||||
'<text:p text:style-name="Text_20_body">Some '
|
||||
'<text:span text:style-name="T7">underlined and </text:span>'
|
||||
'<text:span text:style-name="T8">highlighted</text:span> text.</text:p>'
|
||||
'</office:text>'
|
||||
)
|
||||
|
||||
# Hard Break
|
||||
odt._text = "Some text.\nNext line\n"
|
||||
odt.tokenizeText()
|
||||
@@ -422,7 +440,7 @@ def testCoreToOdt_Convert(mockGUI):
|
||||
assert odt.errData == []
|
||||
assert xmlToText(odt._xText) == (
|
||||
'<office:text>'
|
||||
'<text:p text:style-name="Text_20_body">Some <text:span text:style-name="T7">'
|
||||
'<text:p text:style-name="Text_20_body">Some <text:span text:style-name="T9">'
|
||||
'bold<text:tab />text</text:span></text:p>'
|
||||
'</office:text>'
|
||||
)
|
||||
@@ -467,13 +485,13 @@ def testCoreToOdt_Convert(mockGUI):
|
||||
assert xmlToText(odt._xText) == (
|
||||
'<office:text>'
|
||||
'<text:h text:style-name="Heading_20_3" text:outline-level="3">Scene</text:h>'
|
||||
'<text:p text:style-name="Text_20_Meta"><text:span text:style-name="T7">'
|
||||
'<text:p text:style-name="Text_20_Meta"><text:span text:style-name="T9">'
|
||||
'Point of View:</text:span> Jane</text:p>'
|
||||
'<text:p text:style-name="Text_20_Meta"><text:span text:style-name="T7">'
|
||||
'<text:p text:style-name="Text_20_Meta"><text:span text:style-name="T9">'
|
||||
'Synopsis:</text:span> So it begins</text:p>'
|
||||
'<text:p text:style-name="Text_20_Meta"><text:span text:style-name="T7">'
|
||||
'<text:p text:style-name="Text_20_Meta"><text:span text:style-name="T9">'
|
||||
'Short Description:</text:span> Then what</text:p>'
|
||||
'<text:p text:style-name="Text_20_Meta"><text:span text:style-name="T7">'
|
||||
'<text:p text:style-name="Text_20_Meta"><text:span text:style-name="T9">'
|
||||
'Comment:</text:span> A plain comment</text:p>'
|
||||
'</office:text>'
|
||||
)
|
||||
@@ -535,26 +553,26 @@ def testCoreToOdt_Convert(mockGUI):
|
||||
assert xmlToText(odt._xText) == (
|
||||
'<office:text>'
|
||||
'<text:h text:style-name="Heading_20_3" text:outline-level="3">Scene</text:h>'
|
||||
'<text:p text:style-name="P3"><text:span text:style-name="T7">'
|
||||
'<text:p text:style-name="P1"><text:span text:style-name="T9">'
|
||||
'Point of View:</text:span> Jane</text:p>'
|
||||
'<text:p text:style-name="P4"><text:span text:style-name="T7">'
|
||||
'<text:p text:style-name="P2"><text:span text:style-name="T9">'
|
||||
'Characters:</text:span> John</text:p>'
|
||||
'<text:p text:style-name="Text_20_Meta"><text:span text:style-name="T7">'
|
||||
'<text:p text:style-name="Text_20_Meta"><text:span text:style-name="T9">'
|
||||
'Plot:</text:span> Main</text:p>'
|
||||
'<text:p text:style-name="P5">Right align</text:p>'
|
||||
'<text:p text:style-name="P3">Right align</text:p>'
|
||||
'<text:p text:style-name="Text_20_body">Left Align</text:p>'
|
||||
'<text:p text:style-name="P6">Centered</text:p>'
|
||||
'<text:p text:style-name="P7">Left indent</text:p>'
|
||||
'<text:p text:style-name="P8">Right indent</text:p>'
|
||||
'<text:p text:style-name="P4">Centered</text:p>'
|
||||
'<text:p text:style-name="P5">Left indent</text:p>'
|
||||
'<text:p text:style-name="P6">Right indent</text:p>'
|
||||
'</office:text>'
|
||||
)
|
||||
assert getStyle("P3")._pAttr["margin-bottom"] == ["fo", "0.000cm"] # type: ignore
|
||||
assert getStyle("P4")._pAttr["margin-bottom"] == ["fo", "0.000cm"] # type: ignore
|
||||
assert getStyle("P4")._pAttr["margin-top"] == ["fo", "0.000cm"] # type: ignore
|
||||
assert getStyle("P5")._pAttr["text-align"] == ["fo", "right"] # type: ignore
|
||||
assert getStyle("P6")._pAttr["text-align"] == ["fo", "center"] # type: ignore
|
||||
assert getStyle("P7")._pAttr["margin-left"] == ["fo", "1.693cm"] # type: ignore
|
||||
assert getStyle("P8")._pAttr["margin-right"] == ["fo", "1.693cm"] # type: ignore
|
||||
assert getStyle("P1")._pAttr["margin-bottom"] == ["fo", "0.000cm"] # type: ignore
|
||||
assert getStyle("P2")._pAttr["margin-bottom"] == ["fo", "0.000cm"] # type: ignore
|
||||
assert getStyle("P2")._pAttr["margin-top"] == ["fo", "0.000cm"] # type: ignore
|
||||
assert getStyle("P3")._pAttr["text-align"] == ["fo", "right"] # type: ignore
|
||||
assert getStyle("P4")._pAttr["text-align"] == ["fo", "center"] # type: ignore
|
||||
assert getStyle("P5")._pAttr["margin-left"] == ["fo", "1.693cm"] # type: ignore
|
||||
assert getStyle("P6")._pAttr["margin-right"] == ["fo", "1.693cm"] # type: ignore
|
||||
|
||||
# Justified
|
||||
odt._text = (
|
||||
@@ -573,11 +591,11 @@ def testCoreToOdt_Convert(mockGUI):
|
||||
'<office:text>'
|
||||
'<text:h text:style-name="Heading_20_3" text:outline-level="3">Scene</text:h>'
|
||||
'<text:p text:style-name="Text_20_body">Regular paragraph</text:p>'
|
||||
'<text:p text:style-name="P9">with<text:line-break />break</text:p>'
|
||||
'<text:p text:style-name="P9">Left Align</text:p>'
|
||||
'<text:p text:style-name="P7">with<text:line-break />break</text:p>'
|
||||
'<text:p text:style-name="P7">Left Align</text:p>'
|
||||
'</office:text>'
|
||||
)
|
||||
assert getStyle("P9")._pAttr["text-align"] == ["fo", "left"] # type: ignore
|
||||
assert getStyle("P7")._pAttr["text-align"] == ["fo", "left"] # type: ignore
|
||||
|
||||
# Page Breaks
|
||||
odt._text = (
|
||||
@@ -593,9 +611,9 @@ def testCoreToOdt_Convert(mockGUI):
|
||||
assert odt.errData == []
|
||||
assert xmlToText(odt._xText) == (
|
||||
'<office:text>'
|
||||
'<text:h text:style-name="P2" text:outline-level="2">Chapter One</text:h>'
|
||||
'<text:h text:style-name="P8" text:outline-level="2">Chapter One</text:h>'
|
||||
'<text:p text:style-name="Text_20_body">Text</text:p>'
|
||||
'<text:h text:style-name="P2" text:outline-level="2">Chapter Two</text:h>'
|
||||
'<text:h text:style-name="P8" text:outline-level="2">Chapter Two</text:h>'
|
||||
'<text:p text:style-name="Text_20_body">Text</text:p>'
|
||||
'</office:text>'
|
||||
)
|
||||
@@ -612,12 +630,12 @@ def testCoreToOdt_Convert(mockGUI):
|
||||
assert odt.errData == []
|
||||
assert xmlToText(odt._xText) == (
|
||||
'<office:text>'
|
||||
'<text:p text:style-name="Text_20_body">Test text **<text:span text:style-name="T8">'
|
||||
'<text:p text:style-name="Text_20_body">Test text **<text:span text:style-name="T10">'
|
||||
'bold</text:span>** and more.</text:p>'
|
||||
'</office:text>'
|
||||
)
|
||||
|
||||
# END Test testCoreToOdt_Convert
|
||||
# END Test testCoreToOdt_ConvertParagraphs
|
||||
|
||||
|
||||
@pytest.mark.core
|
||||
@@ -1081,6 +1099,17 @@ def testCoreToOdt_ODTTextStyle():
|
||||
txtStyle.setFontStyle("stuff")
|
||||
assert txtStyle._tAttr["font-style"] == ["fo", None]
|
||||
|
||||
# Background Color
|
||||
assert txtStyle._tAttr["background-color"] == ["fo", None]
|
||||
txtStyle.setBackgroundColor("stuff")
|
||||
assert txtStyle._tAttr["background-color"] == ["fo", None]
|
||||
txtStyle.setBackgroundColor("012345")
|
||||
assert txtStyle._tAttr["background-color"] == ["fo", None]
|
||||
txtStyle.setBackgroundColor("#012345")
|
||||
assert txtStyle._tAttr["background-color"] == ["fo", "#012345"]
|
||||
txtStyle.setBackgroundColor("stuff")
|
||||
assert txtStyle._tAttr["background-color"] == ["fo", None]
|
||||
|
||||
# Text Position
|
||||
assert txtStyle._tAttr["text-position"] == ["style", None]
|
||||
txtStyle.setTextPosition("stuff")
|
||||
|
||||
@@ -491,6 +491,13 @@ def testGuiEditor_Actions(qtbot, nwGUI, projPath, ipsumText, mockRnd):
|
||||
assert nwGUI.docEditor.docAction(nwDocAction.UNDO) is True
|
||||
assert nwGUI.docEditor.getText() == text
|
||||
|
||||
# Mark
|
||||
nwGUI.docEditor.setCursorPosition(46)
|
||||
assert nwGUI.docEditor.docAction(nwDocAction.SC_MARK) is True
|
||||
assert nwGUI.docEditor.getText() == text.replace("consectetur", "[m]consectetur[/m]")
|
||||
assert nwGUI.docEditor.docAction(nwDocAction.UNDO) is True
|
||||
assert nwGUI.docEditor.getText() == text
|
||||
|
||||
# Superscript
|
||||
nwGUI.docEditor.setCursorPosition(46)
|
||||
assert nwGUI.docEditor.docAction(nwDocAction.SC_SUP) is True
|
||||
|
||||
Reference in New Issue
Block a user