novelWriter 2.7.4__py3-none-any.whl → 2.8b1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (196) hide show
  1. novelwriter/__init__.py +8 -7
  2. novelwriter/assets/icons/font_awesome.icons +22 -4
  3. novelwriter/assets/icons/material_filled_normal.icons +20 -2
  4. novelwriter/assets/icons/material_filled_thin.icons +20 -2
  5. novelwriter/assets/icons/material_rounded_normal.icons +20 -2
  6. novelwriter/assets/icons/material_rounded_thin.icons +20 -2
  7. novelwriter/assets/icons/material_sharp_normal.icons +20 -2
  8. novelwriter/assets/icons/material_sharp_thin.icons +20 -2
  9. novelwriter/assets/icons/remix_filled.icons +20 -2
  10. novelwriter/assets/icons/remix_outline.icons +20 -2
  11. novelwriter/assets/images/welcome.webp +0 -0
  12. novelwriter/assets/manual.pdf +0 -0
  13. novelwriter/assets/manual_fr.pdf +0 -0
  14. novelwriter/assets/sample.zip +0 -0
  15. novelwriter/assets/text/credits_en.htm +61 -11
  16. novelwriter/assets/themes/aura.conf +97 -0
  17. novelwriter/assets/themes/aura_bright.conf +95 -0
  18. novelwriter/assets/themes/aura_soft.conf +97 -0
  19. novelwriter/assets/themes/b2t_garden_dark.conf +97 -0
  20. novelwriter/assets/themes/b2t_garden_light.conf +97 -0
  21. novelwriter/assets/themes/b2t_suburb_dark.conf +97 -0
  22. novelwriter/assets/themes/b2t_suburb_light.conf +97 -0
  23. novelwriter/assets/themes/b4t_classic_o_dark.conf +97 -0
  24. novelwriter/assets/themes/b4t_classic_o_light.conf +97 -0
  25. novelwriter/assets/themes/b4t_modern_c_dark.conf +97 -0
  26. novelwriter/assets/themes/b4t_modern_c_light.conf +97 -0
  27. novelwriter/assets/themes/blue_streak_dark.conf +97 -0
  28. novelwriter/assets/themes/blue_streak_light.conf +97 -0
  29. novelwriter/assets/themes/castle_day.conf +95 -0
  30. novelwriter/assets/themes/castle_night.conf +95 -0
  31. novelwriter/assets/themes/catppuccin_latte.conf +97 -0
  32. novelwriter/assets/themes/catppuccin_mocha.conf +97 -0
  33. novelwriter/assets/themes/chalky_soil.conf +95 -0
  34. novelwriter/assets/themes/chernozem.conf +95 -0
  35. novelwriter/assets/themes/cyberpunk_night.conf +88 -40
  36. novelwriter/assets/themes/default_dark.conf +89 -41
  37. novelwriter/assets/themes/default_light.conf +89 -41
  38. novelwriter/assets/themes/dracula.conf +91 -42
  39. novelwriter/assets/themes/espresso.conf +97 -0
  40. novelwriter/assets/themes/everforest_dark.conf +97 -0
  41. novelwriter/assets/themes/everforest_light.conf +97 -0
  42. novelwriter/assets/themes/floral_daydream.conf +95 -0
  43. novelwriter/assets/themes/floral_midnight.conf +95 -0
  44. novelwriter/assets/themes/full_moon.conf +95 -0
  45. novelwriter/assets/themes/grey_dark.conf +97 -0
  46. novelwriter/assets/themes/grey_light.conf +97 -0
  47. novelwriter/assets/themes/horizon_dark.conf +97 -0
  48. novelwriter/assets/themes/horizon_light.conf +97 -0
  49. novelwriter/assets/themes/jewel_case_dark.conf +95 -0
  50. novelwriter/assets/themes/jewel_case_light.conf +95 -0
  51. novelwriter/assets/themes/lcars.conf +97 -0
  52. novelwriter/assets/themes/light_owl.conf +117 -0
  53. novelwriter/assets/themes/new_moon.conf +97 -0
  54. novelwriter/assets/themes/night_owl.conf +117 -0
  55. novelwriter/assets/themes/noctis.conf +129 -0
  56. novelwriter/assets/themes/noctis_lux.conf +129 -0
  57. novelwriter/assets/themes/nord.conf +97 -0
  58. novelwriter/assets/themes/nordlicht.conf +95 -0
  59. novelwriter/assets/themes/otium_dark.conf +95 -0
  60. novelwriter/assets/themes/otium_light.conf +95 -0
  61. novelwriter/assets/themes/paragon.conf +96 -0
  62. novelwriter/assets/themes/primer_light.conf +97 -0
  63. novelwriter/assets/themes/primer_night.conf +97 -0
  64. novelwriter/assets/themes/rose_pine.conf +97 -0
  65. novelwriter/assets/themes/rose_pine_dawn.conf +97 -0
  66. novelwriter/assets/themes/ruby_day.conf +95 -0
  67. novelwriter/assets/themes/ruby_night.conf +95 -0
  68. novelwriter/assets/themes/selenium_dark.conf +95 -0
  69. novelwriter/assets/themes/selenium_light.conf +95 -0
  70. novelwriter/assets/themes/sepia_dark.conf +95 -0
  71. novelwriter/assets/themes/sepia_light.conf +95 -0
  72. novelwriter/assets/themes/snazzy.conf +102 -40
  73. novelwriter/assets/themes/solarized_dark.conf +108 -40
  74. novelwriter/assets/themes/solarized_light.conf +108 -40
  75. novelwriter/assets/themes/sultana_light.conf +95 -0
  76. novelwriter/assets/themes/sultana_night.conf +95 -0
  77. novelwriter/assets/themes/tango_dark.conf +111 -0
  78. novelwriter/assets/themes/tango_light.conf +111 -0
  79. novelwriter/assets/themes/tomorrow.conf +117 -0
  80. novelwriter/assets/themes/tomorrow_night.conf +117 -0
  81. novelwriter/assets/themes/tomorrow_night_blue.conf +117 -0
  82. novelwriter/assets/themes/tomorrow_night_bright.conf +117 -0
  83. novelwriter/assets/themes/tomorrow_night_eighties.conf +117 -0
  84. novelwriter/assets/themes/vivid_black_green.conf +97 -0
  85. novelwriter/assets/themes/vivid_black_red.conf +97 -0
  86. novelwriter/assets/themes/vivid_white_green.conf +97 -0
  87. novelwriter/assets/themes/vivid_white_red.conf +97 -0
  88. novelwriter/assets/themes/warpgate.conf +96 -0
  89. novelwriter/assets/themes/waterlily_dark.conf +95 -0
  90. novelwriter/assets/themes/waterlily_light.conf +95 -0
  91. novelwriter/common.py +47 -17
  92. novelwriter/config.py +57 -62
  93. novelwriter/constants.py +32 -6
  94. novelwriter/core/buildsettings.py +3 -23
  95. novelwriter/core/coretools.py +21 -25
  96. novelwriter/core/docbuild.py +4 -9
  97. novelwriter/core/document.py +2 -6
  98. novelwriter/core/index.py +33 -53
  99. novelwriter/core/indexdata.py +17 -22
  100. novelwriter/core/item.py +11 -35
  101. novelwriter/core/itemmodel.py +5 -21
  102. novelwriter/core/novelmodel.py +3 -7
  103. novelwriter/core/options.py +3 -4
  104. novelwriter/core/project.py +31 -21
  105. novelwriter/core/projectdata.py +2 -21
  106. novelwriter/core/projectxml.py +13 -21
  107. novelwriter/core/sessions.py +2 -4
  108. novelwriter/core/spellcheck.py +12 -13
  109. novelwriter/core/status.py +27 -20
  110. novelwriter/core/storage.py +5 -10
  111. novelwriter/core/tree.py +6 -15
  112. novelwriter/dialogs/about.py +9 -10
  113. novelwriter/dialogs/docmerge.py +17 -14
  114. novelwriter/dialogs/docsplit.py +18 -14
  115. novelwriter/dialogs/editlabel.py +15 -9
  116. novelwriter/dialogs/preferences.py +69 -68
  117. novelwriter/dialogs/projectsettings.py +88 -67
  118. novelwriter/dialogs/quotes.py +15 -10
  119. novelwriter/dialogs/wordlist.py +18 -21
  120. novelwriter/enum.py +75 -30
  121. novelwriter/error.py +6 -11
  122. novelwriter/extensions/configlayout.py +8 -34
  123. novelwriter/extensions/eventfilters.py +3 -3
  124. novelwriter/extensions/modified.py +87 -32
  125. novelwriter/extensions/novelselector.py +13 -12
  126. novelwriter/extensions/pagedsidebar.py +10 -18
  127. novelwriter/extensions/progressbars.py +5 -11
  128. novelwriter/extensions/statusled.py +3 -6
  129. novelwriter/extensions/switch.py +8 -11
  130. novelwriter/extensions/switchbox.py +2 -11
  131. novelwriter/extensions/versioninfo.py +6 -7
  132. novelwriter/formats/shared.py +10 -2
  133. novelwriter/formats/todocx.py +15 -37
  134. novelwriter/formats/tohtml.py +52 -61
  135. novelwriter/formats/tokenizer.py +33 -64
  136. novelwriter/formats/tomarkdown.py +4 -11
  137. novelwriter/formats/toodt.py +12 -71
  138. novelwriter/formats/toqdoc.py +11 -21
  139. novelwriter/formats/toraw.py +2 -6
  140. novelwriter/gui/doceditor.py +207 -245
  141. novelwriter/gui/dochighlight.py +142 -101
  142. novelwriter/gui/docviewer.py +53 -84
  143. novelwriter/gui/docviewerpanel.py +18 -41
  144. novelwriter/gui/editordocument.py +12 -17
  145. novelwriter/gui/itemdetails.py +5 -14
  146. novelwriter/gui/mainmenu.py +24 -32
  147. novelwriter/gui/noveltree.py +13 -51
  148. novelwriter/gui/outline.py +20 -61
  149. novelwriter/gui/projtree.py +40 -96
  150. novelwriter/gui/search.py +9 -24
  151. novelwriter/gui/sidebar.py +54 -22
  152. novelwriter/gui/statusbar.py +7 -22
  153. novelwriter/gui/theme.py +482 -368
  154. novelwriter/guimain.py +87 -101
  155. novelwriter/shared.py +79 -48
  156. novelwriter/splash.py +9 -5
  157. novelwriter/text/comments.py +1 -1
  158. novelwriter/text/counting.py +9 -5
  159. novelwriter/text/patterns.py +20 -15
  160. novelwriter/tools/dictionaries.py +18 -16
  161. novelwriter/tools/lipsum.py +15 -17
  162. novelwriter/tools/manusbuild.py +25 -45
  163. novelwriter/tools/manuscript.py +94 -95
  164. novelwriter/tools/manussettings.py +149 -104
  165. novelwriter/tools/noveldetails.py +10 -24
  166. novelwriter/tools/welcome.py +24 -72
  167. novelwriter/tools/writingstats.py +17 -26
  168. novelwriter/types.py +25 -13
  169. {novelwriter-2.7.4.dist-info → novelwriter-2.8b1.dist-info}/METADATA +7 -7
  170. novelwriter-2.8b1.dist-info/RECORD +212 -0
  171. novelwriter/assets/images/welcome-dark.jpg +0 -0
  172. novelwriter/assets/images/welcome-light.jpg +0 -0
  173. novelwriter/assets/syntax/cyberpunk_night.conf +0 -28
  174. novelwriter/assets/syntax/default_dark.conf +0 -42
  175. novelwriter/assets/syntax/default_light.conf +0 -42
  176. novelwriter/assets/syntax/dracula.conf +0 -44
  177. novelwriter/assets/syntax/grey_dark.conf +0 -29
  178. novelwriter/assets/syntax/grey_light.conf +0 -29
  179. novelwriter/assets/syntax/light_owl.conf +0 -49
  180. novelwriter/assets/syntax/night_owl.conf +0 -49
  181. novelwriter/assets/syntax/snazzy.conf +0 -42
  182. novelwriter/assets/syntax/solarized_dark.conf +0 -29
  183. novelwriter/assets/syntax/solarized_light.conf +0 -29
  184. novelwriter/assets/syntax/tango.conf +0 -39
  185. novelwriter/assets/syntax/tomorrow.conf +0 -49
  186. novelwriter/assets/syntax/tomorrow_night.conf +0 -49
  187. novelwriter/assets/syntax/tomorrow_night_blue.conf +0 -49
  188. novelwriter/assets/syntax/tomorrow_night_bright.conf +0 -49
  189. novelwriter/assets/syntax/tomorrow_night_eighties.conf +0 -49
  190. novelwriter/assets/themes/default.conf +0 -3
  191. novelwriter-2.7.4.dist-info/RECORD +0 -163
  192. {novelwriter-2.7.4.dist-info → novelwriter-2.8b1.dist-info}/WHEEL +0 -0
  193. {novelwriter-2.7.4.dist-info → novelwriter-2.8b1.dist-info}/entry_points.txt +0 -0
  194. {novelwriter-2.7.4.dist-info → novelwriter-2.8b1.dist-info}/licenses/LICENSE.md +0 -0
  195. {novelwriter-2.7.4.dist-info → novelwriter-2.8b1.dist-info}/licenses/setup/LICENSE-Apache-2.0.txt +0 -0
  196. {novelwriter-2.7.4.dist-info → novelwriter-2.8b1.dist-info}/top_level.txt +0 -0
@@ -23,7 +23,7 @@ General Public License for more details.
23
23
 
24
24
  You should have received a copy of the GNU General Public License
25
25
  along with this program. If not, see <https://www.gnu.org/licenses/>.
26
- """
26
+ """ # noqa
27
27
  from __future__ import annotations
28
28
 
29
29
  import logging
@@ -40,7 +40,7 @@ from novelwriter import __version__
40
40
  from novelwriter.common import xmlElement, xmlIndent, xmlSubElem
41
41
  from novelwriter.constants import nwHeadFmt, nwStyles
42
42
  from novelwriter.formats.shared import BlockFmt, BlockTyp, TextFmt, stripEscape
43
- from novelwriter.formats.tokenizer import Tokenizer
43
+ from novelwriter.formats.tokenizer import COMMENT_BLOCKS, Tokenizer
44
44
  from novelwriter.types import FONT_STYLE, QtHexRgb
45
45
 
46
46
  if TYPE_CHECKING:
@@ -128,7 +128,7 @@ FONT_WEIGHT_MAP = {"400": "normal", "700": "bold"}
128
128
 
129
129
 
130
130
  class ToOdt(Tokenizer):
131
- """Core: Open Document Writer
131
+ """Core: Open Document Writer.
132
132
 
133
133
  Extend the Tokenizer class to writer Open Document files. The output
134
134
  should conform to the 1.3 Extended standard.
@@ -189,8 +189,6 @@ class ToOdt(Tokenizer):
189
189
  self._mDocLeft = "2.000cm"
190
190
  self._mDocRight = "2.000cm"
191
191
 
192
- return
193
-
194
192
  ##
195
193
  # Setters
196
194
  ##
@@ -205,20 +203,18 @@ class ToOdt(Tokenizer):
205
203
  self._mDocBtm = f"{bottom/10.0:.3f}cm"
206
204
  self._mDocLeft = f"{left/10.0:.3f}cm"
207
205
  self._mDocRight = f"{right/10.0:.3f}cm"
208
- return
209
206
 
210
207
  def setHeaderFormat(self, value: str, offset: int) -> None:
211
208
  """Set the document header format."""
212
209
  self._headerFormat = value.strip()
213
210
  self._pageOffset = offset
214
- return
215
211
 
216
212
  ##
217
213
  # Class Methods
218
214
  ##
219
215
 
220
216
  def initDocument(self) -> None:
221
- """Initialises a new open document XML tree."""
217
+ """Initialise a new open document XML tree."""
222
218
  super().initDocument()
223
219
 
224
220
  # Initialise Variables
@@ -325,8 +321,6 @@ class ToOdt(Tokenizer):
325
321
  self._useableStyles()
326
322
  self._writeHeader()
327
323
 
328
- return
329
-
330
324
  def doConvert(self) -> None:
331
325
  """Convert the list of text tokens into XML elements."""
332
326
  xText = self._xText
@@ -389,14 +383,12 @@ class ToOdt(Tokenizer):
389
383
  elif tType == BlockTyp.SKIP:
390
384
  self._addTextPar(xText, S_TEXT, oStyle, "")
391
385
 
392
- elif tType == BlockTyp.COMMENT:
386
+ elif tType in COMMENT_BLOCKS:
393
387
  self._addTextPar(xText, S_META, oStyle, tText, tFmt=tFormat)
394
388
 
395
389
  elif tType == BlockTyp.KEYWORD:
396
390
  self._addTextPar(xText, S_META, oStyle, tText, tFmt=tFormat)
397
391
 
398
- return
399
-
400
392
  def closeDocument(self) -> None:
401
393
  """Add additional collected information to the XML."""
402
394
  for style in self._autoPara.values():
@@ -412,7 +404,6 @@ class ToOdt(Tokenizer):
412
404
  _mkTag("text", "name"): f"Manuscript{key[:1].upper()}{key[1:]}",
413
405
  })
414
406
  self._xText.insert(0, xFields)
415
- return
416
407
 
417
408
  def saveDocument(self, path: Path) -> None:
418
409
  """Save the data to an .fodt or .odt file."""
@@ -456,8 +447,6 @@ class ToOdt(Tokenizer):
456
447
 
457
448
  logger.info("Wrote file: %s", path)
458
449
 
459
- return
460
-
461
450
  ##
462
451
  # Internal Functions
463
452
  ##
@@ -670,7 +659,7 @@ class ToOdt(Tokenizer):
670
659
  return None
671
660
 
672
661
  def _emToCm(self, value: float) -> str:
673
- """Converts an em value to centimetres."""
662
+ """Convert an em value to centimetres."""
674
663
  return f"{value*self._fontSize*2.54/72.0:.3f}cm"
675
664
 
676
665
  def _emToPt(self, scale: float) -> str:
@@ -705,8 +694,6 @@ class ToOdt(Tokenizer):
705
694
  _mkTag("fo", "margin-bottom"): self._emToCm(0.5),
706
695
  })
707
696
 
708
- return
709
-
710
697
  def _defaultStyles(self) -> None:
711
698
  """Set the default styles."""
712
699
  hScale = self._scaleHeads
@@ -783,8 +770,6 @@ class ToOdt(Tokenizer):
783
770
  _mkTag("number", "min-integer-digits"): "1",
784
771
  })
785
772
 
786
- return
787
-
788
773
  def _useableStyles(self) -> None:
789
774
  """Set the usable styles."""
790
775
  hScale = self._scaleHeads
@@ -954,8 +939,6 @@ class ToOdt(Tokenizer):
954
939
  style.packXML(self._xStyl)
955
940
  self._mainPara[style.name] = style
956
941
 
957
- return
958
-
959
942
  def _writeHeader(self) -> None:
960
943
  """Write the header elements."""
961
944
  xPage = ET.SubElement(self._xMast, _mkTag("style", "master-page"), attrib={
@@ -993,8 +976,6 @@ class ToOdt(Tokenizer):
993
976
  _mkTag("text", "style-name"): "Header"
994
977
  })
995
978
 
996
- return
997
-
998
979
 
999
980
  # Auto-Style Classes
1000
981
  # ==================
@@ -1004,6 +985,7 @@ class ODTParagraphStyle:
1004
985
  exporter. Only the used settings are exposed here to keep the class
1005
986
  minimal and fast.
1006
987
  """
988
+
1007
989
  VALID_ALIGN: Final[list[str]] = ["start", "center", "end", "justify", "left", "right"]
1008
990
  VALID_BREAK: Final[list[str]] = ["auto", "page", "even-page", "odd-page", "inherit"]
1009
991
  VALID_LEVEL: Final[list[str]] = ["1", "2", "3", "4"]
@@ -1046,8 +1028,6 @@ class ODTParagraphStyle:
1046
1028
  "opacity": ["loext", None],
1047
1029
  }
1048
1030
 
1049
- return
1050
-
1051
1031
  @property
1052
1032
  def name(self) -> str:
1053
1033
  return self._name
@@ -1059,7 +1039,6 @@ class ODTParagraphStyle:
1059
1039
  def setName(self, name: str) -> None:
1060
1040
  """Set the paragraph style name."""
1061
1041
  self._name = name
1062
- return
1063
1042
 
1064
1043
  ##
1065
1044
  # Attribute Setters
@@ -1068,17 +1047,14 @@ class ODTParagraphStyle:
1068
1047
  def setDisplayName(self, value: str | None) -> None:
1069
1048
  """Set style display name."""
1070
1049
  self._mAttr["display-name"][1] = value
1071
- return
1072
1050
 
1073
1051
  def setParentStyleName(self, value: str | None) -> None:
1074
1052
  """Set parent style name."""
1075
1053
  self._mAttr["parent-style-name"][1] = value
1076
- return
1077
1054
 
1078
1055
  def setNextStyleName(self, value: str | None) -> None:
1079
1056
  """Set next style name."""
1080
1057
  self._mAttr["next-style-name"][1] = value
1081
- return
1082
1058
 
1083
1059
  def setOutlineLevel(self, value: str | None) -> None:
1084
1060
  """Set paragraph outline level."""
@@ -1086,7 +1062,6 @@ class ODTParagraphStyle:
1086
1062
  self._mAttr["default-outline-level"][1] = value
1087
1063
  else:
1088
1064
  self._mAttr["default-outline-level"][1] = None
1089
- return
1090
1065
 
1091
1066
  def setClass(self, value: str | None) -> None:
1092
1067
  """Set paragraph class."""
@@ -1094,7 +1069,6 @@ class ODTParagraphStyle:
1094
1069
  self._mAttr["class"][1] = value
1095
1070
  else:
1096
1071
  self._mAttr["class"][1] = None
1097
- return
1098
1072
 
1099
1073
  ##
1100
1074
  # Paragraph Setters
@@ -1103,32 +1077,26 @@ class ODTParagraphStyle:
1103
1077
  def setMarginTop(self, value: str | None) -> None:
1104
1078
  """Set paragraph top margin."""
1105
1079
  self._pAttr["margin-top"][1] = value
1106
- return
1107
1080
 
1108
1081
  def setMarginBottom(self, value: str | None) -> None:
1109
1082
  """Set paragraph bottom margin."""
1110
1083
  self._pAttr["margin-bottom"][1] = value
1111
- return
1112
1084
 
1113
1085
  def setMarginLeft(self, value: str | None) -> None:
1114
1086
  """Set paragraph left margin."""
1115
1087
  self._pAttr["margin-left"][1] = value
1116
- return
1117
1088
 
1118
1089
  def setMarginRight(self, value: str | None) -> None:
1119
1090
  """Set paragraph right margin."""
1120
1091
  self._pAttr["margin-right"][1] = value
1121
- return
1122
1092
 
1123
1093
  def setTextIndent(self, value: str | None) -> None:
1124
1094
  """Set text indentation."""
1125
1095
  self._pAttr["text-indent"][1] = value
1126
- return
1127
1096
 
1128
1097
  def setLineHeight(self, value: str | None) -> None:
1129
1098
  """Set line height."""
1130
1099
  self._pAttr["line-height"][1] = value
1131
- return
1132
1100
 
1133
1101
  def setTextAlign(self, value: str | None) -> None:
1134
1102
  """Set paragraph text alignment."""
@@ -1136,7 +1104,6 @@ class ODTParagraphStyle:
1136
1104
  self._pAttr["text-align"][1] = value
1137
1105
  else:
1138
1106
  self._pAttr["text-align"][1] = None
1139
- return
1140
1107
 
1141
1108
  def setBreakBefore(self, value: str | None) -> None:
1142
1109
  """Set page break before policy."""
@@ -1144,7 +1111,6 @@ class ODTParagraphStyle:
1144
1111
  self._pAttr["break-before"][1] = value
1145
1112
  else:
1146
1113
  self._pAttr["break-before"][1] = None
1147
- return
1148
1114
 
1149
1115
  def setBreakAfter(self, value: str | None) -> None:
1150
1116
  """Set page break after policy."""
@@ -1152,7 +1118,6 @@ class ODTParagraphStyle:
1152
1118
  self._pAttr["break-after"][1] = value
1153
1119
  else:
1154
1120
  self._pAttr["break-after"][1] = None
1155
- return
1156
1121
 
1157
1122
  ##
1158
1123
  # Text Setters
@@ -1161,17 +1126,14 @@ class ODTParagraphStyle:
1161
1126
  def setFontName(self, value: str | None) -> None:
1162
1127
  """Set font name."""
1163
1128
  self._tAttr["font-name"][1] = value
1164
- return
1165
1129
 
1166
1130
  def setFontFamily(self, value: str | None) -> None:
1167
1131
  """Set font family."""
1168
1132
  self._tAttr["font-family"][1] = value
1169
- return
1170
1133
 
1171
1134
  def setFontSize(self, value: str | None) -> None:
1172
1135
  """Set font size."""
1173
1136
  self._tAttr["font-size"][1] = value
1174
- return
1175
1137
 
1176
1138
  def setFontWeight(self, value: str | None) -> None:
1177
1139
  """Set font weight."""
@@ -1179,7 +1141,6 @@ class ODTParagraphStyle:
1179
1141
  self._tAttr["font-weight"][1] = value
1180
1142
  else:
1181
1143
  self._tAttr["font-weight"][1] = None
1182
- return
1183
1144
 
1184
1145
  def setColor(self, value: QColor | None) -> None:
1185
1146
  """Set text colour."""
@@ -1189,7 +1150,6 @@ class ODTParagraphStyle:
1189
1150
  else:
1190
1151
  self._tAttr["color"][1] = None
1191
1152
  self._tAttr["opacity"][1] = None
1192
- return
1193
1153
 
1194
1154
  ##
1195
1155
  # Methods
@@ -1233,14 +1193,13 @@ class ODTParagraphStyle:
1233
1193
  if attr := {_mkTag(n, m): v for m, (n, v) in self._tAttr.items() if v}:
1234
1194
  ET.SubElement(xEntry, _mkTag("style", "text-properties"), attrib=attr)
1235
1195
 
1236
- return
1237
-
1238
1196
 
1239
1197
  class ODTTextStyle:
1240
1198
  """Wrapper class for the text style setting used by the exporter.
1241
1199
  Only the used settings are exposed here to keep the class minimal
1242
1200
  and fast.
1243
1201
  """
1202
+
1244
1203
  VALID_WEIGHT: Final[list[str]] = ["normal", "bold", *FONT_WEIGHT_NUM]
1245
1204
  VALID_STYLE: Final[list[str]] = ["normal", "italic", "oblique"]
1246
1205
  VALID_POS: Final[list[str]] = ["super", "sub"]
@@ -1263,7 +1222,6 @@ class ODTTextStyle:
1263
1222
  "text-underline-width": ["style", None],
1264
1223
  "text-underline-color": ["style", None],
1265
1224
  }
1266
- return
1267
1225
 
1268
1226
  @property
1269
1227
  def name(self) -> str:
@@ -1279,7 +1237,6 @@ class ODTTextStyle:
1279
1237
  self._tAttr["font-weight"][1] = value
1280
1238
  else:
1281
1239
  self._tAttr["font-weight"][1] = None
1282
- return
1283
1240
 
1284
1241
  def setFontStyle(self, value: str | None) -> None:
1285
1242
  """Set text font style."""
@@ -1287,7 +1244,6 @@ class ODTTextStyle:
1287
1244
  self._tAttr["font-style"][1] = value
1288
1245
  else:
1289
1246
  self._tAttr["font-style"][1] = None
1290
- return
1291
1247
 
1292
1248
  def setColor(self, value: QColor | None) -> None:
1293
1249
  """Set text colour."""
@@ -1295,7 +1251,6 @@ class ODTTextStyle:
1295
1251
  self._tAttr["color"][1] = value.name(QtHexRgb)
1296
1252
  else:
1297
1253
  self._tAttr["color"][1] = None
1298
- return
1299
1254
 
1300
1255
  def setBackgroundColor(self, value: QColor | None) -> None:
1301
1256
  """Set text background colour."""
@@ -1303,7 +1258,6 @@ class ODTTextStyle:
1303
1258
  self._tAttr["background-color"][1] = value.name(QtHexRgb)
1304
1259
  else:
1305
1260
  self._tAttr["background-color"][1] = None
1306
- return
1307
1261
 
1308
1262
  def setTextPosition(self, value: str | None) -> None:
1309
1263
  """Set text vertical position."""
@@ -1311,7 +1265,6 @@ class ODTTextStyle:
1311
1265
  self._tAttr["text-position"][1] = f"{value} 58%"
1312
1266
  else:
1313
1267
  self._tAttr["text-position"][1] = None
1314
- return
1315
1268
 
1316
1269
  def setStrikeStyle(self, value: str | None) -> None:
1317
1270
  """Set text line-trough style."""
@@ -1319,7 +1272,6 @@ class ODTTextStyle:
1319
1272
  self._tAttr["text-line-through-style"][1] = value
1320
1273
  else:
1321
1274
  self._tAttr["text-line-through-style"][1] = None
1322
- return
1323
1275
 
1324
1276
  def setStrikeType(self, value: str | None) -> None:
1325
1277
  """Set text line-through type."""
@@ -1327,7 +1279,6 @@ class ODTTextStyle:
1327
1279
  self._tAttr["text-line-through-type"][1] = value
1328
1280
  else:
1329
1281
  self._tAttr["text-line-through-type"][1] = None
1330
- return
1331
1282
 
1332
1283
  def setUnderlineStyle(self, value: str | None) -> None:
1333
1284
  """Set text underline style."""
@@ -1335,7 +1286,6 @@ class ODTTextStyle:
1335
1286
  self._tAttr["text-underline-style"][1] = value
1336
1287
  else:
1337
1288
  self._tAttr["text-underline-style"][1] = None
1338
- return
1339
1289
 
1340
1290
  def setUnderlineWidth(self, value: str | None) -> None:
1341
1291
  """Set text underline width."""
@@ -1343,7 +1293,6 @@ class ODTTextStyle:
1343
1293
  self._tAttr["text-underline-width"][1] = value
1344
1294
  else:
1345
1295
  self._tAttr["text-underline-width"][1] = None
1346
- return
1347
1296
 
1348
1297
  def setUnderlineColor(self, value: str | None) -> None:
1349
1298
  """Set text underline colour."""
@@ -1351,7 +1300,6 @@ class ODTTextStyle:
1351
1300
  self._tAttr["text-underline-color"][1] = value
1352
1301
  else:
1353
1302
  self._tAttr["text-underline-color"][1] = None
1354
- return
1355
1303
 
1356
1304
  ##
1357
1305
  # Methods
@@ -1365,7 +1313,6 @@ class ODTTextStyle:
1365
1313
  })
1366
1314
  if attr := {_mkTag(n, m): v for m, (n, v) in self._tAttr.items() if v}:
1367
1315
  ET.SubElement(xEntry, _mkTag("style", "text-properties"), attrib=attr)
1368
- return
1369
1316
 
1370
1317
 
1371
1318
  # XML Complex Element Helper Class
@@ -1378,7 +1325,9 @@ X_SPAN_SING = 3
1378
1325
 
1379
1326
 
1380
1327
  class XMLParagraph:
1381
- """This is a helper class to manage the text content of a single
1328
+ """ODT Text Paragraph.
1329
+
1330
+ This is a helper class to manage the text content of a single
1382
1331
  XML element using mixed content tags.
1383
1332
 
1384
1333
  Rules:
@@ -1408,8 +1357,6 @@ class XMLParagraph:
1408
1357
  self._rawTxt = ""
1409
1358
  self._xRoot.text = ""
1410
1359
 
1411
- return
1412
-
1413
1360
  def appendText(self, text: str) -> None:
1414
1361
  """Append text to the XML element. We do this one character at
1415
1362
  the time in order to be able to process line breaks, tabs and
@@ -1424,7 +1371,7 @@ class XMLParagraph:
1424
1371
  if c == " ":
1425
1372
  nSpaces += 1
1426
1373
  continue
1427
- elif nSpaces > 0:
1374
+ if nSpaces > 0:
1428
1375
  self._processSpaces(nSpaces)
1429
1376
  nSpaces = 0
1430
1377
 
@@ -1468,8 +1415,6 @@ class XMLParagraph:
1468
1415
  # Handle trailing spaces
1469
1416
  self._processSpaces(nSpaces)
1470
1417
 
1471
- return
1472
-
1473
1418
  def appendSpan(self, text: str, style: str, link: str) -> None:
1474
1419
  """Append a text span to the XML element. The span is always
1475
1420
  closed since we do not produce nested spans (like Libre Office).
@@ -1491,7 +1436,6 @@ class XMLParagraph:
1491
1436
  self._nState = X_SPAN_TEXT
1492
1437
  self.appendText(text)
1493
1438
  self._nState = X_ROOT_TAIL
1494
- return
1495
1439
 
1496
1440
  def appendNode(self, xNode: ET.Element | None) -> None:
1497
1441
  """Append an XML node to the paragraph. We only check for the
@@ -1504,7 +1448,6 @@ class XMLParagraph:
1504
1448
  self._xTail = xNode
1505
1449
  self._xTail.tail = ""
1506
1450
  self._nState = X_ROOT_TAIL
1507
- return
1508
1451
 
1509
1452
  def checkError(self) -> tuple[int, str]:
1510
1453
  """Check that the number of characters written matches the
@@ -1575,5 +1518,3 @@ class XMLParagraph:
1575
1518
  self._xSing.tail = ""
1576
1519
  self._nState = X_SPAN_SING
1577
1520
  self._chrPos += nSpaces - 1
1578
-
1579
- return
@@ -20,7 +20,7 @@ General Public License for more details.
20
20
 
21
21
  You should have received a copy of the GNU General Public License
22
22
  along with this program. If not, see <https://www.gnu.org/licenses/>.
23
- """
23
+ """ # noqa
24
24
  from __future__ import annotations
25
25
 
26
26
  import logging
@@ -37,7 +37,7 @@ from PyQt6.QtPrintSupport import QPrinter
37
37
  from novelwriter import __version__
38
38
  from novelwriter.constants import nwStyles, nwUnicode
39
39
  from novelwriter.formats.shared import BlockFmt, BlockTyp, T_Formats, TextFmt, stripEscape
40
- from novelwriter.formats.tokenizer import HEADINGS, Tokenizer
40
+ from novelwriter.formats.tokenizer import HEADING_BLOCKS, META_BLOCKS, Tokenizer
41
41
  from novelwriter.types import (
42
42
  QtAlignAbsolute, QtAlignCenter, QtAlignJustify, QtAlignLeft, QtAlignRight,
43
43
  QtKeepAnchor, QtMoveAnchor, QtPageBreakAfter, QtPageBreakAuto,
@@ -56,6 +56,7 @@ T_TextStyle = tuple[QTextBlockFormat, QTextCharFormat]
56
56
 
57
57
 
58
58
  def newBlock(cursor: QTextCursor, bFmt: QTextBlockFormat) -> None:
59
+ """Insert a new block if not at the beginning of the document."""
59
60
  if cursor.position() > 0:
60
61
  cursor.insertBlock(bFmt)
61
62
  else:
@@ -63,7 +64,7 @@ def newBlock(cursor: QTextCursor, bFmt: QTextBlockFormat) -> None:
63
64
 
64
65
 
65
66
  class ToQTextDocument(Tokenizer):
66
- """Core: QTextDocument Writer
67
+ """Core: QTextDocument Writer.
67
68
 
68
69
  Extend the Tokenizer class to generate a QTextDocument output. This
69
70
  is intended for usage in the document viewer and build tool preview.
@@ -92,8 +93,6 @@ class ToQTextDocument(Tokenizer):
92
93
  self._pageSize = QPageSize(QPageSize.PageSizeId.A4)
93
94
  self._pageMargins = QMarginsF(20.0, 20.0, 20.0, 20.0)
94
95
 
95
- return
96
-
97
96
  ##
98
97
  # Properties
99
98
  ##
@@ -113,17 +112,14 @@ class ToQTextDocument(Tokenizer):
113
112
  """Set the document page size and margins in millimetres."""
114
113
  self._pageSize = QPageSize(QSizeF(width, height), QPageSize.Unit.Millimeter)
115
114
  self._pageMargins = QMarginsF(left, top, right, bottom)
116
- return
117
115
 
118
116
  def setShowNewPage(self, state: bool) -> None:
119
117
  """Add markers for page breaks."""
120
118
  self._newPage = state
121
- return
122
119
 
123
120
  def disableAnchors(self) -> None:
124
121
  """Disable anchors for when writing to file."""
125
122
  self._anchors = False
126
- return
127
123
 
128
124
  ##
129
125
  # Class Methods
@@ -200,8 +196,6 @@ class ToQTextDocument(Tokenizer):
200
196
 
201
197
  self._init = True
202
198
 
203
- return
204
-
205
199
  def doConvert(self) -> None:
206
200
  """Write text tokens into the document."""
207
201
  if not self._init:
@@ -214,7 +208,7 @@ class ToQTextDocument(Tokenizer):
214
208
  for tType, tMeta, tText, tFormat, tStyle in self._blocks:
215
209
 
216
210
  bFmt = QTextBlockFormat(self._blockFmt)
217
- if tType in (BlockTyp.COMMENT, BlockTyp.KEYWORD):
211
+ if tType in META_BLOCKS:
218
212
  bFmt.setTopMargin(self._mMeta[0])
219
213
  bFmt.setBottomMargin(self._mMeta[1])
220
214
  elif tType == BlockTyp.SEP:
@@ -248,17 +242,21 @@ class ToQTextDocument(Tokenizer):
248
242
  if tStyle & BlockFmt.IND_T:
249
243
  bFmt.setTextIndent(self._tIndent)
250
244
 
251
- if tType in (BlockTyp.TEXT, BlockTyp.COMMENT, BlockTyp.KEYWORD):
245
+ if tType == BlockTyp.TEXT:
252
246
  newBlock(cursor, bFmt)
253
247
  self._insertFragments(tText, tFormat, cursor, self._charFmt)
254
248
 
255
- elif tType in HEADINGS:
249
+ elif tType in HEADING_BLOCKS:
256
250
  bFmt, cFmt = self._genHeadStyle(tType, tMeta, bFmt)
257
251
  for tPart in tText.split("\n"):
258
252
  newBlock(cursor, bFmt)
259
253
  cursor.insertText(tPart, cFmt)
260
254
  bFmt.setPageBreakPolicy(QtPageBreakAuto)
261
255
 
256
+ elif tType in META_BLOCKS:
257
+ newBlock(cursor, bFmt)
258
+ self._insertFragments(tText, tFormat, cursor, self._charFmt)
259
+
262
260
  elif tType == BlockTyp.SEP:
263
261
  newBlock(cursor, bFmt)
264
262
  cursor.insertText(tText, self._charFmt)
@@ -293,8 +291,6 @@ class ToQTextDocument(Tokenizer):
293
291
  self._document.setPageSize(printer.pageRect(QPrinter.Unit.DevicePixel).size())
294
292
  self._document.print(printer)
295
293
 
296
- return
297
-
298
294
  def closeDocument(self) -> None:
299
295
  """Run close document tasks."""
300
296
  self._document.blockSignals(True)
@@ -329,8 +325,6 @@ class ToQTextDocument(Tokenizer):
329
325
 
330
326
  self._document.blockSignals(False)
331
327
 
332
- return
333
-
334
328
  ##
335
329
  # Internal Functions
336
330
  ##
@@ -435,8 +429,6 @@ class ToQTextDocument(Tokenizer):
435
429
  # Insert whatever is left in the buffer
436
430
  cursor.insertText(stripEscape(temp[start:]), cFmt)
437
431
 
438
- return
439
-
440
432
  def _insertNewPageMarker(self, cursor: QTextCursor) -> None:
441
433
  """Insert a new page marker."""
442
434
  if self._newPage:
@@ -471,8 +463,6 @@ class ToQTextDocument(Tokenizer):
471
463
  if root := self._document.rootFrame():
472
464
  cursor.swap(root.lastCursorPosition())
473
465
 
474
- return
475
-
476
466
  def _genHeadStyle(self, hType: BlockTyp, hKey: str, rFmt: QTextBlockFormat) -> T_TextStyle:
477
467
  """Generate a heading style set."""
478
468
  mTop, mBottom = self._mHead.get(hType, (0.0, 0.0))
@@ -20,7 +20,7 @@ General Public License for more details.
20
20
 
21
21
  You should have received a copy of the GNU General Public License
22
22
  along with this program. If not, see <https://www.gnu.org/licenses/>.
23
- """
23
+ """ # noqa
24
24
  from __future__ import annotations
25
25
 
26
26
  import json
@@ -41,7 +41,7 @@ logger = logging.getLogger(__name__)
41
41
 
42
42
 
43
43
  class ToRaw(Tokenizer):
44
- """Core: Raw novelWriter Text Writer
44
+ """Core: Raw novelWriter Text Writer.
45
45
 
46
46
  A class that will collect the minimally altered original source text
47
47
  and write it to either a text or JSON file.
@@ -51,7 +51,6 @@ class ToRaw(Tokenizer):
51
51
  super().__init__(project)
52
52
  self._keepRaw = True
53
53
  self._noTokens = True
54
- return
55
54
 
56
55
  def doConvert(self) -> None:
57
56
  """No conversion to perform."""
@@ -86,10 +85,7 @@ class ToRaw(Tokenizer):
86
85
 
87
86
  logger.info("Wrote file: %s", path)
88
87
 
89
- return
90
-
91
88
  def replaceTabs(self, nSpaces: int = 8, spaceChar: str = " ") -> None:
92
89
  """Replace tabs with spaces."""
93
90
  spaces = spaceChar*nSpaces
94
91
  self._raw = [p.replace("\t", spaces) for p in self._raw]
95
- return