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.
- novelwriter/__init__.py +8 -7
 - novelwriter/assets/icons/font_awesome.icons +22 -4
 - novelwriter/assets/icons/material_filled_normal.icons +20 -2
 - novelwriter/assets/icons/material_filled_thin.icons +20 -2
 - novelwriter/assets/icons/material_rounded_normal.icons +20 -2
 - novelwriter/assets/icons/material_rounded_thin.icons +20 -2
 - novelwriter/assets/icons/material_sharp_normal.icons +20 -2
 - novelwriter/assets/icons/material_sharp_thin.icons +20 -2
 - novelwriter/assets/icons/remix_filled.icons +20 -2
 - novelwriter/assets/icons/remix_outline.icons +20 -2
 - novelwriter/assets/images/welcome.webp +0 -0
 - novelwriter/assets/manual.pdf +0 -0
 - novelwriter/assets/manual_fr.pdf +0 -0
 - novelwriter/assets/sample.zip +0 -0
 - novelwriter/assets/text/credits_en.htm +61 -11
 - novelwriter/assets/themes/aura.conf +97 -0
 - novelwriter/assets/themes/aura_bright.conf +95 -0
 - novelwriter/assets/themes/aura_soft.conf +97 -0
 - novelwriter/assets/themes/b2t_garden_dark.conf +97 -0
 - novelwriter/assets/themes/b2t_garden_light.conf +97 -0
 - novelwriter/assets/themes/b2t_suburb_dark.conf +97 -0
 - novelwriter/assets/themes/b2t_suburb_light.conf +97 -0
 - novelwriter/assets/themes/b4t_classic_o_dark.conf +97 -0
 - novelwriter/assets/themes/b4t_classic_o_light.conf +97 -0
 - novelwriter/assets/themes/b4t_modern_c_dark.conf +97 -0
 - novelwriter/assets/themes/b4t_modern_c_light.conf +97 -0
 - novelwriter/assets/themes/blue_streak_dark.conf +97 -0
 - novelwriter/assets/themes/blue_streak_light.conf +97 -0
 - novelwriter/assets/themes/castle_day.conf +95 -0
 - novelwriter/assets/themes/castle_night.conf +95 -0
 - novelwriter/assets/themes/catppuccin_latte.conf +97 -0
 - novelwriter/assets/themes/catppuccin_mocha.conf +97 -0
 - novelwriter/assets/themes/chalky_soil.conf +95 -0
 - novelwriter/assets/themes/chernozem.conf +95 -0
 - novelwriter/assets/themes/cyberpunk_night.conf +88 -40
 - novelwriter/assets/themes/default_dark.conf +89 -41
 - novelwriter/assets/themes/default_light.conf +89 -41
 - novelwriter/assets/themes/dracula.conf +91 -42
 - novelwriter/assets/themes/espresso.conf +97 -0
 - novelwriter/assets/themes/everforest_dark.conf +97 -0
 - novelwriter/assets/themes/everforest_light.conf +97 -0
 - novelwriter/assets/themes/floral_daydream.conf +95 -0
 - novelwriter/assets/themes/floral_midnight.conf +95 -0
 - novelwriter/assets/themes/full_moon.conf +95 -0
 - novelwriter/assets/themes/grey_dark.conf +97 -0
 - novelwriter/assets/themes/grey_light.conf +97 -0
 - novelwriter/assets/themes/horizon_dark.conf +97 -0
 - novelwriter/assets/themes/horizon_light.conf +97 -0
 - novelwriter/assets/themes/jewel_case_dark.conf +95 -0
 - novelwriter/assets/themes/jewel_case_light.conf +95 -0
 - novelwriter/assets/themes/lcars.conf +97 -0
 - novelwriter/assets/themes/light_owl.conf +117 -0
 - novelwriter/assets/themes/new_moon.conf +97 -0
 - novelwriter/assets/themes/night_owl.conf +117 -0
 - novelwriter/assets/themes/noctis.conf +129 -0
 - novelwriter/assets/themes/noctis_lux.conf +129 -0
 - novelwriter/assets/themes/nord.conf +97 -0
 - novelwriter/assets/themes/nordlicht.conf +95 -0
 - novelwriter/assets/themes/otium_dark.conf +95 -0
 - novelwriter/assets/themes/otium_light.conf +95 -0
 - novelwriter/assets/themes/paragon.conf +96 -0
 - novelwriter/assets/themes/primer_light.conf +97 -0
 - novelwriter/assets/themes/primer_night.conf +97 -0
 - novelwriter/assets/themes/rose_pine.conf +97 -0
 - novelwriter/assets/themes/rose_pine_dawn.conf +97 -0
 - novelwriter/assets/themes/ruby_day.conf +95 -0
 - novelwriter/assets/themes/ruby_night.conf +95 -0
 - novelwriter/assets/themes/selenium_dark.conf +95 -0
 - novelwriter/assets/themes/selenium_light.conf +95 -0
 - novelwriter/assets/themes/sepia_dark.conf +95 -0
 - novelwriter/assets/themes/sepia_light.conf +95 -0
 - novelwriter/assets/themes/snazzy.conf +102 -40
 - novelwriter/assets/themes/solarized_dark.conf +108 -40
 - novelwriter/assets/themes/solarized_light.conf +108 -40
 - novelwriter/assets/themes/sultana_light.conf +95 -0
 - novelwriter/assets/themes/sultana_night.conf +95 -0
 - novelwriter/assets/themes/tango_dark.conf +111 -0
 - novelwriter/assets/themes/tango_light.conf +111 -0
 - novelwriter/assets/themes/tomorrow.conf +117 -0
 - novelwriter/assets/themes/tomorrow_night.conf +117 -0
 - novelwriter/assets/themes/tomorrow_night_blue.conf +117 -0
 - novelwriter/assets/themes/tomorrow_night_bright.conf +117 -0
 - novelwriter/assets/themes/tomorrow_night_eighties.conf +117 -0
 - novelwriter/assets/themes/vivid_black_green.conf +97 -0
 - novelwriter/assets/themes/vivid_black_red.conf +97 -0
 - novelwriter/assets/themes/vivid_white_green.conf +97 -0
 - novelwriter/assets/themes/vivid_white_red.conf +97 -0
 - novelwriter/assets/themes/warpgate.conf +96 -0
 - novelwriter/assets/themes/waterlily_dark.conf +95 -0
 - novelwriter/assets/themes/waterlily_light.conf +95 -0
 - novelwriter/common.py +47 -17
 - novelwriter/config.py +57 -62
 - novelwriter/constants.py +32 -6
 - novelwriter/core/buildsettings.py +3 -23
 - novelwriter/core/coretools.py +21 -25
 - novelwriter/core/docbuild.py +4 -9
 - novelwriter/core/document.py +2 -6
 - novelwriter/core/index.py +33 -53
 - novelwriter/core/indexdata.py +17 -22
 - novelwriter/core/item.py +11 -35
 - novelwriter/core/itemmodel.py +5 -21
 - novelwriter/core/novelmodel.py +3 -7
 - novelwriter/core/options.py +3 -4
 - novelwriter/core/project.py +31 -21
 - novelwriter/core/projectdata.py +2 -21
 - novelwriter/core/projectxml.py +13 -21
 - novelwriter/core/sessions.py +2 -4
 - novelwriter/core/spellcheck.py +12 -13
 - novelwriter/core/status.py +27 -20
 - novelwriter/core/storage.py +5 -10
 - novelwriter/core/tree.py +6 -15
 - novelwriter/dialogs/about.py +9 -10
 - novelwriter/dialogs/docmerge.py +17 -14
 - novelwriter/dialogs/docsplit.py +18 -14
 - novelwriter/dialogs/editlabel.py +15 -9
 - novelwriter/dialogs/preferences.py +69 -68
 - novelwriter/dialogs/projectsettings.py +88 -67
 - novelwriter/dialogs/quotes.py +15 -10
 - novelwriter/dialogs/wordlist.py +18 -21
 - novelwriter/enum.py +75 -30
 - novelwriter/error.py +6 -11
 - novelwriter/extensions/configlayout.py +8 -34
 - novelwriter/extensions/eventfilters.py +3 -3
 - novelwriter/extensions/modified.py +87 -32
 - novelwriter/extensions/novelselector.py +13 -12
 - novelwriter/extensions/pagedsidebar.py +10 -18
 - novelwriter/extensions/progressbars.py +5 -11
 - novelwriter/extensions/statusled.py +3 -6
 - novelwriter/extensions/switch.py +8 -11
 - novelwriter/extensions/switchbox.py +2 -11
 - novelwriter/extensions/versioninfo.py +6 -7
 - novelwriter/formats/shared.py +10 -2
 - novelwriter/formats/todocx.py +15 -37
 - novelwriter/formats/tohtml.py +52 -61
 - novelwriter/formats/tokenizer.py +33 -64
 - novelwriter/formats/tomarkdown.py +4 -11
 - novelwriter/formats/toodt.py +12 -71
 - novelwriter/formats/toqdoc.py +11 -21
 - novelwriter/formats/toraw.py +2 -6
 - novelwriter/gui/doceditor.py +207 -245
 - novelwriter/gui/dochighlight.py +142 -101
 - novelwriter/gui/docviewer.py +53 -84
 - novelwriter/gui/docviewerpanel.py +18 -41
 - novelwriter/gui/editordocument.py +12 -17
 - novelwriter/gui/itemdetails.py +5 -14
 - novelwriter/gui/mainmenu.py +24 -32
 - novelwriter/gui/noveltree.py +13 -51
 - novelwriter/gui/outline.py +20 -61
 - novelwriter/gui/projtree.py +40 -96
 - novelwriter/gui/search.py +9 -24
 - novelwriter/gui/sidebar.py +54 -22
 - novelwriter/gui/statusbar.py +7 -22
 - novelwriter/gui/theme.py +482 -368
 - novelwriter/guimain.py +87 -101
 - novelwriter/shared.py +79 -48
 - novelwriter/splash.py +9 -5
 - novelwriter/text/comments.py +1 -1
 - novelwriter/text/counting.py +9 -5
 - novelwriter/text/patterns.py +20 -15
 - novelwriter/tools/dictionaries.py +18 -16
 - novelwriter/tools/lipsum.py +15 -17
 - novelwriter/tools/manusbuild.py +25 -45
 - novelwriter/tools/manuscript.py +94 -95
 - novelwriter/tools/manussettings.py +149 -104
 - novelwriter/tools/noveldetails.py +10 -24
 - novelwriter/tools/welcome.py +24 -72
 - novelwriter/tools/writingstats.py +17 -26
 - novelwriter/types.py +25 -13
 - {novelwriter-2.7.4.dist-info → novelwriter-2.8b1.dist-info}/METADATA +7 -7
 - novelwriter-2.8b1.dist-info/RECORD +212 -0
 - novelwriter/assets/images/welcome-dark.jpg +0 -0
 - novelwriter/assets/images/welcome-light.jpg +0 -0
 - novelwriter/assets/syntax/cyberpunk_night.conf +0 -28
 - novelwriter/assets/syntax/default_dark.conf +0 -42
 - novelwriter/assets/syntax/default_light.conf +0 -42
 - novelwriter/assets/syntax/dracula.conf +0 -44
 - novelwriter/assets/syntax/grey_dark.conf +0 -29
 - novelwriter/assets/syntax/grey_light.conf +0 -29
 - novelwriter/assets/syntax/light_owl.conf +0 -49
 - novelwriter/assets/syntax/night_owl.conf +0 -49
 - novelwriter/assets/syntax/snazzy.conf +0 -42
 - novelwriter/assets/syntax/solarized_dark.conf +0 -29
 - novelwriter/assets/syntax/solarized_light.conf +0 -29
 - novelwriter/assets/syntax/tango.conf +0 -39
 - novelwriter/assets/syntax/tomorrow.conf +0 -49
 - novelwriter/assets/syntax/tomorrow_night.conf +0 -49
 - novelwriter/assets/syntax/tomorrow_night_blue.conf +0 -49
 - novelwriter/assets/syntax/tomorrow_night_bright.conf +0 -49
 - novelwriter/assets/syntax/tomorrow_night_eighties.conf +0 -49
 - novelwriter/assets/themes/default.conf +0 -3
 - novelwriter-2.7.4.dist-info/RECORD +0 -163
 - {novelwriter-2.7.4.dist-info → novelwriter-2.8b1.dist-info}/WHEEL +0 -0
 - {novelwriter-2.7.4.dist-info → novelwriter-2.8b1.dist-info}/entry_points.txt +0 -0
 - {novelwriter-2.7.4.dist-info → novelwriter-2.8b1.dist-info}/licenses/LICENSE.md +0 -0
 - {novelwriter-2.7.4.dist-info → novelwriter-2.8b1.dist-info}/licenses/setup/LICENSE-Apache-2.0.txt +0 -0
 - {novelwriter-2.7.4.dist-info → novelwriter-2.8b1.dist-info}/top_level.txt +0 -0
 
    
        novelwriter/gui/doceditor.py
    CHANGED
    
    | 
         @@ -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
         
     | 
| 
         @@ -39,17 +39,18 @@ from enum import Enum, IntFlag 
     | 
|
| 
       39 
39 
     | 
    
         
             
            from time import time
         
     | 
| 
       40 
40 
     | 
    
         | 
| 
       41 
41 
     | 
    
         
             
            from PyQt6.QtCore import (
         
     | 
| 
       42 
     | 
    
         
            -
                QObject, QPoint, QRegularExpression, QRunnable, Qt, QTimer, 
     | 
| 
       43 
     | 
    
         
            -
                pyqtSlot
         
     | 
| 
      
 42 
     | 
    
         
            +
                QObject, QPoint, QRect, QRegularExpression, QRunnable, Qt, QTimer,
         
     | 
| 
      
 43 
     | 
    
         
            +
                QVariant, pyqtSignal, pyqtSlot
         
     | 
| 
       44 
44 
     | 
    
         
             
            )
         
     | 
| 
       45 
45 
     | 
    
         
             
            from PyQt6.QtGui import (
         
     | 
| 
       46 
     | 
    
         
            -
                QAction, QCursor, QDragEnterEvent, QDragMoveEvent, QDropEvent, 
     | 
| 
       47 
     | 
    
         
            -
                QKeySequence, QMouseEvent, QPalette, QPixmap, 
     | 
| 
       48 
     | 
    
         
            -
                QTextBlock, QTextCursor, QTextDocument, 
     | 
| 
      
 46 
     | 
    
         
            +
                QAction, QCursor, QDragEnterEvent, QDragMoveEvent, QDropEvent,
         
     | 
| 
      
 47 
     | 
    
         
            +
                QInputMethodEvent, QKeyEvent, QKeySequence, QMouseEvent, QPalette, QPixmap,
         
     | 
| 
      
 48 
     | 
    
         
            +
                QResizeEvent, QShortcut, QTextBlock, QTextCursor, QTextDocument,
         
     | 
| 
      
 49 
     | 
    
         
            +
                QTextFormat, QTextOption
         
     | 
| 
       49 
50 
     | 
    
         
             
            )
         
     | 
| 
       50 
51 
     | 
    
         
             
            from PyQt6.QtWidgets import (
         
     | 
| 
       51 
52 
     | 
    
         
             
                QApplication, QFrame, QGridLayout, QHBoxLayout, QLabel, QLineEdit, QMenu,
         
     | 
| 
       52 
     | 
    
         
            -
                QPlainTextEdit, QToolBar, QVBoxLayout, QWidget
         
     | 
| 
      
 53 
     | 
    
         
            +
                QPlainTextEdit, QTextEdit, QToolBar, QVBoxLayout, QWidget
         
     | 
| 
       53 
54 
     | 
    
         
             
            )
         
     | 
| 
       54 
55 
     | 
    
         | 
| 
       55 
56 
     | 
    
         
             
            from novelwriter import CONFIG, SHARED
         
     | 
| 
         @@ -74,8 +75,10 @@ from novelwriter.text.counting import standardCounter 
     | 
|
| 
       74 
75 
     | 
    
         
             
            from novelwriter.tools.lipsum import GuiLipsum
         
     | 
| 
       75 
76 
     | 
    
         
             
            from novelwriter.types import (
         
     | 
| 
       76 
77 
     | 
    
         
             
                QtAlignCenterTop, QtAlignJustify, QtAlignLeft, QtAlignLeftTop,
         
     | 
| 
       77 
     | 
    
         
            -
                QtAlignRight, QtKeepAnchor, QtModCtrl, QtModNone, 
     | 
| 
       78 
     | 
    
         
            -
                QtMoveAnchor, QtMoveLeft, QtMoveRight, 
     | 
| 
      
 78 
     | 
    
         
            +
                QtAlignRight, QtImCursorRectangle, QtKeepAnchor, QtModCtrl, QtModNone,
         
     | 
| 
      
 79 
     | 
    
         
            +
                QtModShift, QtMouseLeft, QtMoveAnchor, QtMoveLeft, QtMoveRight,
         
     | 
| 
      
 80 
     | 
    
         
            +
                QtScrollAlwaysOff, QtScrollAsNeeded, QtSelectBlock, QtSelectDocument,
         
     | 
| 
      
 81 
     | 
    
         
            +
                QtSelectWord, QtTransparent
         
     | 
| 
       79 
82 
     | 
    
         
             
            )
         
     | 
| 
       80 
83 
     | 
    
         | 
| 
       81 
84 
     | 
    
         
             
            logger = logging.getLogger(__name__)
         
     | 
| 
         @@ -97,7 +100,7 @@ class _TagAction(IntFlag): 
     | 
|
| 
       97 
100 
     | 
    
         | 
| 
       98 
101 
     | 
    
         | 
| 
       99 
102 
     | 
    
         
             
            class GuiDocEditor(QPlainTextEdit):
         
     | 
| 
       100 
     | 
    
         
            -
                """Gui Widget: Main Document Editor"""
         
     | 
| 
      
 103 
     | 
    
         
            +
                """Gui Widget: Main Document Editor."""
         
     | 
| 
       101 
104 
     | 
    
         | 
| 
       102 
105 
     | 
    
         
             
                __slots__ = (
         
     | 
| 
       103 
106 
     | 
    
         
             
                    "_autoReplace", "_completer", "_doReplace", "_docChanged", "_docHandle", "_followTag1",
         
     | 
| 
         @@ -145,13 +148,15 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       145 
148 
     | 
    
         
             
                    self._lastActive = 0.0    # Timestamp of last activity
         
     | 
| 
       146 
149 
     | 
    
         
             
                    self._lastFind   = None   # Position of the last found search word
         
     | 
| 
       147 
150 
     | 
    
         
             
                    self._doReplace  = False  # Switch to temporarily disable auto-replace
         
     | 
| 
      
 151 
     | 
    
         
            +
                    self._lineColor  = QtTransparent
         
     | 
| 
      
 152 
     | 
    
         
            +
                    self._selection  = QTextEdit.ExtraSelection()
         
     | 
| 
       148 
153 
     | 
    
         | 
| 
       149 
154 
     | 
    
         
             
                    # Auto-Replace
         
     | 
| 
       150 
155 
     | 
    
         
             
                    self._autoReplace = TextAutoReplace()
         
     | 
| 
       151 
156 
     | 
    
         | 
| 
       152 
157 
     | 
    
         
             
                    # Completer
         
     | 
| 
       153 
158 
     | 
    
         
             
                    self._completer = CommandCompleter(self)
         
     | 
| 
       154 
     | 
    
         
            -
                    self._completer. 
     | 
| 
      
 159 
     | 
    
         
            +
                    self._completer.insertText.connect(self._insertCompletion)
         
     | 
| 
       155 
160 
     | 
    
         | 
| 
       156 
161 
     | 
    
         
             
                    # Create Custom Document
         
     | 
| 
       157 
162 
     | 
    
         
             
                    self._qDocument = GuiTextDocument(self)
         
     | 
| 
         @@ -233,8 +238,6 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       233 
238 
     | 
    
         | 
| 
       234 
239 
     | 
    
         
             
                    logger.debug("Ready: GuiDocEditor")
         
     | 
| 
       235 
240 
     | 
    
         | 
| 
       236 
     | 
    
         
            -
                    return
         
     | 
| 
       237 
     | 
    
         
            -
             
     | 
| 
       238 
241 
     | 
    
         
             
                ##
         
     | 
| 
       239 
242 
     | 
    
         
             
                #  Properties
         
     | 
| 
       240 
243 
     | 
    
         
             
                ##
         
     | 
| 
         @@ -283,18 +286,18 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       283 
286 
     | 
    
         
             
                    self.docHeader.clearHeader()
         
     | 
| 
       284 
287 
     | 
    
         
             
                    self.docFooter.setHandle(self._docHandle)
         
     | 
| 
       285 
288 
     | 
    
         
             
                    self.docToolBar.setVisible(False)
         
     | 
| 
      
 289 
     | 
    
         
            +
                    self.setExtraSelections([])
         
     | 
| 
       286 
290 
     | 
    
         | 
| 
       287 
291 
     | 
    
         
             
                    self.itemHandleChanged.emit("")
         
     | 
| 
       288 
292 
     | 
    
         | 
| 
       289 
     | 
    
         
            -
                    return
         
     | 
| 
       290 
     | 
    
         
            -
             
     | 
| 
       291 
293 
     | 
    
         
             
                def updateTheme(self) -> None:
         
     | 
| 
       292 
294 
     | 
    
         
             
                    """Update theme elements."""
         
     | 
| 
      
 295 
     | 
    
         
            +
                    logger.debug("Theme Update: GuiDocEditor")
         
     | 
| 
      
 296 
     | 
    
         
            +
             
     | 
| 
       293 
297 
     | 
    
         
             
                    self.docSearch.updateTheme()
         
     | 
| 
       294 
298 
     | 
    
         
             
                    self.docHeader.updateTheme()
         
     | 
| 
       295 
299 
     | 
    
         
             
                    self.docFooter.updateTheme()
         
     | 
| 
       296 
300 
     | 
    
         
             
                    self.docToolBar.updateTheme()
         
     | 
| 
       297 
     | 
    
         
            -
                    return
         
     | 
| 
       298 
301 
     | 
    
         | 
| 
       299 
302 
     | 
    
         
             
                def updateSyntaxColors(self) -> None:
         
     | 
| 
       300 
303 
     | 
    
         
             
                    """Update the syntax highlighting theme."""
         
     | 
| 
         @@ -315,7 +318,9 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       315 
318 
     | 
    
         
             
                    self.docHeader.matchColors()
         
     | 
| 
       316 
319 
     | 
    
         
             
                    self.docFooter.matchColors()
         
     | 
| 
       317 
320 
     | 
    
         | 
| 
       318 
     | 
    
         
            -
                     
     | 
| 
      
 321 
     | 
    
         
            +
                    self._lineColor = syntax.line
         
     | 
| 
      
 322 
     | 
    
         
            +
                    self._selection.format.setBackground(self._lineColor)
         
     | 
| 
      
 323 
     | 
    
         
            +
                    self._selection.format.setProperty(QTextFormat.Property.FullWidthSelection, True)
         
     | 
| 
       319 
324 
     | 
    
         | 
| 
       320 
325 
     | 
    
         
             
                def initEditor(self) -> None:
         
     | 
| 
       321 
326 
     | 
    
         
             
                    """Initialise or re-initialise the editor with the user's
         
     | 
| 
         @@ -372,6 +377,8 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       372 
377 
     | 
    
         
             
                    # Refresh sizes
         
     | 
| 
       373 
378 
     | 
    
         
             
                    self.setTabStopDistance(CONFIG.tabWidth)
         
     | 
| 
       374 
379 
     | 
    
         
             
                    self.setCursorWidth(CONFIG.cursorWidth)
         
     | 
| 
      
 380 
     | 
    
         
            +
                    self.setExtraSelections([])
         
     | 
| 
      
 381 
     | 
    
         
            +
                    self._cursorMoved()
         
     | 
| 
       375 
382 
     | 
    
         | 
| 
       376 
383 
     | 
    
         
             
                    # If we have a document open, we should refresh it in case the
         
     | 
| 
       377 
384 
     | 
    
         
             
                    # font changed, otherwise we just clear the editor entirely,
         
     | 
| 
         @@ -382,8 +389,6 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       382 
389 
     | 
    
         
             
                    else:
         
     | 
| 
       383 
390 
     | 
    
         
             
                        self.clearEditor()
         
     | 
| 
       384 
391 
     | 
    
         | 
| 
       385 
     | 
    
         
            -
                    return
         
     | 
| 
       386 
     | 
    
         
            -
             
     | 
| 
       387 
392 
     | 
    
         
             
                def loadText(self, tHandle: str, tLine: int | None = None) -> bool:
         
     | 
| 
       388 
393 
     | 
    
         
             
                    """Load text from a document into the editor. If we have an I/O
         
     | 
| 
       389 
394 
     | 
    
         
             
                    error, we must handle this and clear the editor so that we don't
         
     | 
| 
         @@ -461,7 +466,6 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       461 
466 
     | 
    
         
             
                    self.updateDocMargins()
         
     | 
| 
       462 
467 
     | 
    
         
             
                    self.setDocumentChanged(True)
         
     | 
| 
       463 
468 
     | 
    
         
             
                    QApplication.restoreOverrideCursor()
         
     | 
| 
       464 
     | 
    
         
            -
                    return
         
     | 
| 
       465 
469 
     | 
    
         | 
| 
       466 
470 
     | 
    
         
             
                def saveText(self) -> bool:
         
     | 
| 
       467 
471 
     | 
    
         
             
                    """Save the text currently in the editor to the NWDocument
         
     | 
| 
         @@ -529,7 +533,6 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       529 
533 
     | 
    
         
             
                                vBar.setValue(vBar.value() + 1)
         
     | 
| 
       530 
534 
     | 
    
         
             
                                count += 1
         
     | 
| 
       531 
535 
     | 
    
         
             
                        QApplication.processEvents()
         
     | 
| 
       532 
     | 
    
         
            -
                    return
         
     | 
| 
       533 
536 
     | 
    
         | 
| 
       534 
537 
     | 
    
         
             
                def updateDocMargins(self) -> None:
         
     | 
| 
       535 
538 
     | 
    
         
             
                    """Automatically adjust the margins so the text is centred if
         
     | 
| 
         @@ -570,8 +573,6 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       570 
573 
     | 
    
         
             
                    lM = max(self._vpMargin, fH)
         
     | 
| 
       571 
574 
     | 
    
         
             
                    self.setViewportMargins(tM, uM, tM, lM)
         
     | 
| 
       572 
575 
     | 
    
         | 
| 
       573 
     | 
    
         
            -
                    return
         
     | 
| 
       574 
     | 
    
         
            -
             
     | 
| 
       575 
576 
     | 
    
         
             
                ##
         
     | 
| 
       576 
577 
     | 
    
         
             
                #  Getters
         
     | 
| 
       577 
578 
     | 
    
         
             
                ##
         
     | 
| 
         @@ -581,20 +582,19 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       581 
582 
     | 
    
         
             
                    QTextDocument->toRawText instead of toPlainText. The former preserves
         
     | 
| 
       582 
583 
     | 
    
         
             
                    non-breaking spaces, the latter does not. We still want to get rid of
         
     | 
| 
       583 
584 
     | 
    
         
             
                    paragraph and line separators though.
         
     | 
| 
      
 585 
     | 
    
         
            +
             
     | 
| 
       584 
586 
     | 
    
         
             
                    See: https://doc.qt.io/qt-6/qtextdocument.html#toPlainText
         
     | 
| 
       585 
587 
     | 
    
         
             
                    """
         
     | 
| 
       586 
588 
     | 
    
         
             
                    text = self._qDocument.toRawText()
         
     | 
| 
       587 
589 
     | 
    
         
             
                    text = text.replace(nwUnicode.U_LSEP, "\n")  # Line separators
         
     | 
| 
       588 
     | 
    
         
            -
                     
     | 
| 
       589 
     | 
    
         
            -
                    return text
         
     | 
| 
      
 590 
     | 
    
         
            +
                    return text.replace(nwUnicode.U_PSEP, "\n")  # Paragraph separators
         
     | 
| 
       590 
591 
     | 
    
         | 
| 
       591 
592 
     | 
    
         
             
                def getSelectedText(self) -> str:
         
     | 
| 
       592 
593 
     | 
    
         
             
                    """Get currently selected text."""
         
     | 
| 
       593 
594 
     | 
    
         
             
                    if (cursor := self.textCursor()).hasSelection():
         
     | 
| 
       594 
595 
     | 
    
         
             
                        text = cursor.selectedText()
         
     | 
| 
       595 
596 
     | 
    
         
             
                        text = text.replace(nwUnicode.U_LSEP, "\n")  # Line separators
         
     | 
| 
       596 
     | 
    
         
            -
                         
     | 
| 
       597 
     | 
    
         
            -
                        return text
         
     | 
| 
      
 597 
     | 
    
         
            +
                        return text.replace(nwUnicode.U_PSEP, "\n")  # Paragraph separators
         
     | 
| 
       598 
598 
     | 
    
         
             
                    return ""
         
     | 
| 
       599 
599 
     | 
    
         | 
| 
       600 
600 
     | 
    
         
             
                def getCursorPosition(self) -> int:
         
     | 
| 
         @@ -615,7 +615,6 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       615 
615 
     | 
    
         
             
                        logger.debug("Document changed status is '%s'", state)
         
     | 
| 
       616 
616 
     | 
    
         
             
                        self._docChanged = state
         
     | 
| 
       617 
617 
     | 
    
         
             
                        self.editedStatusChanged.emit(self._docChanged)
         
     | 
| 
       618 
     | 
    
         
            -
                    return
         
     | 
| 
       619 
618 
     | 
    
         | 
| 
       620 
619 
     | 
    
         
             
                def setCursorPosition(self, position: int) -> None:
         
     | 
| 
       621 
620 
     | 
    
         
             
                    """Move the cursor to a given position in the document."""
         
     | 
| 
         @@ -624,14 +623,12 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       624 
623 
     | 
    
         
             
                        cursor.setPosition(minmax(position, 0, chars-1))
         
     | 
| 
       625 
624 
     | 
    
         
             
                        self.setTextCursor(cursor)
         
     | 
| 
       626 
625 
     | 
    
         
             
                        self.centerCursor()
         
     | 
| 
       627 
     | 
    
         
            -
                    return
         
     | 
| 
       628 
626 
     | 
    
         | 
| 
       629 
627 
     | 
    
         
             
                def saveCursorPosition(self) -> None:
         
     | 
| 
       630 
628 
     | 
    
         
             
                    """Save the cursor position to the current project item."""
         
     | 
| 
       631 
629 
     | 
    
         
             
                    if self._nwItem is not None:
         
     | 
| 
       632 
630 
     | 
    
         
             
                        cursPos = self.getCursorPosition()
         
     | 
| 
       633 
631 
     | 
    
         
             
                        self._nwItem.setCursorPos(cursPos)
         
     | 
| 
       634 
     | 
    
         
            -
                    return
         
     | 
| 
       635 
632 
     | 
    
         | 
| 
       636 
633 
     | 
    
         
             
                def setCursorLine(self, line: int | None) -> None:
         
     | 
| 
       637 
634 
     | 
    
         
             
                    """Move the cursor to a given line in the document."""
         
     | 
| 
         @@ -640,7 +637,6 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       640 
637 
     | 
    
         
             
                        if block:
         
     | 
| 
       641 
638 
     | 
    
         
             
                            self.setCursorPosition(block.position())
         
     | 
| 
       642 
639 
     | 
    
         
             
                            logger.debug("Cursor moved to line %d", line)
         
     | 
| 
       643 
     | 
    
         
            -
                    return
         
     | 
| 
       644 
640 
     | 
    
         | 
| 
       645 
641 
     | 
    
         
             
                def setCursorSelection(self, start: int, length: int) -> None:
         
     | 
| 
       646 
642 
     | 
    
         
             
                    """Make a text selection."""
         
     | 
| 
         @@ -649,14 +645,15 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       649 
645 
     | 
    
         
             
                        cursor.setPosition(start, QtMoveAnchor)
         
     | 
| 
       650 
646 
     | 
    
         
             
                        cursor.setPosition(start + length, QtKeepAnchor)
         
     | 
| 
       651 
647 
     | 
    
         
             
                        self.setTextCursor(cursor)
         
     | 
| 
       652 
     | 
    
         
            -
                    return
         
     | 
| 
       653 
648 
     | 
    
         | 
| 
       654 
649 
     | 
    
         
             
                ##
         
     | 
| 
       655 
650 
     | 
    
         
             
                #  Spell Checking
         
     | 
| 
       656 
651 
     | 
    
         
             
                ##
         
     | 
| 
       657 
652 
     | 
    
         | 
| 
       658 
653 
     | 
    
         
             
                def toggleSpellCheck(self, state: bool | None) -> None:
         
     | 
| 
       659 
     | 
    
         
            -
                    """ 
     | 
| 
      
 654 
     | 
    
         
            +
                    """Toggle spell checking.
         
     | 
| 
      
 655 
     | 
    
         
            +
             
     | 
| 
      
 656 
     | 
    
         
            +
                    This is the main spell check setting function, and this one
         
     | 
| 
       660 
657 
     | 
    
         
             
                    should call all other setSpellCheck functions in other classes.
         
     | 
| 
       661 
658 
     | 
    
         
             
                    If the spell check state is not defined (None), then toggle the
         
     | 
| 
       662 
659 
     | 
    
         
             
                    current status saved in this class.
         
     | 
| 
         @@ -678,9 +675,7 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       678 
675 
     | 
    
         
             
                    self.spellCheckStateChanged.emit(state)
         
     | 
| 
       679 
676 
     | 
    
         
             
                    self.spellCheckDocument()
         
     | 
| 
       680 
677 
     | 
    
         | 
| 
       681 
     | 
    
         
            -
                    logger.debug("Spell check is set to '%s'",  
     | 
| 
       682 
     | 
    
         
            -
             
     | 
| 
       683 
     | 
    
         
            -
                    return
         
     | 
| 
      
 678 
     | 
    
         
            +
                    logger.debug("Spell check is set to '%s'", state)
         
     | 
| 
       684 
679 
     | 
    
         | 
| 
       685 
680 
     | 
    
         
             
                def spellCheckDocument(self) -> None:
         
     | 
| 
       686 
681 
     | 
    
         
             
                    """Rerun the highlighter to update spell checking status of the
         
     | 
| 
         @@ -693,7 +688,6 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       693 
688 
     | 
    
         
             
                    QApplication.restoreOverrideCursor()
         
     | 
| 
       694 
689 
     | 
    
         
             
                    logger.debug("Document highlighted in %.3f ms", 1000*(time() - start))
         
     | 
| 
       695 
690 
     | 
    
         
             
                    self.updateStatusMessage.emit(self.tr("Spell check complete"))
         
     | 
| 
       696 
     | 
    
         
            -
                    return
         
     | 
| 
       697 
691 
     | 
    
         | 
| 
       698 
692 
     | 
    
         
             
                ##
         
     | 
| 
       699 
693 
     | 
    
         
             
                #  General Class Methods
         
     | 
| 
         @@ -733,14 +727,16 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       733 
727 
     | 
    
         
             
                        self._toggleFormat(2, "*")
         
     | 
| 
       734 
728 
     | 
    
         
             
                    elif action == nwDocAction.MD_STRIKE:
         
     | 
| 
       735 
729 
     | 
    
         
             
                        self._toggleFormat(2, "~")
         
     | 
| 
      
 730 
     | 
    
         
            +
                    elif action == nwDocAction.MD_MARK:
         
     | 
| 
      
 731 
     | 
    
         
            +
                        self._toggleFormat(2, "=")
         
     | 
| 
       736 
732 
     | 
    
         
             
                    elif action == nwDocAction.S_QUOTE:
         
     | 
| 
       737 
733 
     | 
    
         
             
                        self._wrapSelection(CONFIG.fmtSQuoteOpen, CONFIG.fmtSQuoteClose)
         
     | 
| 
       738 
734 
     | 
    
         
             
                    elif action == nwDocAction.D_QUOTE:
         
     | 
| 
       739 
735 
     | 
    
         
             
                        self._wrapSelection(CONFIG.fmtDQuoteOpen, CONFIG.fmtDQuoteClose)
         
     | 
| 
       740 
736 
     | 
    
         
             
                    elif action == nwDocAction.SEL_ALL:
         
     | 
| 
       741 
     | 
    
         
            -
                        self._makeSelection( 
     | 
| 
      
 737 
     | 
    
         
            +
                        self._makeSelection(QtSelectDocument)
         
     | 
| 
       742 
738 
     | 
    
         
             
                    elif action == nwDocAction.SEL_PARA:
         
     | 
| 
       743 
     | 
    
         
            -
                        self._makeSelection( 
     | 
| 
      
 739 
     | 
    
         
            +
                        self._makeSelection(QtSelectBlock)
         
     | 
| 
       744 
740 
     | 
    
         
             
                    elif action == nwDocAction.BLOCK_H1:
         
     | 
| 
       745 
741 
     | 
    
         
             
                        self._formatBlock(nwDocAction.BLOCK_H1)
         
     | 
| 
       746 
742 
     | 
    
         
             
                    elif action == nwDocAction.BLOCK_H2:
         
     | 
| 
         @@ -792,7 +788,7 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       792 
788 
     | 
    
         
             
                    elif action == nwDocAction.SC_SUB:
         
     | 
| 
       793 
789 
     | 
    
         
             
                        self._wrapSelection(nwShortcode.SUB_O, nwShortcode.SUB_C)
         
     | 
| 
       794 
790 
     | 
    
         
             
                    else:
         
     | 
| 
       795 
     | 
    
         
            -
                        logger.debug("Unknown or unsupported document action '%s'",  
     | 
| 
      
 791 
     | 
    
         
            +
                        logger.debug("Unknown or unsupported document action '%s'", action)
         
     | 
| 
       796 
792 
     | 
    
         
             
                        self._allowAutoReplace(True)
         
     | 
| 
       797 
793 
     | 
    
         
             
                        return False
         
     | 
| 
       798 
794 
     | 
    
         | 
| 
         @@ -820,7 +816,6 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       820 
816 
     | 
    
         
             
                            details=self.tr("File Location: {0}").format(self._nwDocument.fileLocation),
         
     | 
| 
       821 
817 
     | 
    
         
             
                            log=False
         
     | 
| 
       822 
818 
     | 
    
         
             
                        )
         
     | 
| 
       823 
     | 
    
         
            -
                    return
         
     | 
| 
       824 
819 
     | 
    
         | 
| 
       825 
820 
     | 
    
         
             
                def insertText(self, insert: str | nwDocInsert) -> None:
         
     | 
| 
       826 
821 
     | 
    
         
             
                    """Insert a specific type of text at the cursor position."""
         
     | 
| 
         @@ -914,7 +909,7 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       914 
909 
     | 
    
         
             
                    return True
         
     | 
| 
       915 
910 
     | 
    
         | 
| 
       916 
911 
     | 
    
         
             
                ##
         
     | 
| 
       917 
     | 
    
         
            -
                #   
     | 
| 
      
 912 
     | 
    
         
            +
                #  Events and Overloads
         
     | 
| 
       918 
913 
     | 
    
         
             
                ##
         
     | 
| 
       919 
914 
     | 
    
         | 
| 
       920 
915 
     | 
    
         
             
                def keyPressEvent(self, event: QKeyEvent) -> None:
         
     | 
| 
         @@ -962,7 +957,6 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       962 
957 
     | 
    
         
             
                        event.acceptProposedAction()
         
     | 
| 
       963 
958 
     | 
    
         
             
                    else:
         
     | 
| 
       964 
959 
     | 
    
         
             
                        super().dragEnterEvent(event)
         
     | 
| 
       965 
     | 
    
         
            -
                    return
         
     | 
| 
       966 
960 
     | 
    
         | 
| 
       967 
961 
     | 
    
         
             
                def dragMoveEvent(self, event: QDragMoveEvent) -> None:
         
     | 
| 
       968 
962 
     | 
    
         
             
                    """Overload drag move event to handle dragged items."""
         
     | 
| 
         @@ -970,7 +964,6 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       970 
964 
     | 
    
         
             
                        event.acceptProposedAction()
         
     | 
| 
       971 
965 
     | 
    
         
             
                    else:
         
     | 
| 
       972 
966 
     | 
    
         
             
                        super().dragMoveEvent(event)
         
     | 
| 
       973 
     | 
    
         
            -
                    return
         
     | 
| 
       974 
967 
     | 
    
         | 
| 
       975 
968 
     | 
    
         
             
                def dropEvent(self, event: QDropEvent) -> None:
         
     | 
| 
       976 
969 
     | 
    
         
             
                    """Overload drop event to handle dragged items."""
         
     | 
| 
         @@ -980,7 +973,6 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       980 
973 
     | 
    
         
             
                                self.openDocumentRequest.emit(handles[0], nwDocMode.EDIT, "", True)
         
     | 
| 
       981 
974 
     | 
    
         
             
                    else:
         
     | 
| 
       982 
975 
     | 
    
         
             
                        super().dropEvent(event)
         
     | 
| 
       983 
     | 
    
         
            -
                    return
         
     | 
| 
       984 
976 
     | 
    
         | 
| 
       985 
977 
     | 
    
         
             
                def focusNextPrevChild(self, _next: bool) -> bool:
         
     | 
| 
       986 
978 
     | 
    
         
             
                    """Capture the focus request from the tab key on the text
         
     | 
| 
         @@ -1007,7 +999,6 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       1007 
999 
     | 
    
         
             
                        else:
         
     | 
| 
       1008 
1000 
     | 
    
         
             
                            self._processTag(cursor)
         
     | 
| 
       1009 
1001 
     | 
    
         
             
                    super().mouseReleaseEvent(event)
         
     | 
| 
       1010 
     | 
    
         
            -
                    return
         
     | 
| 
       1011 
1002 
     | 
    
         | 
| 
       1012 
1003 
     | 
    
         
             
                def resizeEvent(self, event: QResizeEvent) -> None:
         
     | 
| 
       1013 
1004 
     | 
    
         
             
                    """If the text editor is resized, we must make sure the document
         
     | 
| 
         @@ -1015,7 +1006,26 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       1015 
1006 
     | 
    
         
             
                    """
         
     | 
| 
       1016 
1007 
     | 
    
         
             
                    self.updateDocMargins()
         
     | 
| 
       1017 
1008 
     | 
    
         
             
                    super().resizeEvent(event)
         
     | 
| 
       1018 
     | 
    
         
            -
             
     | 
| 
      
 1009 
     | 
    
         
            +
             
     | 
| 
      
 1010 
     | 
    
         
            +
                def inputMethodEvent(self, event: QInputMethodEvent) -> None:
         
     | 
| 
      
 1011 
     | 
    
         
            +
                    """Handle text being input from CJK input methods."""
         
     | 
| 
      
 1012 
     | 
    
         
            +
                    super().inputMethodEvent(event)
         
     | 
| 
      
 1013 
     | 
    
         
            +
                    if event.commitString():
         
     | 
| 
      
 1014 
     | 
    
         
            +
                        # See issues #2267 and #2517
         
     | 
| 
      
 1015 
     | 
    
         
            +
                        self.ensureCursorVisible()
         
     | 
| 
      
 1016 
     | 
    
         
            +
                        self._completerToCursor()
         
     | 
| 
      
 1017 
     | 
    
         
            +
             
     | 
| 
      
 1018 
     | 
    
         
            +
                def inputMethodQuery(self, query: Qt.InputMethodQuery) -> QRect | QVariant:
         
     | 
| 
      
 1019 
     | 
    
         
            +
                    """Adjust completion windows for CJK input methods to consider
         
     | 
| 
      
 1020 
     | 
    
         
            +
                    the viewport margins.
         
     | 
| 
      
 1021 
     | 
    
         
            +
                    """
         
     | 
| 
      
 1022 
     | 
    
         
            +
                    if query == QtImCursorRectangle:
         
     | 
| 
      
 1023 
     | 
    
         
            +
                        # See issues #2267 and #2517
         
     | 
| 
      
 1024 
     | 
    
         
            +
                        vM = self.viewportMargins()
         
     | 
| 
      
 1025 
     | 
    
         
            +
                        rect = self.cursorRect()
         
     | 
| 
      
 1026 
     | 
    
         
            +
                        rect.translate(vM.left(), vM.top())
         
     | 
| 
      
 1027 
     | 
    
         
            +
                        return rect
         
     | 
| 
      
 1028 
     | 
    
         
            +
                    return super().inputMethodQuery(query)
         
     | 
| 
       1019 
1029 
     | 
    
         | 
| 
       1020 
1030 
     | 
    
         
             
                ##
         
     | 
| 
       1021 
1031 
     | 
    
         
             
                #  Public Slots
         
     | 
| 
         @@ -1023,14 +1033,13 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       1023 
1033 
     | 
    
         | 
| 
       1024 
1034 
     | 
    
         
             
                @pyqtSlot(str, Enum)
         
     | 
| 
       1025 
1035 
     | 
    
         
             
                def onProjectItemChanged(self, tHandle: str, change: nwChange) -> None:
         
     | 
| 
       1026 
     | 
    
         
            -
                    """Called when an item label is 
     | 
| 
       1027 
     | 
    
         
            -
                    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.
         
     | 
| 
       1028 
1038 
     | 
    
         
             
                    """
         
     | 
| 
       1029 
1039 
     | 
    
         
             
                    if tHandle == self._docHandle and change == nwChange.UPDATE:
         
     | 
| 
       1030 
1040 
     | 
    
         
             
                        self.docHeader.setHandle(tHandle)
         
     | 
| 
       1031 
1041 
     | 
    
         
             
                        self.docFooter.updateInfo()
         
     | 
| 
       1032 
1042 
     | 
    
         
             
                        self.updateDocMargins()
         
     | 
| 
       1033 
     | 
    
         
            -
                    return
         
     | 
| 
       1034 
1043 
     | 
    
         | 
| 
       1035 
1044 
     | 
    
         
             
                @pyqtSlot(str)
         
     | 
| 
       1036 
1045 
     | 
    
         
             
                def insertKeyWord(self, keyword: str) -> bool:
         
     | 
| 
         @@ -1041,8 +1050,7 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       1041 
1050 
     | 
    
         
             
                        logger.error("Invalid keyword '%s'", keyword)
         
     | 
| 
       1042 
1051 
     | 
    
         
             
                        return False
         
     | 
| 
       1043 
1052 
     | 
    
         
             
                    logger.debug("Inserting keyword '%s'", keyword)
         
     | 
| 
       1044 
     | 
    
         
            -
                     
     | 
| 
       1045 
     | 
    
         
            -
                    return state
         
     | 
| 
      
 1053 
     | 
    
         
            +
                    return self.insertNewBlock(f"{keyword}: ")
         
     | 
| 
       1046 
1054 
     | 
    
         | 
| 
       1047 
1055 
     | 
    
         
             
                @pyqtSlot()
         
     | 
| 
       1048 
1056 
     | 
    
         
             
                def toggleSearch(self) -> None:
         
     | 
| 
         @@ -1051,14 +1059,12 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       1051 
1059 
     | 
    
         
             
                        self.closeSearch()
         
     | 
| 
       1052 
1060 
     | 
    
         
             
                    else:
         
     | 
| 
       1053 
1061 
     | 
    
         
             
                        self.beginSearch()
         
     | 
| 
       1054 
     | 
    
         
            -
                    return
         
     | 
| 
       1055 
1062 
     | 
    
         | 
| 
       1056 
1063 
     | 
    
         
             
                @pyqtSlot(list, list)
         
     | 
| 
       1057 
1064 
     | 
    
         
             
                def updateChangedTags(self, updated: list[str], deleted: list[str]) -> None:
         
     | 
| 
       1058 
1065 
     | 
    
         
             
                    """Tags have changed, so just in case we rehighlight them."""
         
     | 
| 
       1059 
1066 
     | 
    
         
             
                    if updated or deleted:
         
     | 
| 
       1060 
1067 
     | 
    
         
             
                        self._qDocument.syntaxHighlighter.rehighlightByType(BLOCK_META)
         
     | 
| 
       1061 
     | 
    
         
            -
                    return
         
     | 
| 
       1062 
1068 
     | 
    
         | 
| 
       1063 
1069 
     | 
    
         
             
                ##
         
     | 
| 
       1064 
1070 
     | 
    
         
             
                #  Private Slots
         
     | 
| 
         @@ -1080,37 +1086,34 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       1080 
1086 
     | 
    
         | 
| 
       1081 
1087 
     | 
    
         
             
                    if (block := self._qDocument.findBlock(pos)).isValid():
         
     | 
| 
       1082 
1088 
     | 
    
         
             
                        text = block.text()
         
     | 
| 
      
 1089 
     | 
    
         
            +
             
     | 
| 
       1083 
1090 
     | 
    
         
             
                        if text and text[0] in "@%" and added + removed == 1:
         
     | 
| 
       1084 
1091 
     | 
    
         
             
                            # Only run on single character changes, or it will trigger
         
     | 
| 
       1085 
1092 
     | 
    
         
             
                            # at unwanted times when other changes are made to the document
         
     | 
| 
       1086 
1093 
     | 
    
         
             
                            cursor = self.textCursor()
         
     | 
| 
       1087 
1094 
     | 
    
         
             
                            bPos = cursor.positionInBlock()
         
     | 
| 
       1088 
     | 
    
         
            -
                            if bPos > 0 
     | 
| 
      
 1095 
     | 
    
         
            +
                            if bPos > 0:
         
     | 
| 
       1089 
1096 
     | 
    
         
             
                                if text[0] == "@":
         
     | 
| 
       1090 
1097 
     | 
    
         
             
                                    show = self._completer.updateMetaText(text, bPos)
         
     | 
| 
       1091 
1098 
     | 
    
         
             
                                else:
         
     | 
| 
       1092 
1099 
     | 
    
         
             
                                    show = self._completer.updateCommentText(text, bPos)
         
     | 
| 
       1093 
1100 
     | 
    
         
             
                                if show:
         
     | 
| 
       1094 
     | 
    
         
            -
                                    point = self.cursorRect().bottomRight()
         
     | 
| 
       1095 
     | 
    
         
            -
                                    self._completer.move(viewport.mapToGlobal(point))
         
     | 
| 
       1096 
1101 
     | 
    
         
             
                                    self._completer.show()
         
     | 
| 
       1097 
     | 
    
         
            -
             
     | 
| 
       1098 
     | 
    
         
            -
                                    self._completer.close()
         
     | 
| 
       1099 
     | 
    
         
            -
                        else:
         
     | 
| 
       1100 
     | 
    
         
            -
                            self._completer.close()
         
     | 
| 
      
 1102 
     | 
    
         
            +
                                    self._completerToCursor()
         
     | 
| 
       1101 
1103 
     | 
    
         | 
| 
       1102 
1104 
     | 
    
         
             
                        if self._doReplace and added == 1:
         
     | 
| 
       1103 
1105 
     | 
    
         
             
                            cursor = self.textCursor()
         
     | 
| 
       1104 
1106 
     | 
    
         
             
                            if self._autoReplace.process(text, cursor):
         
     | 
| 
       1105 
1107 
     | 
    
         
             
                                self._qDocument.syntaxHighlighter.rehighlightBlock(cursor.block())
         
     | 
| 
       1106 
1108 
     | 
    
         | 
| 
       1107 
     | 
    
         
            -
                    return
         
     | 
| 
       1108 
     | 
    
         
            -
             
     | 
| 
       1109 
1109 
     | 
    
         
             
                @pyqtSlot()
         
     | 
| 
       1110 
1110 
     | 
    
         
             
                def _cursorMoved(self) -> None:
         
     | 
| 
       1111 
1111 
     | 
    
         
             
                    """Triggered when the cursor moved in the editor."""
         
     | 
| 
       1112 
1112 
     | 
    
         
             
                    self.docFooter.updateLineCount(self.textCursor())
         
     | 
| 
       1113 
     | 
    
         
            -
                     
     | 
| 
      
 1113 
     | 
    
         
            +
                    if CONFIG.lineHighlight:
         
     | 
| 
      
 1114 
     | 
    
         
            +
                        self._selection.cursor = self.textCursor()
         
     | 
| 
      
 1115 
     | 
    
         
            +
                        self._selection.cursor.clearSelection()
         
     | 
| 
      
 1116 
     | 
    
         
            +
                        self.setExtraSelections([self._selection])
         
     | 
| 
       1114 
1117 
     | 
    
         | 
| 
       1115 
1118 
     | 
    
         
             
                @pyqtSlot(int, int, str)
         
     | 
| 
       1116 
1119 
     | 
    
         
             
                def _insertCompletion(self, pos: int, length: int, text: str) -> None:
         
     | 
| 
         @@ -1121,14 +1124,12 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       1121 
1124 
     | 
    
         
             
                        cursor.setPosition(check, QtMoveAnchor)
         
     | 
| 
       1122 
1125 
     | 
    
         
             
                        cursor.setPosition(check + length, QtKeepAnchor)
         
     | 
| 
       1123 
1126 
     | 
    
         
             
                        cursor.insertText(text)
         
     | 
| 
       1124 
     | 
    
         
            -
                        self._completer. 
     | 
| 
       1125 
     | 
    
         
            -
                    return
         
     | 
| 
      
 1127 
     | 
    
         
            +
                        self._completer.close()
         
     | 
| 
       1126 
1128 
     | 
    
         | 
| 
       1127 
1129 
     | 
    
         
             
                @pyqtSlot()
         
     | 
| 
       1128 
1130 
     | 
    
         
             
                def _openContextFromCursor(self) -> None:
         
     | 
| 
       1129 
1131 
     | 
    
         
             
                    """Open the spell check context menu at the cursor."""
         
     | 
| 
       1130 
1132 
     | 
    
         
             
                    self._openContextMenu(self.cursorRect().center())
         
     | 
| 
       1131 
     | 
    
         
            -
                    return
         
     | 
| 
       1132 
1133 
     | 
    
         | 
| 
       1133 
1134 
     | 
    
         
             
                @pyqtSlot("QPoint")
         
     | 
| 
       1134 
1135 
     | 
    
         
             
                def _openContextMenu(self, pos: QPoint) -> None:
         
     | 
| 
         @@ -1176,23 +1177,19 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       1176 
1177 
     | 
    
         
             
                    action = qtAddAction(ctxMenu, self.tr("Select All"))
         
     | 
| 
       1177 
1178 
     | 
    
         
             
                    action.triggered.connect(qtLambda(self.docAction, nwDocAction.SEL_ALL))
         
     | 
| 
       1178 
1179 
     | 
    
         
             
                    action = qtAddAction(ctxMenu, self.tr("Select Word"))
         
     | 
| 
       1179 
     | 
    
         
            -
                    action.triggered.connect(qtLambda(
         
     | 
| 
       1180 
     | 
    
         
            -
                        self._makePosSelection, QTextCursor.SelectionType.WordUnderCursor, pos,
         
     | 
| 
       1181 
     | 
    
         
            -
                    ))
         
     | 
| 
      
 1180 
     | 
    
         
            +
                    action.triggered.connect(qtLambda(self._makePosSelection, QtSelectWord, pos))
         
     | 
| 
       1182 
1181 
     | 
    
         
             
                    action = qtAddAction(ctxMenu, self.tr("Select Paragraph"))
         
     | 
| 
       1183 
     | 
    
         
            -
                    action.triggered.connect(qtLambda(
         
     | 
| 
       1184 
     | 
    
         
            -
                        self._makePosSelection, QTextCursor.SelectionType.BlockUnderCursor, pos
         
     | 
| 
       1185 
     | 
    
         
            -
                    ))
         
     | 
| 
      
 1182 
     | 
    
         
            +
                    action.triggered.connect(qtLambda(self._makePosSelection, QtSelectBlock, pos))
         
     | 
| 
       1186 
1183 
     | 
    
         | 
| 
       1187 
1184 
     | 
    
         
             
                    # Spell Checking
         
     | 
| 
       1188 
1185 
     | 
    
         
             
                    if SHARED.project.data.spellCheck:
         
     | 
| 
       1189 
     | 
    
         
            -
                        word,  
     | 
| 
       1190 
     | 
    
         
            -
                        if word and  
     | 
| 
      
 1186 
     | 
    
         
            +
                        word, offset, suggest = self._qDocument.spellErrorAtPos(pCursor.position())
         
     | 
| 
      
 1187 
     | 
    
         
            +
                        if word and offset >= 0:
         
     | 
| 
       1191 
1188 
     | 
    
         
             
                            logger.debug("Word '%s' is misspelled", word)
         
     | 
| 
       1192 
1189 
     | 
    
         
             
                            block = pCursor.block()
         
     | 
| 
       1193 
1190 
     | 
    
         
             
                            sCursor = self.textCursor()
         
     | 
| 
       1194 
     | 
    
         
            -
                            sCursor.setPosition(block.position() +  
     | 
| 
       1195 
     | 
    
         
            -
                            sCursor.movePosition(QtMoveRight, QtKeepAnchor,  
     | 
| 
      
 1191 
     | 
    
         
            +
                            sCursor.setPosition(block.position() + offset)
         
     | 
| 
      
 1192 
     | 
    
         
            +
                            sCursor.movePosition(QtMoveRight, QtKeepAnchor, len(word))
         
     | 
| 
       1196 
1193 
     | 
    
         
             
                            if suggest:
         
     | 
| 
       1197 
1194 
     | 
    
         
             
                                ctxMenu.addSeparator()
         
     | 
| 
       1198 
1195 
     | 
    
         
             
                                qtAddAction(ctxMenu, self.tr("Spelling Suggestion(s)"))
         
     | 
| 
         @@ -1215,8 +1212,6 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       1215 
1212 
     | 
    
         | 
| 
       1216 
1213 
     | 
    
         
             
                    ctxMenu.setParent(None)
         
     | 
| 
       1217 
1214 
     | 
    
         | 
| 
       1218 
     | 
    
         
            -
                    return
         
     | 
| 
       1219 
     | 
    
         
            -
             
     | 
| 
       1220 
1215 
     | 
    
         
             
                @pyqtSlot()
         
     | 
| 
       1221 
1216 
     | 
    
         
             
                def _runDocumentTasks(self) -> None:
         
     | 
| 
       1222 
1217 
     | 
    
         
             
                    """Run timer document tasks."""
         
     | 
| 
         @@ -1253,11 +1248,10 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       1253 
1248 
     | 
    
         
             
                            if not self.textCursor().hasSelection():
         
     | 
| 
       1254 
1249 
     | 
    
         
             
                                # Selection counter should take precedence (#2155)
         
     | 
| 
       1255 
1250 
     | 
    
         
             
                                self.docFooter.updateMainCount(mCount, False)
         
     | 
| 
       1256 
     | 
    
         
            -
                    return
         
     | 
| 
       1257 
1251 
     | 
    
         | 
| 
       1258 
1252 
     | 
    
         
             
                @pyqtSlot()
         
     | 
| 
       1259 
1253 
     | 
    
         
             
                def _updateSelectedStatus(self) -> None:
         
     | 
| 
       1260 
     | 
    
         
            -
                    """ 
     | 
| 
      
 1254 
     | 
    
         
            +
                    """Process user change in text selection. Forward this
         
     | 
| 
       1261 
1255 
     | 
    
         
             
                    information to the footer, and start the selection word counter.
         
     | 
| 
       1262 
1256 
     | 
    
         
             
                    """
         
     | 
| 
       1263 
1257 
     | 
    
         
             
                    if self.textCursor().hasSelection():
         
     | 
| 
         @@ -1266,7 +1260,6 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       1266 
1260 
     | 
    
         
             
                    else:
         
     | 
| 
       1267 
1261 
     | 
    
         
             
                        self._timerSel.stop()
         
     | 
| 
       1268 
1262 
     | 
    
         
             
                        self.docFooter.updateMainCount(0, False)
         
     | 
| 
       1269 
     | 
    
         
            -
                    return
         
     | 
| 
       1270 
1263 
     | 
    
         | 
| 
       1271 
1264 
     | 
    
         
             
                @pyqtSlot()
         
     | 
| 
       1272 
1265 
     | 
    
         
             
                def _runSelCounter(self) -> None:
         
     | 
| 
         @@ -1284,14 +1277,12 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       1284 
1277 
     | 
    
         
             
                    if self._docHandle and self._nwItem:
         
     | 
| 
       1285 
1278 
     | 
    
         
             
                        self.docFooter.updateMainCount(cCount if CONFIG.useCharCount else wCount, True)
         
     | 
| 
       1286 
1279 
     | 
    
         
             
                        self._timerSel.stop()
         
     | 
| 
       1287 
     | 
    
         
            -
                    return
         
     | 
| 
       1288 
1280 
     | 
    
         | 
| 
       1289 
1281 
     | 
    
         
             
                @pyqtSlot()
         
     | 
| 
       1290 
1282 
     | 
    
         
             
                def _closeCurrentDocument(self) -> None:
         
     | 
| 
       1291 
1283 
     | 
    
         
             
                    """Close the document. Forwarded to the main Gui."""
         
     | 
| 
       1292 
1284 
     | 
    
         
             
                    self.closeEditorRequest.emit()
         
     | 
| 
       1293 
1285 
     | 
    
         
             
                    self.docToolBar.setVisible(False)
         
     | 
| 
       1294 
     | 
    
         
            -
                    return
         
     | 
| 
       1295 
1286 
     | 
    
         | 
| 
       1296 
1287 
     | 
    
         
             
                @pyqtSlot()
         
     | 
| 
       1297 
1288 
     | 
    
         
             
                def _toggleToolBarVisibility(self) -> None:
         
     | 
| 
         @@ -1299,7 +1290,6 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       1299 
1290 
     | 
    
         
             
                    state = not self.docToolBar.isVisible()
         
     | 
| 
       1300 
1291 
     | 
    
         
             
                    self.docToolBar.setVisible(state)
         
     | 
| 
       1301 
1292 
     | 
    
         
             
                    CONFIG.showEditToolBar = state
         
     | 
| 
       1302 
     | 
    
         
            -
                    return
         
     | 
| 
       1303 
1293 
     | 
    
         | 
| 
       1304 
1294 
     | 
    
         
             
                ##
         
     | 
| 
       1305 
1295 
     | 
    
         
             
                #  Search & Replace
         
     | 
| 
         @@ -1310,14 +1300,12 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       1310 
1300 
     | 
    
         
             
                    self.docSearch.setSearchText(self.getSelectedText() or None)
         
     | 
| 
       1311 
1301 
     | 
    
         
             
                    resS, _ = self.findAllOccurences()
         
     | 
| 
       1312 
1302 
     | 
    
         
             
                    self.docSearch.setResultCount(None, len(resS))
         
     | 
| 
       1313 
     | 
    
         
            -
                    return
         
     | 
| 
       1314 
1303 
     | 
    
         | 
| 
       1315 
1304 
     | 
    
         
             
                def beginReplace(self) -> None:
         
     | 
| 
       1316 
1305 
     | 
    
         
             
                    """Initialise the search box and reset the replace text box."""
         
     | 
| 
       1317 
1306 
     | 
    
         
             
                    self.beginSearch()
         
     | 
| 
       1318 
1307 
     | 
    
         
             
                    self.docSearch.setReplaceText("")
         
     | 
| 
       1319 
1308 
     | 
    
         
             
                    self.updateDocMargins()
         
     | 
| 
       1320 
     | 
    
         
            -
                    return
         
     | 
| 
       1321 
1309 
     | 
    
         | 
| 
       1322 
1310 
     | 
    
         
             
                def findNext(self, goBack: bool = False) -> None:
         
     | 
| 
       1323 
1311 
     | 
    
         
             
                    """Search for the next or previous occurrence of the search bar
         
     | 
| 
         @@ -1605,8 +1593,6 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       1605 
1593 
     | 
    
         | 
| 
       1606 
1594 
     | 
    
         
             
                    self.setTextCursor(cursor)
         
     | 
| 
       1607 
1595 
     | 
    
         | 
| 
       1608 
     | 
    
         
            -
                    return
         
     | 
| 
       1609 
     | 
    
         
            -
             
     | 
| 
       1610 
1596 
     | 
    
         
             
                def _replaceQuotes(self, sQuote: str, oQuote: str, cQuote: str) -> None:
         
     | 
| 
       1611 
1597 
     | 
    
         
             
                    """Replace all straight quotes in the selected text."""
         
     | 
| 
       1612 
1598 
     | 
    
         
             
                    cursor = self.textCursor()
         
     | 
| 
         @@ -1763,7 +1749,7 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       1763 
1749 
     | 
    
         
             
                    elif action == nwDocAction.BLOCK_TXT:
         
     | 
| 
       1764 
1750 
     | 
    
         
             
                        text = temp
         
     | 
| 
       1765 
1751 
     | 
    
         
             
                    else:
         
     | 
| 
       1766 
     | 
    
         
            -
                        logger.error("Unknown or unsupported block format requested: '%s'",  
     | 
| 
      
 1752 
     | 
    
         
            +
                        logger.error("Unknown or unsupported block format requested: '%s'", action)
         
     | 
| 
       1767 
1753 
     | 
    
         
             
                        return nwDocAction.NO_ACTION, "", 0
         
     | 
| 
       1768 
1754 
     | 
    
         | 
| 
       1769 
1755 
     | 
    
         
             
                    return action, text, offset
         
     | 
| 
         @@ -1773,7 +1759,7 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       1773 
1759 
     | 
    
         
             
                    cursor = self.textCursor()
         
     | 
| 
       1774 
1760 
     | 
    
         
             
                    block = cursor.block()
         
     | 
| 
       1775 
1761 
     | 
    
         
             
                    if not block.isValid():
         
     | 
| 
       1776 
     | 
    
         
            -
                        logger.debug("Invalid block selected for action '%s'",  
     | 
| 
      
 1762 
     | 
    
         
            +
                        logger.debug("Invalid block selected for action '%s'", action)
         
     | 
| 
       1777 
1763 
     | 
    
         
             
                        return False
         
     | 
| 
       1778 
1764 
     | 
    
         | 
| 
       1779 
1765 
     | 
    
         
             
                    action, text, offset = self._processBlockFormat(action, block.text())
         
     | 
| 
         @@ -1783,7 +1769,7 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       1783 
1769 
     | 
    
         
             
                    pos = cursor.position()
         
     | 
| 
       1784 
1770 
     | 
    
         | 
| 
       1785 
1771 
     | 
    
         
             
                    cursor.beginEditBlock()
         
     | 
| 
       1786 
     | 
    
         
            -
                    self._makeSelection( 
     | 
| 
      
 1772 
     | 
    
         
            +
                    self._makeSelection(QtSelectBlock, cursor)
         
     | 
| 
       1787 
1773 
     | 
    
         
             
                    cursor.insertText(text)
         
     | 
| 
       1788 
1774 
     | 
    
         
             
                    cursor.endEditBlock()
         
     | 
| 
       1789 
1775 
     | 
    
         | 
| 
         @@ -1811,7 +1797,7 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       1811 
1797 
     | 
    
         
             
                        if pAction != nwDocAction.NO_ACTION and blockText.strip():
         
     | 
| 
       1812 
1798 
     | 
    
         
             
                            action = pAction  # First block decides further actions
         
     | 
| 
       1813 
1799 
     | 
    
         
             
                            cursor.setPosition(block.position())
         
     | 
| 
       1814 
     | 
    
         
            -
                            self._makeSelection( 
     | 
| 
      
 1800 
     | 
    
         
            +
                            self._makeSelection(QtSelectBlock, cursor)
         
     | 
| 
       1815 
1801 
     | 
    
         
             
                            cursor.insertText(text)
         
     | 
| 
       1816 
1802 
     | 
    
         
             
                            toggle = False
         
     | 
| 
       1817 
1803 
     | 
    
         | 
| 
         @@ -1831,7 +1817,7 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       1831 
1817 
     | 
    
         
             
                    """Strip line breaks within paragraphs in the selected text."""
         
     | 
| 
       1832 
1818 
     | 
    
         
             
                    cursor = self.textCursor()
         
     | 
| 
       1833 
1819 
     | 
    
         
             
                    if not cursor.hasSelection():
         
     | 
| 
       1834 
     | 
    
         
            -
                        cursor.select( 
     | 
| 
      
 1820 
     | 
    
         
            +
                        cursor.select(QtSelectDocument)
         
     | 
| 
       1835 
1821 
     | 
    
         | 
| 
       1836 
1822 
     | 
    
         
             
                    rS = 0
         
     | 
| 
       1837 
1823 
     | 
    
         
             
                    rE = self._qDocument.characterCount()
         
     | 
| 
         @@ -1866,8 +1852,6 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       1866 
1852 
     | 
    
         
             
                    cursor.insertText(cleanText.rstrip() + "\n")
         
     | 
| 
       1867 
1853 
     | 
    
         
             
                    cursor.endEditBlock()
         
     | 
| 
       1868 
1854 
     | 
    
         | 
| 
       1869 
     | 
    
         
            -
                    return
         
     | 
| 
       1870 
     | 
    
         
            -
             
     | 
| 
       1871 
1855 
     | 
    
         
             
                def _insertCommentStructure(self, style: nwComment) -> None:
         
     | 
| 
       1872 
1856 
     | 
    
         
             
                    """Insert a shortcut/comment combo."""
         
     | 
| 
       1873 
1857 
     | 
    
         
             
                    if self._docHandle and style == nwComment.FOOTNOTE:
         
     | 
| 
         @@ -1898,6 +1882,12 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       1898 
1882 
     | 
    
         
             
                #  Internal Functions
         
     | 
| 
       1899 
1883 
     | 
    
         
             
                ##
         
     | 
| 
       1900 
1884 
     | 
    
         | 
| 
      
 1885 
     | 
    
         
            +
                def _completerToCursor(self) -> None:
         
     | 
| 
      
 1886 
     | 
    
         
            +
                    """Make sure the completer menu is positioned by the cursor."""
         
     | 
| 
      
 1887 
     | 
    
         
            +
                    if self._completer.isVisible() and (viewport := self.viewport()):
         
     | 
| 
      
 1888 
     | 
    
         
            +
                        point = self.cursorRect().bottomLeft()
         
     | 
| 
      
 1889 
     | 
    
         
            +
                        self._completer.move(viewport.mapToGlobal(point))
         
     | 
| 
      
 1890 
     | 
    
         
            +
             
     | 
| 
       1901 
1891 
     | 
    
         
             
                def _correctWord(self, cursor: QTextCursor, word: str) -> None:
         
     | 
| 
       1902 
1892 
     | 
    
         
             
                    """Slot for the spell check context menu triggering the
         
     | 
| 
       1903 
1893 
     | 
    
         
             
                    replacement of a word with the word from the dictionary.
         
     | 
| 
         @@ -1909,7 +1899,6 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       1909 
1899 
     | 
    
         
             
                    cursor.endEditBlock()
         
     | 
| 
       1910 
1900 
     | 
    
         
             
                    cursor.setPosition(pos)
         
     | 
| 
       1911 
1901 
     | 
    
         
             
                    self.setTextCursor(cursor)
         
     | 
| 
       1912 
     | 
    
         
            -
                    return
         
     | 
| 
       1913 
1902 
     | 
    
         | 
| 
       1914 
1903 
     | 
    
         
             
                def _addWord(self, word: str, block: QTextBlock, save: bool) -> None:
         
     | 
| 
       1915 
1904 
     | 
    
         
             
                    """Slot for the spell check context menu triggered when the user
         
     | 
| 
         @@ -1918,7 +1907,6 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       1918 
1907 
     | 
    
         
             
                    logger.debug("Added '%s' to project dictionary, %s", word, "saved" if save else "unsaved")
         
     | 
| 
       1919 
1908 
     | 
    
         
             
                    SHARED.spelling.addWord(word, save=save)
         
     | 
| 
       1920 
1909 
     | 
    
         
             
                    self._qDocument.syntaxHighlighter.rehighlightBlock(block)
         
     | 
| 
       1921 
     | 
    
         
            -
                    return
         
     | 
| 
       1922 
1910 
     | 
    
         | 
| 
       1923 
1911 
     | 
    
         
             
                def _processTag(
         
     | 
| 
       1924 
1912 
     | 
    
         
             
                    self, cursor: QTextCursor | None = None, follow: bool = True, create: bool = False
         
     | 
| 
         @@ -1992,7 +1980,6 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       1992 
1980 
     | 
    
         
             
                    if self._docHandle:
         
     | 
| 
       1993 
1981 
     | 
    
         
             
                        text = block.text().lstrip("#").lstrip("!").strip()
         
     | 
| 
       1994 
1982 
     | 
    
         
             
                        self.requestProjectItemRenamed.emit(self._docHandle, text)
         
     | 
| 
       1995 
     | 
    
         
            -
                    return
         
     | 
| 
       1996 
1983 
     | 
    
         | 
| 
       1997 
1984 
     | 
    
         
             
                def _autoSelect(self) -> QTextCursor:
         
     | 
| 
       1998 
1985 
     | 
    
         
             
                    """Return a cursor which may or may not have a selection based
         
     | 
| 
         @@ -2047,10 +2034,10 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       2047 
2034 
     | 
    
         
             
                    cursor.clearSelection()
         
     | 
| 
       2048 
2035 
     | 
    
         
             
                    cursor.select(mode)
         
     | 
| 
       2049 
2036 
     | 
    
         | 
| 
       2050 
     | 
    
         
            -
                    if mode ==  
     | 
| 
      
 2037 
     | 
    
         
            +
                    if mode == QtSelectWord:
         
     | 
| 
       2051 
2038 
     | 
    
         
             
                        cursor = self._autoSelect()
         
     | 
| 
       2052 
2039 
     | 
    
         | 
| 
       2053 
     | 
    
         
            -
                    elif mode ==  
     | 
| 
      
 2040 
     | 
    
         
            +
                    elif mode == QtSelectBlock:
         
     | 
| 
       2054 
2041 
     | 
    
         
             
                        # This selection mode also selects the preceding paragraph
         
     | 
| 
       2055 
2042 
     | 
    
         
             
                        # separator, which we want to avoid.
         
     | 
| 
       2056 
2043 
     | 
    
         
             
                        posS = cursor.selectionStart()
         
     | 
| 
         @@ -2062,14 +2049,11 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       2062 
2049 
     | 
    
         | 
| 
       2063 
2050 
     | 
    
         
             
                    self.setTextCursor(cursor)
         
     | 
| 
       2064 
2051 
     | 
    
         | 
| 
       2065 
     | 
    
         
            -
                    return
         
     | 
| 
       2066 
     | 
    
         
            -
             
     | 
| 
       2067 
2052 
     | 
    
         
             
                def _makePosSelection(self, mode: QTextCursor.SelectionType, pos: QPoint) -> None:
         
     | 
| 
       2068 
2053 
     | 
    
         
             
                    """Select text based on selection mode, but first move cursor."""
         
     | 
| 
       2069 
2054 
     | 
    
         
             
                    cursor = self.cursorForPosition(pos)
         
     | 
| 
       2070 
2055 
     | 
    
         
             
                    self.setTextCursor(cursor)
         
     | 
| 
       2071 
2056 
     | 
    
         
             
                    self._makeSelection(mode)
         
     | 
| 
       2072 
     | 
    
         
            -
                    return
         
     | 
| 
       2073 
2057 
     | 
    
         | 
| 
       2074 
2058 
     | 
    
         
             
                def _allowAutoReplace(self, state: bool) -> None:
         
     | 
| 
       2075 
2059 
     | 
    
         
             
                    """Enable/disable the auto-replace feature temporarily."""
         
     | 
| 
         @@ -2077,11 +2061,10 @@ class GuiDocEditor(QPlainTextEdit): 
     | 
|
| 
       2077 
2061 
     | 
    
         
             
                        self._doReplace = CONFIG.doReplace
         
     | 
| 
       2078 
2062 
     | 
    
         
             
                    else:
         
     | 
| 
       2079 
2063 
     | 
    
         
             
                        self._doReplace = False
         
     | 
| 
       2080 
     | 
    
         
            -
                    return
         
     | 
| 
       2081 
2064 
     | 
    
         | 
| 
       2082 
2065 
     | 
    
         | 
| 
       2083 
2066 
     | 
    
         
             
            class CommandCompleter(QMenu):
         
     | 
| 
       2084 
     | 
    
         
            -
                """GuiWidget: Command Completer Menu
         
     | 
| 
      
 2067 
     | 
    
         
            +
                """GuiWidget: Command Completer Menu.
         
     | 
| 
       2085 
2068 
     | 
    
         | 
| 
       2086 
2069 
     | 
    
         
             
                This is a context menu with options populated from the user's
         
     | 
| 
       2087 
2070 
     | 
    
         
             
                defined tags and keys. It also helps to type the meta data keyword
         
     | 
| 
         @@ -2089,11 +2072,13 @@ class CommandCompleter(QMenu): 
     | 
|
| 
       2089 
2072 
     | 
    
         
             
                called on every keystroke on a line starting with @ or %.
         
     | 
| 
       2090 
2073 
     | 
    
         
             
                """
         
     | 
| 
       2091 
2074 
     | 
    
         | 
| 
       2092 
     | 
    
         
            -
                 
     | 
| 
      
 2075 
     | 
    
         
            +
                __slots__ = ("_parent",)
         
     | 
| 
      
 2076 
     | 
    
         
            +
             
     | 
| 
      
 2077 
     | 
    
         
            +
                insertText = pyqtSignal(int, int, str)
         
     | 
| 
       2093 
2078 
     | 
    
         | 
| 
       2094 
2079 
     | 
    
         
             
                def __init__(self, parent: QWidget) -> None:
         
     | 
| 
       2095 
2080 
     | 
    
         
             
                    super().__init__(parent=parent)
         
     | 
| 
       2096 
     | 
    
         
            -
                     
     | 
| 
      
 2081 
     | 
    
         
            +
                    self._parent = parent
         
     | 
| 
       2097 
2082 
     | 
    
         | 
| 
       2098 
2083 
     | 
    
         
             
                def updateMetaText(self, text: str, pos: int) -> bool:
         
     | 
| 
       2099 
2084 
     | 
    
         
             
                    """Update the menu options based on the line of text."""
         
     | 
| 
         @@ -2179,15 +2164,14 @@ class CommandCompleter(QMenu): 
     | 
|
| 
       2179 
2164 
     | 
    
         | 
| 
       2180 
2165 
     | 
    
         
             
                def keyPressEvent(self, event: QKeyEvent) -> None:
         
     | 
| 
       2181 
2166 
     | 
    
         
             
                    """Capture keypresses and forward most of them to the editor."""
         
     | 
| 
       2182 
     | 
    
         
            -
                    parent = self.parent()
         
     | 
| 
       2183 
2167 
     | 
    
         
             
                    if event.key() in (
         
     | 
| 
       2184 
2168 
     | 
    
         
             
                        Qt.Key.Key_Up, Qt.Key.Key_Down, Qt.Key.Key_Return,
         
     | 
| 
       2185 
2169 
     | 
    
         
             
                        Qt.Key.Key_Enter, Qt.Key.Key_Escape
         
     | 
| 
       2186 
2170 
     | 
    
         
             
                    ):
         
     | 
| 
       2187 
2171 
     | 
    
         
             
                        super().keyPressEvent(event)
         
     | 
| 
       2188 
     | 
    
         
            -
                     
     | 
| 
       2189 
     | 
    
         
            -
                         
     | 
| 
       2190 
     | 
    
         
            -
             
     | 
| 
      
 2172 
     | 
    
         
            +
                    else:
         
     | 
| 
      
 2173 
     | 
    
         
            +
                        self.close()  # Close to release the event lock before forwarding the key press (#2510)
         
     | 
| 
      
 2174 
     | 
    
         
            +
                        self._parent.keyPressEvent(event)
         
     | 
| 
       2191 
2175 
     | 
    
         | 
| 
       2192 
2176 
     | 
    
         
             
                ##
         
     | 
| 
       2193 
2177 
     | 
    
         
             
                #  Internal Functions
         
     | 
| 
         @@ -2195,12 +2179,11 @@ class CommandCompleter(QMenu): 
     | 
|
| 
       2195 
2179 
     | 
    
         | 
| 
       2196 
2180 
     | 
    
         
             
                def _emitComplete(self, pos: int, length: int, value: str) -> None:
         
     | 
| 
       2197 
2181 
     | 
    
         
             
                    """Emit the signal to indicate a selection has been made."""
         
     | 
| 
       2198 
     | 
    
         
            -
                    self. 
     | 
| 
       2199 
     | 
    
         
            -
                    return
         
     | 
| 
      
 2182 
     | 
    
         
            +
                    self.insertText.emit(pos, length, value)
         
     | 
| 
       2200 
2183 
     | 
    
         | 
| 
       2201 
2184 
     | 
    
         | 
| 
       2202 
2185 
     | 
    
         
             
            class BackgroundWordCounter(QRunnable):
         
     | 
| 
       2203 
     | 
    
         
            -
                """The Off-GUI Thread Word Counter
         
     | 
| 
      
 2186 
     | 
    
         
            +
                """The Off-GUI Thread Word Counter.
         
     | 
| 
       2204 
2187 
     | 
    
         | 
| 
       2205 
2188 
     | 
    
         
             
                A runnable for the word counter to be run in the thread pool off the
         
     | 
| 
       2206 
2189 
     | 
    
         
             
                main GUI thread.
         
     | 
| 
         @@ -2212,9 +2195,9 @@ class BackgroundWordCounter(QRunnable): 
     | 
|
| 
       2212 
2195 
     | 
    
         
             
                    self._forSelection = forSelection
         
     | 
| 
       2213 
2196 
     | 
    
         
             
                    self._isRunning = False
         
     | 
| 
       2214 
2197 
     | 
    
         
             
                    self.signals = BackgroundWordCounterSignals()
         
     | 
| 
       2215 
     | 
    
         
            -
                    return
         
     | 
| 
       2216 
2198 
     | 
    
         | 
| 
       2217 
2199 
     | 
    
         
             
                def isRunning(self) -> bool:
         
     | 
| 
      
 2200 
     | 
    
         
            +
                    """Return True if the word counter is already running."""
         
     | 
| 
       2218 
2201 
     | 
    
         
             
                    return self._isRunning
         
     | 
| 
       2219 
2202 
     | 
    
         | 
| 
       2220 
2203 
     | 
    
         
             
                @pyqtSlot()
         
     | 
| 
         @@ -2232,17 +2215,17 @@ class BackgroundWordCounter(QRunnable): 
     | 
|
| 
       2232 
2215 
     | 
    
         
             
                    self.signals.countsReady.emit(cC, wC, pC)
         
     | 
| 
       2233 
2216 
     | 
    
         
             
                    self._isRunning = False
         
     | 
| 
       2234 
2217 
     | 
    
         | 
| 
       2235 
     | 
    
         
            -
                    return
         
     | 
| 
       2236 
     | 
    
         
            -
             
     | 
| 
       2237 
2218 
     | 
    
         | 
| 
       2238 
2219 
     | 
    
         
             
            class BackgroundWordCounterSignals(QObject):
         
     | 
| 
       2239 
2220 
     | 
    
         
             
                """The QRunnable cannot emit a signal, so we need a simple QObject
         
     | 
| 
       2240 
2221 
     | 
    
         
             
                to hold the word counter signal.
         
     | 
| 
       2241 
2222 
     | 
    
         
             
                """
         
     | 
| 
      
 2223 
     | 
    
         
            +
             
     | 
| 
       2242 
2224 
     | 
    
         
             
                countsReady = pyqtSignal(int, int, int)
         
     | 
| 
       2243 
2225 
     | 
    
         | 
| 
       2244 
2226 
     | 
    
         | 
| 
       2245 
2227 
     | 
    
         
             
            class TextAutoReplace:
         
     | 
| 
      
 2228 
     | 
    
         
            +
                """Encapsulates the editor auto replace feature."""
         
     | 
| 
       2246 
2229 
     | 
    
         | 
| 
       2247 
2230 
     | 
    
         
             
                __slots__ = (
         
     | 
| 
       2248 
2231 
     | 
    
         
             
                    "_doPadAfter", "_doPadBefore", "_padAfter", "_padBefore", "_padChar",
         
     | 
| 
         @@ -2252,7 +2235,6 @@ class TextAutoReplace: 
     | 
|
| 
       2252 
2235 
     | 
    
         | 
| 
       2253 
2236 
     | 
    
         
             
                def __init__(self) -> None:
         
     | 
| 
       2254 
2237 
     | 
    
         
             
                    self.initSettings()
         
     | 
| 
       2255 
     | 
    
         
            -
                    return
         
     | 
| 
       2256 
2238 
     | 
    
         | 
| 
       2257 
2239 
     | 
    
         
             
                def initSettings(self) -> None:
         
     | 
| 
       2258 
2240 
     | 
    
         
             
                    """Initialise the auto-replace settings from config."""
         
     | 
| 
         @@ -2271,27 +2253,28 @@ class TextAutoReplace: 
     | 
|
| 
       2271 
2253 
     | 
    
         
             
                    self._padAfter    = CONFIG.fmtPadAfter
         
     | 
| 
       2272 
2254 
     | 
    
         
             
                    self._doPadBefore = bool(CONFIG.fmtPadBefore)
         
     | 
| 
       2273 
2255 
     | 
    
         
             
                    self._doPadAfter  = bool(CONFIG.fmtPadAfter)
         
     | 
| 
       2274 
     | 
    
         
            -
                    return
         
     | 
| 
       2275 
2256 
     | 
    
         | 
| 
       2276 
2257 
     | 
    
         
             
                def process(self, text: str, cursor: QTextCursor) -> bool:
         
     | 
| 
       2277 
2258 
     | 
    
         
             
                    """Auto-replace text elements based on main configuration.
         
     | 
| 
       2278 
2259 
     | 
    
         
             
                    Returns True if anything was changed.
         
     | 
| 
       2279 
2260 
     | 
    
         
             
                    """
         
     | 
| 
       2280 
     | 
    
         
            -
                     
     | 
| 
       2281 
     | 
    
         
            -
                     
     | 
| 
       2282 
     | 
    
         
            -
                     
     | 
| 
      
 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:
         
     | 
| 
       2283 
2266 
     | 
    
         
             
                        return False
         
     | 
| 
       2284 
2267 
     | 
    
         | 
| 
       2285 
     | 
    
         
            -
                     
     | 
| 
       2286 
     | 
    
         
            -
                     
     | 
| 
       2287 
     | 
    
         
            -
             
     | 
| 
      
 2268 
     | 
    
         
            +
                    cursor.movePosition(QtMoveLeft, QtKeepAnchor, min(4, bPos))
         
     | 
| 
      
 2269 
     | 
    
         
            +
                    last = cursor.selectedText()
         
     | 
| 
      
 2270 
     | 
    
         
            +
                    delete, insert = self._determine(last, bPos)
         
     | 
| 
       2288 
2271 
     | 
    
         | 
| 
       2289 
2272 
     | 
    
         
             
                    check = insert
         
     | 
| 
       2290 
2273 
     | 
    
         
             
                    if self._doPadBefore and check in self._padBefore:
         
     | 
| 
       2291 
2274 
     | 
    
         
             
                        if not (check == ":" and length > 1 and text[0] == "@"):
         
     | 
| 
       2292 
2275 
     | 
    
         
             
                            delete = max(delete, 1)
         
     | 
| 
       2293 
     | 
    
         
            -
                            chkPos =  
     | 
| 
       2294 
     | 
    
         
            -
                            if chkPos >= 0 and  
     | 
| 
      
 2276 
     | 
    
         
            +
                            chkPos = len(last) - delete - 1
         
     | 
| 
      
 2277 
     | 
    
         
            +
                            if chkPos >= 0 and last[chkPos].isspace():
         
     | 
| 
       2295 
2278 
     | 
    
         
             
                                # Strip existing space before inserting a new (#1061)
         
     | 
| 
       2296 
2279 
     | 
    
         
             
                                delete += 1
         
     | 
| 
       2297 
2280 
     | 
    
         
             
                            insert = self._padChar + insert
         
     | 
| 
         @@ -2302,6 +2285,7 @@ class TextAutoReplace: 
     | 
|
| 
       2302 
2285 
     | 
    
         
             
                            insert = insert + self._padChar
         
     | 
| 
       2303 
2286 
     | 
    
         | 
| 
       2304 
2287 
     | 
    
         
             
                    if delete > 0:
         
     | 
| 
      
 2288 
     | 
    
         
            +
                        cursor.setPosition(aPos)
         
     | 
| 
       2305 
2289 
     | 
    
         
             
                        cursor.movePosition(QtMoveLeft, QtKeepAnchor, delete)
         
     | 
| 
       2306 
2290 
     | 
    
         
             
                        cursor.insertText(insert)
         
     | 
| 
       2307 
2291 
     | 
    
         
             
                        return True
         
     | 
| 
         @@ -2310,42 +2294,55 @@ class TextAutoReplace: 
     | 
|
| 
       2310 
2294 
     | 
    
         | 
| 
       2311 
2295 
     | 
    
         
             
                def _determine(self, text: str, pos: int) -> tuple[int, str]:
         
     | 
| 
       2312 
2296 
     | 
    
         
             
                    """Determine what to replace, if anything."""
         
     | 
| 
       2313 
     | 
    
         
            -
                    t1 = text[ 
     | 
| 
       2314 
     | 
    
         
            -
                    t2 = text[ 
     | 
| 
       2315 
     | 
    
         
            -
                    t3 = text[ 
     | 
| 
       2316 
     | 
    
         
            -
                    t4 = text[ 
     | 
| 
       2317 
     | 
    
         
            -
             
     | 
| 
       2318 
     | 
    
         
            -
             
     | 
| 
       2319 
     | 
    
         
            -
                         
     | 
| 
       2320 
     | 
    
         
            -
             
     | 
| 
       2321 
     | 
    
         
            -
                    leading = t2[:1].isspace()
         
     | 
| 
       2322 
     | 
    
         
            -
                    if self._replaceDQuote:
         
     | 
| 
       2323 
     | 
    
         
            -
                        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:
         
     | 
| 
       2324 
2305 
     | 
    
         
             
                            return 1, self._quoteDO
         
     | 
| 
       2325 
     | 
    
         
            -
                        elif  
     | 
| 
       2326 
     | 
    
         
            -
                             
     | 
| 
       2327 
     | 
    
         
            -
             
     | 
| 
       2328 
     | 
    
         
            -
                             
     | 
| 
       2329 
     | 
    
         
            -
             
     | 
| 
       2330 
     | 
    
         
            -
                             
     | 
| 
       2331 
     | 
    
         
            -
             
     | 
| 
       2332 
     | 
    
         
            -
                             
     | 
| 
       2333 
     | 
    
         
            -
             
     | 
| 
      
 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
         
     | 
| 
       2334 
2322 
     | 
    
         | 
| 
       2335 
     | 
    
         
            -
                    if self._replaceSQuote:
         
     | 
| 
       2336 
     | 
    
         
            -
                         
     | 
| 
      
 2323 
     | 
    
         
            +
                    if self._replaceSQuote and t1 == "'":
         
     | 
| 
      
 2324 
     | 
    
         
            +
                        # Process Single Quote
         
     | 
| 
      
 2325 
     | 
    
         
            +
                        if pos == 1:
         
     | 
| 
       2337 
2326 
     | 
    
         
             
                            return 1, self._quoteSO
         
     | 
| 
       2338 
     | 
    
         
            -
                        elif  
     | 
| 
       2339 
     | 
    
         
            -
                             
     | 
| 
       2340 
     | 
    
         
            -
             
     | 
| 
       2341 
     | 
    
         
            -
                             
     | 
| 
       2342 
     | 
    
         
            -
             
     | 
| 
       2343 
     | 
    
         
            -
                             
     | 
| 
       2344 
     | 
    
         
            -
             
     | 
| 
       2345 
     | 
    
         
            -
                             
     | 
| 
       2346 
     | 
    
         
            -
             
     | 
| 
      
 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
         
     | 
| 
       2347 
2343 
     | 
    
         | 
| 
       2348 
     | 
    
         
            -
                    if self._replaceDash:
         
     | 
| 
      
 2344 
     | 
    
         
            +
                    if self._replaceDash and t1 == "-":
         
     | 
| 
      
 2345 
     | 
    
         
            +
                        # Process Dashes
         
     | 
| 
       2349 
2346 
     | 
    
         
             
                        if t4 == "----":
         
     | 
| 
       2350 
2347 
     | 
    
         
             
                            return 4, "\u2015"  # Horizontal bar
         
     | 
| 
       2351 
2348 
     | 
    
         
             
                        elif t3 == "---":
         
     | 
| 
         @@ -2358,6 +2355,7 @@ class TextAutoReplace: 
     | 
|
| 
       2358 
2355 
     | 
    
         
             
                            return 2, "\u2015"  # Horizontal bar
         
     | 
| 
       2359 
2356 
     | 
    
         | 
| 
       2360 
2357 
     | 
    
         
             
                    if self._replaceDots and t3 == "...":
         
     | 
| 
      
 2358 
     | 
    
         
            +
                        # Process Dots
         
     | 
| 
       2361 
2359 
     | 
    
         
             
                        return 3, "\u2026"  # Ellipsis
         
     | 
| 
       2362 
2360 
     | 
    
         | 
| 
       2363 
2361 
     | 
    
         
             
                    if t1 == "\u2028":  # Line separator
         
     | 
| 
         @@ -2368,7 +2366,7 @@ class TextAutoReplace: 
     | 
|
| 
       2368 
2366 
     | 
    
         | 
| 
       2369 
2367 
     | 
    
         | 
| 
       2370 
2368 
     | 
    
         
             
            class GuiDocToolBar(QWidget):
         
     | 
| 
       2371 
     | 
    
         
            -
                """The Formatting and Options Fold Out Menu
         
     | 
| 
      
 2369 
     | 
    
         
            +
                """The Formatting and Options Fold Out Menu.
         
     | 
| 
       2372 
2370 
     | 
    
         | 
| 
       2373 
2371 
     | 
    
         
             
                Only used by DocEditor, and is opened by the first button in the
         
     | 
| 
       2374 
2372 
     | 
    
         
             
                header.
         
     | 
| 
         @@ -2405,6 +2403,12 @@ class GuiDocToolBar(QWidget): 
     | 
|
| 
       2405 
2403 
     | 
    
         
             
                        qtLambda(self.requestDocAction.emit, nwDocAction.MD_STRIKE)
         
     | 
| 
       2406 
2404 
     | 
    
         
             
                    )
         
     | 
| 
       2407 
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 
     | 
    
         
            +
             
     | 
| 
       2408 
2412 
     | 
    
         
             
                    self.tbBold = NIconToolButton(self, iSz)
         
     | 
| 
       2409 
2413 
     | 
    
         
             
                    self.tbBold.setToolTip(self.tr("Shortcode Bold"))
         
     | 
| 
       2410 
2414 
     | 
    
         
             
                    self.tbBold.clicked.connect(
         
     | 
| 
         @@ -2454,6 +2458,7 @@ class GuiDocToolBar(QWidget): 
     | 
|
| 
       2454 
2458 
     | 
    
         
             
                    self.outerBox.addWidget(self.tbBoldMD)
         
     | 
| 
       2455 
2459 
     | 
    
         
             
                    self.outerBox.addWidget(self.tbItalicMD)
         
     | 
| 
       2456 
2460 
     | 
    
         
             
                    self.outerBox.addWidget(self.tbStrikeMD)
         
     | 
| 
      
 2461 
     | 
    
         
            +
                    self.outerBox.addWidget(self.tbMarkMD)
         
     | 
| 
       2457 
2462 
     | 
    
         
             
                    self.outerBox.addSpacing(4)
         
     | 
| 
       2458 
2463 
     | 
    
         
             
                    self.outerBox.addWidget(self.tbBold)
         
     | 
| 
       2459 
2464 
     | 
    
         
             
                    self.outerBox.addWidget(self.tbItalic)
         
     | 
| 
         @@ -2473,34 +2478,32 @@ class GuiDocToolBar(QWidget): 
     | 
|
| 
       2473 
2478 
     | 
    
         | 
| 
       2474 
2479 
     | 
    
         
             
                    logger.debug("Ready: GuiDocToolBar")
         
     | 
| 
       2475 
2480 
     | 
    
         | 
| 
       2476 
     | 
    
         
            -
                    return
         
     | 
| 
       2477 
     | 
    
         
            -
             
     | 
| 
       2478 
2481 
     | 
    
         
             
                def updateTheme(self) -> None:
         
     | 
| 
       2479 
2482 
     | 
    
         
             
                    """Initialise GUI elements that depend on specific settings."""
         
     | 
| 
       2480 
     | 
    
         
            -
                     
     | 
| 
      
 2483 
     | 
    
         
            +
                    logger.debug("Theme Update: GuiDocToolBar")
         
     | 
| 
       2481 
2484 
     | 
    
         | 
| 
      
 2485 
     | 
    
         
            +
                    syntax = SHARED.theme.syntaxTheme
         
     | 
| 
       2482 
2486 
     | 
    
         
             
                    palette = self.palette()
         
     | 
| 
       2483 
2487 
     | 
    
         
             
                    palette.setColor(QPalette.ColorRole.Window, syntax.back)
         
     | 
| 
       2484 
2488 
     | 
    
         
             
                    palette.setColor(QPalette.ColorRole.WindowText, syntax.text)
         
     | 
| 
       2485 
2489 
     | 
    
         
             
                    palette.setColor(QPalette.ColorRole.Text, syntax.text)
         
     | 
| 
       2486 
2490 
     | 
    
         
             
                    self.setPalette(palette)
         
     | 
| 
       2487 
2491 
     | 
    
         | 
| 
       2488 
     | 
    
         
            -
                    self.tbBoldMD.setThemeIcon("fmt_bold", " 
     | 
| 
       2489 
     | 
    
         
            -
                    self.tbItalicMD.setThemeIcon("fmt_italic", " 
     | 
| 
       2490 
     | 
    
         
            -
                    self.tbStrikeMD.setThemeIcon("fmt_strike", " 
     | 
| 
       2491 
     | 
    
         
            -
                    self. 
     | 
| 
       2492 
     | 
    
         
            -
                    self. 
     | 
| 
       2493 
     | 
    
         
            -
                    self. 
     | 
| 
       2494 
     | 
    
         
            -
                    self. 
     | 
| 
       2495 
     | 
    
         
            -
                    self. 
     | 
| 
       2496 
     | 
    
         
            -
                    self. 
     | 
| 
       2497 
     | 
    
         
            -
                    self. 
     | 
| 
       2498 
     | 
    
         
            -
             
     | 
| 
       2499 
     | 
    
         
            -
                    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")
         
     | 
| 
       2500 
2503 
     | 
    
         | 
| 
       2501 
2504 
     | 
    
         | 
| 
       2502 
2505 
     | 
    
         
             
            class GuiDocEditSearch(QFrame):
         
     | 
| 
       2503 
     | 
    
         
            -
                """The Embedded Document Search/Replace Feature
         
     | 
| 
      
 2506 
     | 
    
         
            +
                """The Embedded Document Search/Replace Feature.
         
     | 
| 
       2504 
2507 
     | 
    
         | 
| 
       2505 
2508 
     | 
    
         
             
                Only used by DocEditor, and is at a fixed position in the
         
     | 
| 
       2506 
2509 
     | 
    
         
             
                QTextEdit's viewport.
         
     | 
| 
         @@ -2590,7 +2593,7 @@ class GuiDocEditSearch(QFrame): 
     | 
|
| 
       2590 
2593 
     | 
    
         
             
                    # Buttons
         
     | 
| 
       2591 
2594 
     | 
    
         
             
                    # =======
         
     | 
| 
       2592 
2595 
     | 
    
         | 
| 
       2593 
     | 
    
         
            -
                    self.showReplace = NIconToggleButton(self, iSz 
     | 
| 
      
 2596 
     | 
    
         
            +
                    self.showReplace = NIconToggleButton(self, iSz)
         
     | 
| 
       2594 
2597 
     | 
    
         
             
                    self.showReplace.toggled.connect(self._doToggleReplace)
         
     | 
| 
       2595 
2598 
     | 
    
         | 
| 
       2596 
2599 
     | 
    
         
             
                    self.searchButton = NIconToolButton(self, iSz)
         
     | 
| 
         @@ -2630,8 +2633,6 @@ class GuiDocEditSearch(QFrame): 
     | 
|
| 
       2630 
2633 
     | 
    
         | 
| 
       2631 
2634 
     | 
    
         
             
                    logger.debug("Ready: GuiDocEditSearch")
         
     | 
| 
       2632 
2635 
     | 
    
         | 
| 
       2633 
     | 
    
         
            -
                    return
         
     | 
| 
       2634 
     | 
    
         
            -
             
     | 
| 
       2635 
2636 
     | 
    
         
             
                ##
         
     | 
| 
       2636 
2637 
     | 
    
         
             
                #  Properties
         
     | 
| 
       2637 
2638 
     | 
    
         
             
                ##
         
     | 
| 
         @@ -2680,14 +2681,12 @@ class GuiDocEditSearch(QFrame): 
     | 
|
| 
       2680 
2681 
     | 
    
         
             
                    self.searchBox.selectAll()
         
     | 
| 
       2681 
2682 
     | 
    
         
             
                    if CONFIG.searchRegEx:
         
     | 
| 
       2682 
2683 
     | 
    
         
             
                        self._alertSearchValid(True)
         
     | 
| 
       2683 
     | 
    
         
            -
                    return
         
     | 
| 
       2684 
2684 
     | 
    
         | 
| 
       2685 
2685 
     | 
    
         
             
                def setReplaceText(self, text: str) -> None:
         
     | 
| 
       2686 
2686 
     | 
    
         
             
                    """Set the replace text."""
         
     | 
| 
       2687 
2687 
     | 
    
         
             
                    self.showReplace.setChecked(True)
         
     | 
| 
       2688 
2688 
     | 
    
         
             
                    self.replaceBox.setFocus()
         
     | 
| 
       2689 
2689 
     | 
    
         
             
                    self.replaceBox.setText(text)
         
     | 
| 
       2690 
     | 
    
         
            -
                    return
         
     | 
| 
       2691 
2690 
     | 
    
         | 
| 
       2692 
2691 
     | 
    
         
             
                def setResultCount(self, currRes: int | None, resCount: int | None) -> None:
         
     | 
| 
       2693 
2692 
     | 
    
         
             
                    """Set the count values for the current search."""
         
     | 
| 
         @@ -2702,7 +2701,6 @@ class GuiDocEditSearch(QFrame): 
     | 
|
| 
       2702 
2701 
     | 
    
         
             
                    self.resultLabel.setMinimumWidth(minWidth)
         
     | 
| 
       2703 
2702 
     | 
    
         
             
                    self.adjustSize()
         
     | 
| 
       2704 
2703 
     | 
    
         
             
                    self.docEditor.updateDocMargins()
         
     | 
| 
       2705 
     | 
    
         
            -
                    return
         
     | 
| 
       2706 
2704 
     | 
    
         | 
| 
       2707 
2705 
     | 
    
         
             
                ##
         
     | 
| 
       2708 
2706 
     | 
    
         
             
                #  Methods
         
     | 
| 
         @@ -2718,36 +2716,35 @@ class GuiDocEditSearch(QFrame): 
     | 
|
| 
       2718 
2716 
     | 
    
         
             
                    self.resultLabel.setMinimumWidth(
         
     | 
| 
       2719 
2717 
     | 
    
         
             
                        SHARED.theme.getTextWidth("?/?", SHARED.theme.guiFontSmall)
         
     | 
| 
       2720 
2718 
     | 
    
         
             
                    )
         
     | 
| 
       2721 
     | 
    
         
            -
                    return
         
     | 
| 
       2722 
2719 
     | 
    
         | 
| 
       2723 
2720 
     | 
    
         
             
                def updateTheme(self) -> None:
         
     | 
| 
       2724 
2721 
     | 
    
         
             
                    """Update theme elements."""
         
     | 
| 
       2725 
     | 
    
         
            -
                     
     | 
| 
      
 2722 
     | 
    
         
            +
                    logger.debug("Theme Update: GuiDocEditSearch")
         
     | 
| 
       2726 
2723 
     | 
    
         | 
| 
      
 2724 
     | 
    
         
            +
                    palette = QApplication.palette()
         
     | 
| 
       2727 
2725 
     | 
    
         
             
                    self.setPalette(palette)
         
     | 
| 
       2728 
2726 
     | 
    
         
             
                    self.searchBox.setPalette(palette)
         
     | 
| 
       2729 
2727 
     | 
    
         
             
                    self.replaceBox.setPalette(palette)
         
     | 
| 
       2730 
2728 
     | 
    
         | 
| 
       2731 
2729 
     | 
    
         
             
                    # Set icons
         
     | 
| 
       2732 
     | 
    
         
            -
                    self.toggleCase.setIcon(SHARED.theme.getIcon("search_case"))
         
     | 
| 
       2733 
     | 
    
         
            -
                    self.toggleWord.setIcon(SHARED.theme.getIcon("search_word"))
         
     | 
| 
       2734 
     | 
    
         
            -
                    self.toggleRegEx.setIcon(SHARED.theme.getIcon("search_regex"))
         
     | 
| 
       2735 
     | 
    
         
            -
                    self.toggleLoop.setIcon(SHARED.theme.getIcon("search_loop"))
         
     | 
| 
       2736 
     | 
    
         
            -
                    self.toggleProject.setIcon(SHARED.theme.getIcon("search_project"))
         
     | 
| 
       2737 
     | 
    
         
            -
                    self.toggleMatchCap.setIcon(SHARED.theme.getIcon("search_preserve"))
         
     | 
| 
       2738 
     | 
    
         
            -
                    self.cancelSearch.setIcon(SHARED.theme.getIcon("search_cancel"))
         
     | 
| 
       2739 
     | 
    
         
            -
                    self.searchButton.setThemeIcon("search", " 
     | 
| 
       2740 
     | 
    
         
            -
                    self.replaceButton.setThemeIcon("search_replace", " 
     | 
| 
      
 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")
         
     | 
| 
       2741 
2740 
     | 
    
         | 
| 
       2742 
2741 
     | 
    
         
             
                    # Set stylesheets
         
     | 
| 
       2743 
2742 
     | 
    
         
             
                    self.searchOpt.setStyleSheet("QToolBar {padding: 0;}")
         
     | 
| 
       2744 
2743 
     | 
    
         
             
                    self.showReplace.setStyleSheet("QToolButton {border: none; background: transparent;}")
         
     | 
| 
       2745 
2744 
     | 
    
         | 
| 
       2746 
     | 
    
         
            -
                    return
         
     | 
| 
       2747 
     | 
    
         
            -
             
     | 
| 
       2748 
2745 
     | 
    
         
             
                def cycleFocus(self) -> bool:
         
     | 
| 
       2749 
     | 
    
         
            -
                    """ 
     | 
| 
       2750 
     | 
    
         
            -
                    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.
         
     | 
| 
       2751 
2748 
     | 
    
         
             
                    """
         
     | 
| 
       2752 
2749 
     | 
    
         
             
                    if self.searchBox.hasFocus():
         
     | 
| 
       2753 
2750 
     | 
    
         
             
                        self.replaceBox.setFocus()
         
     | 
| 
         @@ -2772,7 +2769,6 @@ class GuiDocEditSearch(QFrame): 
     | 
|
| 
       2772 
2769 
     | 
    
         
             
                    self.setVisible(False)
         
     | 
| 
       2773 
2770 
     | 
    
         
             
                    self.docEditor.updateDocMargins()
         
     | 
| 
       2774 
2771 
     | 
    
         
             
                    self.docEditor.setFocus()
         
     | 
| 
       2775 
     | 
    
         
            -
                    return
         
     | 
| 
       2776 
2772 
     | 
    
         | 
| 
       2777 
2773 
     | 
    
         
             
                ##
         
     | 
| 
       2778 
2774 
     | 
    
         
             
                #  Private Slots
         
     | 
| 
         @@ -2782,13 +2778,11 @@ class GuiDocEditSearch(QFrame): 
     | 
|
| 
       2782 
2778 
     | 
    
         
             
                def _doSearch(self) -> None:
         
     | 
| 
       2783 
2779 
     | 
    
         
             
                    """Call the search action function for the document editor."""
         
     | 
| 
       2784 
2780 
     | 
    
         
             
                    self.docEditor.findNext(goBack=(QApplication.keyboardModifiers() == QtModShift))
         
     | 
| 
       2785 
     | 
    
         
            -
                    return
         
     | 
| 
       2786 
2781 
     | 
    
         | 
| 
       2787 
2782 
     | 
    
         
             
                @pyqtSlot()
         
     | 
| 
       2788 
2783 
     | 
    
         
             
                def _doReplace(self) -> None:
         
     | 
| 
       2789 
2784 
     | 
    
         
             
                    """Call the replace action function for the document editor."""
         
     | 
| 
       2790 
2785 
     | 
    
         
             
                    self.docEditor.replaceNext()
         
     | 
| 
       2791 
     | 
    
         
            -
                    return
         
     | 
| 
       2792 
2786 
     | 
    
         | 
| 
       2793 
2787 
     | 
    
         
             
                @pyqtSlot(bool)
         
     | 
| 
       2794 
2788 
     | 
    
         
             
                def _doToggleReplace(self, state: bool) -> None:
         
     | 
| 
         @@ -2797,43 +2791,36 @@ class GuiDocEditSearch(QFrame): 
     | 
|
| 
       2797 
2791 
     | 
    
         
             
                    self.replaceButton.setVisible(state)
         
     | 
| 
       2798 
2792 
     | 
    
         
             
                    self.adjustSize()
         
     | 
| 
       2799 
2793 
     | 
    
         
             
                    self.docEditor.updateDocMargins()
         
     | 
| 
       2800 
     | 
    
         
            -
                    return
         
     | 
| 
       2801 
2794 
     | 
    
         | 
| 
       2802 
2795 
     | 
    
         
             
                @pyqtSlot(bool)
         
     | 
| 
       2803 
2796 
     | 
    
         
             
                def _doToggleCase(self, state: bool) -> None:
         
     | 
| 
       2804 
2797 
     | 
    
         
             
                    """Enable/disable case sensitive mode."""
         
     | 
| 
       2805 
2798 
     | 
    
         
             
                    CONFIG.searchCase = state
         
     | 
| 
       2806 
     | 
    
         
            -
                    return
         
     | 
| 
       2807 
2799 
     | 
    
         | 
| 
       2808 
2800 
     | 
    
         
             
                @pyqtSlot(bool)
         
     | 
| 
       2809 
2801 
     | 
    
         
             
                def _doToggleWord(self, state: bool) -> None:
         
     | 
| 
       2810 
2802 
     | 
    
         
             
                    """Enable/disable whole word search mode."""
         
     | 
| 
       2811 
2803 
     | 
    
         
             
                    CONFIG.searchWord = state
         
     | 
| 
       2812 
     | 
    
         
            -
                    return
         
     | 
| 
       2813 
2804 
     | 
    
         | 
| 
       2814 
2805 
     | 
    
         
             
                @pyqtSlot(bool)
         
     | 
| 
       2815 
2806 
     | 
    
         
             
                def _doToggleRegEx(self, state: bool) -> None:
         
     | 
| 
       2816 
2807 
     | 
    
         
             
                    """Enable/disable regular expression search mode."""
         
     | 
| 
       2817 
2808 
     | 
    
         
             
                    CONFIG.searchRegEx = state
         
     | 
| 
       2818 
     | 
    
         
            -
                    return
         
     | 
| 
       2819 
2809 
     | 
    
         | 
| 
       2820 
2810 
     | 
    
         
             
                @pyqtSlot(bool)
         
     | 
| 
       2821 
2811 
     | 
    
         
             
                def _doToggleLoop(self, state: bool) -> None:
         
     | 
| 
       2822 
2812 
     | 
    
         
             
                    """Enable/disable looping the search."""
         
     | 
| 
       2823 
2813 
     | 
    
         
             
                    CONFIG.searchLoop = state
         
     | 
| 
       2824 
     | 
    
         
            -
                    return
         
     | 
| 
       2825 
2814 
     | 
    
         | 
| 
       2826 
2815 
     | 
    
         
             
                @pyqtSlot(bool)
         
     | 
| 
       2827 
2816 
     | 
    
         
             
                def _doToggleProject(self, state: bool) -> None:
         
     | 
| 
       2828 
2817 
     | 
    
         
             
                    """Enable/disable continuing search in next project file."""
         
     | 
| 
       2829 
2818 
     | 
    
         
             
                    CONFIG.searchNextFile = state
         
     | 
| 
       2830 
     | 
    
         
            -
                    return
         
     | 
| 
       2831 
2819 
     | 
    
         | 
| 
       2832 
2820 
     | 
    
         
             
                @pyqtSlot(bool)
         
     | 
| 
       2833 
2821 
     | 
    
         
             
                def _doToggleMatchCap(self, state: bool) -> None:
         
     | 
| 
       2834 
2822 
     | 
    
         
             
                    """Enable/disable preserving capitalisation when replacing."""
         
     | 
| 
       2835 
2823 
     | 
    
         
             
                    CONFIG.searchMatchCap = state
         
     | 
| 
       2836 
     | 
    
         
            -
                    return
         
     | 
| 
       2837 
2824 
     | 
    
         | 
| 
       2838 
2825 
     | 
    
         
             
                ##
         
     | 
| 
       2839 
2826 
     | 
    
         
             
                #  Internal Functions
         
     | 
| 
         @@ -2849,11 +2836,10 @@ class GuiDocEditSearch(QFrame): 
     | 
|
| 
       2849 
2836 
     | 
    
         
             
                        palette.text().color() if isValid else SHARED.theme.errorText
         
     | 
| 
       2850 
2837 
     | 
    
         
             
                    )
         
     | 
| 
       2851 
2838 
     | 
    
         
             
                    self.searchBox.setPalette(palette)
         
     | 
| 
       2852 
     | 
    
         
            -
                    return
         
     | 
| 
       2853 
2839 
     | 
    
         | 
| 
       2854 
2840 
     | 
    
         | 
| 
       2855 
2841 
     | 
    
         
             
            class GuiDocEditHeader(QWidget):
         
     | 
| 
       2856 
     | 
    
         
            -
                """The Embedded Document Header
         
     | 
| 
      
 2842 
     | 
    
         
            +
                """The Embedded Document Header.
         
     | 
| 
       2857 
2843 
     | 
    
         | 
| 
       2858 
2844 
     | 
    
         
             
                Only used by DocEditor, and is at a fixed position in the
         
     | 
| 
       2859 
2845 
     | 
    
         
             
                QTextEdit's viewport.
         
     | 
| 
         @@ -2944,8 +2930,6 @@ class GuiDocEditHeader(QWidget): 
     | 
|
| 
       2944 
2930 
     | 
    
         | 
| 
       2945 
2931 
     | 
    
         
             
                    logger.debug("Ready: GuiDocEditHeader")
         
     | 
| 
       2946 
2932 
     | 
    
         | 
| 
       2947 
     | 
    
         
            -
                    return
         
     | 
| 
       2948 
     | 
    
         
            -
             
     | 
| 
       2949 
2933 
     | 
    
         
             
                ##
         
     | 
| 
       2950 
2934 
     | 
    
         
             
                #  Methods
         
     | 
| 
       2951 
2935 
     | 
    
         
             
                ##
         
     | 
| 
         @@ -2962,7 +2946,6 @@ class GuiDocEditHeader(QWidget): 
     | 
|
| 
       2962 
2946 
     | 
    
         
             
                    self.searchButton.setVisible(False)
         
     | 
| 
       2963 
2947 
     | 
    
         
             
                    self.closeButton.setVisible(False)
         
     | 
| 
       2964 
2948 
     | 
    
         
             
                    self.minmaxButton.setVisible(False)
         
     | 
| 
       2965 
     | 
    
         
            -
                    return
         
     | 
| 
       2966 
2949 
     | 
    
         | 
| 
       2967 
2950 
     | 
    
         
             
                def setOutline(self, data: dict[int, str]) -> None:
         
     | 
| 
       2968 
2951 
     | 
    
         
             
                    """Set the document outline dataset."""
         
     | 
| 
         @@ -2974,21 +2957,21 @@ class GuiDocEditHeader(QWidget): 
     | 
|
| 
       2974 
2957 
     | 
    
         
             
                            action.triggered.connect(qtLambda(self._gotoBlock, number))
         
     | 
| 
       2975 
2958 
     | 
    
         
             
                        self._docOutline = data
         
     | 
| 
       2976 
2959 
     | 
    
         
             
                        logger.debug("Document outline updated in %.3f ms", 1000*(time() - tStart))
         
     | 
| 
       2977 
     | 
    
         
            -
                    return
         
     | 
| 
       2978 
2960 
     | 
    
         | 
| 
       2979 
2961 
     | 
    
         
             
                def updateFont(self) -> None:
         
     | 
| 
       2980 
2962 
     | 
    
         
             
                    """Update the font settings."""
         
     | 
| 
       2981 
2963 
     | 
    
         
             
                    self.setFont(SHARED.theme.guiFont)
         
     | 
| 
       2982 
2964 
     | 
    
         
             
                    self.itemTitle.setFont(SHARED.theme.guiFontSmall)
         
     | 
| 
       2983 
     | 
    
         
            -
                    return
         
     | 
| 
       2984 
2965 
     | 
    
         | 
| 
       2985 
2966 
     | 
    
         
             
                def updateTheme(self) -> None:
         
     | 
| 
       2986 
2967 
     | 
    
         
             
                    """Update theme elements."""
         
     | 
| 
       2987 
     | 
    
         
            -
                     
     | 
| 
       2988 
     | 
    
         
            -
             
     | 
| 
       2989 
     | 
    
         
            -
                    self. 
     | 
| 
       2990 
     | 
    
         
            -
                    self. 
     | 
| 
       2991 
     | 
    
         
            -
                    self. 
     | 
| 
      
 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")
         
     | 
| 
       2992 
2975 
     | 
    
         | 
| 
       2993 
2976 
     | 
    
         
             
                    buttonStyle = SHARED.theme.getStyleSheet(STYLES_MIN_TOOLBUTTON)
         
     | 
| 
       2994 
2977 
     | 
    
         
             
                    self.tbButton.setStyleSheet(buttonStyle)
         
     | 
| 
         @@ -2999,8 +2982,6 @@ class GuiDocEditHeader(QWidget): 
     | 
|
| 
       2999 
2982 
     | 
    
         | 
| 
       3000 
2983 
     | 
    
         
             
                    self.matchColors()
         
     | 
| 
       3001 
2984 
     | 
    
         | 
| 
       3002 
     | 
    
         
            -
                    return
         
     | 
| 
       3003 
     | 
    
         
            -
             
     | 
| 
       3004 
2985 
     | 
    
         
             
                def matchColors(self) -> None:
         
     | 
| 
       3005 
2986 
     | 
    
         
             
                    """Update the colours of the widget to match those of the syntax
         
     | 
| 
       3006 
2987 
     | 
    
         
             
                    theme rather than the main GUI.
         
     | 
| 
         @@ -3014,12 +2995,10 @@ class GuiDocEditHeader(QWidget): 
     | 
|
| 
       3014 
2995 
     | 
    
         
             
                    self.itemTitle.setTextColors(
         
     | 
| 
       3015 
2996 
     | 
    
         
             
                        color=palette.windowText().color(), faded=SHARED.theme.fadedText
         
     | 
| 
       3016 
2997 
     | 
    
         
             
                    )
         
     | 
| 
       3017 
     | 
    
         
            -
                    return
         
     | 
| 
       3018 
2998 
     | 
    
         | 
| 
       3019 
2999 
     | 
    
         
             
                def changeFocusState(self, state: bool) -> None:
         
     | 
| 
       3020 
3000 
     | 
    
         
             
                    """Toggle focus state."""
         
     | 
| 
       3021 
3001 
     | 
    
         
             
                    self.itemTitle.setColorState(state)
         
     | 
| 
       3022 
     | 
    
         
            -
                    return
         
     | 
| 
       3023 
3002 
     | 
    
         | 
| 
       3024 
3003 
     | 
    
         
             
                def setHandle(self, tHandle: str) -> None:
         
     | 
| 
       3025 
3004 
     | 
    
         
             
                    """Set the document title from the handle, or alternatively, set
         
     | 
| 
         @@ -3040,8 +3019,6 @@ class GuiDocEditHeader(QWidget): 
     | 
|
| 
       3040 
3019 
     | 
    
         
             
                    self.closeButton.setVisible(True)
         
     | 
| 
       3041 
3020 
     | 
    
         
             
                    self.minmaxButton.setVisible(True)
         
     | 
| 
       3042 
3021 
     | 
    
         | 
| 
       3043 
     | 
    
         
            -
                    return
         
     | 
| 
       3044 
     | 
    
         
            -
             
     | 
| 
       3045 
3022 
     | 
    
         
             
                ##
         
     | 
| 
       3046 
3023 
     | 
    
         
             
                #  Private Slots
         
     | 
| 
       3047 
3024 
     | 
    
         
             
                ##
         
     | 
| 
         @@ -3051,19 +3028,16 @@ class GuiDocEditHeader(QWidget): 
     | 
|
| 
       3051 
3028 
     | 
    
         
             
                    """Trigger the close editor on the main window."""
         
     | 
| 
       3052 
3029 
     | 
    
         
             
                    self.clearHeader()
         
     | 
| 
       3053 
3030 
     | 
    
         
             
                    self.closeDocumentRequest.emit()
         
     | 
| 
       3054 
     | 
    
         
            -
                    return
         
     | 
| 
       3055 
3031 
     | 
    
         | 
| 
       3056 
3032 
     | 
    
         
             
                @pyqtSlot(int)
         
     | 
| 
       3057 
3033 
     | 
    
         
             
                def _gotoBlock(self, blockNumber: int) -> None:
         
     | 
| 
       3058 
3034 
     | 
    
         
             
                    """Move cursor to a specific heading."""
         
     | 
| 
       3059 
3035 
     | 
    
         
             
                    self.docEditor.setCursorLine(blockNumber + 1)
         
     | 
| 
       3060 
     | 
    
         
            -
                    return
         
     | 
| 
       3061 
3036 
     | 
    
         | 
| 
       3062 
3037 
     | 
    
         
             
                @pyqtSlot(bool)
         
     | 
| 
       3063 
3038 
     | 
    
         
             
                def _focusModeChanged(self, focusMode: bool) -> None:
         
     | 
| 
       3064 
3039 
     | 
    
         
             
                    """Update minimise/maximise icon of the Focus Mode button."""
         
     | 
| 
       3065 
     | 
    
         
            -
                    self.minmaxButton.setThemeIcon("minimise" if focusMode else "maximise", " 
     | 
| 
       3066 
     | 
    
         
            -
                    return
         
     | 
| 
      
 3040 
     | 
    
         
            +
                    self.minmaxButton.setThemeIcon("minimise" if focusMode else "maximise", "action")
         
     | 
| 
       3067 
3041 
     | 
    
         | 
| 
       3068 
3042 
     | 
    
         
             
                ##
         
     | 
| 
       3069 
3043 
     | 
    
         
             
                #  Events
         
     | 
| 
         @@ -3075,11 +3049,10 @@ class GuiDocEditHeader(QWidget): 
     | 
|
| 
       3075 
3049 
     | 
    
         
             
                    """
         
     | 
| 
       3076 
3050 
     | 
    
         
             
                    if event.button() == QtMouseLeft:
         
     | 
| 
       3077 
3051 
     | 
    
         
             
                        self.docEditor.requestProjectItemSelected.emit(self._docHandle or "", True)
         
     | 
| 
       3078 
     | 
    
         
            -
                    return
         
     | 
| 
       3079 
3052 
     | 
    
         | 
| 
       3080 
3053 
     | 
    
         | 
| 
       3081 
3054 
     | 
    
         
             
            class GuiDocEditFooter(QWidget):
         
     | 
| 
       3082 
     | 
    
         
            -
                """The Embedded Document Footer
         
     | 
| 
      
 3055 
     | 
    
         
            +
                """The Embedded Document Footer.
         
     | 
| 
       3083 
3056 
     | 
    
         | 
| 
       3084 
3057 
     | 
    
         
             
                Only used by DocEditor, and is at a fixed position in the
         
     | 
| 
       3085 
3058 
     | 
    
         
             
                QTextEdit's viewport.
         
     | 
| 
         @@ -3164,8 +3137,6 @@ class GuiDocEditFooter(QWidget): 
     | 
|
| 
       3164 
3137 
     | 
    
         | 
| 
       3165 
3138 
     | 
    
         
             
                    logger.debug("Ready: GuiDocEditFooter")
         
     | 
| 
       3166 
3139 
     | 
    
         | 
| 
       3167 
     | 
    
         
            -
                    return
         
     | 
| 
       3168 
     | 
    
         
            -
             
     | 
| 
       3169 
3140 
     | 
    
         
             
                ##
         
     | 
| 
       3170 
3141 
     | 
    
         
             
                #  Methods
         
     | 
| 
       3171 
3142 
     | 
    
         
             
                ##
         
     | 
| 
         @@ -3175,7 +3146,6 @@ class GuiDocEditFooter(QWidget): 
     | 
|
| 
       3175 
3146 
     | 
    
         
             
                    self._trMainCount = trStats(nwLabels.STATS_DISPLAY[
         
     | 
| 
       3176 
3147 
     | 
    
         
             
                        nwStats.CHARS if CONFIG.useCharCount else nwStats.WORDS
         
     | 
| 
       3177 
3148 
     | 
    
         
             
                    ])
         
     | 
| 
       3178 
     | 
    
         
            -
                    return
         
     | 
| 
       3179 
3149 
     | 
    
         | 
| 
       3180 
3150 
     | 
    
         
             
                def updateFont(self) -> None:
         
     | 
| 
       3181 
3151 
     | 
    
         
             
                    """Update the font settings."""
         
     | 
| 
         @@ -3183,15 +3153,15 @@ class GuiDocEditFooter(QWidget): 
     | 
|
| 
       3183 
3153 
     | 
    
         
             
                    self.statusText.setFont(SHARED.theme.guiFontSmall)
         
     | 
| 
       3184 
3154 
     | 
    
         
             
                    self.linesText.setFont(SHARED.theme.guiFontSmall)
         
     | 
| 
       3185 
3155 
     | 
    
         
             
                    self.wordsText.setFont(SHARED.theme.guiFontSmall)
         
     | 
| 
       3186 
     | 
    
         
            -
                    return
         
     | 
| 
       3187 
3156 
     | 
    
         | 
| 
       3188 
3157 
     | 
    
         
             
                def updateTheme(self) -> None:
         
     | 
| 
       3189 
3158 
     | 
    
         
             
                    """Update theme elements."""
         
     | 
| 
      
 3159 
     | 
    
         
            +
                    logger.debug("Theme Update: GuiDocEditFooter")
         
     | 
| 
      
 3160 
     | 
    
         
            +
             
     | 
| 
       3190 
3161 
     | 
    
         
             
                    iPx = round(0.9*SHARED.theme.baseIconHeight)
         
     | 
| 
       3191 
3162 
     | 
    
         
             
                    self.linesIcon.setPixmap(SHARED.theme.getPixmap("lines", (iPx, iPx)))
         
     | 
| 
       3192 
3163 
     | 
    
         
             
                    self.wordsIcon.setPixmap(SHARED.theme.getPixmap("stats", (iPx, iPx)))
         
     | 
| 
       3193 
3164 
     | 
    
         
             
                    self.matchColors()
         
     | 
| 
       3194 
     | 
    
         
            -
                    return
         
     | 
| 
       3195 
3165 
     | 
    
         | 
| 
       3196 
3166 
     | 
    
         
             
                def matchColors(self) -> None:
         
     | 
| 
       3197 
3167 
     | 
    
         
             
                    """Update the colours of the widget to match those of the syntax
         
     | 
| 
         @@ -3209,8 +3179,6 @@ class GuiDocEditFooter(QWidget): 
     | 
|
| 
       3209 
3179 
     | 
    
         
             
                    self.linesText.setPalette(palette)
         
     | 
| 
       3210 
3180 
     | 
    
         
             
                    self.wordsText.setPalette(palette)
         
     | 
| 
       3211 
3181 
     | 
    
         | 
| 
       3212 
     | 
    
         
            -
                    return
         
     | 
| 
       3213 
     | 
    
         
            -
             
     | 
| 
       3214 
3182 
     | 
    
         
             
                def setHandle(self, tHandle: str | None) -> None:
         
     | 
| 
       3215 
3183 
     | 
    
         
             
                    """Set the handle that will populate the footer's data."""
         
     | 
| 
       3216 
3184 
     | 
    
         
             
                    self._docHandle = tHandle
         
     | 
| 
         @@ -3223,8 +3191,6 @@ class GuiDocEditFooter(QWidget): 
     | 
|
| 
       3223 
3191 
     | 
    
         
             
                    self.updateInfo()
         
     | 
| 
       3224 
3192 
     | 
    
         
             
                    self.updateMainCount(0, False)
         
     | 
| 
       3225 
3193 
     | 
    
         | 
| 
       3226 
     | 
    
         
            -
                    return
         
     | 
| 
       3227 
     | 
    
         
            -
             
     | 
| 
       3228 
3194 
     | 
    
         
             
                def updateInfo(self) -> None:
         
     | 
| 
       3229 
3195 
     | 
    
         
             
                    """Update the content of text labels."""
         
     | 
| 
       3230 
3196 
     | 
    
         
             
                    if self._tItem is None:
         
     | 
| 
         @@ -3239,8 +3205,6 @@ class GuiDocEditFooter(QWidget): 
     | 
|
| 
       3239 
3205 
     | 
    
         
             
                    self.statusIcon.setPixmap(sIcon)
         
     | 
| 
       3240 
3206 
     | 
    
         
             
                    self.statusText.setText(sText)
         
     | 
| 
       3241 
3207 
     | 
    
         | 
| 
       3242 
     | 
    
         
            -
                    return
         
     | 
| 
       3243 
     | 
    
         
            -
             
     | 
| 
       3244 
3208 
     | 
    
         
             
                def updateLineCount(self, cursor: QTextCursor) -> None:
         
     | 
| 
       3245 
3209 
     | 
    
         
             
                    """Update the line and document position counter."""
         
     | 
| 
       3246 
3210 
     | 
    
         
             
                    if document := cursor.document():
         
     | 
| 
         @@ -3250,7 +3214,6 @@ class GuiDocEditFooter(QWidget): 
     | 
|
| 
       3250 
3214 
     | 
    
         
             
                        self.linesText.setText(
         
     | 
| 
       3251 
3215 
     | 
    
         
             
                            self._trLineCount.format(f"{cLine:n}", f"{100*cPos//cCount:d} %")
         
     | 
| 
       3252 
3216 
     | 
    
         
             
                        )
         
     | 
| 
       3253 
     | 
    
         
            -
                    return
         
     | 
| 
       3254 
3217 
     | 
    
         | 
| 
       3255 
3218 
     | 
    
         
             
                def updateMainCount(self, count: int, selection: bool) -> None:
         
     | 
| 
       3256 
3219 
     | 
    
         
             
                    """Update main counter information."""
         
     | 
| 
         @@ -3263,4 +3226,3 @@ class GuiDocEditFooter(QWidget): 
     | 
|
| 
       3263 
3226 
     | 
    
         
             
                    else:
         
     | 
| 
       3264 
3227 
     | 
    
         
             
                        text = self._trMainCount.format("0", "+0")
         
     | 
| 
       3265 
3228 
     | 
    
         
             
                    self.wordsText.setText(text)
         
     | 
| 
       3266 
     | 
    
         
            -
                    return
         
     |