novelWriter 2.7.5__py3-none-any.whl → 2.8b1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +160 -225
 - 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 +23 -13
 - {novelwriter-2.7.5.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.5.dist-info/RECORD +0 -163
 - {novelwriter-2.7.5.dist-info → novelwriter-2.8b1.dist-info}/WHEEL +0 -0
 - {novelwriter-2.7.5.dist-info → novelwriter-2.8b1.dist-info}/entry_points.txt +0 -0
 - {novelwriter-2.7.5.dist-info → novelwriter-2.8b1.dist-info}/licenses/LICENSE.md +0 -0
 - {novelwriter-2.7.5.dist-info → novelwriter-2.8b1.dist-info}/licenses/setup/LICENSE-Apache-2.0.txt +0 -0
 - {novelwriter-2.7.5.dist-info → novelwriter-2.8b1.dist-info}/top_level.txt +0 -0
 
    
        novelwriter/config.py
    CHANGED
    
    | 
         @@ -22,7 +22,7 @@ General Public License for more details. 
     | 
|
| 
       22 
22 
     | 
    
         | 
| 
       23 
23 
     | 
    
         
             
            You should have received a copy of the GNU General Public License
         
     | 
| 
       24 
24 
     | 
    
         
             
            along with this program. If not, see <https://www.gnu.org/licenses/>.
         
     | 
| 
       25 
     | 
    
         
            -
            """
         
     | 
| 
      
 25 
     | 
    
         
            +
            """  # noqa
         
     | 
| 
       26 
26 
     | 
    
         
             
            from __future__ import annotations
         
     | 
| 
       27 
27 
     | 
    
         | 
| 
       28 
28 
     | 
    
         
             
            import json
         
     | 
| 
         @@ -45,6 +45,7 @@ from novelwriter.common import ( 
     | 
|
| 
       45 
45 
     | 
    
         
             
                formatTimeStamp, processDialogSymbols, simplified
         
     | 
| 
       46 
46 
     | 
    
         
             
            )
         
     | 
| 
       47 
47 
     | 
    
         
             
            from novelwriter.constants import nwFiles, nwQuotes, nwUnicode
         
     | 
| 
      
 48 
     | 
    
         
            +
            from novelwriter.enum import nwTheme
         
     | 
| 
       48 
49 
     | 
    
         
             
            from novelwriter.error import formatException, logException
         
     | 
| 
       49 
50 
     | 
    
         | 
| 
       50 
51 
     | 
    
         
             
            if TYPE_CHECKING:
         
     | 
| 
         @@ -55,13 +56,20 @@ if TYPE_CHECKING: 
     | 
|
| 
       55 
56 
     | 
    
         | 
| 
       56 
57 
     | 
    
         
             
            logger = logging.getLogger(__name__)
         
     | 
| 
       57 
58 
     | 
    
         | 
| 
       58 
     | 
    
         
            -
             
     | 
| 
       59 
     | 
    
         
            -
             
     | 
| 
      
 59 
     | 
    
         
            +
            DEF_GUI_DARK = "default_dark"
         
     | 
| 
      
 60 
     | 
    
         
            +
            DEF_GUI_LIGHT = "default_light"
         
     | 
| 
       60 
61 
     | 
    
         
             
            DEF_ICONS = "material_rounded_normal"
         
     | 
| 
       61 
62 
     | 
    
         
             
            DEF_TREECOL = "theme"
         
     | 
| 
       62 
63 
     | 
    
         | 
| 
       63 
64 
     | 
    
         | 
| 
       64 
65 
     | 
    
         
             
            class Config:
         
     | 
| 
      
 66 
     | 
    
         
            +
                """User Config.
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                The main user config. The state of the config is stored in the
         
     | 
| 
      
 69 
     | 
    
         
            +
                novelwriter.conf file between sessions. Most of the settings can be
         
     | 
| 
      
 70 
     | 
    
         
            +
                modified by the user in the Preferences dialog, but some just record
         
     | 
| 
      
 71 
     | 
    
         
            +
                various states of the GUI.
         
     | 
| 
      
 72 
     | 
    
         
            +
                """
         
     | 
| 
       65 
73 
     | 
    
         | 
| 
       66 
74 
     | 
    
         
             
                __slots__ = (
         
     | 
| 
       67 
75 
     | 
    
         
             
                    "_appPath", "_appRoot", "_backPath", "_backupPath", "_confPath", "_dLocale", "_dShortDate",
         
     | 
| 
         @@ -69,22 +77,23 @@ class Config: 
     | 
|
| 
       69 
77 
     | 
    
         
             
                    "_manuals", "_nwLangPath", "_qLocale", "_qtLangPath", "_qtTrans", "_recentPaths",
         
     | 
| 
       70 
78 
     | 
    
         
             
                    "_recentProjects", "_splash", "allowOpenDial", "altDialogClose", "altDialogOpen",
         
     | 
| 
       71 
79 
     | 
    
         
             
                    "appHandle", "appName", "askBeforeBackup", "askBeforeExit", "autoSaveDoc", "autoSaveProj",
         
     | 
| 
       72 
     | 
    
         
            -
                    "autoScroll", "autoScrollPos", "autoSelect", "backupOnClose", "cursorWidth", " 
     | 
| 
       73 
     | 
    
         
            -
                    "dialogStyle", "doJustify", "doReplace", "doReplaceDQuote", "doReplaceDash",
         
     | 
| 
      
 80 
     | 
    
         
            +
                    "autoScroll", "autoScrollPos", "autoSelect", "backupOnClose", "cursorWidth", "darkTheme",
         
     | 
| 
      
 81 
     | 
    
         
            +
                    "dialogLine", "dialogStyle", "doJustify", "doReplace", "doReplaceDQuote", "doReplaceDash",
         
     | 
| 
       74 
82 
     | 
    
         
             
                    "doReplaceDots", "doReplaceSQuote", "emphLabels", "fmtApostrophe", "fmtDQuoteClose",
         
     | 
| 
       75 
83 
     | 
    
         
             
                    "fmtDQuoteOpen", "fmtPadAfter", "fmtPadBefore", "fmtPadThin", "fmtSQuoteClose",
         
     | 
| 
       76 
     | 
    
         
            -
                    "fmtSQuoteOpen", "focusWidth", "guiFont", "guiLocale", " 
     | 
| 
       77 
     | 
    
         
            -
                    " 
     | 
| 
       78 
     | 
    
         
            -
                    " 
     | 
| 
       79 
     | 
    
         
            -
                    " 
     | 
| 
       80 
     | 
    
         
            -
                    "nativeFont", "osDarwin", "osLinux", "osType", "osUnknown", "osWindows", 
     | 
| 
       81 
     | 
    
         
            -
                    "prefsWinSize", "scrollPastEnd", "searchCase", "searchLoop", 
     | 
| 
       82 
     | 
    
         
            -
                    "searchNextFile", "searchProjCase", "searchProjRegEx", "searchProjWord", 
     | 
| 
       83 
     | 
    
         
            -
                    "searchWord", "showEditToolBar", "showFullPath", "showLineEndings", 
     | 
| 
       84 
     | 
    
         
            -
                    " 
     | 
| 
       85 
     | 
    
         
            -
                    " 
     | 
| 
       86 
     | 
    
         
            -
                    " 
     | 
| 
       87 
     | 
    
         
            -
                    " 
     | 
| 
      
 84 
     | 
    
         
            +
                    "fmtSQuoteOpen", "focusWidth", "guiFont", "guiLocale", "hasEnchant", "hideFocusFooter",
         
     | 
| 
      
 85 
     | 
    
         
            +
                    "hideHScroll", "hideVScroll", "highlightEmph", "hostName", "iconColDocs", "iconColTree",
         
     | 
| 
      
 86 
     | 
    
         
            +
                    "iconTheme", "incNotesWCount", "isDebug", "kernelVer", "lastNotes", "lightTheme",
         
     | 
| 
      
 87 
     | 
    
         
            +
                    "lineHighlight", "mainPanePos", "mainWinSize", "memInfo", "narratorBreak",
         
     | 
| 
      
 88 
     | 
    
         
            +
                    "narratorDialog", "nativeFont", "osDarwin", "osLinux", "osType", "osUnknown", "osWindows",
         
     | 
| 
      
 89 
     | 
    
         
            +
                    "outlinePanePos", "prefsWinSize", "scrollPastEnd", "searchCase", "searchLoop",
         
     | 
| 
      
 90 
     | 
    
         
            +
                    "searchMatchCap", "searchNextFile", "searchProjCase", "searchProjRegEx", "searchProjWord",
         
     | 
| 
      
 91 
     | 
    
         
            +
                    "searchRegEx", "searchWord", "showEditToolBar", "showFullPath", "showLineEndings",
         
     | 
| 
      
 92 
     | 
    
         
            +
                    "showMultiSpaces", "showSessionTime", "showTabsNSpaces", "showViewerPanel",
         
     | 
| 
      
 93 
     | 
    
         
            +
                    "spellLanguage", "stopWhenIdle", "tabWidth", "textFont", "textMargin", "textWidth",
         
     | 
| 
      
 94 
     | 
    
         
            +
                    "themeMode", "useCharCount", "userIdleTime", "verPyQtString", "verPyQtValue",
         
     | 
| 
      
 95 
     | 
    
         
            +
                    "verPyString", "verQtString", "verQtValue", "viewComments", "viewNotes", "viewPanePos",
         
     | 
| 
      
 96 
     | 
    
         
            +
                    "viewSynopsis", "welcomeWinSize",
         
     | 
| 
       88 
97 
     | 
    
         
             
                )
         
     | 
| 
       89 
98 
     | 
    
         | 
| 
       90 
99 
     | 
    
         
             
                LANG_NW   = 1
         
     | 
| 
         @@ -153,14 +162,15 @@ class Config: 
     | 
|
| 
       153 
162 
     | 
    
         | 
| 
       154 
163 
     | 
    
         
             
                    # General GUI Settings
         
     | 
| 
       155 
164 
     | 
    
         
             
                    self.guiLocale    = self._qLocale.name()
         
     | 
| 
       156 
     | 
    
         
            -
                    self. 
     | 
| 
       157 
     | 
    
         
            -
                    self. 
     | 
| 
       158 
     | 
    
         
            -
                    self. 
     | 
| 
       159 
     | 
    
         
            -
                    self. 
     | 
| 
       160 
     | 
    
         
            -
                    self. 
     | 
| 
       161 
     | 
    
         
            -
                    self. 
     | 
| 
       162 
     | 
    
         
            -
                    self. 
     | 
| 
       163 
     | 
    
         
            -
                    self. 
     | 
| 
      
 165 
     | 
    
         
            +
                    self.lightTheme   = DEF_GUI_LIGHT  # Light GUI theme
         
     | 
| 
      
 166 
     | 
    
         
            +
                    self.darkTheme    = DEF_GUI_DARK   # Dark GUI theme
         
     | 
| 
      
 167 
     | 
    
         
            +
                    self.themeMode    = nwTheme.AUTO   # Colour theme mode
         
     | 
| 
      
 168 
     | 
    
         
            +
                    self.guiFont      = QFont()        # Main GUI font
         
     | 
| 
      
 169 
     | 
    
         
            +
                    self.hideVScroll  = False          # Hide vertical scroll bars on main widgets
         
     | 
| 
      
 170 
     | 
    
         
            +
                    self.hideHScroll  = False          # Hide horizontal scroll bars on main widgets
         
     | 
| 
      
 171 
     | 
    
         
            +
                    self.lastNotes    = "0x0"          # The latest release notes that have been shown
         
     | 
| 
      
 172 
     | 
    
         
            +
                    self.nativeFont   = True           # Use native font dialog
         
     | 
| 
      
 173 
     | 
    
         
            +
                    self.useCharCount = False          # Use character count as primary count
         
     | 
| 
       164 
174 
     | 
    
         | 
| 
       165 
175 
     | 
    
         
             
                    # Icons
         
     | 
| 
       166 
176 
     | 
    
         
             
                    self.iconTheme   = DEF_ICONS    # Icons theme
         
     | 
| 
         @@ -178,8 +188,8 @@ class Config: 
     | 
|
| 
       178 
188 
     | 
    
         
             
                    # Project Settings
         
     | 
| 
       179 
189 
     | 
    
         
             
                    self.autoSaveProj    = 60     # Interval for auto-saving project, in seconds
         
     | 
| 
       180 
190 
     | 
    
         
             
                    self.autoSaveDoc     = 30     # Interval for auto-saving document, in seconds
         
     | 
| 
       181 
     | 
    
         
            -
                    self.emphLabels      =  
     | 
| 
       182 
     | 
    
         
            -
                    self.backupOnClose   =  
     | 
| 
      
 191 
     | 
    
         
            +
                    self.emphLabels      = False  # Add emphasis to H1 and H2 item labels
         
     | 
| 
      
 192 
     | 
    
         
            +
                    self.backupOnClose   = True   # Flag for running automatic backups
         
     | 
| 
       183 
193 
     | 
    
         
             
                    self.askBeforeBackup = True   # Flag for asking before running automatic backup
         
     | 
| 
       184 
194 
     | 
    
         
             
                    self.askBeforeExit   = True   # Flag for asking before exiting the app
         
     | 
| 
       185 
195 
     | 
    
         | 
| 
         @@ -189,6 +199,7 @@ class Config: 
     | 
|
| 
       189 
199 
     | 
    
         
             
                    self.textMargin      = 40       # Editor/viewer text margin
         
     | 
| 
       190 
200 
     | 
    
         
             
                    self.tabWidth        = 40       # Editor tabulator width
         
     | 
| 
       191 
201 
     | 
    
         
             
                    self.cursorWidth     = 1        # Editor cursor width
         
     | 
| 
      
 202 
     | 
    
         
            +
                    self.lineHighlight   = False    # Highlight current line in editor
         
     | 
| 
       192 
203 
     | 
    
         | 
| 
       193 
204 
     | 
    
         
             
                    self.focusWidth      = 800      # Focus Mode text width
         
     | 
| 
       194 
205 
     | 
    
         
             
                    self.hideFocusFooter = False    # Hide document footer in Focus Mode
         
     | 
| 
         @@ -198,7 +209,7 @@ class Config: 
     | 
|
| 
       198 
209 
     | 
    
         
             
                    self.doJustify       = False    # Justify text
         
     | 
| 
       199 
210 
     | 
    
         
             
                    self.showTabsNSpaces = False    # Show tabs and spaces in editor
         
     | 
| 
       200 
211 
     | 
    
         
             
                    self.showLineEndings = False    # Show line endings in editor
         
     | 
| 
       201 
     | 
    
         
            -
                    self.showMultiSpaces =  
     | 
| 
      
 212 
     | 
    
         
            +
                    self.showMultiSpaces = False    # Highlight multiple spaces in the text
         
     | 
| 
       202 
213 
     | 
    
         | 
| 
       203 
214 
     | 
    
         
             
                    self.doReplace       = True     # Enable auto-replace as you type
         
     | 
| 
       204 
215 
     | 
    
         
             
                    self.doReplaceSQuote = True     # Smart single quotes
         
     | 
| 
         @@ -206,7 +217,7 @@ class Config: 
     | 
|
| 
       206 
217 
     | 
    
         
             
                    self.doReplaceDash   = True     # Replace multiple hyphens with dashes
         
     | 
| 
       207 
218 
     | 
    
         
             
                    self.doReplaceDots   = True     # Replace three dots with ellipsis
         
     | 
| 
       208 
219 
     | 
    
         | 
| 
       209 
     | 
    
         
            -
                    self.autoScroll      =  
     | 
| 
      
 220 
     | 
    
         
            +
                    self.autoScroll      = True     # Typewriter-like scrolling
         
     | 
| 
       210 
221 
     | 
    
         
             
                    self.autoScrollPos   = 30       # Start point for typewriter-like scrolling
         
     | 
| 
       211 
222 
     | 
    
         
             
                    self.scrollPastEnd   = True     # Scroll past end of document, and centre cursor
         
     | 
| 
       212 
223 
     | 
    
         | 
| 
         @@ -245,6 +256,7 @@ class Config: 
     | 
|
| 
       245 
256 
     | 
    
         
             
                    self.showSessionTime = True   # Show the session time in the status bar
         
     | 
| 
       246 
257 
     | 
    
         
             
                    self.viewComments    = True   # Comments are shown in the viewer
         
     | 
| 
       247 
258 
     | 
    
         
             
                    self.viewSynopsis    = True   # Synopsis is shown in the viewer
         
     | 
| 
      
 259 
     | 
    
         
            +
                    self.viewNotes       = True   # Notes are shown in the viewer
         
     | 
| 
       248 
260 
     | 
    
         | 
| 
       249 
261 
     | 
    
         
             
                    # Search Box States
         
     | 
| 
       250 
262 
     | 
    
         
             
                    self.searchCase      = False
         
     | 
| 
         @@ -295,8 +307,6 @@ class Config: 
     | 
|
| 
       295 
307 
     | 
    
         
             
                    # Packages
         
     | 
| 
       296 
308 
     | 
    
         
             
                    self.hasEnchant = False  # The pyenchant package
         
     | 
| 
       297 
309 
     | 
    
         | 
| 
       298 
     | 
    
         
            -
                    return
         
     | 
| 
       299 
     | 
    
         
            -
             
     | 
| 
       300 
310 
     | 
    
         
             
                ##
         
     | 
| 
       301 
311 
     | 
    
         
             
                #  Properties
         
     | 
| 
       302 
312 
     | 
    
         
             
                ##
         
     | 
| 
         @@ -345,7 +355,6 @@ class Config: 
     | 
|
| 
       345 
355 
     | 
    
         
             
                def setLastAuthor(self, value: str) -> None:
         
     | 
| 
       346 
356 
     | 
    
         
             
                    """Set tle last used author name."""
         
     | 
| 
       347 
357 
     | 
    
         
             
                    self._lastAuthor = simplified(value)
         
     | 
| 
       348 
     | 
    
         
            -
                    return
         
     | 
| 
       349 
358 
     | 
    
         | 
| 
       350 
359 
     | 
    
         
             
                def setMainWinSize(self, width: int, height: int) -> None:
         
     | 
| 
       351 
360 
     | 
    
         
             
                    """Set the size of the main window, but only if the change is
         
     | 
| 
         @@ -357,17 +366,14 @@ class Config: 
     | 
|
| 
       357 
366 
     | 
    
         
             
                        self.mainWinSize[0] = width
         
     | 
| 
       358 
367 
     | 
    
         
             
                    if abs(self.mainWinSize[1] - height) > 5:
         
     | 
| 
       359 
368 
     | 
    
         
             
                        self.mainWinSize[1] = height
         
     | 
| 
       360 
     | 
    
         
            -
                    return
         
     | 
| 
       361 
369 
     | 
    
         | 
| 
       362 
370 
     | 
    
         
             
                def setWelcomeWinSize(self, width: int, height: int) -> None:
         
     | 
| 
       363 
371 
     | 
    
         
             
                    """Set the size of the Preferences dialog window."""
         
     | 
| 
       364 
372 
     | 
    
         
             
                    self.welcomeWinSize = [width, height]
         
     | 
| 
       365 
     | 
    
         
            -
                    return
         
     | 
| 
       366 
373 
     | 
    
         | 
| 
       367 
374 
     | 
    
         
             
                def setPreferencesWinSize(self, width: int, height: int) -> None:
         
     | 
| 
       368 
375 
     | 
    
         
             
                    """Set the size of the Preferences dialog window."""
         
     | 
| 
       369 
376 
     | 
    
         
             
                    self.prefsWinSize = [width, height]
         
     | 
| 
       370 
     | 
    
         
            -
                    return
         
     | 
| 
       371 
377 
     | 
    
         | 
| 
       372 
378 
     | 
    
         
             
                def setLastPath(self, key: str, path: str | Path) -> None:
         
     | 
| 
       373 
379 
     | 
    
         
             
                    """Set the last used path. Only the folder is saved, so if the
         
     | 
| 
         @@ -379,12 +385,10 @@ class Config: 
     | 
|
| 
       379 
385 
     | 
    
         
             
                            path = path.parent
         
     | 
| 
       380 
386 
     | 
    
         
             
                        if path.is_dir():
         
     | 
| 
       381 
387 
     | 
    
         
             
                            self._recentPaths.setPath(key, path)
         
     | 
| 
       382 
     | 
    
         
            -
                    return
         
     | 
| 
       383 
388 
     | 
    
         | 
| 
       384 
389 
     | 
    
         
             
                def setBackupPath(self, path: Path | str) -> None:
         
     | 
| 
       385 
390 
     | 
    
         
             
                    """Set the current backup path."""
         
     | 
| 
       386 
391 
     | 
    
         
             
                    self._backupPath = checkPath(path, self._backPath)
         
     | 
| 
       387 
     | 
    
         
            -
                    return
         
     | 
| 
       388 
392 
     | 
    
         | 
| 
       389 
393 
     | 
    
         
             
                def setGuiFont(self, value: QFont | str | None) -> None:
         
     | 
| 
       390 
394 
     | 
    
         
             
                    """Update the GUI's font style from settings."""
         
     | 
| 
         @@ -403,9 +407,8 @@ class Config: 
     | 
|
| 
       403 
407 
     | 
    
         
             
                        else:
         
     | 
| 
       404 
408 
     | 
    
         
             
                            font = QFontDatabase.systemFont(QFontDatabase.SystemFont.GeneralFont)
         
     | 
| 
       405 
409 
     | 
    
         
             
                        self.guiFont = fontMatcher(font)
         
     | 
| 
       406 
     | 
    
         
            -
                        logger.debug(" 
     | 
| 
      
 410 
     | 
    
         
            +
                        logger.debug("Main font set to: %s", describeFont(font))
         
     | 
| 
       407 
411 
     | 
    
         
             
                    QApplication.setFont(self.guiFont)
         
     | 
| 
       408 
     | 
    
         
            -
                    return
         
     | 
| 
       409 
412 
     | 
    
         | 
| 
       410 
413 
     | 
    
         
             
                def setTextFont(self, value: QFont | str | None) -> None:
         
     | 
| 
       411 
414 
     | 
    
         
             
                    """Set the text font if it exists. If it doesn't, or is None,
         
     | 
| 
         @@ -431,14 +434,13 @@ class Config: 
     | 
|
| 
       431 
434 
     | 
    
         
             
                            font = QFontDatabase.systemFont(QFontDatabase.SystemFont.GeneralFont)
         
     | 
| 
       432 
435 
     | 
    
         
             
                        self.textFont = fontMatcher(font)
         
     | 
| 
       433 
436 
     | 
    
         
             
                        logger.debug("Text font set to: %s", describeFont(self.textFont))
         
     | 
| 
       434 
     | 
    
         
            -
                    return
         
     | 
| 
       435 
437 
     | 
    
         | 
| 
       436 
438 
     | 
    
         
             
                ##
         
     | 
| 
       437 
439 
     | 
    
         
             
                #  Methods
         
     | 
| 
       438 
440 
     | 
    
         
             
                ##
         
     | 
| 
       439 
441 
     | 
    
         | 
| 
       440 
442 
     | 
    
         
             
                def homePath(self) -> Path:
         
     | 
| 
       441 
     | 
    
         
            -
                    """ 
     | 
| 
      
 443 
     | 
    
         
            +
                    """Return the user's home folder."""
         
     | 
| 
       442 
444 
     | 
    
         
             
                    return self._homePath
         
     | 
| 
       443 
445 
     | 
    
         | 
| 
       444 
446 
     | 
    
         
             
                def dataPath(self, target: str | None = None) -> Path:
         
     | 
| 
         @@ -520,7 +522,6 @@ class Config: 
     | 
|
| 
       520 
522 
     | 
    
         
             
                    """Send a message to the splash screen."""
         
     | 
| 
       521 
523 
     | 
    
         
             
                    if self._splash:
         
     | 
| 
       522 
524 
     | 
    
         
             
                        self._splash.showStatus(message)
         
     | 
| 
       523 
     | 
    
         
            -
                    return
         
     | 
| 
       524 
525 
     | 
    
         | 
| 
       525 
526 
     | 
    
         
             
                ##
         
     | 
| 
       526 
527 
     | 
    
         
             
                #  Config Actions
         
     | 
| 
         @@ -551,11 +552,10 @@ class Config: 
     | 
|
| 
       551 
552 
     | 
    
         
             
                    self._confPath.mkdir(exist_ok=True)
         
     | 
| 
       552 
553 
     | 
    
         
             
                    self._dataPath.mkdir(exist_ok=True)
         
     | 
| 
       553 
554 
     | 
    
         | 
| 
       554 
     | 
    
         
            -
                    # Also create the  
     | 
| 
      
 555 
     | 
    
         
            +
                    # Also create the themes and icons folders if possible
         
     | 
| 
       555 
556 
     | 
    
         
             
                    if self._dataPath.is_dir():
         
     | 
| 
       556 
557 
     | 
    
         
             
                        (self._dataPath / "cache").mkdir(exist_ok=True)
         
     | 
| 
       557 
558 
     | 
    
         
             
                        (self._dataPath / "icons").mkdir(exist_ok=True)
         
     | 
| 
       558 
     | 
    
         
            -
                        (self._dataPath / "syntax").mkdir(exist_ok=True)
         
     | 
| 
       559 
559 
     | 
    
         
             
                        (self._dataPath / "themes").mkdir(exist_ok=True)
         
     | 
| 
       560 
560 
     | 
    
         | 
| 
       561 
561 
     | 
    
         
             
                    self._recentPaths.loadCache()
         
     | 
| 
         @@ -564,8 +564,6 @@ class Config: 
     | 
|
| 
       564 
564 
     | 
    
         | 
| 
       565 
565 
     | 
    
         
             
                    logger.debug("Config instance initialised")
         
     | 
| 
       566 
566 
     | 
    
         | 
| 
       567 
     | 
    
         
            -
                    return
         
     | 
| 
       568 
     | 
    
         
            -
             
     | 
| 
       569 
567 
     | 
    
         
             
                def initLocalisation(self, nwApp: QApplication) -> None:
         
     | 
| 
       570 
568 
     | 
    
         
             
                    """Initialise the localisation of the GUI."""
         
     | 
| 
       571 
569 
     | 
    
         
             
                    self.splashMessage("Loading localisation ...")
         
     | 
| 
         @@ -593,8 +591,6 @@ class Config: 
     | 
|
| 
       593 
591 
     | 
    
         
             
                                    nwApp.installTranslator(qTrans)
         
     | 
| 
       594 
592 
     | 
    
         
             
                                    self._qtTrans[lngFile] = qTrans
         
     | 
| 
       595 
593 
     | 
    
         | 
| 
       596 
     | 
    
         
            -
                    return
         
     | 
| 
       597 
     | 
    
         
            -
             
     | 
| 
       598 
594 
     | 
    
         
             
                def loadConfig(self, splash: NSplashScreen | None = None) -> bool:
         
     | 
| 
       599 
595 
     | 
    
         
             
                    """Load preferences from file and replace default settings."""
         
     | 
| 
       600 
596 
     | 
    
         
             
                    self._splash = splash
         
     | 
| 
         @@ -626,8 +622,9 @@ class Config: 
     | 
|
| 
       626 
622 
     | 
    
         
             
                    # Main
         
     | 
| 
       627 
623 
     | 
    
         
             
                    sec = "Main"
         
     | 
| 
       628 
624 
     | 
    
         
             
                    self.setGuiFont(conf.rdStr(sec, "font", ""))
         
     | 
| 
       629 
     | 
    
         
            -
                    self. 
     | 
| 
       630 
     | 
    
         
            -
                    self. 
     | 
| 
      
 625 
     | 
    
         
            +
                    self.lightTheme   = conf.rdStr(sec, "lighttheme", self.lightTheme)
         
     | 
| 
      
 626 
     | 
    
         
            +
                    self.darkTheme    = conf.rdStr(sec, "darktheme", self.darkTheme)
         
     | 
| 
      
 627 
     | 
    
         
            +
                    self.themeMode    = conf.rdEnum(sec, "thememode", self.themeMode)
         
     | 
| 
       631 
628 
     | 
    
         
             
                    self.iconTheme    = conf.rdStr(sec, "icons", self.iconTheme)
         
     | 
| 
       632 
629 
     | 
    
         
             
                    self.iconColTree  = conf.rdStr(sec, "iconcoltree", self.iconColTree)
         
     | 
| 
       633 
630 
     | 
    
         
             
                    self.iconColDocs  = conf.rdBool(sec, "iconcoldocs", self.iconColDocs)
         
     | 
| 
         @@ -665,6 +662,7 @@ class Config: 
     | 
|
| 
       665 
662 
     | 
    
         
             
                    self.textMargin      = conf.rdInt(sec, "margin", self.textMargin)
         
     | 
| 
       666 
663 
     | 
    
         
             
                    self.tabWidth        = conf.rdInt(sec, "tabwidth", self.tabWidth)
         
     | 
| 
       667 
664 
     | 
    
         
             
                    self.cursorWidth     = conf.rdInt(sec, "cursorwidth", self.cursorWidth)
         
     | 
| 
      
 665 
     | 
    
         
            +
                    self.lineHighlight   = conf.rdBool(sec, "linehighlight", self.lineHighlight)
         
     | 
| 
       668 
666 
     | 
    
         
             
                    self.focusWidth      = conf.rdInt(sec, "focuswidth", self.focusWidth)
         
     | 
| 
       669 
667 
     | 
    
         
             
                    self.hideFocusFooter = conf.rdBool(sec, "hidefocusfooter", self.hideFocusFooter)
         
     | 
| 
       670 
668 
     | 
    
         
             
                    self.doJustify       = conf.rdBool(sec, "justify", self.doJustify)
         
     | 
| 
         @@ -708,6 +706,7 @@ class Config: 
     | 
|
| 
       708 
706 
     | 
    
         
             
                    self.showSessionTime = conf.rdBool(sec, "showsessiontime", self.showSessionTime)
         
     | 
| 
       709 
707 
     | 
    
         
             
                    self.viewComments    = conf.rdBool(sec, "viewcomments", self.viewComments)
         
     | 
| 
       710 
708 
     | 
    
         
             
                    self.viewSynopsis    = conf.rdBool(sec, "viewsynopsis", self.viewSynopsis)
         
     | 
| 
      
 709 
     | 
    
         
            +
                    self.viewNotes       = conf.rdBool(sec, "viewnotes", self.viewNotes)
         
     | 
| 
       711 
710 
     | 
    
         
             
                    self.searchCase      = conf.rdBool(sec, "searchcase", self.searchCase)
         
     | 
| 
       712 
711 
     | 
    
         
             
                    self.searchWord      = conf.rdBool(sec, "searchword", self.searchWord)
         
     | 
| 
       713 
712 
     | 
    
         
             
                    self.searchRegEx     = conf.rdBool(sec, "searchregex", self.searchRegEx)
         
     | 
| 
         @@ -721,7 +720,7 @@ class Config: 
     | 
|
| 
       721 
720 
     | 
    
         
             
                    # Check Values
         
     | 
| 
       722 
721 
     | 
    
         
             
                    # ============
         
     | 
| 
       723 
722 
     | 
    
         | 
| 
       724 
     | 
    
         
            -
                    self._prepareFont(self.guiFont, " 
     | 
| 
      
 723 
     | 
    
         
            +
                    self._prepareFont(self.guiFont, "main")
         
     | 
| 
       725 
724 
     | 
    
         
             
                    self._prepareFont(self.textFont, "document")
         
     | 
| 
       726 
725 
     | 
    
         | 
| 
       727 
726 
     | 
    
         
             
                    # If we're using straight quotes, disable auto-replace
         
     | 
| 
         @@ -751,8 +750,9 @@ class Config: 
     | 
|
| 
       751 
750 
     | 
    
         | 
| 
       752 
751 
     | 
    
         
             
                    conf["Main"] = {
         
     | 
| 
       753 
752 
     | 
    
         
             
                        "font":         self.guiFont.toString(),
         
     | 
| 
       754 
     | 
    
         
            -
                        " 
     | 
| 
       755 
     | 
    
         
            -
                        " 
     | 
| 
      
 753 
     | 
    
         
            +
                        "lighttheme":   str(self.lightTheme),
         
     | 
| 
      
 754 
     | 
    
         
            +
                        "darktheme":    str(self.darkTheme),
         
     | 
| 
      
 755 
     | 
    
         
            +
                        "thememode":    self.themeMode.name,
         
     | 
| 
       756 
756 
     | 
    
         
             
                        "icons":        str(self.iconTheme),
         
     | 
| 
       757 
757 
     | 
    
         
             
                        "iconcoltree":  str(self.iconColTree),
         
     | 
| 
       758 
758 
     | 
    
         
             
                        "iconcoldocs":  str(self.iconColDocs),
         
     | 
| 
         @@ -790,6 +790,7 @@ class Config: 
     | 
|
| 
       790 
790 
     | 
    
         
             
                        "margin":          str(self.textMargin),
         
     | 
| 
       791 
791 
     | 
    
         
             
                        "tabwidth":        str(self.tabWidth),
         
     | 
| 
       792 
792 
     | 
    
         
             
                        "cursorwidth":     str(self.cursorWidth),
         
     | 
| 
      
 793 
     | 
    
         
            +
                        "lineHighlight":   str(self.lineHighlight),
         
     | 
| 
       793 
794 
     | 
    
         
             
                        "focuswidth":      str(self.focusWidth),
         
     | 
| 
       794 
795 
     | 
    
         
             
                        "hidefocusfooter": str(self.hideFocusFooter),
         
     | 
| 
       795 
796 
     | 
    
         
             
                        "justify":         str(self.doJustify),
         
     | 
| 
         @@ -833,6 +834,7 @@ class Config: 
     | 
|
| 
       833 
834 
     | 
    
         
             
                        "showsessiontime": str(self.showSessionTime),
         
     | 
| 
       834 
835 
     | 
    
         
             
                        "viewcomments":    str(self.viewComments),
         
     | 
| 
       835 
836 
     | 
    
         
             
                        "viewsynopsis":    str(self.viewSynopsis),
         
     | 
| 
      
 837 
     | 
    
         
            +
                        "viewnotes":       str(self.viewNotes),
         
     | 
| 
       836 
838 
     | 
    
         
             
                        "searchcase":      str(self.searchCase),
         
     | 
| 
       837 
839 
     | 
    
         
             
                        "searchword":      str(self.searchWord),
         
     | 
| 
       838 
840 
     | 
    
         
             
                        "searchregex":     str(self.searchRegEx),
         
     | 
| 
         @@ -862,7 +864,6 @@ class Config: 
     | 
|
| 
       862 
864 
     | 
    
         
             
                def finishStartup(self) -> None:
         
     | 
| 
       863 
865 
     | 
    
         
             
                    """Call after startup is complete."""
         
     | 
| 
       864 
866 
     | 
    
         
             
                    self._splash = None
         
     | 
| 
       865 
     | 
    
         
            -
                    return
         
     | 
| 
       866 
867 
     | 
    
         | 
| 
       867 
868 
     | 
    
         
             
                ##
         
     | 
| 
       868 
869 
     | 
    
         
             
                #  Internal Functions
         
     | 
| 
         @@ -884,7 +885,6 @@ class Config: 
     | 
|
| 
       884 
885 
     | 
    
         
             
                    else:
         
     | 
| 
       885 
886 
     | 
    
         
             
                        self.hasEnchant = True
         
     | 
| 
       886 
887 
     | 
    
         
             
                        logger.debug("Checking package 'pyenchant': OK")
         
     | 
| 
       887 
     | 
    
         
            -
                    return
         
     | 
| 
       888 
888 
     | 
    
         | 
| 
       889 
889 
     | 
    
         
             
                def _prepareFont(self, font: QFont, kind: str) -> None:
         
     | 
| 
       890 
890 
     | 
    
         
             
                    """Check Unicode availability in font. This also initialises any
         
     | 
| 
         @@ -895,16 +895,15 @@ class Config: 
     | 
|
| 
       895 
895 
     | 
    
         
             
                    for char in nwUnicode.UI_SYMBOLS:
         
     | 
| 
       896 
896 
     | 
    
         
             
                        if not metrics.inFont(char):  # type: ignore
         
     | 
| 
       897 
897 
     | 
    
         
             
                            logger.warning("No glyph U+%04x in font", ord(char))  # pragma: no cover
         
     | 
| 
       898 
     | 
    
         
            -
                    return
         
     | 
| 
       899 
898 
     | 
    
         | 
| 
       900 
899 
     | 
    
         | 
| 
       901 
900 
     | 
    
         
             
            class RecentProjects:
         
     | 
| 
      
 901 
     | 
    
         
            +
                """A record of recently opened projects."""
         
     | 
| 
       902 
902 
     | 
    
         | 
| 
       903 
903 
     | 
    
         
             
                def __init__(self, config: Config) -> None:
         
     | 
| 
       904 
904 
     | 
    
         
             
                    self._conf = config
         
     | 
| 
       905 
905 
     | 
    
         
             
                    self._data: dict[str, dict[str, str | int]] = {}
         
     | 
| 
       906 
906 
     | 
    
         
             
                    self._map: dict[str, str] = {}
         
     | 
| 
       907 
     | 
    
         
            -
                    return
         
     | 
| 
       908 
907 
     | 
    
         | 
| 
       909 
908 
     | 
    
         
             
                def loadCache(self) -> bool:
         
     | 
| 
       910 
909 
     | 
    
         
             
                    """Load the cache file for recent projects."""
         
     | 
| 
         @@ -966,14 +965,12 @@ class RecentProjects: 
     | 
|
| 
       966 
965 
     | 
    
         
             
                        self.saveCache()
         
     | 
| 
       967 
966 
     | 
    
         
             
                    except Exception:
         
     | 
| 
       968 
967 
     | 
    
         
             
                        pass
         
     | 
| 
       969 
     | 
    
         
            -
                    return
         
     | 
| 
       970 
968 
     | 
    
         | 
| 
       971 
969 
     | 
    
         
             
                def remove(self, path: str | Path) -> None:
         
     | 
| 
       972 
970 
     | 
    
         
             
                    """Try to remove a path from the recent projects cache."""
         
     | 
| 
       973 
971 
     | 
    
         
             
                    if self._data.pop(str(path), None) is not None:
         
     | 
| 
       974 
972 
     | 
    
         
             
                        logger.debug("Removed recent: %s", path)
         
     | 
| 
       975 
973 
     | 
    
         
             
                        self.saveCache()
         
     | 
| 
       976 
     | 
    
         
            -
                    return
         
     | 
| 
       977 
974 
     | 
    
         | 
| 
       978 
975 
     | 
    
         
             
                def _setEntry(
         
     | 
| 
       979 
976 
     | 
    
         
             
                    self, puuid: str, path: str, title: str, words: int, chars: int, saved: int
         
     | 
| 
         @@ -988,24 +985,22 @@ class RecentProjects: 
     | 
|
| 
       988 
985 
     | 
    
         
             
                    }
         
     | 
| 
       989 
986 
     | 
    
         
             
                    if puuid:
         
     | 
| 
       990 
987 
     | 
    
         
             
                        self._map[puuid] = path
         
     | 
| 
       991 
     | 
    
         
            -
                    return
         
     | 
| 
       992 
988 
     | 
    
         | 
| 
       993 
989 
     | 
    
         | 
| 
       994 
990 
     | 
    
         
             
            class RecentPaths:
         
     | 
| 
      
 991 
     | 
    
         
            +
                """A record of recently used file paths."""
         
     | 
| 
       995 
992 
     | 
    
         | 
| 
       996 
993 
     | 
    
         
             
                KEYS: Final[list[str]] = ["default", "project", "import", "outline", "stats"]
         
     | 
| 
       997 
994 
     | 
    
         | 
| 
       998 
995 
     | 
    
         
             
                def __init__(self, config: Config) -> None:
         
     | 
| 
       999 
996 
     | 
    
         
             
                    self._conf = config
         
     | 
| 
       1000 
997 
     | 
    
         
             
                    self._data = {}
         
     | 
| 
       1001 
     | 
    
         
            -
                    return
         
     | 
| 
       1002 
998 
     | 
    
         | 
| 
       1003 
999 
     | 
    
         
             
                def setPath(self, key: str, path: Path | str) -> None:
         
     | 
| 
       1004 
1000 
     | 
    
         
             
                    """Set a path for a given key, and save the cache."""
         
     | 
| 
       1005 
1001 
     | 
    
         
             
                    if key in self.KEYS:
         
     | 
| 
       1006 
1002 
     | 
    
         
             
                        self._data[key] = str(path)
         
     | 
| 
       1007 
1003 
     | 
    
         
             
                    self.saveCache()
         
     | 
| 
       1008 
     | 
    
         
            -
                    return
         
     | 
| 
       1009 
1004 
     | 
    
         | 
| 
       1010 
1005 
     | 
    
         
             
                def getPath(self, key: str) -> str | None:
         
     | 
| 
       1011 
1006 
     | 
    
         
             
                    """Get a path for a given key, or return None."""
         
     | 
    
        novelwriter/constants.py
    CHANGED
    
    | 
         @@ -20,7 +20,7 @@ General Public License for more details. 
     | 
|
| 
       20 
20 
     | 
    
         | 
| 
       21 
21 
     | 
    
         
             
            You should have received a copy of the GNU General Public License
         
     | 
| 
       22 
22 
     | 
    
         
             
            along with this program. If not, see <https://www.gnu.org/licenses/>.
         
     | 
| 
       23 
     | 
    
         
            -
            """
         
     | 
| 
      
 23 
     | 
    
         
            +
            """  # noqa
         
     | 
| 
       24 
24 
     | 
    
         
             
            from __future__ import annotations
         
     | 
| 
       25 
25 
     | 
    
         | 
| 
       26 
26 
     | 
    
         
             
            from typing import Final
         
     | 
| 
         @@ -28,21 +28,23 @@ from typing import Final 
     | 
|
| 
       28 
28 
     | 
    
         
             
            from PyQt6.QtCore import QT_TRANSLATE_NOOP, QCoreApplication
         
     | 
| 
       29 
29 
     | 
    
         | 
| 
       30 
30 
     | 
    
         
             
            from novelwriter.enum import (
         
     | 
| 
       31 
     | 
    
         
            -
                nwBuildFmt, nwComment, nwItemClass, nwItemLayout, nwOutline, nwStatusShape
         
     | 
| 
      
 31 
     | 
    
         
            +
                nwBuildFmt, nwComment, nwItemClass, nwItemLayout, nwOutline, nwStatusShape,
         
     | 
| 
      
 32 
     | 
    
         
            +
                nwTheme
         
     | 
| 
       32 
33 
     | 
    
         
             
            )
         
     | 
| 
       33 
34 
     | 
    
         | 
| 
       34 
35 
     | 
    
         | 
| 
       35 
36 
     | 
    
         
             
            def trConst(text: str) -> str:
         
     | 
| 
       36 
     | 
    
         
            -
                """ 
     | 
| 
      
 37 
     | 
    
         
            +
                """Translate a constant."""
         
     | 
| 
       37 
38 
     | 
    
         
             
                return QCoreApplication.translate("Constant", text)
         
     | 
| 
       38 
39 
     | 
    
         | 
| 
       39 
40 
     | 
    
         | 
| 
       40 
41 
     | 
    
         
             
            def trStats(text: str) -> str:
         
     | 
| 
       41 
     | 
    
         
            -
                """ 
     | 
| 
      
 42 
     | 
    
         
            +
                """Translate a stats constants."""
         
     | 
| 
       42 
43 
     | 
    
         
             
                return QCoreApplication.translate("Stats", text)
         
     | 
| 
       43 
44 
     | 
    
         | 
| 
       44 
45 
     | 
    
         | 
| 
       45 
46 
     | 
    
         
             
            class nwConst:
         
     | 
| 
      
 47 
     | 
    
         
            +
                """Various Constants."""
         
     | 
| 
       46 
48 
     | 
    
         | 
| 
       47 
49 
     | 
    
         
             
                # Date and Time Formats
         
     | 
| 
       48 
50 
     | 
    
         
             
                FMT_TSTAMP = "%Y-%m-%d %H:%M:%S"  # Default format
         
     | 
| 
         @@ -69,6 +71,7 @@ class nwConst: 
     | 
|
| 
       69 
71 
     | 
    
         | 
| 
       70 
72 
     | 
    
         | 
| 
       71 
73 
     | 
    
         
             
            class nwRegEx:
         
     | 
| 
      
 74 
     | 
    
         
            +
                """Common RegExes."""
         
     | 
| 
       72 
75 
     | 
    
         | 
| 
       73 
76 
     | 
    
         
             
                URL    = r"https?://(?:www\.|(?!www))[\w/()@:%_\+-.~#?&=]+"
         
     | 
| 
       74 
77 
     | 
    
         
             
                WORDS  = r"\b[^\s\-\+\/–—\[\]:]+\b"
         
     | 
| 
         @@ -76,11 +79,13 @@ class nwRegEx: 
     | 
|
| 
       76 
79 
     | 
    
         
             
                FMT_EI = r"(?<![\w\\])(_)(?![\s_])(.+?)(?<![\s\\])(\1)(?!\w)"
         
     | 
| 
       77 
80 
     | 
    
         
             
                FMT_EB = r"(?<![\w\\])(\*{2})(?![\s\*])(.+?)(?<![\s\\])(\1)(?!\w)"
         
     | 
| 
       78 
81 
     | 
    
         
             
                FMT_ST = r"(?<![\w\\])(~{2})(?![\s~])(.+?)(?<![\s\\])(\1)(?!\w)"
         
     | 
| 
      
 82 
     | 
    
         
            +
                FMT_HL = r"(?<![\w\\])(={2})(?![\s=])(.+?)(?<![\s\\])(\1)(?!\w)"
         
     | 
| 
       79 
83 
     | 
    
         
             
                FMT_SC = r"(?i)(?<!\\)(\[(?:b|/b|i|/i|s|/s|u|/u|m|/m|sup|/sup|sub|/sub|br)\])"
         
     | 
| 
       80 
84 
     | 
    
         
             
                FMT_SV = r"(?i)(?<!\\)(\[(?:footnote|field):)(.+?)(?<!\\)(\])"
         
     | 
| 
       81 
85 
     | 
    
         | 
| 
       82 
86 
     | 
    
         | 
| 
       83 
87 
     | 
    
         
             
            class nwShortcode:
         
     | 
| 
      
 88 
     | 
    
         
            +
                """Document ShortCodes."""
         
     | 
| 
       84 
89 
     | 
    
         | 
| 
       85 
90 
     | 
    
         
             
                BOLD_O   = "[b]"
         
     | 
| 
       86 
91 
     | 
    
         
             
                BOLD_C   = "[/b]"
         
     | 
| 
         @@ -110,6 +115,7 @@ class nwShortcode: 
     | 
|
| 
       110 
115 
     | 
    
         | 
| 
       111 
116 
     | 
    
         | 
| 
       112 
117 
     | 
    
         
             
            class nwStyles:
         
     | 
| 
      
 118 
     | 
    
         
            +
                """Style Settings for Headings."""
         
     | 
| 
       113 
119 
     | 
    
         | 
| 
       114 
120 
     | 
    
         
             
                H_VALID = ("H0", "H1", "H2", "H3", "H4")
         
     | 
| 
       115 
121 
     | 
    
         
             
                H_LEVEL: Final[dict[str, int]] = {"H0": 0, "H1": 1, "H2": 2, "H3": 3, "H4": 4}
         
     | 
| 
         @@ -141,6 +147,7 @@ class nwStyles: 
     | 
|
| 
       141 
147 
     | 
    
         | 
| 
       142 
148 
     | 
    
         | 
| 
       143 
149 
     | 
    
         
             
            class nwFiles:
         
     | 
| 
      
 150 
     | 
    
         
            +
                """novelWriter Files."""
         
     | 
| 
       144 
151 
     | 
    
         | 
| 
       145 
152 
     | 
    
         
             
                # Config Files
         
     | 
| 
       146 
153 
     | 
    
         
             
                CONF_FILE   = "novelwriter.conf"
         
     | 
| 
         @@ -161,6 +168,7 @@ class nwFiles: 
     | 
|
| 
       161 
168 
     | 
    
         | 
| 
       162 
169 
     | 
    
         | 
| 
       163 
170 
     | 
    
         
             
            class nwKeyWords:
         
     | 
| 
      
 171 
     | 
    
         
            +
                """Meta Data KeyWord Constants."""
         
     | 
| 
       164 
172 
     | 
    
         | 
| 
       165 
173 
     | 
    
         
             
                TAG_KEY     = "@tag"
         
     | 
| 
       166 
174 
     | 
    
         
             
                POV_KEY     = "@pov"
         
     | 
| 
         @@ -208,6 +216,7 @@ class nwKeyWords: 
     | 
|
| 
       208 
216 
     | 
    
         | 
| 
       209 
217 
     | 
    
         | 
| 
       210 
218 
     | 
    
         
             
            class nwLists:
         
     | 
| 
      
 219 
     | 
    
         
            +
                """Various Lists."""
         
     | 
| 
       211 
220 
     | 
    
         | 
| 
       212 
221 
     | 
    
         
             
                USER_CLASSES: Final[list[nwItemClass]] = [
         
     | 
| 
       213 
222 
     | 
    
         
             
                    nwItemClass.CHARACTER,
         
     | 
| 
         @@ -221,6 +230,7 @@ class nwLists: 
     | 
|
| 
       221 
230 
     | 
    
         | 
| 
       222 
231 
     | 
    
         | 
| 
       223 
232 
     | 
    
         
             
            class nwStats:
         
     | 
| 
      
 233 
     | 
    
         
            +
                """Text Statistics."""
         
     | 
| 
       224 
234 
     | 
    
         | 
| 
       225 
235 
     | 
    
         
             
                CHARS        = "allChars"
         
     | 
| 
       226 
236 
     | 
    
         
             
                CHARS_TEXT   = "textChars"
         
     | 
| 
         @@ -244,6 +254,7 @@ class nwStats: 
     | 
|
| 
       244 
254 
     | 
    
         | 
| 
       245 
255 
     | 
    
         | 
| 
       246 
256 
     | 
    
         
             
            class nwLabels:
         
     | 
| 
      
 257 
     | 
    
         
            +
                """Various Common GUI Labels."""
         
     | 
| 
       247 
258 
     | 
    
         | 
| 
       248 
259 
     | 
    
         
             
                CLASS_NAME: Final[dict[nwItemClass, str]] = {
         
     | 
| 
       249 
260 
     | 
    
         
             
                    nwItemClass.NO_CLASS:  QT_TRANSLATE_NOOP("Constant", "None"),
         
     | 
| 
         @@ -446,20 +457,31 @@ class nwLabels: 
     | 
|
| 
       446 
457 
     | 
    
         
             
                    "Custom": (-1.0, -1.0),
         
     | 
| 
       447 
458 
     | 
    
         
             
                }
         
     | 
| 
       448 
459 
     | 
    
         
             
                THEME_COLORS: Final[dict[str, str]] = {
         
     | 
| 
       449 
     | 
    
         
            -
                    "theme":   QT_TRANSLATE_NOOP("Constant", "Theme Colours"),
         
     | 
| 
       450 
460 
     | 
    
         
             
                    "default": QT_TRANSLATE_NOOP("Constant", "Foreground Colour"),
         
     | 
| 
      
 461 
     | 
    
         
            +
                    "base":    QT_TRANSLATE_NOOP("Constant", "Background Colour"),
         
     | 
| 
       451 
462 
     | 
    
         
             
                    "faded":   QT_TRANSLATE_NOOP("Constant", "Faded Colour"),
         
     | 
| 
       452 
463 
     | 
    
         
             
                    "red":     QT_TRANSLATE_NOOP("Constant", "Red"),
         
     | 
| 
       453 
464 
     | 
    
         
             
                    "orange":  QT_TRANSLATE_NOOP("Constant", "Orange"),
         
     | 
| 
       454 
465 
     | 
    
         
             
                    "yellow":  QT_TRANSLATE_NOOP("Constant", "Yellow"),
         
     | 
| 
       455 
466 
     | 
    
         
             
                    "green":   QT_TRANSLATE_NOOP("Constant", "Green"),
         
     | 
| 
       456 
     | 
    
         
            -
                    " 
     | 
| 
      
 467 
     | 
    
         
            +
                    "cyan":    QT_TRANSLATE_NOOP("Constant", "Cyan"),
         
     | 
| 
       457 
468 
     | 
    
         
             
                    "blue":    QT_TRANSLATE_NOOP("Constant", "Blue"),
         
     | 
| 
       458 
469 
     | 
    
         
             
                    "purple":  QT_TRANSLATE_NOOP("Constant", "Purple"),
         
     | 
| 
       459 
470 
     | 
    
         
             
                }
         
     | 
| 
      
 471 
     | 
    
         
            +
                THEME_MODE_ICON: Final[dict[nwTheme, str]] = {
         
     | 
| 
      
 472 
     | 
    
         
            +
                    nwTheme.AUTO:  "theme_auto",
         
     | 
| 
      
 473 
     | 
    
         
            +
                    nwTheme.LIGHT: "theme_light",
         
     | 
| 
      
 474 
     | 
    
         
            +
                    nwTheme.DARK:  "theme_dark",
         
     | 
| 
      
 475 
     | 
    
         
            +
                }
         
     | 
| 
      
 476 
     | 
    
         
            +
                THEME_MODE_LABEL: Final[dict[nwTheme, str]] = {
         
     | 
| 
      
 477 
     | 
    
         
            +
                    nwTheme.AUTO:  QT_TRANSLATE_NOOP("Constant", "System Theme"),
         
     | 
| 
      
 478 
     | 
    
         
            +
                    nwTheme.LIGHT: QT_TRANSLATE_NOOP("Constant", "Light Theme"),
         
     | 
| 
      
 479 
     | 
    
         
            +
                    nwTheme.DARK:  QT_TRANSLATE_NOOP("Constant", "Dark Theme"),
         
     | 
| 
      
 480 
     | 
    
         
            +
                }
         
     | 
| 
       460 
481 
     | 
    
         | 
| 
       461 
482 
     | 
    
         | 
| 
       462 
483 
     | 
    
         
             
            class nwHeadFmt:
         
     | 
| 
      
 484 
     | 
    
         
            +
                """Manuscript Header Formats."""
         
     | 
| 
       463 
485 
     | 
    
         | 
| 
       464 
486 
     | 
    
         
             
                BR         = "{BR}"
         
     | 
| 
       465 
487 
     | 
    
         
             
                TITLE      = "{Title}"
         
     | 
| 
         @@ -486,8 +508,10 @@ class nwHeadFmt: 
     | 
|
| 
       486 
508 
     | 
    
         | 
| 
       487 
509 
     | 
    
         
             
            class nwQuotes:
         
     | 
| 
       488 
510 
     | 
    
         
             
                """Allowed quotation marks.
         
     | 
| 
      
 511 
     | 
    
         
            +
             
     | 
| 
       489 
512 
     | 
    
         
             
                Source: https://en.wikipedia.org/wiki/Quotation_mark
         
     | 
| 
       490 
513 
     | 
    
         
             
                """
         
     | 
| 
      
 514 
     | 
    
         
            +
             
     | 
| 
       491 
515 
     | 
    
         
             
                SYMBOLS: Final[dict[str, str]] = {
         
     | 
| 
       492 
516 
     | 
    
         
             
                    "\u0027": QT_TRANSLATE_NOOP("Constant", "Straight single quotation mark"),
         
     | 
| 
       493 
517 
     | 
    
         
             
                    "\u0022": QT_TRANSLATE_NOOP("Constant", "Straight double quotation mark"),
         
     | 
| 
         @@ -529,6 +553,7 @@ class nwQuotes: 
     | 
|
| 
       529 
553 
     | 
    
         | 
| 
       530 
554 
     | 
    
         
             
            class nwUnicode:
         
     | 
| 
       531 
555 
     | 
    
         
             
                """Supported unicode character constants and their HTML equivalents."""
         
     | 
| 
      
 556 
     | 
    
         
            +
             
     | 
| 
       532 
557 
     | 
    
         
             
                # Unicode Constants
         
     | 
| 
       533 
558 
     | 
    
         
             
                # =================
         
     | 
| 
       534 
559 
     | 
    
         | 
| 
         @@ -660,6 +685,7 @@ class nwUnicode: 
     | 
|
| 
       660 
685 
     | 
    
         | 
| 
       661 
686 
     | 
    
         | 
| 
       662 
687 
     | 
    
         
             
            class nwHtmlUnicode:
         
     | 
| 
      
 688 
     | 
    
         
            +
                """Unicode to HTML Map."""
         
     | 
| 
       663 
689 
     | 
    
         | 
| 
       664 
690 
     | 
    
         
             
                U_TO_H: Final[dict[str, str]] = {
         
     | 
| 
       665 
691 
     | 
    
         
             
                    # Quotes
         
     |