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
 
| 
         @@ -0,0 +1,95 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            [Main]
         
     | 
| 
      
 2 
     | 
    
         
            +
            name   = Waterlily Dark
         
     | 
| 
      
 3 
     | 
    
         
            +
            mode   = dark
         
     | 
| 
      
 4 
     | 
    
         
            +
            author = Myian
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            [Base]
         
     | 
| 
      
 7 
     | 
    
         
            +
            base    = #1e2b33
         
     | 
| 
      
 8 
     | 
    
         
            +
            default = #d0dee6
         
     | 
| 
      
 9 
     | 
    
         
            +
            faded   = #7b8e99
         
     | 
| 
      
 10 
     | 
    
         
            +
            red     = #ff7474
         
     | 
| 
      
 11 
     | 
    
         
            +
            orange  = #fca469
         
     | 
| 
      
 12 
     | 
    
         
            +
            yellow  = #f7eaa4
         
     | 
| 
      
 13 
     | 
    
         
            +
            green   = #9ae37f
         
     | 
| 
      
 14 
     | 
    
         
            +
            cyan    = #8ef3d1
         
     | 
| 
      
 15 
     | 
    
         
            +
            blue    = #71caeb
         
     | 
| 
      
 16 
     | 
    
         
            +
            purple  = #c89dfd
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
            [Project]
         
     | 
| 
      
 19 
     | 
    
         
            +
            root     = default
         
     | 
| 
      
 20 
     | 
    
         
            +
            folder   = blue
         
     | 
| 
      
 21 
     | 
    
         
            +
            file     = purple
         
     | 
| 
      
 22 
     | 
    
         
            +
            title    = green
         
     | 
| 
      
 23 
     | 
    
         
            +
            chapter  = yellow
         
     | 
| 
      
 24 
     | 
    
         
            +
            scene    = #ff9fbd
         
     | 
| 
      
 25 
     | 
    
         
            +
            note     = faded
         
     | 
| 
      
 26 
     | 
    
         
            +
            active   = #ff9fbd
         
     | 
| 
      
 27 
     | 
    
         
            +
            inactive = faded
         
     | 
| 
      
 28 
     | 
    
         
            +
            disabled = #3e5366
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
            [Icon]
         
     | 
| 
      
 31 
     | 
    
         
            +
            tool      = default
         
     | 
| 
      
 32 
     | 
    
         
            +
            sidebar   = default
         
     | 
| 
      
 33 
     | 
    
         
            +
            accept    = green
         
     | 
| 
      
 34 
     | 
    
         
            +
            reject    = red
         
     | 
| 
      
 35 
     | 
    
         
            +
            action    = blue
         
     | 
| 
      
 36 
     | 
    
         
            +
            altaction = orange
         
     | 
| 
      
 37 
     | 
    
         
            +
            apply     = green
         
     | 
| 
      
 38 
     | 
    
         
            +
            create    = yellow
         
     | 
| 
      
 39 
     | 
    
         
            +
            destroy   = faded
         
     | 
| 
      
 40 
     | 
    
         
            +
            reset     = green
         
     | 
| 
      
 41 
     | 
    
         
            +
            add       = green
         
     | 
| 
      
 42 
     | 
    
         
            +
            change    = green
         
     | 
| 
      
 43 
     | 
    
         
            +
            remove    = red
         
     | 
| 
      
 44 
     | 
    
         
            +
            shortcode = default
         
     | 
| 
      
 45 
     | 
    
         
            +
            markdown  = orange
         
     | 
| 
      
 46 
     | 
    
         
            +
            systemio  = yellow
         
     | 
| 
      
 47 
     | 
    
         
            +
            info      = blue
         
     | 
| 
      
 48 
     | 
    
         
            +
            warning   = orange
         
     | 
| 
      
 49 
     | 
    
         
            +
            error     = red
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
            [Palette]
         
     | 
| 
      
 52 
     | 
    
         
            +
            window          = #151f25
         
     | 
| 
      
 53 
     | 
    
         
            +
            windowtext      = default
         
     | 
| 
      
 54 
     | 
    
         
            +
            base            = base
         
     | 
| 
      
 55 
     | 
    
         
            +
            alternatebase   = #3b515f
         
     | 
| 
      
 56 
     | 
    
         
            +
            text            = default
         
     | 
| 
      
 57 
     | 
    
         
            +
            tooltipbase     = #ffbad0
         
     | 
| 
      
 58 
     | 
    
         
            +
            tooltiptext     = base
         
     | 
| 
      
 59 
     | 
    
         
            +
            button          = base
         
     | 
| 
      
 60 
     | 
    
         
            +
            buttontext      = default
         
     | 
| 
      
 61 
     | 
    
         
            +
            brighttext      = base
         
     | 
| 
      
 62 
     | 
    
         
            +
            highlight       = #87bcc0
         
     | 
| 
      
 63 
     | 
    
         
            +
            highlightedtext = base
         
     | 
| 
      
 64 
     | 
    
         
            +
            link            = blue
         
     | 
| 
      
 65 
     | 
    
         
            +
            linkvisited     = blue
         
     | 
| 
      
 66 
     | 
    
         
            +
            accent          = #ff9fbd
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
            [GUI]
         
     | 
| 
      
 69 
     | 
    
         
            +
            helptext  = faded
         
     | 
| 
      
 70 
     | 
    
         
            +
            fadedtext = faded
         
     | 
| 
      
 71 
     | 
    
         
            +
            errortext = red
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
            [Syntax]
         
     | 
| 
      
 74 
     | 
    
         
            +
            background     = base
         
     | 
| 
      
 75 
     | 
    
         
            +
            text           = default
         
     | 
| 
      
 76 
     | 
    
         
            +
            line           = #283842
         
     | 
| 
      
 77 
     | 
    
         
            +
            link           = blue
         
     | 
| 
      
 78 
     | 
    
         
            +
            headertext     = #e8eef1
         
     | 
| 
      
 79 
     | 
    
         
            +
            headertag      = faded
         
     | 
| 
      
 80 
     | 
    
         
            +
            emphasis       = green
         
     | 
| 
      
 81 
     | 
    
         
            +
            whitespace     = green:64
         
     | 
| 
      
 82 
     | 
    
         
            +
            dialog         = #ff9fbd
         
     | 
| 
      
 83 
     | 
    
         
            +
            altdialog      = orange
         
     | 
| 
      
 84 
     | 
    
         
            +
            note           = blue
         
     | 
| 
      
 85 
     | 
    
         
            +
            hidden         = faded
         
     | 
| 
      
 86 
     | 
    
         
            +
            shortcode      = purple
         
     | 
| 
      
 87 
     | 
    
         
            +
            keyword        = purple
         
     | 
| 
      
 88 
     | 
    
         
            +
            tag            = yellow
         
     | 
| 
      
 89 
     | 
    
         
            +
            value          = cyan
         
     | 
| 
      
 90 
     | 
    
         
            +
            optional       = faded
         
     | 
| 
      
 91 
     | 
    
         
            +
            spellcheckline = #ff5d5d
         
     | 
| 
      
 92 
     | 
    
         
            +
            errorline      = #4ae698
         
     | 
| 
      
 93 
     | 
    
         
            +
            replacetag     = blue
         
     | 
| 
      
 94 
     | 
    
         
            +
            modifier       = purple
         
     | 
| 
      
 95 
     | 
    
         
            +
            texthighlight  = blue:64
         
     | 
| 
         @@ -0,0 +1,95 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            [Main]
         
     | 
| 
      
 2 
     | 
    
         
            +
            name   = Waterlily Light
         
     | 
| 
      
 3 
     | 
    
         
            +
            mode   = light
         
     | 
| 
      
 4 
     | 
    
         
            +
            author = Myian
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            [Base]
         
     | 
| 
      
 7 
     | 
    
         
            +
            base    = #f4fcfb
         
     | 
| 
      
 8 
     | 
    
         
            +
            default = #435e66
         
     | 
| 
      
 9 
     | 
    
         
            +
            faded   = #91acab
         
     | 
| 
      
 10 
     | 
    
         
            +
            red     = #d36868
         
     | 
| 
      
 11 
     | 
    
         
            +
            orange  = #e08b63
         
     | 
| 
      
 12 
     | 
    
         
            +
            yellow  = #cab330
         
     | 
| 
      
 13 
     | 
    
         
            +
            green   = #62a729
         
     | 
| 
      
 14 
     | 
    
         
            +
            cyan    = #41a594
         
     | 
| 
      
 15 
     | 
    
         
            +
            blue    = #589dca
         
     | 
| 
      
 16 
     | 
    
         
            +
            purple  = #bd7fe7
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
            [Project]
         
     | 
| 
      
 19 
     | 
    
         
            +
            root     = default
         
     | 
| 
      
 20 
     | 
    
         
            +
            folder   = blue
         
     | 
| 
      
 21 
     | 
    
         
            +
            file     = purple
         
     | 
| 
      
 22 
     | 
    
         
            +
            title    = green
         
     | 
| 
      
 23 
     | 
    
         
            +
            chapter  = yellow
         
     | 
| 
      
 24 
     | 
    
         
            +
            scene    = #e6859a
         
     | 
| 
      
 25 
     | 
    
         
            +
            note     = faded
         
     | 
| 
      
 26 
     | 
    
         
            +
            active   = #da7b8f
         
     | 
| 
      
 27 
     | 
    
         
            +
            inactive = faded
         
     | 
| 
      
 28 
     | 
    
         
            +
            disabled = #b6cac7
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
            [Icon]
         
     | 
| 
      
 31 
     | 
    
         
            +
            tool      = default
         
     | 
| 
      
 32 
     | 
    
         
            +
            sidebar   = default
         
     | 
| 
      
 33 
     | 
    
         
            +
            accept    = green
         
     | 
| 
      
 34 
     | 
    
         
            +
            reject    = red
         
     | 
| 
      
 35 
     | 
    
         
            +
            action    = blue
         
     | 
| 
      
 36 
     | 
    
         
            +
            altaction = orange
         
     | 
| 
      
 37 
     | 
    
         
            +
            apply     = green
         
     | 
| 
      
 38 
     | 
    
         
            +
            create    = yellow
         
     | 
| 
      
 39 
     | 
    
         
            +
            destroy   = faded
         
     | 
| 
      
 40 
     | 
    
         
            +
            reset     = green
         
     | 
| 
      
 41 
     | 
    
         
            +
            add       = green
         
     | 
| 
      
 42 
     | 
    
         
            +
            change    = green
         
     | 
| 
      
 43 
     | 
    
         
            +
            remove    = red
         
     | 
| 
      
 44 
     | 
    
         
            +
            shortcode = default
         
     | 
| 
      
 45 
     | 
    
         
            +
            markdown  = orange
         
     | 
| 
      
 46 
     | 
    
         
            +
            systemio  = yellow
         
     | 
| 
      
 47 
     | 
    
         
            +
            info      = blue
         
     | 
| 
      
 48 
     | 
    
         
            +
            warning   = orange
         
     | 
| 
      
 49 
     | 
    
         
            +
            error     = red
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
            [Palette]
         
     | 
| 
      
 52 
     | 
    
         
            +
            window          = #e2eeed
         
     | 
| 
      
 53 
     | 
    
         
            +
            windowtext      = default
         
     | 
| 
      
 54 
     | 
    
         
            +
            base            = base
         
     | 
| 
      
 55 
     | 
    
         
            +
            alternatebase   = #c7e0e0
         
     | 
| 
      
 56 
     | 
    
         
            +
            text            = default
         
     | 
| 
      
 57 
     | 
    
         
            +
            tooltipbase     = #ffdfe6
         
     | 
| 
      
 58 
     | 
    
         
            +
            tooltiptext     = #223f47
         
     | 
| 
      
 59 
     | 
    
         
            +
            button          = base
         
     | 
| 
      
 60 
     | 
    
         
            +
            buttontext      = default
         
     | 
| 
      
 61 
     | 
    
         
            +
            brighttext      = base
         
     | 
| 
      
 62 
     | 
    
         
            +
            highlight       = #4da1af
         
     | 
| 
      
 63 
     | 
    
         
            +
            highlightedtext = base
         
     | 
| 
      
 64 
     | 
    
         
            +
            link            = blue
         
     | 
| 
      
 65 
     | 
    
         
            +
            linkvisited     = blue
         
     | 
| 
      
 66 
     | 
    
         
            +
            accent          = #e6859a
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
            [GUI]
         
     | 
| 
      
 69 
     | 
    
         
            +
            helptext  = default:192
         
     | 
| 
      
 70 
     | 
    
         
            +
            fadedtext = faded
         
     | 
| 
      
 71 
     | 
    
         
            +
            errortext = red
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
            [Syntax]
         
     | 
| 
      
 74 
     | 
    
         
            +
            background     = base
         
     | 
| 
      
 75 
     | 
    
         
            +
            text           = default
         
     | 
| 
      
 76 
     | 
    
         
            +
            line           = #e2eeed
         
     | 
| 
      
 77 
     | 
    
         
            +
            link           = #0b9caf
         
     | 
| 
      
 78 
     | 
    
         
            +
            headertext     = #57757e
         
     | 
| 
      
 79 
     | 
    
         
            +
            headertag      = #b6cac7
         
     | 
| 
      
 80 
     | 
    
         
            +
            emphasis       = #1e920e
         
     | 
| 
      
 81 
     | 
    
         
            +
            whitespace     = #1e920e64
         
     | 
| 
      
 82 
     | 
    
         
            +
            dialog         = #d15574
         
     | 
| 
      
 83 
     | 
    
         
            +
            altdialog      = #dd6b37
         
     | 
| 
      
 84 
     | 
    
         
            +
            note           = #0b9caf
         
     | 
| 
      
 85 
     | 
    
         
            +
            hidden         = #87a3a0
         
     | 
| 
      
 86 
     | 
    
         
            +
            shortcode      = #9a54c9
         
     | 
| 
      
 87 
     | 
    
         
            +
            keyword        = #9a54c9
         
     | 
| 
      
 88 
     | 
    
         
            +
            tag            = #c9a02e
         
     | 
| 
      
 89 
     | 
    
         
            +
            value          = #05af77
         
     | 
| 
      
 90 
     | 
    
         
            +
            optional       = #87a3a0
         
     | 
| 
      
 91 
     | 
    
         
            +
            spellcheckline = #ff3e3e
         
     | 
| 
      
 92 
     | 
    
         
            +
            errorline      = #05af77
         
     | 
| 
      
 93 
     | 
    
         
            +
            replacetag     = #0b9caf
         
     | 
| 
      
 94 
     | 
    
         
            +
            modifier       = #9a54c9
         
     | 
| 
      
 95 
     | 
    
         
            +
            texthighlight  = cyan:64
         
     | 
    
        novelwriter/common.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 
     | 
    
         
             
            import json
         
     | 
| 
         @@ -31,6 +31,7 @@ import xml.etree.ElementTree as ET 
     | 
|
| 
       31 
31 
     | 
    
         | 
| 
       32 
32 
     | 
    
         
             
            from configparser import ConfigParser
         
     | 
| 
       33 
33 
     | 
    
         
             
            from datetime import datetime
         
     | 
| 
      
 34 
     | 
    
         
            +
            from enum import Enum
         
     | 
| 
       34 
35 
     | 
    
         
             
            from pathlib import Path
         
     | 
| 
       35 
36 
     | 
    
         
             
            from typing import TYPE_CHECKING, Any, Literal, TypeGuard, TypeVar
         
     | 
| 
       36 
37 
     | 
    
         
             
            from urllib.parse import urljoin
         
     | 
| 
         @@ -134,7 +135,7 @@ def checkPath(value: Any, default: Path) -> Path: 
     | 
|
| 
       134 
135 
     | 
    
         | 
| 
       135 
136 
     | 
    
         
             
            def isHandle(value: Any) -> TypeGuard[str]:
         
     | 
| 
       136 
137 
     | 
    
         
             
                """Check if a string is a valid novelWriter handle.
         
     | 
| 
       137 
     | 
    
         
            -
                Note: This is case sensitive. Must be lower case 
     | 
| 
      
 138 
     | 
    
         
            +
                Note: This is case sensitive. Must be lower case.
         
     | 
| 
       138 
139 
     | 
    
         
             
                """
         
     | 
| 
       139 
140 
     | 
    
         
             
                if not isinstance(value, str):
         
     | 
| 
       140 
141 
     | 
    
         
             
                    return False
         
     | 
| 
         @@ -218,7 +219,7 @@ def firstFloat(*args: Any) -> float: 
     | 
|
| 
       218 
219 
     | 
    
         
             
            ##
         
     | 
| 
       219 
220 
     | 
    
         | 
| 
       220 
221 
     | 
    
         
             
            def formatInt(value: int) -> str:
         
     | 
| 
       221 
     | 
    
         
            -
                """ 
     | 
| 
      
 222 
     | 
    
         
            +
                """Format an integer with k, M, G etc."""
         
     | 
| 
       222 
223 
     | 
    
         
             
                if not isinstance(value, int):
         
     | 
| 
       223 
224 
     | 
    
         
             
                    return "ERR"
         
     | 
| 
       224 
225 
     | 
    
         | 
| 
         @@ -444,6 +445,7 @@ def fontMatcher(font: QFont) -> QFont: 
     | 
|
| 
       444 
445 
     | 
    
         
             
                default Qt font matching algorithm doesn't handle well changing
         
     | 
| 
       445 
446 
     | 
    
         
             
                application fonts at runtime.
         
     | 
| 
       446 
447 
     | 
    
         
             
                """
         
     | 
| 
      
 448 
     | 
    
         
            +
                font.setStyleName(None)  # Make sure no font style name is set from config, see #2502
         
     | 
| 
       447 
449 
     | 
    
         
             
                info = QFontInfo(font)
         
     | 
| 
       448 
450 
     | 
    
         
             
                if (famRequest := font.family()) != (famActual := info.family()):
         
     | 
| 
       449 
451 
     | 
    
         
             
                    logger.warning("Font mismatch: Requested '%s', but got '%s'", famRequest, famActual)
         
     | 
| 
         @@ -462,21 +464,21 @@ def fontMatcher(font: QFont) -> QFont: 
     | 
|
| 
       462 
464 
     | 
    
         | 
| 
       463 
465 
     | 
    
         | 
| 
       464 
466 
     | 
    
         
             
            def qtLambda(func: Callable, *args: Any, **kwargs: Any) -> Callable:
         
     | 
| 
       465 
     | 
    
         
            -
                """A replacement for Python lambdas that works for Qt slots."""
         
     | 
| 
      
 467 
     | 
    
         
            +
                """A replacement for Python lambdas that works for Qt slots."""  # noqa: D401
         
     | 
| 
       466 
468 
     | 
    
         
             
                def wrapper(*a_: Any) -> None:
         
     | 
| 
       467 
469 
     | 
    
         
             
                    func(*args, **kwargs)
         
     | 
| 
       468 
470 
     | 
    
         
             
                return wrapper
         
     | 
| 
       469 
471 
     | 
    
         | 
| 
       470 
472 
     | 
    
         | 
| 
       471 
473 
     | 
    
         
             
            def qtAddAction(parent: QWidget, label: str) -> QAction:
         
     | 
| 
       472 
     | 
    
         
            -
                """Helper to add action to widget and always return the action."""
         
     | 
| 
      
 474 
     | 
    
         
            +
                """Helper to add action to widget and always return the action."""  # noqa: D401
         
     | 
| 
       473 
475 
     | 
    
         
             
                action = QAction(label, parent)
         
     | 
| 
       474 
476 
     | 
    
         
             
                parent.addAction(action)
         
     | 
| 
       475 
477 
     | 
    
         
             
                return action
         
     | 
| 
       476 
478 
     | 
    
         | 
| 
       477 
479 
     | 
    
         | 
| 
       478 
480 
     | 
    
         
             
            def qtAddMenu(parent: QMenuBar | QMenu, label: str) -> QMenu:
         
     | 
| 
       479 
     | 
    
         
            -
                """Helper to add menu to menu and always return the menu."""
         
     | 
| 
      
 481 
     | 
    
         
            +
                """Helper to add menu to menu and always return the menu."""  # noqa: D401
         
     | 
| 
       480 
482 
     | 
    
         
             
                menu = QMenu(label, parent)
         
     | 
| 
       481 
483 
     | 
    
         
             
                parent.addMenu(menu)
         
     | 
| 
       482 
484 
     | 
    
         
             
                return menu
         
     | 
| 
         @@ -485,7 +487,6 @@ def qtAddMenu(parent: QMenuBar | QMenu, label: str) -> QMenu: 
     | 
|
| 
       485 
487 
     | 
    
         
             
            def encodeMimeHandles(mimeData: QMimeData, handles: list[str]) -> None:
         
     | 
| 
       486 
488 
     | 
    
         
             
                """Encode handles into a mime data object."""
         
     | 
| 
       487 
489 
     | 
    
         
             
                mimeData.setData(nwConst.MIME_HANDLE, b"|".join(h.encode() for h in handles))
         
     | 
| 
       488 
     | 
    
         
            -
                return
         
     | 
| 
       489 
490 
     | 
    
         | 
| 
       490 
491 
     | 
    
         | 
| 
       491 
492 
     | 
    
         
             
            def decodeMimeHandles(mimeData: QMimeData) -> list[str]:
         
     | 
| 
         @@ -493,6 +494,21 @@ def decodeMimeHandles(mimeData: QMimeData) -> list[str]: 
     | 
|
| 
       493 
494 
     | 
    
         
             
                return mimeData.data(nwConst.MIME_HANDLE).data().decode().split("|")
         
     | 
| 
       494 
495 
     | 
    
         | 
| 
       495 
496 
     | 
    
         | 
| 
      
 497 
     | 
    
         
            +
            def utf16CharMap(text: str) -> list[int]:
         
     | 
| 
      
 498 
     | 
    
         
            +
                """Compute mapping from Python string index to QString index.
         
     | 
| 
      
 499 
     | 
    
         
            +
                Python strings are always one character per position in either
         
     | 
| 
      
 500 
     | 
    
         
            +
                ASCII, UCS-2 or UCS-4. QStrings are in UTF-16, so wide characters
         
     | 
| 
      
 501 
     | 
    
         
            +
                use 2 indices, and thus create an offset.
         
     | 
| 
      
 502 
     | 
    
         
            +
                """
         
     | 
| 
      
 503 
     | 
    
         
            +
                utf16Map = list(range(0, len(text) + 1))
         
     | 
| 
      
 504 
     | 
    
         
            +
                offset = 0
         
     | 
| 
      
 505 
     | 
    
         
            +
                for i, c in enumerate(text, 1):
         
     | 
| 
      
 506 
     | 
    
         
            +
                    if ord(c) > 0xffff:
         
     | 
| 
      
 507 
     | 
    
         
            +
                        offset += 1
         
     | 
| 
      
 508 
     | 
    
         
            +
                    utf16Map[i] = i + offset
         
     | 
| 
      
 509 
     | 
    
         
            +
                return utf16Map
         
     | 
| 
      
 510 
     | 
    
         
            +
             
     | 
| 
      
 511 
     | 
    
         
            +
             
     | 
| 
       496 
512 
     | 
    
         
             
            ##
         
     | 
| 
       497 
513 
     | 
    
         
             
            #  Encoder Functions
         
     | 
| 
       498 
514 
     | 
    
         
             
            ##
         
     | 
| 
         @@ -519,7 +535,7 @@ def jsonEncode(data: dict | list | tuple, n: int = 0, nmax: int = 0) -> str: 
     | 
|
| 
       519 
535 
     | 
    
         
             
                    elif first in ("{", "["):
         
     | 
| 
       520 
536 
     | 
    
         
             
                        n += 1
         
     | 
| 
       521 
537 
     | 
    
         
             
                        indent = "\n"+"  "*n
         
     | 
| 
       522 
     | 
    
         
            -
                        if n > nmax  
     | 
| 
      
 538 
     | 
    
         
            +
                        if n > nmax > 0:
         
     | 
| 
       523 
539 
     | 
    
         
             
                            buffer.append(chunk)
         
     | 
| 
       524 
540 
     | 
    
         
             
                        else:
         
     | 
| 
       525 
541 
     | 
    
         
             
                            buffer.append(chunk[0] + indent + chunk[1:])
         
     | 
| 
         @@ -527,13 +543,13 @@ def jsonEncode(data: dict | list | tuple, n: int = 0, nmax: int = 0) -> str: 
     | 
|
| 
       527 
543 
     | 
    
         
             
                    elif first in ("}", "]"):
         
     | 
| 
       528 
544 
     | 
    
         
             
                        n -= 1
         
     | 
| 
       529 
545 
     | 
    
         
             
                        indent = "\n"+"  "*n
         
     | 
| 
       530 
     | 
    
         
            -
                        if n >= nmax  
     | 
| 
      
 546 
     | 
    
         
            +
                        if n >= nmax > 0:
         
     | 
| 
       531 
547 
     | 
    
         
             
                            buffer.append(chunk)
         
     | 
| 
       532 
548 
     | 
    
         
             
                        else:
         
     | 
| 
       533 
549 
     | 
    
         
             
                            buffer.append(indent + chunk)
         
     | 
| 
       534 
550 
     | 
    
         | 
| 
       535 
551 
     | 
    
         
             
                    elif first == ",":
         
     | 
| 
       536 
     | 
    
         
            -
                        if n > nmax  
     | 
| 
      
 552 
     | 
    
         
            +
                        if n > nmax > 0:
         
     | 
| 
       537 
553 
     | 
    
         
             
                            buffer.append(chunk)
         
     | 
| 
       538 
554 
     | 
    
         
             
                        else:
         
     | 
| 
       539 
555 
     | 
    
         
             
                            buffer.append(chunk[0] + indent + chunk[1:].lstrip())
         
     | 
| 
         @@ -544,6 +560,12 @@ def jsonEncode(data: dict | list | tuple, n: int = 0, nmax: int = 0) -> str: 
     | 
|
| 
       544 
560 
     | 
    
         
             
                return "".join(buffer)
         
     | 
| 
       545 
561 
     | 
    
         | 
| 
       546 
562 
     | 
    
         | 
| 
      
 563 
     | 
    
         
            +
            def jsonCombine(data: dict[str, str]) -> str:
         
     | 
| 
      
 564 
     | 
    
         
            +
                """Combine multiple already packed JSON strings."""
         
     | 
| 
      
 565 
     | 
    
         
            +
                payload = ",\n".join(f'  "{k}": {v}' for k, v in data.items())
         
     | 
| 
      
 566 
     | 
    
         
            +
                return f"{{\n{payload}\n}}\n"
         
     | 
| 
      
 567 
     | 
    
         
            +
             
     | 
| 
      
 568 
     | 
    
         
            +
             
     | 
| 
       547 
569 
     | 
    
         
             
            ##
         
     | 
| 
       548 
570 
     | 
    
         
             
            #  XML Helpers
         
     | 
| 
       549 
571 
     | 
    
         
             
            ##
         
     | 
| 
         @@ -551,7 +573,7 @@ def jsonEncode(data: dict | list | tuple, n: int = 0, nmax: int = 0) -> str: 
     | 
|
| 
       551 
573 
     | 
    
         
             
            def xmlIndent(xml: ET.Element | ET.ElementTree) -> None:
         
     | 
| 
       552 
574 
     | 
    
         
             
                """A modified version of the XML indent function in the standard
         
     | 
| 
       553 
575 
     | 
    
         
             
                library. It behaves more closely to how the one from lxml does.
         
     | 
| 
       554 
     | 
    
         
            -
                """
         
     | 
| 
      
 576 
     | 
    
         
            +
                """  # noqa: D401
         
     | 
| 
       555 
577 
     | 
    
         
             
                tree = xml.getroot() if isinstance(xml, ET.ElementTree) else xml
         
     | 
| 
       556 
578 
     | 
    
         
             
                if not isinstance(tree, ET.Element):
         
     | 
| 
       557 
579 
     | 
    
         
             
                    return
         
     | 
| 
         @@ -581,8 +603,6 @@ def xmlIndent(xml: ET.Element | ET.ElementTree) -> None: 
     | 
|
| 
       581 
603 
     | 
    
         
             
                    if last is not None:
         
     | 
| 
       582 
604 
     | 
    
         
             
                        last.tail = indentations[level]
         
     | 
| 
       583 
605 
     | 
    
         | 
| 
       584 
     | 
    
         
            -
                    return
         
     | 
| 
       585 
     | 
    
         
            -
             
     | 
| 
       586 
606 
     | 
    
         
             
                if len(tree):
         
     | 
| 
       587 
607 
     | 
    
         
             
                    indentChildren(tree, 0)
         
     | 
| 
       588 
608 
     | 
    
         
             
                tree.tail = "\n"
         
     | 
| 
         @@ -597,7 +617,7 @@ def xmlElement( 
     | 
|
| 
       597 
617 
     | 
    
         
             
                attrib: dict | None = None,
         
     | 
| 
       598 
618 
     | 
    
         
             
                tail: str | None = None,
         
     | 
| 
       599 
619 
     | 
    
         
             
            ) -> ET.Element:
         
     | 
| 
       600 
     | 
    
         
            -
                """A custom implementation of Element with more arguments."""
         
     | 
| 
      
 620 
     | 
    
         
            +
                """A custom implementation of Element with more arguments."""  # noqa: D401
         
     | 
| 
       601 
621 
     | 
    
         
             
                xSub = ET.Element(tag, attrib=attrib or {})
         
     | 
| 
       602 
622 
     | 
    
         
             
                if text is not None:
         
     | 
| 
       603 
623 
     | 
    
         
             
                    if isinstance(text, bool):
         
     | 
| 
         @@ -617,7 +637,7 @@ def xmlSubElem( 
     | 
|
| 
       617 
637 
     | 
    
         
             
                attrib: dict | None = None,
         
     | 
| 
       618 
638 
     | 
    
         
             
                tail: str | None = None,
         
     | 
| 
       619 
639 
     | 
    
         
             
            ) -> ET.Element:
         
     | 
| 
       620 
     | 
    
         
            -
                """A custom implementation of SubElement with more arguments."""
         
     | 
| 
      
 640 
     | 
    
         
            +
                """A custom implementation of SubElement with more arguments."""  # noqa: D401
         
     | 
| 
       621 
641 
     | 
    
         
             
                xSub = ET.SubElement(parent, tag, attrib=attrib or {})
         
     | 
| 
       622 
642 
     | 
    
         
             
                if text is not None:
         
     | 
| 
       623 
643 
     | 
    
         
             
                    if isinstance(text, bool):
         
     | 
| 
         @@ -648,6 +668,7 @@ def readTextFile(path: str | Path) -> str: 
     | 
|
| 
       648 
668 
     | 
    
         | 
| 
       649 
669 
     | 
    
         
             
            def makeFileNameSafe(text: str) -> str:
         
     | 
| 
       650 
670 
     | 
    
         
             
                """Return a filename-safe string.
         
     | 
| 
      
 671 
     | 
    
         
            +
             
     | 
| 
       651 
672 
     | 
    
         
             
                See: https://unicode.org/reports/tr15/#Norm_Forms
         
     | 
| 
       652 
673 
     | 
    
         
             
                """
         
     | 
| 
       653 
674 
     | 
    
         
             
                text = unicodedata.normalize("NFKC", text).strip()
         
     | 
| 
         @@ -676,8 +697,11 @@ def openExternalPath(path: Path) -> bool: 
     | 
|
| 
       676 
697 
     | 
    
         
             
            #  Classes
         
     | 
| 
       677 
698 
     | 
    
         
             
            ##
         
     | 
| 
       678 
699 
     | 
    
         | 
| 
      
 700 
     | 
    
         
            +
            _T_Enum = TypeVar("_T_Enum", bound=Enum)
         
     | 
| 
      
 701 
     | 
    
         
            +
             
     | 
| 
      
 702 
     | 
    
         
            +
             
     | 
| 
       679 
703 
     | 
    
         
             
            class NWConfigParser(ConfigParser):
         
     | 
| 
       680 
     | 
    
         
            -
                """Common: Adapted Config Parser
         
     | 
| 
      
 704 
     | 
    
         
            +
                """Common: Adapted Config Parser.
         
     | 
| 
       681 
705 
     | 
    
         | 
| 
       682 
706 
     | 
    
         
             
                This is a subclass of the standard config parser that adds type safe
         
     | 
| 
       683 
707 
     | 
    
         
             
                helper functions, and support for lists. It also turns off
         
     | 
| 
         @@ -686,7 +710,6 @@ class NWConfigParser(ConfigParser): 
     | 
|
| 
       686 
710 
     | 
    
         | 
| 
       687 
711 
     | 
    
         
             
                def __init__(self) -> None:
         
     | 
| 
       688 
712 
     | 
    
         
             
                    super().__init__(interpolation=None)
         
     | 
| 
       689 
     | 
    
         
            -
                    return
         
     | 
| 
       690 
713 
     | 
    
         | 
| 
       691 
714 
     | 
    
         
             
                def rdStr(self, section: str, option: str, default: str) -> str:
         
     | 
| 
       692 
715 
     | 
    
         
             
                    """Read string value."""
         
     | 
| 
         @@ -737,3 +760,10 @@ class NWConfigParser(ConfigParser): 
     | 
|
| 
       737 
760 
     | 
    
         
             
                        for i in range(min(len(data), len(result))):
         
     | 
| 
       738 
761 
     | 
    
         
             
                            result[i] = checkInt(data[i].strip(), result[i])
         
     | 
| 
       739 
762 
     | 
    
         
             
                    return result
         
     | 
| 
      
 763 
     | 
    
         
            +
             
     | 
| 
      
 764 
     | 
    
         
            +
                def rdEnum(self, section: str, option: str, default: _T_Enum) -> _T_Enum:
         
     | 
| 
      
 765 
     | 
    
         
            +
                    """Read enum value."""
         
     | 
| 
      
 766 
     | 
    
         
            +
                    if self.has_option(section, option):
         
     | 
| 
      
 767 
     | 
    
         
            +
                        data = self.get(section, option, fallback="")
         
     | 
| 
      
 768 
     | 
    
         
            +
                        return type(default).__members__.get(data.upper(), default)
         
     | 
| 
      
 769 
     | 
    
         
            +
                    return default
         
     |