novelWriter 2.7.5__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 +160 -225
  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 +23 -13
  169. {novelwriter-2.7.5.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.5.dist-info/RECORD +0 -163
  192. {novelwriter-2.7.5.dist-info → novelwriter-2.8b1.dist-info}/WHEEL +0 -0
  193. {novelwriter-2.7.5.dist-info → novelwriter-2.8b1.dist-info}/entry_points.txt +0 -0
  194. {novelwriter-2.7.5.dist-info → novelwriter-2.8b1.dist-info}/licenses/LICENSE.md +0 -0
  195. {novelwriter-2.7.5.dist-info → novelwriter-2.8b1.dist-info}/licenses/setup/LICENSE-Apache-2.0.txt +0 -0
  196. {novelwriter-2.7.5.dist-info → novelwriter-2.8b1.dist-info}/top_level.txt +0 -0
@@ -29,7 +29,7 @@ General Public License for more details.
29
29
 
30
30
  You should have received a copy of the GNU General Public License
31
31
  along with this program. If not, see <https://www.gnu.org/licenses/>.
32
- """
32
+ """ # noqa
33
33
  from __future__ import annotations
34
34
 
35
35
  import bisect
@@ -46,11 +46,11 @@ from PyQt6.QtGui import (
46
46
  QAction, QCursor, QDragEnterEvent, QDragMoveEvent, QDropEvent,
47
47
  QInputMethodEvent, QKeyEvent, QKeySequence, QMouseEvent, QPalette, QPixmap,
48
48
  QResizeEvent, QShortcut, QTextBlock, QTextCursor, QTextDocument,
49
- QTextOption
49
+ QTextFormat, QTextOption
50
50
  )
51
51
  from PyQt6.QtWidgets import (
52
52
  QApplication, QFrame, QGridLayout, QHBoxLayout, QLabel, QLineEdit, QMenu,
53
- QPlainTextEdit, QToolBar, QVBoxLayout, QWidget
53
+ QPlainTextEdit, QTextEdit, QToolBar, QVBoxLayout, QWidget
54
54
  )
55
55
 
56
56
  from novelwriter import CONFIG, SHARED
@@ -77,7 +77,8 @@ from novelwriter.types import (
77
77
  QtAlignCenterTop, QtAlignJustify, QtAlignLeft, QtAlignLeftTop,
78
78
  QtAlignRight, QtImCursorRectangle, QtKeepAnchor, QtModCtrl, QtModNone,
79
79
  QtModShift, QtMouseLeft, QtMoveAnchor, QtMoveLeft, QtMoveRight,
80
- QtScrollAlwaysOff, QtScrollAsNeeded
80
+ QtScrollAlwaysOff, QtScrollAsNeeded, QtSelectBlock, QtSelectDocument,
81
+ QtSelectWord, QtTransparent
81
82
  )
82
83
 
83
84
  logger = logging.getLogger(__name__)
@@ -99,7 +100,7 @@ class _TagAction(IntFlag):
99
100
 
100
101
 
101
102
  class GuiDocEditor(QPlainTextEdit):
102
- """Gui Widget: Main Document Editor"""
103
+ """Gui Widget: Main Document Editor."""
103
104
 
104
105
  __slots__ = (
105
106
  "_autoReplace", "_completer", "_doReplace", "_docChanged", "_docHandle", "_followTag1",
@@ -147,6 +148,8 @@ class GuiDocEditor(QPlainTextEdit):
147
148
  self._lastActive = 0.0 # Timestamp of last activity
148
149
  self._lastFind = None # Position of the last found search word
149
150
  self._doReplace = False # Switch to temporarily disable auto-replace
151
+ self._lineColor = QtTransparent
152
+ self._selection = QTextEdit.ExtraSelection()
150
153
 
151
154
  # Auto-Replace
152
155
  self._autoReplace = TextAutoReplace()
@@ -235,8 +238,6 @@ class GuiDocEditor(QPlainTextEdit):
235
238
 
236
239
  logger.debug("Ready: GuiDocEditor")
237
240
 
238
- return
239
-
240
241
  ##
241
242
  # Properties
242
243
  ##
@@ -285,18 +286,18 @@ class GuiDocEditor(QPlainTextEdit):
285
286
  self.docHeader.clearHeader()
286
287
  self.docFooter.setHandle(self._docHandle)
287
288
  self.docToolBar.setVisible(False)
289
+ self.setExtraSelections([])
288
290
 
289
291
  self.itemHandleChanged.emit("")
290
292
 
291
- return
292
-
293
293
  def updateTheme(self) -> None:
294
294
  """Update theme elements."""
295
+ logger.debug("Theme Update: GuiDocEditor")
296
+
295
297
  self.docSearch.updateTheme()
296
298
  self.docHeader.updateTheme()
297
299
  self.docFooter.updateTheme()
298
300
  self.docToolBar.updateTheme()
299
- return
300
301
 
301
302
  def updateSyntaxColors(self) -> None:
302
303
  """Update the syntax highlighting theme."""
@@ -317,7 +318,9 @@ class GuiDocEditor(QPlainTextEdit):
317
318
  self.docHeader.matchColors()
318
319
  self.docFooter.matchColors()
319
320
 
320
- return
321
+ self._lineColor = syntax.line
322
+ self._selection.format.setBackground(self._lineColor)
323
+ self._selection.format.setProperty(QTextFormat.Property.FullWidthSelection, True)
321
324
 
322
325
  def initEditor(self) -> None:
323
326
  """Initialise or re-initialise the editor with the user's
@@ -374,6 +377,8 @@ class GuiDocEditor(QPlainTextEdit):
374
377
  # Refresh sizes
375
378
  self.setTabStopDistance(CONFIG.tabWidth)
376
379
  self.setCursorWidth(CONFIG.cursorWidth)
380
+ self.setExtraSelections([])
381
+ self._cursorMoved()
377
382
 
378
383
  # If we have a document open, we should refresh it in case the
379
384
  # font changed, otherwise we just clear the editor entirely,
@@ -384,8 +389,6 @@ class GuiDocEditor(QPlainTextEdit):
384
389
  else:
385
390
  self.clearEditor()
386
391
 
387
- return
388
-
389
392
  def loadText(self, tHandle: str, tLine: int | None = None) -> bool:
390
393
  """Load text from a document into the editor. If we have an I/O
391
394
  error, we must handle this and clear the editor so that we don't
@@ -463,7 +466,6 @@ class GuiDocEditor(QPlainTextEdit):
463
466
  self.updateDocMargins()
464
467
  self.setDocumentChanged(True)
465
468
  QApplication.restoreOverrideCursor()
466
- return
467
469
 
468
470
  def saveText(self) -> bool:
469
471
  """Save the text currently in the editor to the NWDocument
@@ -531,7 +533,6 @@ class GuiDocEditor(QPlainTextEdit):
531
533
  vBar.setValue(vBar.value() + 1)
532
534
  count += 1
533
535
  QApplication.processEvents()
534
- return
535
536
 
536
537
  def updateDocMargins(self) -> None:
537
538
  """Automatically adjust the margins so the text is centred if
@@ -572,8 +573,6 @@ class GuiDocEditor(QPlainTextEdit):
572
573
  lM = max(self._vpMargin, fH)
573
574
  self.setViewportMargins(tM, uM, tM, lM)
574
575
 
575
- return
576
-
577
576
  ##
578
577
  # Getters
579
578
  ##
@@ -583,20 +582,19 @@ class GuiDocEditor(QPlainTextEdit):
583
582
  QTextDocument->toRawText instead of toPlainText. The former preserves
584
583
  non-breaking spaces, the latter does not. We still want to get rid of
585
584
  paragraph and line separators though.
585
+
586
586
  See: https://doc.qt.io/qt-6/qtextdocument.html#toPlainText
587
587
  """
588
588
  text = self._qDocument.toRawText()
589
589
  text = text.replace(nwUnicode.U_LSEP, "\n") # Line separators
590
- text = text.replace(nwUnicode.U_PSEP, "\n") # Paragraph separators
591
- return text
590
+ return text.replace(nwUnicode.U_PSEP, "\n") # Paragraph separators
592
591
 
593
592
  def getSelectedText(self) -> str:
594
593
  """Get currently selected text."""
595
594
  if (cursor := self.textCursor()).hasSelection():
596
595
  text = cursor.selectedText()
597
596
  text = text.replace(nwUnicode.U_LSEP, "\n") # Line separators
598
- text = text.replace(nwUnicode.U_PSEP, "\n") # Paragraph separators
599
- return text
597
+ return text.replace(nwUnicode.U_PSEP, "\n") # Paragraph separators
600
598
  return ""
601
599
 
602
600
  def getCursorPosition(self) -> int:
@@ -617,7 +615,6 @@ class GuiDocEditor(QPlainTextEdit):
617
615
  logger.debug("Document changed status is '%s'", state)
618
616
  self._docChanged = state
619
617
  self.editedStatusChanged.emit(self._docChanged)
620
- return
621
618
 
622
619
  def setCursorPosition(self, position: int) -> None:
623
620
  """Move the cursor to a given position in the document."""
@@ -626,14 +623,12 @@ class GuiDocEditor(QPlainTextEdit):
626
623
  cursor.setPosition(minmax(position, 0, chars-1))
627
624
  self.setTextCursor(cursor)
628
625
  self.centerCursor()
629
- return
630
626
 
631
627
  def saveCursorPosition(self) -> None:
632
628
  """Save the cursor position to the current project item."""
633
629
  if self._nwItem is not None:
634
630
  cursPos = self.getCursorPosition()
635
631
  self._nwItem.setCursorPos(cursPos)
636
- return
637
632
 
638
633
  def setCursorLine(self, line: int | None) -> None:
639
634
  """Move the cursor to a given line in the document."""
@@ -642,7 +637,6 @@ class GuiDocEditor(QPlainTextEdit):
642
637
  if block:
643
638
  self.setCursorPosition(block.position())
644
639
  logger.debug("Cursor moved to line %d", line)
645
- return
646
640
 
647
641
  def setCursorSelection(self, start: int, length: int) -> None:
648
642
  """Make a text selection."""
@@ -651,14 +645,15 @@ class GuiDocEditor(QPlainTextEdit):
651
645
  cursor.setPosition(start, QtMoveAnchor)
652
646
  cursor.setPosition(start + length, QtKeepAnchor)
653
647
  self.setTextCursor(cursor)
654
- return
655
648
 
656
649
  ##
657
650
  # Spell Checking
658
651
  ##
659
652
 
660
653
  def toggleSpellCheck(self, state: bool | None) -> None:
661
- """This is the main spell check setting function, and this one
654
+ """Toggle spell checking.
655
+
656
+ This is the main spell check setting function, and this one
662
657
  should call all other setSpellCheck functions in other classes.
663
658
  If the spell check state is not defined (None), then toggle the
664
659
  current status saved in this class.
@@ -680,9 +675,7 @@ class GuiDocEditor(QPlainTextEdit):
680
675
  self.spellCheckStateChanged.emit(state)
681
676
  self.spellCheckDocument()
682
677
 
683
- logger.debug("Spell check is set to '%s'", str(state))
684
-
685
- return
678
+ logger.debug("Spell check is set to '%s'", state)
686
679
 
687
680
  def spellCheckDocument(self) -> None:
688
681
  """Rerun the highlighter to update spell checking status of the
@@ -695,7 +688,6 @@ class GuiDocEditor(QPlainTextEdit):
695
688
  QApplication.restoreOverrideCursor()
696
689
  logger.debug("Document highlighted in %.3f ms", 1000*(time() - start))
697
690
  self.updateStatusMessage.emit(self.tr("Spell check complete"))
698
- return
699
691
 
700
692
  ##
701
693
  # General Class Methods
@@ -735,14 +727,16 @@ class GuiDocEditor(QPlainTextEdit):
735
727
  self._toggleFormat(2, "*")
736
728
  elif action == nwDocAction.MD_STRIKE:
737
729
  self._toggleFormat(2, "~")
730
+ elif action == nwDocAction.MD_MARK:
731
+ self._toggleFormat(2, "=")
738
732
  elif action == nwDocAction.S_QUOTE:
739
733
  self._wrapSelection(CONFIG.fmtSQuoteOpen, CONFIG.fmtSQuoteClose)
740
734
  elif action == nwDocAction.D_QUOTE:
741
735
  self._wrapSelection(CONFIG.fmtDQuoteOpen, CONFIG.fmtDQuoteClose)
742
736
  elif action == nwDocAction.SEL_ALL:
743
- self._makeSelection(QTextCursor.SelectionType.Document)
737
+ self._makeSelection(QtSelectDocument)
744
738
  elif action == nwDocAction.SEL_PARA:
745
- self._makeSelection(QTextCursor.SelectionType.BlockUnderCursor)
739
+ self._makeSelection(QtSelectBlock)
746
740
  elif action == nwDocAction.BLOCK_H1:
747
741
  self._formatBlock(nwDocAction.BLOCK_H1)
748
742
  elif action == nwDocAction.BLOCK_H2:
@@ -794,7 +788,7 @@ class GuiDocEditor(QPlainTextEdit):
794
788
  elif action == nwDocAction.SC_SUB:
795
789
  self._wrapSelection(nwShortcode.SUB_O, nwShortcode.SUB_C)
796
790
  else:
797
- logger.debug("Unknown or unsupported document action '%s'", str(action))
791
+ logger.debug("Unknown or unsupported document action '%s'", action)
798
792
  self._allowAutoReplace(True)
799
793
  return False
800
794
 
@@ -822,7 +816,6 @@ class GuiDocEditor(QPlainTextEdit):
822
816
  details=self.tr("File Location: {0}").format(self._nwDocument.fileLocation),
823
817
  log=False
824
818
  )
825
- return
826
819
 
827
820
  def insertText(self, insert: str | nwDocInsert) -> None:
828
821
  """Insert a specific type of text at the cursor position."""
@@ -964,7 +957,6 @@ class GuiDocEditor(QPlainTextEdit):
964
957
  event.acceptProposedAction()
965
958
  else:
966
959
  super().dragEnterEvent(event)
967
- return
968
960
 
969
961
  def dragMoveEvent(self, event: QDragMoveEvent) -> None:
970
962
  """Overload drag move event to handle dragged items."""
@@ -972,7 +964,6 @@ class GuiDocEditor(QPlainTextEdit):
972
964
  event.acceptProposedAction()
973
965
  else:
974
966
  super().dragMoveEvent(event)
975
- return
976
967
 
977
968
  def dropEvent(self, event: QDropEvent) -> None:
978
969
  """Overload drop event to handle dragged items."""
@@ -982,7 +973,6 @@ class GuiDocEditor(QPlainTextEdit):
982
973
  self.openDocumentRequest.emit(handles[0], nwDocMode.EDIT, "", True)
983
974
  else:
984
975
  super().dropEvent(event)
985
- return
986
976
 
987
977
  def focusNextPrevChild(self, _next: bool) -> bool:
988
978
  """Capture the focus request from the tab key on the text
@@ -1009,7 +999,6 @@ class GuiDocEditor(QPlainTextEdit):
1009
999
  else:
1010
1000
  self._processTag(cursor)
1011
1001
  super().mouseReleaseEvent(event)
1012
- return
1013
1002
 
1014
1003
  def resizeEvent(self, event: QResizeEvent) -> None:
1015
1004
  """If the text editor is resized, we must make sure the document
@@ -1017,7 +1006,6 @@ class GuiDocEditor(QPlainTextEdit):
1017
1006
  """
1018
1007
  self.updateDocMargins()
1019
1008
  super().resizeEvent(event)
1020
- return
1021
1009
 
1022
1010
  def inputMethodEvent(self, event: QInputMethodEvent) -> None:
1023
1011
  """Handle text being input from CJK input methods."""
@@ -1045,14 +1033,13 @@ class GuiDocEditor(QPlainTextEdit):
1045
1033
 
1046
1034
  @pyqtSlot(str, Enum)
1047
1035
  def onProjectItemChanged(self, tHandle: str, change: nwChange) -> None:
1048
- """Called when an item label is changed to check if the document
1049
- title bar needs updating,
1036
+ """Process project item change. Called when an item label is
1037
+ changed to check if the document title bar needs updating.
1050
1038
  """
1051
1039
  if tHandle == self._docHandle and change == nwChange.UPDATE:
1052
1040
  self.docHeader.setHandle(tHandle)
1053
1041
  self.docFooter.updateInfo()
1054
1042
  self.updateDocMargins()
1055
- return
1056
1043
 
1057
1044
  @pyqtSlot(str)
1058
1045
  def insertKeyWord(self, keyword: str) -> bool:
@@ -1063,8 +1050,7 @@ class GuiDocEditor(QPlainTextEdit):
1063
1050
  logger.error("Invalid keyword '%s'", keyword)
1064
1051
  return False
1065
1052
  logger.debug("Inserting keyword '%s'", keyword)
1066
- state = self.insertNewBlock(f"{keyword}: ")
1067
- return state
1053
+ return self.insertNewBlock(f"{keyword}: ")
1068
1054
 
1069
1055
  @pyqtSlot()
1070
1056
  def toggleSearch(self) -> None:
@@ -1073,14 +1059,12 @@ class GuiDocEditor(QPlainTextEdit):
1073
1059
  self.closeSearch()
1074
1060
  else:
1075
1061
  self.beginSearch()
1076
- return
1077
1062
 
1078
1063
  @pyqtSlot(list, list)
1079
1064
  def updateChangedTags(self, updated: list[str], deleted: list[str]) -> None:
1080
1065
  """Tags have changed, so just in case we rehighlight them."""
1081
1066
  if updated or deleted:
1082
1067
  self._qDocument.syntaxHighlighter.rehighlightByType(BLOCK_META)
1083
- return
1084
1068
 
1085
1069
  ##
1086
1070
  # Private Slots
@@ -1122,13 +1106,14 @@ class GuiDocEditor(QPlainTextEdit):
1122
1106
  if self._autoReplace.process(text, cursor):
1123
1107
  self._qDocument.syntaxHighlighter.rehighlightBlock(cursor.block())
1124
1108
 
1125
- return
1126
-
1127
1109
  @pyqtSlot()
1128
1110
  def _cursorMoved(self) -> None:
1129
1111
  """Triggered when the cursor moved in the editor."""
1130
1112
  self.docFooter.updateLineCount(self.textCursor())
1131
- return
1113
+ if CONFIG.lineHighlight:
1114
+ self._selection.cursor = self.textCursor()
1115
+ self._selection.cursor.clearSelection()
1116
+ self.setExtraSelections([self._selection])
1132
1117
 
1133
1118
  @pyqtSlot(int, int, str)
1134
1119
  def _insertCompletion(self, pos: int, length: int, text: str) -> None:
@@ -1140,13 +1125,11 @@ class GuiDocEditor(QPlainTextEdit):
1140
1125
  cursor.setPosition(check + length, QtKeepAnchor)
1141
1126
  cursor.insertText(text)
1142
1127
  self._completer.close()
1143
- return
1144
1128
 
1145
1129
  @pyqtSlot()
1146
1130
  def _openContextFromCursor(self) -> None:
1147
1131
  """Open the spell check context menu at the cursor."""
1148
1132
  self._openContextMenu(self.cursorRect().center())
1149
- return
1150
1133
 
1151
1134
  @pyqtSlot("QPoint")
1152
1135
  def _openContextMenu(self, pos: QPoint) -> None:
@@ -1194,23 +1177,19 @@ class GuiDocEditor(QPlainTextEdit):
1194
1177
  action = qtAddAction(ctxMenu, self.tr("Select All"))
1195
1178
  action.triggered.connect(qtLambda(self.docAction, nwDocAction.SEL_ALL))
1196
1179
  action = qtAddAction(ctxMenu, self.tr("Select Word"))
1197
- action.triggered.connect(qtLambda(
1198
- self._makePosSelection, QTextCursor.SelectionType.WordUnderCursor, pos,
1199
- ))
1180
+ action.triggered.connect(qtLambda(self._makePosSelection, QtSelectWord, pos))
1200
1181
  action = qtAddAction(ctxMenu, self.tr("Select Paragraph"))
1201
- action.triggered.connect(qtLambda(
1202
- self._makePosSelection, QTextCursor.SelectionType.BlockUnderCursor, pos
1203
- ))
1182
+ action.triggered.connect(qtLambda(self._makePosSelection, QtSelectBlock, pos))
1204
1183
 
1205
1184
  # Spell Checking
1206
1185
  if SHARED.project.data.spellCheck:
1207
- word, cPos, cLen, suggest = self._qDocument.spellErrorAtPos(pCursor.position())
1208
- if word and cPos >= 0 and cLen > 0:
1186
+ word, offset, suggest = self._qDocument.spellErrorAtPos(pCursor.position())
1187
+ if word and offset >= 0:
1209
1188
  logger.debug("Word '%s' is misspelled", word)
1210
1189
  block = pCursor.block()
1211
1190
  sCursor = self.textCursor()
1212
- sCursor.setPosition(block.position() + cPos)
1213
- sCursor.movePosition(QtMoveRight, QtKeepAnchor, cLen)
1191
+ sCursor.setPosition(block.position() + offset)
1192
+ sCursor.movePosition(QtMoveRight, QtKeepAnchor, len(word))
1214
1193
  if suggest:
1215
1194
  ctxMenu.addSeparator()
1216
1195
  qtAddAction(ctxMenu, self.tr("Spelling Suggestion(s)"))
@@ -1233,8 +1212,6 @@ class GuiDocEditor(QPlainTextEdit):
1233
1212
 
1234
1213
  ctxMenu.setParent(None)
1235
1214
 
1236
- return
1237
-
1238
1215
  @pyqtSlot()
1239
1216
  def _runDocumentTasks(self) -> None:
1240
1217
  """Run timer document tasks."""
@@ -1271,11 +1248,10 @@ class GuiDocEditor(QPlainTextEdit):
1271
1248
  if not self.textCursor().hasSelection():
1272
1249
  # Selection counter should take precedence (#2155)
1273
1250
  self.docFooter.updateMainCount(mCount, False)
1274
- return
1275
1251
 
1276
1252
  @pyqtSlot()
1277
1253
  def _updateSelectedStatus(self) -> None:
1278
- """The user made a change in text selection. Forward this
1254
+ """Process user change in text selection. Forward this
1279
1255
  information to the footer, and start the selection word counter.
1280
1256
  """
1281
1257
  if self.textCursor().hasSelection():
@@ -1284,7 +1260,6 @@ class GuiDocEditor(QPlainTextEdit):
1284
1260
  else:
1285
1261
  self._timerSel.stop()
1286
1262
  self.docFooter.updateMainCount(0, False)
1287
- return
1288
1263
 
1289
1264
  @pyqtSlot()
1290
1265
  def _runSelCounter(self) -> None:
@@ -1302,14 +1277,12 @@ class GuiDocEditor(QPlainTextEdit):
1302
1277
  if self._docHandle and self._nwItem:
1303
1278
  self.docFooter.updateMainCount(cCount if CONFIG.useCharCount else wCount, True)
1304
1279
  self._timerSel.stop()
1305
- return
1306
1280
 
1307
1281
  @pyqtSlot()
1308
1282
  def _closeCurrentDocument(self) -> None:
1309
1283
  """Close the document. Forwarded to the main Gui."""
1310
1284
  self.closeEditorRequest.emit()
1311
1285
  self.docToolBar.setVisible(False)
1312
- return
1313
1286
 
1314
1287
  @pyqtSlot()
1315
1288
  def _toggleToolBarVisibility(self) -> None:
@@ -1317,7 +1290,6 @@ class GuiDocEditor(QPlainTextEdit):
1317
1290
  state = not self.docToolBar.isVisible()
1318
1291
  self.docToolBar.setVisible(state)
1319
1292
  CONFIG.showEditToolBar = state
1320
- return
1321
1293
 
1322
1294
  ##
1323
1295
  # Search & Replace
@@ -1328,14 +1300,12 @@ class GuiDocEditor(QPlainTextEdit):
1328
1300
  self.docSearch.setSearchText(self.getSelectedText() or None)
1329
1301
  resS, _ = self.findAllOccurences()
1330
1302
  self.docSearch.setResultCount(None, len(resS))
1331
- return
1332
1303
 
1333
1304
  def beginReplace(self) -> None:
1334
1305
  """Initialise the search box and reset the replace text box."""
1335
1306
  self.beginSearch()
1336
1307
  self.docSearch.setReplaceText("")
1337
1308
  self.updateDocMargins()
1338
- return
1339
1309
 
1340
1310
  def findNext(self, goBack: bool = False) -> None:
1341
1311
  """Search for the next or previous occurrence of the search bar
@@ -1623,8 +1593,6 @@ class GuiDocEditor(QPlainTextEdit):
1623
1593
 
1624
1594
  self.setTextCursor(cursor)
1625
1595
 
1626
- return
1627
-
1628
1596
  def _replaceQuotes(self, sQuote: str, oQuote: str, cQuote: str) -> None:
1629
1597
  """Replace all straight quotes in the selected text."""
1630
1598
  cursor = self.textCursor()
@@ -1781,7 +1749,7 @@ class GuiDocEditor(QPlainTextEdit):
1781
1749
  elif action == nwDocAction.BLOCK_TXT:
1782
1750
  text = temp
1783
1751
  else:
1784
- logger.error("Unknown or unsupported block format requested: '%s'", str(action))
1752
+ logger.error("Unknown or unsupported block format requested: '%s'", action)
1785
1753
  return nwDocAction.NO_ACTION, "", 0
1786
1754
 
1787
1755
  return action, text, offset
@@ -1791,7 +1759,7 @@ class GuiDocEditor(QPlainTextEdit):
1791
1759
  cursor = self.textCursor()
1792
1760
  block = cursor.block()
1793
1761
  if not block.isValid():
1794
- logger.debug("Invalid block selected for action '%s'", str(action))
1762
+ logger.debug("Invalid block selected for action '%s'", action)
1795
1763
  return False
1796
1764
 
1797
1765
  action, text, offset = self._processBlockFormat(action, block.text())
@@ -1801,7 +1769,7 @@ class GuiDocEditor(QPlainTextEdit):
1801
1769
  pos = cursor.position()
1802
1770
 
1803
1771
  cursor.beginEditBlock()
1804
- self._makeSelection(QTextCursor.SelectionType.BlockUnderCursor, cursor)
1772
+ self._makeSelection(QtSelectBlock, cursor)
1805
1773
  cursor.insertText(text)
1806
1774
  cursor.endEditBlock()
1807
1775
 
@@ -1829,7 +1797,7 @@ class GuiDocEditor(QPlainTextEdit):
1829
1797
  if pAction != nwDocAction.NO_ACTION and blockText.strip():
1830
1798
  action = pAction # First block decides further actions
1831
1799
  cursor.setPosition(block.position())
1832
- self._makeSelection(QTextCursor.SelectionType.BlockUnderCursor, cursor)
1800
+ self._makeSelection(QtSelectBlock, cursor)
1833
1801
  cursor.insertText(text)
1834
1802
  toggle = False
1835
1803
 
@@ -1849,7 +1817,7 @@ class GuiDocEditor(QPlainTextEdit):
1849
1817
  """Strip line breaks within paragraphs in the selected text."""
1850
1818
  cursor = self.textCursor()
1851
1819
  if not cursor.hasSelection():
1852
- cursor.select(QTextCursor.SelectionType.Document)
1820
+ cursor.select(QtSelectDocument)
1853
1821
 
1854
1822
  rS = 0
1855
1823
  rE = self._qDocument.characterCount()
@@ -1884,8 +1852,6 @@ class GuiDocEditor(QPlainTextEdit):
1884
1852
  cursor.insertText(cleanText.rstrip() + "\n")
1885
1853
  cursor.endEditBlock()
1886
1854
 
1887
- return
1888
-
1889
1855
  def _insertCommentStructure(self, style: nwComment) -> None:
1890
1856
  """Insert a shortcut/comment combo."""
1891
1857
  if self._docHandle and style == nwComment.FOOTNOTE:
@@ -1933,7 +1899,6 @@ class GuiDocEditor(QPlainTextEdit):
1933
1899
  cursor.endEditBlock()
1934
1900
  cursor.setPosition(pos)
1935
1901
  self.setTextCursor(cursor)
1936
- return
1937
1902
 
1938
1903
  def _addWord(self, word: str, block: QTextBlock, save: bool) -> None:
1939
1904
  """Slot for the spell check context menu triggered when the user
@@ -1942,7 +1907,6 @@ class GuiDocEditor(QPlainTextEdit):
1942
1907
  logger.debug("Added '%s' to project dictionary, %s", word, "saved" if save else "unsaved")
1943
1908
  SHARED.spelling.addWord(word, save=save)
1944
1909
  self._qDocument.syntaxHighlighter.rehighlightBlock(block)
1945
- return
1946
1910
 
1947
1911
  def _processTag(
1948
1912
  self, cursor: QTextCursor | None = None, follow: bool = True, create: bool = False
@@ -2016,7 +1980,6 @@ class GuiDocEditor(QPlainTextEdit):
2016
1980
  if self._docHandle:
2017
1981
  text = block.text().lstrip("#").lstrip("!").strip()
2018
1982
  self.requestProjectItemRenamed.emit(self._docHandle, text)
2019
- return
2020
1983
 
2021
1984
  def _autoSelect(self) -> QTextCursor:
2022
1985
  """Return a cursor which may or may not have a selection based
@@ -2071,10 +2034,10 @@ class GuiDocEditor(QPlainTextEdit):
2071
2034
  cursor.clearSelection()
2072
2035
  cursor.select(mode)
2073
2036
 
2074
- if mode == QTextCursor.SelectionType.WordUnderCursor:
2037
+ if mode == QtSelectWord:
2075
2038
  cursor = self._autoSelect()
2076
2039
 
2077
- elif mode == QTextCursor.SelectionType.BlockUnderCursor:
2040
+ elif mode == QtSelectBlock:
2078
2041
  # This selection mode also selects the preceding paragraph
2079
2042
  # separator, which we want to avoid.
2080
2043
  posS = cursor.selectionStart()
@@ -2086,14 +2049,11 @@ class GuiDocEditor(QPlainTextEdit):
2086
2049
 
2087
2050
  self.setTextCursor(cursor)
2088
2051
 
2089
- return
2090
-
2091
2052
  def _makePosSelection(self, mode: QTextCursor.SelectionType, pos: QPoint) -> None:
2092
2053
  """Select text based on selection mode, but first move cursor."""
2093
2054
  cursor = self.cursorForPosition(pos)
2094
2055
  self.setTextCursor(cursor)
2095
2056
  self._makeSelection(mode)
2096
- return
2097
2057
 
2098
2058
  def _allowAutoReplace(self, state: bool) -> None:
2099
2059
  """Enable/disable the auto-replace feature temporarily."""
@@ -2101,11 +2061,10 @@ class GuiDocEditor(QPlainTextEdit):
2101
2061
  self._doReplace = CONFIG.doReplace
2102
2062
  else:
2103
2063
  self._doReplace = False
2104
- return
2105
2064
 
2106
2065
 
2107
2066
  class CommandCompleter(QMenu):
2108
- """GuiWidget: Command Completer Menu
2067
+ """GuiWidget: Command Completer Menu.
2109
2068
 
2110
2069
  This is a context menu with options populated from the user's
2111
2070
  defined tags and keys. It also helps to type the meta data keyword
@@ -2120,7 +2079,6 @@ class CommandCompleter(QMenu):
2120
2079
  def __init__(self, parent: QWidget) -> None:
2121
2080
  super().__init__(parent=parent)
2122
2081
  self._parent = parent
2123
- return
2124
2082
 
2125
2083
  def updateMetaText(self, text: str, pos: int) -> bool:
2126
2084
  """Update the menu options based on the line of text."""
@@ -2214,7 +2172,6 @@ class CommandCompleter(QMenu):
2214
2172
  else:
2215
2173
  self.close() # Close to release the event lock before forwarding the key press (#2510)
2216
2174
  self._parent.keyPressEvent(event)
2217
- return
2218
2175
 
2219
2176
  ##
2220
2177
  # Internal Functions
@@ -2223,11 +2180,10 @@ class CommandCompleter(QMenu):
2223
2180
  def _emitComplete(self, pos: int, length: int, value: str) -> None:
2224
2181
  """Emit the signal to indicate a selection has been made."""
2225
2182
  self.insertText.emit(pos, length, value)
2226
- return
2227
2183
 
2228
2184
 
2229
2185
  class BackgroundWordCounter(QRunnable):
2230
- """The Off-GUI Thread Word Counter
2186
+ """The Off-GUI Thread Word Counter.
2231
2187
 
2232
2188
  A runnable for the word counter to be run in the thread pool off the
2233
2189
  main GUI thread.
@@ -2239,9 +2195,9 @@ class BackgroundWordCounter(QRunnable):
2239
2195
  self._forSelection = forSelection
2240
2196
  self._isRunning = False
2241
2197
  self.signals = BackgroundWordCounterSignals()
2242
- return
2243
2198
 
2244
2199
  def isRunning(self) -> bool:
2200
+ """Return True if the word counter is already running."""
2245
2201
  return self._isRunning
2246
2202
 
2247
2203
  @pyqtSlot()
@@ -2259,17 +2215,17 @@ class BackgroundWordCounter(QRunnable):
2259
2215
  self.signals.countsReady.emit(cC, wC, pC)
2260
2216
  self._isRunning = False
2261
2217
 
2262
- return
2263
-
2264
2218
 
2265
2219
  class BackgroundWordCounterSignals(QObject):
2266
2220
  """The QRunnable cannot emit a signal, so we need a simple QObject
2267
2221
  to hold the word counter signal.
2268
2222
  """
2223
+
2269
2224
  countsReady = pyqtSignal(int, int, int)
2270
2225
 
2271
2226
 
2272
2227
  class TextAutoReplace:
2228
+ """Encapsulates the editor auto replace feature."""
2273
2229
 
2274
2230
  __slots__ = (
2275
2231
  "_doPadAfter", "_doPadBefore", "_padAfter", "_padBefore", "_padChar",
@@ -2279,7 +2235,6 @@ class TextAutoReplace:
2279
2235
 
2280
2236
  def __init__(self) -> None:
2281
2237
  self.initSettings()
2282
- return
2283
2238
 
2284
2239
  def initSettings(self) -> None:
2285
2240
  """Initialise the auto-replace settings from config."""
@@ -2298,27 +2253,28 @@ class TextAutoReplace:
2298
2253
  self._padAfter = CONFIG.fmtPadAfter
2299
2254
  self._doPadBefore = bool(CONFIG.fmtPadBefore)
2300
2255
  self._doPadAfter = bool(CONFIG.fmtPadAfter)
2301
- return
2302
2256
 
2303
2257
  def process(self, text: str, cursor: QTextCursor) -> bool:
2304
2258
  """Auto-replace text elements based on main configuration.
2305
2259
  Returns True if anything was changed.
2306
2260
  """
2307
- pos = cursor.positionInBlock()
2308
- length = len(text)
2309
- if length < 1 or pos-1 > length:
2261
+ aPos = cursor.position()
2262
+ bPos = cursor.positionInBlock()
2263
+ block = cursor.block()
2264
+ length = block.length() - 1
2265
+ if length < 1 or bPos-1 > length:
2310
2266
  return False
2311
2267
 
2312
- delete, insert = self._determine(text, pos)
2313
- if insert == "":
2314
- return False
2268
+ cursor.movePosition(QtMoveLeft, QtKeepAnchor, min(4, bPos))
2269
+ last = cursor.selectedText()
2270
+ delete, insert = self._determine(last, bPos)
2315
2271
 
2316
2272
  check = insert
2317
2273
  if self._doPadBefore and check in self._padBefore:
2318
2274
  if not (check == ":" and length > 1 and text[0] == "@"):
2319
2275
  delete = max(delete, 1)
2320
- chkPos = pos - delete - 1
2321
- if chkPos >= 0 and text[chkPos].isspace():
2276
+ chkPos = len(last) - delete - 1
2277
+ if chkPos >= 0 and last[chkPos].isspace():
2322
2278
  # Strip existing space before inserting a new (#1061)
2323
2279
  delete += 1
2324
2280
  insert = self._padChar + insert
@@ -2329,6 +2285,7 @@ class TextAutoReplace:
2329
2285
  insert = insert + self._padChar
2330
2286
 
2331
2287
  if delete > 0:
2288
+ cursor.setPosition(aPos)
2332
2289
  cursor.movePosition(QtMoveLeft, QtKeepAnchor, delete)
2333
2290
  cursor.insertText(insert)
2334
2291
  return True
@@ -2337,42 +2294,55 @@ class TextAutoReplace:
2337
2294
 
2338
2295
  def _determine(self, text: str, pos: int) -> tuple[int, str]:
2339
2296
  """Determine what to replace, if anything."""
2340
- t1 = text[pos-1:pos]
2341
- t2 = text[pos-2:pos]
2342
- t3 = text[pos-3:pos]
2343
- t4 = text[pos-4:pos]
2344
- if t1 == "":
2345
- # Return early if there is nothing to check
2346
- return 0, ""
2347
-
2348
- leading = t2[:1].isspace()
2349
- if self._replaceDQuote:
2350
- if leading and t2.endswith('"'):
2297
+ t1 = text[-1:]
2298
+ t2 = text[-2:]
2299
+ t3 = text[-3:]
2300
+ t4 = text[-4:]
2301
+
2302
+ if self._replaceDQuote and t1 == '"':
2303
+ # Process Double Quote
2304
+ if pos == 1:
2351
2305
  return 1, self._quoteDO
2352
- elif t1 == '"':
2353
- if pos == 1:
2354
- return 1, self._quoteDO
2355
- elif pos == 2 and t2 == '>"':
2356
- return 1, self._quoteDO
2357
- elif pos == 3 and t3 == '>>"':
2358
- return 1, self._quoteDO
2359
- else:
2360
- return 1, self._quoteDC
2306
+ elif t2[:1].isspace() and t2.endswith('"'):
2307
+ return 1, self._quoteDO
2308
+ elif pos == 2 and t2 == '>"':
2309
+ return 1, self._quoteDO
2310
+ elif pos == 3 and t3 == '>>"':
2311
+ return 1, self._quoteDO
2312
+ elif pos == 2 and t2 == '_"':
2313
+ return 1, self._quoteDO
2314
+ elif t3[:1].isspace() and t3.endswith('_"'):
2315
+ return 1, self._quoteDO
2316
+ elif pos == 3 and t3 in ('**"', '=="', '~~"'):
2317
+ return 1, self._quoteDO
2318
+ elif t4[:1].isspace() and t4.endswith(('**"', '=="', '~~"')):
2319
+ return 1, self._quoteDO
2320
+ else:
2321
+ return 1, self._quoteDC
2361
2322
 
2362
- if self._replaceSQuote:
2363
- if leading and t2.endswith("'"):
2323
+ if self._replaceSQuote and t1 == "'":
2324
+ # Process Single Quote
2325
+ if pos == 1:
2364
2326
  return 1, self._quoteSO
2365
- elif t1 == "'":
2366
- if pos == 1:
2367
- return 1, self._quoteSO
2368
- elif pos == 2 and t2 == ">'":
2369
- return 1, self._quoteSO
2370
- elif pos == 3 and t3 == ">>'":
2371
- return 1, self._quoteSO
2372
- else:
2373
- return 1, self._quoteSC
2327
+ elif t2[:1].isspace() and t2.endswith("'"):
2328
+ return 1, self._quoteSO
2329
+ elif pos == 2 and t2 == ">'":
2330
+ return 1, self._quoteSO
2331
+ elif pos == 3 and t3 == ">>'":
2332
+ return 1, self._quoteSO
2333
+ elif pos == 2 and t2 == "_'":
2334
+ return 1, self._quoteSO
2335
+ elif t3[:1].isspace() and t3.endswith("_'"):
2336
+ return 1, self._quoteSO
2337
+ elif pos == 3 and t3 in ("**'", "=='", "~~'"):
2338
+ return 1, self._quoteSO
2339
+ elif t4[:1].isspace() and t4.endswith(("**'", "=='", "~~'")):
2340
+ return 1, self._quoteSO
2341
+ else:
2342
+ return 1, self._quoteSC
2374
2343
 
2375
- if self._replaceDash:
2344
+ if self._replaceDash and t1 == "-":
2345
+ # Process Dashes
2376
2346
  if t4 == "----":
2377
2347
  return 4, "\u2015" # Horizontal bar
2378
2348
  elif t3 == "---":
@@ -2385,6 +2355,7 @@ class TextAutoReplace:
2385
2355
  return 2, "\u2015" # Horizontal bar
2386
2356
 
2387
2357
  if self._replaceDots and t3 == "...":
2358
+ # Process Dots
2388
2359
  return 3, "\u2026" # Ellipsis
2389
2360
 
2390
2361
  if t1 == "\u2028": # Line separator
@@ -2395,7 +2366,7 @@ class TextAutoReplace:
2395
2366
 
2396
2367
 
2397
2368
  class GuiDocToolBar(QWidget):
2398
- """The Formatting and Options Fold Out Menu
2369
+ """The Formatting and Options Fold Out Menu.
2399
2370
 
2400
2371
  Only used by DocEditor, and is opened by the first button in the
2401
2372
  header.
@@ -2432,6 +2403,12 @@ class GuiDocToolBar(QWidget):
2432
2403
  qtLambda(self.requestDocAction.emit, nwDocAction.MD_STRIKE)
2433
2404
  )
2434
2405
 
2406
+ self.tbMarkMD = NIconToolButton(self, iSz)
2407
+ self.tbMarkMD.setToolTip(self.tr("Markdown Highlight"))
2408
+ self.tbMarkMD.clicked.connect(
2409
+ qtLambda(self.requestDocAction.emit, nwDocAction.MD_MARK)
2410
+ )
2411
+
2435
2412
  self.tbBold = NIconToolButton(self, iSz)
2436
2413
  self.tbBold.setToolTip(self.tr("Shortcode Bold"))
2437
2414
  self.tbBold.clicked.connect(
@@ -2481,6 +2458,7 @@ class GuiDocToolBar(QWidget):
2481
2458
  self.outerBox.addWidget(self.tbBoldMD)
2482
2459
  self.outerBox.addWidget(self.tbItalicMD)
2483
2460
  self.outerBox.addWidget(self.tbStrikeMD)
2461
+ self.outerBox.addWidget(self.tbMarkMD)
2484
2462
  self.outerBox.addSpacing(4)
2485
2463
  self.outerBox.addWidget(self.tbBold)
2486
2464
  self.outerBox.addWidget(self.tbItalic)
@@ -2500,34 +2478,32 @@ class GuiDocToolBar(QWidget):
2500
2478
 
2501
2479
  logger.debug("Ready: GuiDocToolBar")
2502
2480
 
2503
- return
2504
-
2505
2481
  def updateTheme(self) -> None:
2506
2482
  """Initialise GUI elements that depend on specific settings."""
2507
- syntax = SHARED.theme.syntaxTheme
2483
+ logger.debug("Theme Update: GuiDocToolBar")
2508
2484
 
2485
+ syntax = SHARED.theme.syntaxTheme
2509
2486
  palette = self.palette()
2510
2487
  palette.setColor(QPalette.ColorRole.Window, syntax.back)
2511
2488
  palette.setColor(QPalette.ColorRole.WindowText, syntax.text)
2512
2489
  palette.setColor(QPalette.ColorRole.Text, syntax.text)
2513
2490
  self.setPalette(palette)
2514
2491
 
2515
- self.tbBoldMD.setThemeIcon("fmt_bold", "orange")
2516
- self.tbItalicMD.setThemeIcon("fmt_italic", "orange")
2517
- self.tbStrikeMD.setThemeIcon("fmt_strike", "orange")
2518
- self.tbBold.setThemeIcon("fmt_bold")
2519
- self.tbItalic.setThemeIcon("fmt_italic")
2520
- self.tbStrike.setThemeIcon("fmt_strike")
2521
- self.tbUnderline.setThemeIcon("fmt_underline")
2522
- self.tbMark.setThemeIcon("fmt_mark")
2523
- self.tbSuperscript.setThemeIcon("fmt_superscript")
2524
- self.tbSubscript.setThemeIcon("fmt_subscript")
2525
-
2526
- return
2492
+ self.tbBoldMD.setThemeIcon("fmt_bold", "markdown")
2493
+ self.tbItalicMD.setThemeIcon("fmt_italic", "markdown")
2494
+ self.tbStrikeMD.setThemeIcon("fmt_strike", "markdown")
2495
+ self.tbMarkMD.setThemeIcon("fmt_mark", "markdown")
2496
+ self.tbBold.setThemeIcon("fmt_bold", "shortcode")
2497
+ self.tbItalic.setThemeIcon("fmt_italic", "shortcode")
2498
+ self.tbStrike.setThemeIcon("fmt_strike", "shortcode")
2499
+ self.tbUnderline.setThemeIcon("fmt_underline", "shortcode")
2500
+ self.tbMark.setThemeIcon("fmt_mark", "shortcode")
2501
+ self.tbSuperscript.setThemeIcon("fmt_superscript", "shortcode")
2502
+ self.tbSubscript.setThemeIcon("fmt_subscript", "shortcode")
2527
2503
 
2528
2504
 
2529
2505
  class GuiDocEditSearch(QFrame):
2530
- """The Embedded Document Search/Replace Feature
2506
+ """The Embedded Document Search/Replace Feature.
2531
2507
 
2532
2508
  Only used by DocEditor, and is at a fixed position in the
2533
2509
  QTextEdit's viewport.
@@ -2617,7 +2593,7 @@ class GuiDocEditSearch(QFrame):
2617
2593
  # Buttons
2618
2594
  # =======
2619
2595
 
2620
- self.showReplace = NIconToggleButton(self, iSz, "unfold")
2596
+ self.showReplace = NIconToggleButton(self, iSz)
2621
2597
  self.showReplace.toggled.connect(self._doToggleReplace)
2622
2598
 
2623
2599
  self.searchButton = NIconToolButton(self, iSz)
@@ -2657,8 +2633,6 @@ class GuiDocEditSearch(QFrame):
2657
2633
 
2658
2634
  logger.debug("Ready: GuiDocEditSearch")
2659
2635
 
2660
- return
2661
-
2662
2636
  ##
2663
2637
  # Properties
2664
2638
  ##
@@ -2707,14 +2681,12 @@ class GuiDocEditSearch(QFrame):
2707
2681
  self.searchBox.selectAll()
2708
2682
  if CONFIG.searchRegEx:
2709
2683
  self._alertSearchValid(True)
2710
- return
2711
2684
 
2712
2685
  def setReplaceText(self, text: str) -> None:
2713
2686
  """Set the replace text."""
2714
2687
  self.showReplace.setChecked(True)
2715
2688
  self.replaceBox.setFocus()
2716
2689
  self.replaceBox.setText(text)
2717
- return
2718
2690
 
2719
2691
  def setResultCount(self, currRes: int | None, resCount: int | None) -> None:
2720
2692
  """Set the count values for the current search."""
@@ -2729,7 +2701,6 @@ class GuiDocEditSearch(QFrame):
2729
2701
  self.resultLabel.setMinimumWidth(minWidth)
2730
2702
  self.adjustSize()
2731
2703
  self.docEditor.updateDocMargins()
2732
- return
2733
2704
 
2734
2705
  ##
2735
2706
  # Methods
@@ -2745,36 +2716,35 @@ class GuiDocEditSearch(QFrame):
2745
2716
  self.resultLabel.setMinimumWidth(
2746
2717
  SHARED.theme.getTextWidth("?/?", SHARED.theme.guiFontSmall)
2747
2718
  )
2748
- return
2749
2719
 
2750
2720
  def updateTheme(self) -> None:
2751
2721
  """Update theme elements."""
2752
- palette = QApplication.palette()
2722
+ logger.debug("Theme Update: GuiDocEditSearch")
2753
2723
 
2724
+ palette = QApplication.palette()
2754
2725
  self.setPalette(palette)
2755
2726
  self.searchBox.setPalette(palette)
2756
2727
  self.replaceBox.setPalette(palette)
2757
2728
 
2758
2729
  # Set icons
2759
- self.toggleCase.setIcon(SHARED.theme.getIcon("search_case"))
2760
- self.toggleWord.setIcon(SHARED.theme.getIcon("search_word"))
2761
- self.toggleRegEx.setIcon(SHARED.theme.getIcon("search_regex"))
2762
- self.toggleLoop.setIcon(SHARED.theme.getIcon("search_loop"))
2763
- self.toggleProject.setIcon(SHARED.theme.getIcon("search_project"))
2764
- self.toggleMatchCap.setIcon(SHARED.theme.getIcon("search_preserve"))
2765
- self.cancelSearch.setIcon(SHARED.theme.getIcon("search_cancel"))
2766
- self.searchButton.setThemeIcon("search", "green")
2767
- self.replaceButton.setThemeIcon("search_replace", "green")
2730
+ self.toggleCase.setIcon(SHARED.theme.getIcon("search_case", "tool"))
2731
+ self.toggleWord.setIcon(SHARED.theme.getIcon("search_word", "tool"))
2732
+ self.toggleRegEx.setIcon(SHARED.theme.getIcon("search_regex", "tool"))
2733
+ self.toggleLoop.setIcon(SHARED.theme.getIcon("search_loop", "tool"))
2734
+ self.toggleProject.setIcon(SHARED.theme.getIcon("search_project", "tool"))
2735
+ self.toggleMatchCap.setIcon(SHARED.theme.getIcon("search_preserve", "tool"))
2736
+ self.cancelSearch.setIcon(SHARED.theme.getIcon("search_cancel", "tool"))
2737
+ self.searchButton.setThemeIcon("search", "action")
2738
+ self.replaceButton.setThemeIcon("search_replace", "apply")
2739
+ self.showReplace.setThemeIcon("unfold", "default")
2768
2740
 
2769
2741
  # Set stylesheets
2770
2742
  self.searchOpt.setStyleSheet("QToolBar {padding: 0;}")
2771
2743
  self.showReplace.setStyleSheet("QToolButton {border: none; background: transparent;}")
2772
2744
 
2773
- return
2774
-
2775
2745
  def cycleFocus(self) -> bool:
2776
- """The tab key just alternates focus between the two input
2777
- boxes, if the replace box is visible.
2746
+ """Cycle focus on tab key press. This just alternates focus
2747
+ between the two input boxes, if the replace box is visible.
2778
2748
  """
2779
2749
  if self.searchBox.hasFocus():
2780
2750
  self.replaceBox.setFocus()
@@ -2799,7 +2769,6 @@ class GuiDocEditSearch(QFrame):
2799
2769
  self.setVisible(False)
2800
2770
  self.docEditor.updateDocMargins()
2801
2771
  self.docEditor.setFocus()
2802
- return
2803
2772
 
2804
2773
  ##
2805
2774
  # Private Slots
@@ -2809,13 +2778,11 @@ class GuiDocEditSearch(QFrame):
2809
2778
  def _doSearch(self) -> None:
2810
2779
  """Call the search action function for the document editor."""
2811
2780
  self.docEditor.findNext(goBack=(QApplication.keyboardModifiers() == QtModShift))
2812
- return
2813
2781
 
2814
2782
  @pyqtSlot()
2815
2783
  def _doReplace(self) -> None:
2816
2784
  """Call the replace action function for the document editor."""
2817
2785
  self.docEditor.replaceNext()
2818
- return
2819
2786
 
2820
2787
  @pyqtSlot(bool)
2821
2788
  def _doToggleReplace(self, state: bool) -> None:
@@ -2824,43 +2791,36 @@ class GuiDocEditSearch(QFrame):
2824
2791
  self.replaceButton.setVisible(state)
2825
2792
  self.adjustSize()
2826
2793
  self.docEditor.updateDocMargins()
2827
- return
2828
2794
 
2829
2795
  @pyqtSlot(bool)
2830
2796
  def _doToggleCase(self, state: bool) -> None:
2831
2797
  """Enable/disable case sensitive mode."""
2832
2798
  CONFIG.searchCase = state
2833
- return
2834
2799
 
2835
2800
  @pyqtSlot(bool)
2836
2801
  def _doToggleWord(self, state: bool) -> None:
2837
2802
  """Enable/disable whole word search mode."""
2838
2803
  CONFIG.searchWord = state
2839
- return
2840
2804
 
2841
2805
  @pyqtSlot(bool)
2842
2806
  def _doToggleRegEx(self, state: bool) -> None:
2843
2807
  """Enable/disable regular expression search mode."""
2844
2808
  CONFIG.searchRegEx = state
2845
- return
2846
2809
 
2847
2810
  @pyqtSlot(bool)
2848
2811
  def _doToggleLoop(self, state: bool) -> None:
2849
2812
  """Enable/disable looping the search."""
2850
2813
  CONFIG.searchLoop = state
2851
- return
2852
2814
 
2853
2815
  @pyqtSlot(bool)
2854
2816
  def _doToggleProject(self, state: bool) -> None:
2855
2817
  """Enable/disable continuing search in next project file."""
2856
2818
  CONFIG.searchNextFile = state
2857
- return
2858
2819
 
2859
2820
  @pyqtSlot(bool)
2860
2821
  def _doToggleMatchCap(self, state: bool) -> None:
2861
2822
  """Enable/disable preserving capitalisation when replacing."""
2862
2823
  CONFIG.searchMatchCap = state
2863
- return
2864
2824
 
2865
2825
  ##
2866
2826
  # Internal Functions
@@ -2876,11 +2836,10 @@ class GuiDocEditSearch(QFrame):
2876
2836
  palette.text().color() if isValid else SHARED.theme.errorText
2877
2837
  )
2878
2838
  self.searchBox.setPalette(palette)
2879
- return
2880
2839
 
2881
2840
 
2882
2841
  class GuiDocEditHeader(QWidget):
2883
- """The Embedded Document Header
2842
+ """The Embedded Document Header.
2884
2843
 
2885
2844
  Only used by DocEditor, and is at a fixed position in the
2886
2845
  QTextEdit's viewport.
@@ -2971,8 +2930,6 @@ class GuiDocEditHeader(QWidget):
2971
2930
 
2972
2931
  logger.debug("Ready: GuiDocEditHeader")
2973
2932
 
2974
- return
2975
-
2976
2933
  ##
2977
2934
  # Methods
2978
2935
  ##
@@ -2989,7 +2946,6 @@ class GuiDocEditHeader(QWidget):
2989
2946
  self.searchButton.setVisible(False)
2990
2947
  self.closeButton.setVisible(False)
2991
2948
  self.minmaxButton.setVisible(False)
2992
- return
2993
2949
 
2994
2950
  def setOutline(self, data: dict[int, str]) -> None:
2995
2951
  """Set the document outline dataset."""
@@ -3001,21 +2957,21 @@ class GuiDocEditHeader(QWidget):
3001
2957
  action.triggered.connect(qtLambda(self._gotoBlock, number))
3002
2958
  self._docOutline = data
3003
2959
  logger.debug("Document outline updated in %.3f ms", 1000*(time() - tStart))
3004
- return
3005
2960
 
3006
2961
  def updateFont(self) -> None:
3007
2962
  """Update the font settings."""
3008
2963
  self.setFont(SHARED.theme.guiFont)
3009
2964
  self.itemTitle.setFont(SHARED.theme.guiFontSmall)
3010
- return
3011
2965
 
3012
2966
  def updateTheme(self) -> None:
3013
2967
  """Update theme elements."""
3014
- self.tbButton.setThemeIcon("fmt_toolbar", "blue")
3015
- self.outlineButton.setThemeIcon("list", "blue")
3016
- self.searchButton.setThemeIcon("search", "blue")
3017
- self.minmaxButton.setThemeIcon("maximise", "blue")
3018
- self.closeButton.setThemeIcon("close", "red")
2968
+ logger.debug("Theme Update: GuiDocEditHeader")
2969
+
2970
+ self.tbButton.setThemeIcon("fmt_toolbar", "action")
2971
+ self.outlineButton.setThemeIcon("list", "action")
2972
+ self.searchButton.setThemeIcon("search", "action")
2973
+ self.minmaxButton.setThemeIcon("maximise", "action")
2974
+ self.closeButton.setThemeIcon("close", "reject")
3019
2975
 
3020
2976
  buttonStyle = SHARED.theme.getStyleSheet(STYLES_MIN_TOOLBUTTON)
3021
2977
  self.tbButton.setStyleSheet(buttonStyle)
@@ -3026,8 +2982,6 @@ class GuiDocEditHeader(QWidget):
3026
2982
 
3027
2983
  self.matchColors()
3028
2984
 
3029
- return
3030
-
3031
2985
  def matchColors(self) -> None:
3032
2986
  """Update the colours of the widget to match those of the syntax
3033
2987
  theme rather than the main GUI.
@@ -3041,12 +2995,10 @@ class GuiDocEditHeader(QWidget):
3041
2995
  self.itemTitle.setTextColors(
3042
2996
  color=palette.windowText().color(), faded=SHARED.theme.fadedText
3043
2997
  )
3044
- return
3045
2998
 
3046
2999
  def changeFocusState(self, state: bool) -> None:
3047
3000
  """Toggle focus state."""
3048
3001
  self.itemTitle.setColorState(state)
3049
- return
3050
3002
 
3051
3003
  def setHandle(self, tHandle: str) -> None:
3052
3004
  """Set the document title from the handle, or alternatively, set
@@ -3067,8 +3019,6 @@ class GuiDocEditHeader(QWidget):
3067
3019
  self.closeButton.setVisible(True)
3068
3020
  self.minmaxButton.setVisible(True)
3069
3021
 
3070
- return
3071
-
3072
3022
  ##
3073
3023
  # Private Slots
3074
3024
  ##
@@ -3078,19 +3028,16 @@ class GuiDocEditHeader(QWidget):
3078
3028
  """Trigger the close editor on the main window."""
3079
3029
  self.clearHeader()
3080
3030
  self.closeDocumentRequest.emit()
3081
- return
3082
3031
 
3083
3032
  @pyqtSlot(int)
3084
3033
  def _gotoBlock(self, blockNumber: int) -> None:
3085
3034
  """Move cursor to a specific heading."""
3086
3035
  self.docEditor.setCursorLine(blockNumber + 1)
3087
- return
3088
3036
 
3089
3037
  @pyqtSlot(bool)
3090
3038
  def _focusModeChanged(self, focusMode: bool) -> None:
3091
3039
  """Update minimise/maximise icon of the Focus Mode button."""
3092
- self.minmaxButton.setThemeIcon("minimise" if focusMode else "maximise", "blue")
3093
- return
3040
+ self.minmaxButton.setThemeIcon("minimise" if focusMode else "maximise", "action")
3094
3041
 
3095
3042
  ##
3096
3043
  # Events
@@ -3102,11 +3049,10 @@ class GuiDocEditHeader(QWidget):
3102
3049
  """
3103
3050
  if event.button() == QtMouseLeft:
3104
3051
  self.docEditor.requestProjectItemSelected.emit(self._docHandle or "", True)
3105
- return
3106
3052
 
3107
3053
 
3108
3054
  class GuiDocEditFooter(QWidget):
3109
- """The Embedded Document Footer
3055
+ """The Embedded Document Footer.
3110
3056
 
3111
3057
  Only used by DocEditor, and is at a fixed position in the
3112
3058
  QTextEdit's viewport.
@@ -3191,8 +3137,6 @@ class GuiDocEditFooter(QWidget):
3191
3137
 
3192
3138
  logger.debug("Ready: GuiDocEditFooter")
3193
3139
 
3194
- return
3195
-
3196
3140
  ##
3197
3141
  # Methods
3198
3142
  ##
@@ -3202,7 +3146,6 @@ class GuiDocEditFooter(QWidget):
3202
3146
  self._trMainCount = trStats(nwLabels.STATS_DISPLAY[
3203
3147
  nwStats.CHARS if CONFIG.useCharCount else nwStats.WORDS
3204
3148
  ])
3205
- return
3206
3149
 
3207
3150
  def updateFont(self) -> None:
3208
3151
  """Update the font settings."""
@@ -3210,15 +3153,15 @@ class GuiDocEditFooter(QWidget):
3210
3153
  self.statusText.setFont(SHARED.theme.guiFontSmall)
3211
3154
  self.linesText.setFont(SHARED.theme.guiFontSmall)
3212
3155
  self.wordsText.setFont(SHARED.theme.guiFontSmall)
3213
- return
3214
3156
 
3215
3157
  def updateTheme(self) -> None:
3216
3158
  """Update theme elements."""
3159
+ logger.debug("Theme Update: GuiDocEditFooter")
3160
+
3217
3161
  iPx = round(0.9*SHARED.theme.baseIconHeight)
3218
3162
  self.linesIcon.setPixmap(SHARED.theme.getPixmap("lines", (iPx, iPx)))
3219
3163
  self.wordsIcon.setPixmap(SHARED.theme.getPixmap("stats", (iPx, iPx)))
3220
3164
  self.matchColors()
3221
- return
3222
3165
 
3223
3166
  def matchColors(self) -> None:
3224
3167
  """Update the colours of the widget to match those of the syntax
@@ -3236,8 +3179,6 @@ class GuiDocEditFooter(QWidget):
3236
3179
  self.linesText.setPalette(palette)
3237
3180
  self.wordsText.setPalette(palette)
3238
3181
 
3239
- return
3240
-
3241
3182
  def setHandle(self, tHandle: str | None) -> None:
3242
3183
  """Set the handle that will populate the footer's data."""
3243
3184
  self._docHandle = tHandle
@@ -3250,8 +3191,6 @@ class GuiDocEditFooter(QWidget):
3250
3191
  self.updateInfo()
3251
3192
  self.updateMainCount(0, False)
3252
3193
 
3253
- return
3254
-
3255
3194
  def updateInfo(self) -> None:
3256
3195
  """Update the content of text labels."""
3257
3196
  if self._tItem is None:
@@ -3266,8 +3205,6 @@ class GuiDocEditFooter(QWidget):
3266
3205
  self.statusIcon.setPixmap(sIcon)
3267
3206
  self.statusText.setText(sText)
3268
3207
 
3269
- return
3270
-
3271
3208
  def updateLineCount(self, cursor: QTextCursor) -> None:
3272
3209
  """Update the line and document position counter."""
3273
3210
  if document := cursor.document():
@@ -3277,7 +3214,6 @@ class GuiDocEditFooter(QWidget):
3277
3214
  self.linesText.setText(
3278
3215
  self._trLineCount.format(f"{cLine:n}", f"{100*cPos//cCount:d} %")
3279
3216
  )
3280
- return
3281
3217
 
3282
3218
  def updateMainCount(self, count: int, selection: bool) -> None:
3283
3219
  """Update main counter information."""
@@ -3290,4 +3226,3 @@ class GuiDocEditFooter(QWidget):
3290
3226
  else:
3291
3227
  text = self._trMainCount.format("0", "+0")
3292
3228
  self.wordsText.setText(text)
3293
- return