novelWriter 2.4b1__py3-none-any.whl → 2.4.1__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 (89) hide show
  1. {novelWriter-2.4b1.dist-info → novelWriter-2.4.1.dist-info}/METADATA +5 -6
  2. {novelWriter-2.4b1.dist-info → novelWriter-2.4.1.dist-info}/RECORD +79 -83
  3. novelwriter/__init__.py +15 -8
  4. novelwriter/assets/i18n/nw_de_DE.qm +0 -0
  5. novelwriter/assets/i18n/nw_en_US.qm +0 -0
  6. novelwriter/assets/i18n/nw_es_419.qm +0 -0
  7. novelwriter/assets/i18n/nw_fr_FR.qm +0 -0
  8. novelwriter/assets/i18n/nw_it_IT.qm +0 -0
  9. novelwriter/assets/i18n/nw_ja_JP.qm +0 -0
  10. novelwriter/assets/i18n/nw_nb_NO.qm +0 -0
  11. novelwriter/assets/i18n/nw_nl_NL.qm +0 -0
  12. novelwriter/assets/i18n/nw_pt_BR.qm +0 -0
  13. novelwriter/assets/i18n/nw_zh_CN.qm +0 -0
  14. novelwriter/assets/icons/none.svg +4 -0
  15. novelwriter/assets/icons/typicons_dark/icons.conf +2 -2
  16. novelwriter/assets/icons/typicons_dark/typ_unfold-hidden.svg +4 -0
  17. novelwriter/assets/icons/typicons_dark/typ_unfold-visible.svg +4 -0
  18. novelwriter/assets/icons/typicons_light/icons.conf +2 -2
  19. novelwriter/assets/icons/typicons_light/typ_unfold-hidden.svg +4 -0
  20. novelwriter/assets/icons/typicons_light/typ_unfold-visible.svg +4 -0
  21. novelwriter/assets/manual.pdf +0 -0
  22. novelwriter/assets/sample.zip +0 -0
  23. novelwriter/common.py +11 -3
  24. novelwriter/config.py +12 -4
  25. novelwriter/core/buildsettings.py +7 -7
  26. novelwriter/core/coretools.py +21 -22
  27. novelwriter/core/docbuild.py +2 -2
  28. novelwriter/core/projectxml.py +1 -1
  29. novelwriter/core/spellcheck.py +3 -3
  30. novelwriter/core/status.py +3 -2
  31. novelwriter/core/tokenizer.py +3 -3
  32. novelwriter/core/toodt.py +333 -356
  33. novelwriter/dialogs/about.py +9 -11
  34. novelwriter/dialogs/docmerge.py +17 -14
  35. novelwriter/dialogs/docsplit.py +14 -12
  36. novelwriter/dialogs/editlabel.py +5 -4
  37. novelwriter/dialogs/preferences.py +29 -34
  38. novelwriter/dialogs/projectsettings.py +31 -28
  39. novelwriter/dialogs/quotes.py +10 -9
  40. novelwriter/dialogs/wordlist.py +17 -14
  41. novelwriter/error.py +14 -12
  42. novelwriter/extensions/circularprogress.py +12 -8
  43. novelwriter/extensions/configlayout.py +1 -3
  44. novelwriter/extensions/modified.py +33 -2
  45. novelwriter/extensions/pagedsidebar.py +16 -14
  46. novelwriter/extensions/simpleprogress.py +3 -1
  47. novelwriter/extensions/statusled.py +3 -1
  48. novelwriter/extensions/switch.py +10 -9
  49. novelwriter/extensions/switchbox.py +14 -13
  50. novelwriter/gui/doceditor.py +205 -246
  51. novelwriter/gui/dochighlight.py +26 -9
  52. novelwriter/gui/docviewer.py +55 -59
  53. novelwriter/gui/docviewerpanel.py +16 -13
  54. novelwriter/gui/editordocument.py +4 -4
  55. novelwriter/gui/itemdetails.py +45 -48
  56. novelwriter/gui/mainmenu.py +2 -2
  57. novelwriter/gui/noveltree.py +23 -21
  58. novelwriter/gui/outline.py +93 -94
  59. novelwriter/gui/projtree.py +32 -30
  60. novelwriter/gui/search.py +75 -29
  61. novelwriter/gui/sidebar.py +24 -28
  62. novelwriter/gui/statusbar.py +14 -14
  63. novelwriter/gui/theme.py +61 -39
  64. novelwriter/guimain.py +37 -33
  65. novelwriter/shared.py +21 -9
  66. novelwriter/text/counting.py +1 -0
  67. novelwriter/tools/dictionaries.py +15 -14
  68. novelwriter/tools/lipsum.py +20 -17
  69. novelwriter/tools/manusbuild.py +44 -35
  70. novelwriter/tools/manuscript.py +112 -112
  71. novelwriter/tools/manussettings.py +91 -98
  72. novelwriter/tools/noveldetails.py +20 -18
  73. novelwriter/tools/welcome.py +51 -48
  74. novelwriter/tools/writingstats.py +61 -55
  75. novelwriter/types.py +90 -0
  76. novelwriter/assets/icons/typicons_dark/typ_arrow-down.svg +0 -4
  77. novelwriter/assets/icons/typicons_dark/typ_arrow-right.svg +0 -4
  78. novelwriter/assets/icons/typicons_light/typ_arrow-down.svg +0 -4
  79. novelwriter/assets/icons/typicons_light/typ_arrow-right.svg +0 -4
  80. novelwriter/core/__init__.py +0 -3
  81. novelwriter/dialogs/__init__.py +0 -3
  82. novelwriter/extensions/__init__.py +0 -3
  83. novelwriter/gui/__init__.py +0 -3
  84. novelwriter/text/__init__.py +0 -3
  85. novelwriter/tools/__init__.py +0 -3
  86. {novelWriter-2.4b1.dist-info → novelWriter-2.4.1.dist-info}/LICENSE.md +0 -0
  87. {novelWriter-2.4b1.dist-info → novelWriter-2.4.1.dist-info}/WHEEL +0 -0
  88. {novelWriter-2.4b1.dist-info → novelWriter-2.4.1.dist-info}/entry_points.txt +0 -0
  89. {novelWriter-2.4b1.dist-info → novelWriter-2.4.1.dist-info}/top_level.txt +0 -0
@@ -337,32 +337,32 @@ class DocSearch:
337
337
  """Iteratively search through documents in a project."""
338
338
  self._regEx.setPattern(self._buildPattern(search))
339
339
  logger.debug("Searching with pattern '%s'", self._regEx.pattern())
340
-
341
- num = len(search)
342
340
  storage = project.storage
343
341
  for item in project.tree:
344
342
  if item.isFileType():
345
- text = storage.getDocumentText(item.itemHandle)
346
- rxItt = self._regEx.globalMatch(text)
347
- count = 0
348
- capped = False
349
- results = []
350
- while rxItt.hasNext():
351
- rxMatch = rxItt.next()
352
- pos = rxMatch.capturedStart()
353
- num = rxMatch.capturedLength()
354
- context = text[pos:pos+100].partition("\n")[0]
355
- if context:
356
- results.append((pos, num, context))
357
- count += 1
358
- if count >= nwConst.MAX_SEARCH_RESULT:
359
- capped = True
360
- break
361
-
343
+ results, capped = self.searchText(storage.getDocumentText(item.itemHandle))
362
344
  yield item, results, capped
363
-
364
345
  return
365
346
 
347
+ def searchText(self, text: str) -> tuple[list[tuple[int, int, str]], bool]:
348
+ """Search a piece of text for RegEx matches."""
349
+ rxItt = self._regEx.globalMatch(text)
350
+ count = 0
351
+ capped = False
352
+ results = []
353
+ while rxItt.hasNext():
354
+ rxMatch = rxItt.next()
355
+ pos = rxMatch.capturedStart()
356
+ num = rxMatch.capturedLength()
357
+ context = text[pos:pos+100].partition("\n")[0]
358
+ if context:
359
+ results.append((pos, num, context))
360
+ count += 1
361
+ if count >= nwConst.MAX_SEARCH_RESULT:
362
+ capped = True
363
+ break
364
+ return results, capped
365
+
366
366
  ##
367
367
  # Internal Functions
368
368
  ##
@@ -382,8 +382,7 @@ class DocSearch:
382
382
  escaped += f"\\{c}"
383
383
  search = escaped
384
384
  if self._words:
385
- search = search if search.startswith("\\b") else f"\\b{search}"
386
- search = search if search.endswith("\\b") else f"{search}\\b"
385
+ search = f"(?:^|\\b){search}(?:$|\\b)"
387
386
  return search
388
387
 
389
388
  # END Class DocSearch
@@ -306,8 +306,8 @@ class NWBuildDocument:
306
306
  self._build.getBool("headings.hideScene")
307
307
  )
308
308
  bldObj.setHardSceneFormat(
309
- self._build.getStr("headings.fmtHardScene"),
310
- self._build.getBool("headings.hideHardScene")
309
+ self._build.getStr("headings.fmtAltScene"),
310
+ self._build.getBool("headings.hideAltScene")
311
311
  )
312
312
  bldObj.setSectionFormat(
313
313
  self._build.getStr("headings.fmtSection"),
@@ -449,7 +449,7 @@ class ProjectXMLReader:
449
449
  result[xEntry.attrib["key"]] = checkString(xEntry.text, "")
450
450
  return result
451
451
 
452
- def _parseDictTagText(self, xItem) -> dict:
452
+ def _parseDictTagText(self, xItem: ET.Element) -> dict:
453
453
  """Parse a dictionary stored with key as the tag and the value
454
454
  as the text property.
455
455
  """
@@ -74,7 +74,7 @@ class NWSpellEnchant:
74
74
  # Setters
75
75
  ##
76
76
 
77
- def setLanguage(self, language: str | None):
77
+ def setLanguage(self, language: str | None) -> None:
78
78
  """Load a dictionary for the language specified in the config.
79
79
  If that fails, we load a mock dictionary so that lookups don't
80
80
  crash. Note that enchant will allow loading an empty string as
@@ -182,10 +182,10 @@ class FakeEnchant:
182
182
  def check(self, word: str) -> bool:
183
183
  return True
184
184
 
185
- def suggest(self, word) -> list[str]:
185
+ def suggest(self, word: str) -> list[str]:
186
186
  return []
187
187
 
188
- def add_to_session(self, word: str):
188
+ def add_to_session(self, word: str) -> None:
189
189
  return
190
190
 
191
191
  # END Class FakeEnchant
@@ -35,6 +35,7 @@ from PyQt5.QtCore import QRectF
35
35
 
36
36
  from novelwriter import CONFIG
37
37
  from novelwriter.common import minmax, simplified
38
+ from novelwriter.types import QtPaintAnitAlias, QtTransparent
38
39
 
39
40
  if TYPE_CHECKING: # pragma: no cover
40
41
  from typing import TypeGuard # Requires Python 3.10
@@ -248,10 +249,10 @@ class NWStatus:
248
249
  def _createIcon(self, red: int, green: int, blue: int) -> QIcon:
249
250
  """Generate an icon for a status label."""
250
251
  pixmap = QPixmap(self._iPX, self._iPX)
251
- pixmap.fill(QColor(0, 0, 0, 0))
252
+ pixmap.fill(QtTransparent)
252
253
 
253
254
  painter = QPainter(pixmap)
254
- painter.setRenderHint(QPainter.Antialiasing)
255
+ painter.setRenderHint(QtPaintAnitAlias)
255
256
  painter.fillPath(self._iconPath, QColor(red, green, blue))
256
257
  painter.end()
257
258
 
@@ -49,7 +49,7 @@ ESCAPES = {r"\*": "*", r"\~": "~", r"\_": "_", r"\[": "[", r"\]": "]", r"\ ": ""
49
49
  RX_ESC = re.compile("|".join([re.escape(k) for k in ESCAPES.keys()]), flags=re.DOTALL)
50
50
 
51
51
 
52
- def stripEscape(text) -> str:
52
+ def stripEscape(text: str) -> str:
53
53
  """Strip escaped Markdown characters from paragraph text."""
54
54
  if "\\" in text:
55
55
  return RX_ESC.sub(lambda x: ESCAPES[x.group(0)], text)
@@ -639,8 +639,8 @@ class Tokenizer(ABC):
639
639
  tmpMarkdown.append(f"{aLine}\n")
640
640
 
641
641
  elif aLine.startswith(("### ", "###! ")):
642
- # (Hard) Scene Headings
643
- # =====================
642
+ # (Alternative) Scene Headings
643
+ # ============================
644
644
  # Scene headings in novel documents are treated as centred
645
645
  # separators if the formatting does not change the text. If the
646
646
  # format is empty, the scene can be hidden or a blank paragraph