novelWriter 2.3rc1__py3-none-any.whl → 2.4__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 (125) hide show
  1. {novelWriter-2.3rc1.dist-info → novelWriter-2.4.dist-info}/METADATA +5 -6
  2. {novelWriter-2.3rc1.dist-info → novelWriter-2.4.dist-info}/RECORD +119 -109
  3. {novelWriter-2.3rc1.dist-info → novelWriter-2.4.dist-info}/WHEEL +1 -1
  4. novelWriter-2.4.dist-info/entry_points.txt +2 -0
  5. novelwriter/__init__.py +17 -10
  6. novelwriter/assets/i18n/nw_de_DE.qm +0 -0
  7. novelwriter/assets/i18n/nw_en_US.qm +0 -0
  8. novelwriter/assets/i18n/nw_es_419.qm +0 -0
  9. novelwriter/assets/i18n/nw_fr_FR.qm +0 -0
  10. novelwriter/assets/i18n/nw_it_IT.qm +0 -0
  11. novelwriter/assets/i18n/nw_ja_JP.qm +0 -0
  12. novelwriter/assets/i18n/nw_nb_NO.qm +0 -0
  13. novelwriter/assets/i18n/nw_nl_NL.qm +0 -0
  14. novelwriter/assets/i18n/nw_pt_BR.qm +0 -0
  15. novelwriter/assets/i18n/nw_zh_CN.qm +0 -0
  16. novelwriter/assets/i18n/project_nl_NL.json +11 -0
  17. novelwriter/assets/i18n/project_pt_BR.json +11 -0
  18. novelwriter/assets/icons/none.svg +4 -0
  19. novelwriter/assets/icons/typicons_dark/icons.conf +4 -0
  20. novelwriter/assets/icons/typicons_dark/nw_tb-mark.svg +7 -0
  21. novelwriter/assets/icons/typicons_dark/typ_refresh-flipped.svg +1 -1
  22. novelwriter/assets/icons/typicons_dark/typ_refresh.svg +1 -1
  23. novelwriter/assets/icons/typicons_dark/typ_search-grey.svg +4 -0
  24. novelwriter/assets/icons/typicons_dark/typ_times.svg +1 -1
  25. novelwriter/assets/icons/typicons_dark/typ_unfold-hidden.svg +4 -0
  26. novelwriter/assets/icons/typicons_dark/typ_unfold-visible.svg +4 -0
  27. novelwriter/assets/icons/typicons_light/icons.conf +4 -0
  28. novelwriter/assets/icons/typicons_light/nw_tb-mark.svg +7 -0
  29. novelwriter/assets/icons/typicons_light/typ_refresh-flipped.svg +1 -1
  30. novelwriter/assets/icons/typicons_light/typ_refresh.svg +1 -1
  31. novelwriter/assets/icons/typicons_light/typ_search-grey.svg +4 -0
  32. novelwriter/assets/icons/typicons_light/typ_times.svg +1 -1
  33. novelwriter/assets/icons/typicons_light/typ_unfold-hidden.svg +4 -0
  34. novelwriter/assets/icons/typicons_light/typ_unfold-visible.svg +4 -0
  35. novelwriter/assets/manual.pdf +0 -0
  36. novelwriter/assets/sample.zip +0 -0
  37. novelwriter/assets/syntax/cyberpunk_night.conf +26 -0
  38. novelwriter/assets/syntax/default_dark.conf +1 -0
  39. novelwriter/assets/syntax/default_light.conf +1 -0
  40. novelwriter/assets/syntax/grey_dark.conf +1 -0
  41. novelwriter/assets/syntax/grey_light.conf +1 -0
  42. novelwriter/assets/syntax/light_owl.conf +1 -0
  43. novelwriter/assets/syntax/night_owl.conf +1 -0
  44. novelwriter/assets/syntax/solarized_dark.conf +1 -0
  45. novelwriter/assets/syntax/solarized_light.conf +1 -0
  46. novelwriter/assets/syntax/tango.conf +23 -0
  47. novelwriter/assets/syntax/tomorrow.conf +1 -0
  48. novelwriter/assets/syntax/tomorrow_night.conf +1 -0
  49. novelwriter/assets/syntax/tomorrow_night_blue.conf +1 -0
  50. novelwriter/assets/syntax/tomorrow_night_bright.conf +1 -0
  51. novelwriter/assets/syntax/tomorrow_night_eighties.conf +1 -0
  52. novelwriter/assets/text/credits_en.htm +25 -23
  53. novelwriter/assets/themes/cyberpunk_night.conf +29 -0
  54. novelwriter/common.py +12 -4
  55. novelwriter/config.py +47 -16
  56. novelwriter/constants.py +5 -6
  57. novelwriter/core/buildsettings.py +64 -44
  58. novelwriter/core/coretools.py +97 -13
  59. novelwriter/core/docbuild.py +74 -7
  60. novelwriter/core/document.py +24 -3
  61. novelwriter/core/index.py +31 -112
  62. novelwriter/core/project.py +11 -15
  63. novelwriter/core/projectxml.py +3 -2
  64. novelwriter/core/sessions.py +2 -2
  65. novelwriter/core/spellcheck.py +3 -3
  66. novelwriter/core/status.py +6 -5
  67. novelwriter/core/storage.py +16 -6
  68. novelwriter/core/tohtml.py +22 -25
  69. novelwriter/core/tokenizer.py +417 -237
  70. novelwriter/core/tomd.py +17 -8
  71. novelwriter/core/toodt.py +386 -351
  72. novelwriter/core/tree.py +8 -8
  73. novelwriter/dialogs/about.py +10 -12
  74. novelwriter/dialogs/docmerge.py +17 -14
  75. novelwriter/dialogs/docsplit.py +20 -19
  76. novelwriter/dialogs/editlabel.py +5 -4
  77. novelwriter/dialogs/preferences.py +32 -40
  78. novelwriter/dialogs/projectsettings.py +31 -28
  79. novelwriter/dialogs/quotes.py +10 -9
  80. novelwriter/dialogs/wordlist.py +18 -15
  81. novelwriter/enum.py +17 -14
  82. novelwriter/error.py +14 -12
  83. novelwriter/extensions/circularprogress.py +12 -8
  84. novelwriter/extensions/configlayout.py +23 -3
  85. novelwriter/extensions/modified.py +51 -2
  86. novelwriter/extensions/pagedsidebar.py +16 -14
  87. novelwriter/extensions/simpleprogress.py +3 -1
  88. novelwriter/extensions/statusled.py +3 -1
  89. novelwriter/extensions/switch.py +10 -9
  90. novelwriter/extensions/switchbox.py +14 -13
  91. novelwriter/extensions/versioninfo.py +1 -1
  92. novelwriter/gui/doceditor.py +433 -496
  93. novelwriter/gui/dochighlight.py +54 -33
  94. novelwriter/gui/docviewer.py +162 -175
  95. novelwriter/gui/docviewerpanel.py +20 -37
  96. novelwriter/gui/editordocument.py +15 -4
  97. novelwriter/gui/itemdetails.py +51 -54
  98. novelwriter/gui/mainmenu.py +37 -17
  99. novelwriter/gui/noveltree.py +31 -37
  100. novelwriter/gui/outline.py +120 -98
  101. novelwriter/gui/projtree.py +114 -112
  102. novelwriter/gui/search.py +362 -0
  103. novelwriter/gui/sidebar.py +36 -45
  104. novelwriter/gui/statusbar.py +14 -14
  105. novelwriter/gui/theme.py +116 -34
  106. novelwriter/guimain.py +216 -207
  107. novelwriter/shared.py +31 -6
  108. novelwriter/text/counting.py +138 -0
  109. novelwriter/tools/dictionaries.py +15 -14
  110. novelwriter/tools/lipsum.py +20 -17
  111. novelwriter/tools/manusbuild.py +43 -35
  112. novelwriter/tools/manuscript.py +381 -104
  113. novelwriter/tools/manussettings.py +263 -125
  114. novelwriter/tools/noveldetails.py +21 -19
  115. novelwriter/tools/welcome.py +59 -57
  116. novelwriter/tools/writingstats.py +61 -55
  117. novelwriter/types.py +90 -0
  118. novelWriter-2.3rc1.dist-info/entry_points.txt +0 -5
  119. novelwriter/core/__init__.py +0 -3
  120. novelwriter/dialogs/__init__.py +0 -3
  121. novelwriter/extensions/__init__.py +0 -3
  122. novelwriter/gui/__init__.py +0 -3
  123. novelwriter/tools/__init__.py +0 -3
  124. {novelWriter-2.3rc1.dist-info → novelWriter-2.4.dist-info}/LICENSE.md +0 -0
  125. {novelWriter-2.3rc1.dist-info → novelWriter-2.4.dist-info}/top_level.txt +0 -0
@@ -44,16 +44,21 @@ logger = logging.getLogger(__name__)
44
44
 
45
45
  SPELLRX = QRegularExpression(r"\b[^\s\-\+\/–—\[\]:]+\b")
46
46
  SPELLRX.setPatternOptions(QRegularExpression.UseUnicodePropertiesOption)
47
+ SPELLSC = QRegularExpression(nwRegEx.FMT_SC)
48
+ SPELLSC.setPatternOptions(QRegularExpression.UseUnicodePropertiesOption)
49
+ SPELLSV = QRegularExpression(nwRegEx.FMT_SV)
50
+ SPELLSV.setPatternOptions(QRegularExpression.UseUnicodePropertiesOption)
47
51
 
52
+ BLOCK_NONE = 0
53
+ BLOCK_TEXT = 1
54
+ BLOCK_META = 2
55
+ BLOCK_TITLE = 4
48
56
 
49
- class GuiDocHighlighter(QSyntaxHighlighter):
50
57
 
51
- __slots__ = ("_tItem", "_tHandle", "_spellCheck", "_spellErr", "_hRules", "_hStyles")
58
+ class GuiDocHighlighter(QSyntaxHighlighter):
52
59
 
53
- BLOCK_NONE = 0
54
- BLOCK_TEXT = 1
55
- BLOCK_META = 2
56
- BLOCK_TITLE = 4
60
+ __slots__ = ("_tHandle", "_isInactive", "_spellCheck", "_spellErr",
61
+ "_hRules", "_hStyles", "_rxRules")
57
62
 
58
63
  def __init__(self, document: QTextDocument) -> None:
59
64
  super().__init__(document)
@@ -67,6 +72,7 @@ class GuiDocHighlighter(QSyntaxHighlighter):
67
72
 
68
73
  self._hRules: list[tuple[str, dict]] = []
69
74
  self._hStyles: dict[str, QTextCharFormat] = {}
75
+ self._rxRules: list[tuple[QRegularExpression, dict[str, QTextCharFormat]]] = []
70
76
 
71
77
  self.initHighlighter()
72
78
 
@@ -90,10 +96,10 @@ class GuiDocHighlighter(QSyntaxHighlighter):
90
96
  "header2": self._makeFormat(SHARED.theme.colHead, "bold", 1.6),
91
97
  "header3": self._makeFormat(SHARED.theme.colHead, "bold", 1.4),
92
98
  "header4": self._makeFormat(SHARED.theme.colHead, "bold", 1.2),
93
- "header1h": self._makeFormat(SHARED.theme.colHeadH, "bold", 1.8),
94
- "header2h": self._makeFormat(SHARED.theme.colHeadH, "bold", 1.6),
95
- "header3h": self._makeFormat(SHARED.theme.colHeadH, "bold", 1.4),
96
- "header4h": self._makeFormat(SHARED.theme.colHeadH, "bold", 1.2),
99
+ "head1h": self._makeFormat(SHARED.theme.colHeadH, "bold", 1.8),
100
+ "head2h": self._makeFormat(SHARED.theme.colHeadH, "bold", 1.6),
101
+ "head3h": self._makeFormat(SHARED.theme.colHeadH, "bold", 1.4),
102
+ "head4h": self._makeFormat(SHARED.theme.colHeadH, "bold", 1.2),
97
103
  "bold": self._makeFormat(colEmph, "bold"),
98
104
  "italic": self._makeFormat(colEmph, "italic"),
99
105
  "strike": self._makeFormat(SHARED.theme.colHidden, "strike"),
@@ -116,7 +122,7 @@ class GuiDocHighlighter(QSyntaxHighlighter):
116
122
  # Cache Spell Error Format
117
123
  self._spellErr = QTextCharFormat()
118
124
  self._spellErr.setUnderlineColor(SHARED.theme.colSpell)
119
- self._spellErr.setUnderlineStyle(QTextCharFormat.SpellCheckUnderline)
125
+ self._spellErr.setUnderlineStyle(QTextCharFormat.UnderlineStyle.SpellCheckUnderline)
120
126
 
121
127
  # Multiple or Trailing Spaces
122
128
  if CONFIG.showMultiSpaces:
@@ -218,11 +224,11 @@ class GuiDocHighlighter(QSyntaxHighlighter):
218
224
  ))
219
225
 
220
226
  # Build a QRegExp for each highlight pattern
221
- self.rxRules = []
227
+ self._rxRules = []
222
228
  for regEx, regRules in self._hRules:
223
229
  hReg = QRegularExpression(regEx)
224
230
  hReg.setPatternOptions(QRegularExpression.UseUnicodePropertiesOption)
225
- self.rxRules.append((hReg, regRules))
231
+ self._rxRules.append((hReg, regRules))
226
232
 
227
233
  return
228
234
 
@@ -272,12 +278,12 @@ class GuiDocHighlighter(QSyntaxHighlighter):
272
278
  is significantly faster than running the regex checks used for
273
279
  text paragraphs.
274
280
  """
275
- self.setCurrentBlockState(self.BLOCK_NONE)
281
+ self.setCurrentBlockState(BLOCK_NONE)
276
282
  if self._tHandle is None or not text:
277
283
  return
278
284
 
279
285
  if text.startswith("@"): # Keywords and commands
280
- self.setCurrentBlockState(self.BLOCK_META)
286
+ self.setCurrentBlockState(BLOCK_META)
281
287
  index = SHARED.project.index
282
288
  isValid, bits, pos = index.scanThis(text)
283
289
  isGood = index.checkThese(bits, self._tHandle)
@@ -300,35 +306,39 @@ class GuiDocHighlighter(QSyntaxHighlighter):
300
306
  # so we force a return here
301
307
  return
302
308
 
303
- elif text.startswith(("# ", "#! ", "## ", "##! ", "### ", "#### ")):
304
- self.setCurrentBlockState(self.BLOCK_TITLE)
309
+ elif text.startswith(("# ", "#! ", "## ", "##! ", "### ", "###! ", "#### ")):
310
+ self.setCurrentBlockState(BLOCK_TITLE)
305
311
 
306
- if text.startswith("# "): # Header 1
307
- self.setFormat(0, 1, self._hStyles["header1h"])
312
+ if text.startswith("# "): # Heading 1
313
+ self.setFormat(0, 1, self._hStyles["head1h"])
308
314
  self.setFormat(1, len(text), self._hStyles["header1"])
309
315
 
310
- elif text.startswith("## "): # Header 2
311
- self.setFormat(0, 2, self._hStyles["header2h"])
316
+ elif text.startswith("## "): # Heading 2
317
+ self.setFormat(0, 2, self._hStyles["head2h"])
312
318
  self.setFormat(2, len(text), self._hStyles["header2"])
313
319
 
314
- elif text.startswith("### "): # Header 3
315
- self.setFormat(0, 3, self._hStyles["header3h"])
320
+ elif text.startswith("### "): # Heading 3
321
+ self.setFormat(0, 3, self._hStyles["head3h"])
316
322
  self.setFormat(3, len(text), self._hStyles["header3"])
317
323
 
318
- elif text.startswith("#### "): # Header 4
319
- self.setFormat(0, 4, self._hStyles["header4h"])
324
+ elif text.startswith("#### "): # Heading 4
325
+ self.setFormat(0, 4, self._hStyles["head4h"])
320
326
  self.setFormat(4, len(text), self._hStyles["header4"])
321
327
 
322
328
  elif text.startswith("#! "): # Title
323
- self.setFormat(0, 2, self._hStyles["header1h"])
329
+ self.setFormat(0, 2, self._hStyles["head1h"])
324
330
  self.setFormat(2, len(text), self._hStyles["header1"])
325
331
 
326
332
  elif text.startswith("##! "): # Unnumbered
327
- self.setFormat(0, 3, self._hStyles["header2h"])
333
+ self.setFormat(0, 3, self._hStyles["head2h"])
328
334
  self.setFormat(3, len(text), self._hStyles["header2"])
329
335
 
336
+ elif text.startswith("###! "): # Alternative Scene
337
+ self.setFormat(0, 4, self._hStyles["head3h"])
338
+ self.setFormat(4, len(text), self._hStyles["header3"])
339
+
330
340
  elif text.startswith("%"): # Comments
331
- self.setCurrentBlockState(self.BLOCK_TEXT)
341
+ self.setCurrentBlockState(BLOCK_TEXT)
332
342
  cStyle, _, cPos = processComment(text)
333
343
  if cStyle == nwComment.PLAIN:
334
344
  self.setFormat(0, len(text), self._hStyles["hidden"])
@@ -353,8 +363,8 @@ class GuiDocHighlighter(QSyntaxHighlighter):
353
363
  return
354
364
 
355
365
  # Regular Text
356
- self.setCurrentBlockState(self.BLOCK_TEXT)
357
- for rX, xFmt in self.rxRules:
366
+ self.setCurrentBlockState(BLOCK_TEXT)
367
+ for rX, xFmt in self._rxRules:
358
368
  rxItt = rX.globalMatch(text, 0)
359
369
  while rxItt.hasNext():
360
370
  rxMatch = rxItt.next()
@@ -398,16 +408,16 @@ class GuiDocHighlighter(QSyntaxHighlighter):
398
408
  if style is not None:
399
409
  styles = style.split(",")
400
410
  if "bold" in styles:
401
- charFormat.setFontWeight(QFont.Bold)
411
+ charFormat.setFontWeight(QFont.Weight.Bold)
402
412
  if "italic" in styles:
403
413
  charFormat.setFontItalic(True)
404
414
  if "strike" in styles:
405
415
  charFormat.setFontStrikeOut(True)
406
416
  if "errline" in styles:
407
417
  charFormat.setUnderlineColor(SHARED.theme.colError)
408
- charFormat.setUnderlineStyle(QTextCharFormat.SpellCheckUnderline)
418
+ charFormat.setUnderlineStyle(QTextCharFormat.UnderlineStyle.SpellCheckUnderline)
409
419
  if "background" in styles and color is not None:
410
- charFormat.setBackground(QBrush(color, Qt.SolidPattern))
420
+ charFormat.setBackground(QBrush(color, Qt.BrushStyle.SolidPattern))
411
421
 
412
422
  if size is not None:
413
423
  charFormat.setFontPointSize(int(round(size*CONFIG.textSize)))
@@ -435,6 +445,17 @@ class TextBlockData(QTextBlockUserData):
435
445
  """Run the spell checker and cache the result, and return the
436
446
  list of spell check errors.
437
447
  """
448
+ if "[" in text:
449
+ # Strip shortcodes
450
+ for rX in [SPELLSC, SPELLSV]:
451
+ rxItt = rX.globalMatch(text, 0)
452
+ while rxItt.hasNext():
453
+ rxMatch = rxItt.next()
454
+ xPos = rxMatch.capturedStart(0)
455
+ xLen = rxMatch.capturedLength(0)
456
+ xEnd = rxMatch.capturedEnd(0)
457
+ text = text[:xPos] + " "*xLen + text[xEnd:]
458
+
438
459
  self._spellErrors = []
439
460
  rxSpell = SPELLRX.globalMatch(text.replace("_", " "), 0)
440
461
  while rxSpell.hasNext():