novelWriter 2.3rc1__py3-none-any.whl → 2.4__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-2.3rc1.dist-info → novelWriter-2.4.dist-info}/METADATA +5 -6
- {novelWriter-2.3rc1.dist-info → novelWriter-2.4.dist-info}/RECORD +119 -109
- {novelWriter-2.3rc1.dist-info → novelWriter-2.4.dist-info}/WHEEL +1 -1
- novelWriter-2.4.dist-info/entry_points.txt +2 -0
- novelwriter/__init__.py +17 -10
- novelwriter/assets/i18n/nw_de_DE.qm +0 -0
- novelwriter/assets/i18n/nw_en_US.qm +0 -0
- novelwriter/assets/i18n/nw_es_419.qm +0 -0
- novelwriter/assets/i18n/nw_fr_FR.qm +0 -0
- novelwriter/assets/i18n/nw_it_IT.qm +0 -0
- novelwriter/assets/i18n/nw_ja_JP.qm +0 -0
- novelwriter/assets/i18n/nw_nb_NO.qm +0 -0
- novelwriter/assets/i18n/nw_nl_NL.qm +0 -0
- novelwriter/assets/i18n/nw_pt_BR.qm +0 -0
- novelwriter/assets/i18n/nw_zh_CN.qm +0 -0
- novelwriter/assets/i18n/project_nl_NL.json +11 -0
- novelwriter/assets/i18n/project_pt_BR.json +11 -0
- novelwriter/assets/icons/none.svg +4 -0
- novelwriter/assets/icons/typicons_dark/icons.conf +4 -0
- novelwriter/assets/icons/typicons_dark/nw_tb-mark.svg +7 -0
- novelwriter/assets/icons/typicons_dark/typ_refresh-flipped.svg +1 -1
- novelwriter/assets/icons/typicons_dark/typ_refresh.svg +1 -1
- novelwriter/assets/icons/typicons_dark/typ_search-grey.svg +4 -0
- novelwriter/assets/icons/typicons_dark/typ_times.svg +1 -1
- novelwriter/assets/icons/typicons_dark/typ_unfold-hidden.svg +4 -0
- novelwriter/assets/icons/typicons_dark/typ_unfold-visible.svg +4 -0
- novelwriter/assets/icons/typicons_light/icons.conf +4 -0
- novelwriter/assets/icons/typicons_light/nw_tb-mark.svg +7 -0
- novelwriter/assets/icons/typicons_light/typ_refresh-flipped.svg +1 -1
- novelwriter/assets/icons/typicons_light/typ_refresh.svg +1 -1
- novelwriter/assets/icons/typicons_light/typ_search-grey.svg +4 -0
- novelwriter/assets/icons/typicons_light/typ_times.svg +1 -1
- novelwriter/assets/icons/typicons_light/typ_unfold-hidden.svg +4 -0
- novelwriter/assets/icons/typicons_light/typ_unfold-visible.svg +4 -0
- novelwriter/assets/manual.pdf +0 -0
- novelwriter/assets/sample.zip +0 -0
- novelwriter/assets/syntax/cyberpunk_night.conf +26 -0
- novelwriter/assets/syntax/default_dark.conf +1 -0
- novelwriter/assets/syntax/default_light.conf +1 -0
- novelwriter/assets/syntax/grey_dark.conf +1 -0
- novelwriter/assets/syntax/grey_light.conf +1 -0
- novelwriter/assets/syntax/light_owl.conf +1 -0
- novelwriter/assets/syntax/night_owl.conf +1 -0
- novelwriter/assets/syntax/solarized_dark.conf +1 -0
- novelwriter/assets/syntax/solarized_light.conf +1 -0
- novelwriter/assets/syntax/tango.conf +23 -0
- novelwriter/assets/syntax/tomorrow.conf +1 -0
- novelwriter/assets/syntax/tomorrow_night.conf +1 -0
- novelwriter/assets/syntax/tomorrow_night_blue.conf +1 -0
- novelwriter/assets/syntax/tomorrow_night_bright.conf +1 -0
- novelwriter/assets/syntax/tomorrow_night_eighties.conf +1 -0
- novelwriter/assets/text/credits_en.htm +25 -23
- novelwriter/assets/themes/cyberpunk_night.conf +29 -0
- novelwriter/common.py +12 -4
- novelwriter/config.py +47 -16
- novelwriter/constants.py +5 -6
- novelwriter/core/buildsettings.py +64 -44
- novelwriter/core/coretools.py +97 -13
- novelwriter/core/docbuild.py +74 -7
- novelwriter/core/document.py +24 -3
- novelwriter/core/index.py +31 -112
- novelwriter/core/project.py +11 -15
- novelwriter/core/projectxml.py +3 -2
- novelwriter/core/sessions.py +2 -2
- novelwriter/core/spellcheck.py +3 -3
- novelwriter/core/status.py +6 -5
- novelwriter/core/storage.py +16 -6
- novelwriter/core/tohtml.py +22 -25
- novelwriter/core/tokenizer.py +417 -237
- novelwriter/core/tomd.py +17 -8
- novelwriter/core/toodt.py +386 -351
- novelwriter/core/tree.py +8 -8
- novelwriter/dialogs/about.py +10 -12
- novelwriter/dialogs/docmerge.py +17 -14
- novelwriter/dialogs/docsplit.py +20 -19
- novelwriter/dialogs/editlabel.py +5 -4
- novelwriter/dialogs/preferences.py +32 -40
- novelwriter/dialogs/projectsettings.py +31 -28
- novelwriter/dialogs/quotes.py +10 -9
- novelwriter/dialogs/wordlist.py +18 -15
- novelwriter/enum.py +17 -14
- novelwriter/error.py +14 -12
- novelwriter/extensions/circularprogress.py +12 -8
- novelwriter/extensions/configlayout.py +23 -3
- novelwriter/extensions/modified.py +51 -2
- novelwriter/extensions/pagedsidebar.py +16 -14
- novelwriter/extensions/simpleprogress.py +3 -1
- novelwriter/extensions/statusled.py +3 -1
- novelwriter/extensions/switch.py +10 -9
- novelwriter/extensions/switchbox.py +14 -13
- novelwriter/extensions/versioninfo.py +1 -1
- novelwriter/gui/doceditor.py +433 -496
- novelwriter/gui/dochighlight.py +54 -33
- novelwriter/gui/docviewer.py +162 -175
- novelwriter/gui/docviewerpanel.py +20 -37
- novelwriter/gui/editordocument.py +15 -4
- novelwriter/gui/itemdetails.py +51 -54
- novelwriter/gui/mainmenu.py +37 -17
- novelwriter/gui/noveltree.py +31 -37
- novelwriter/gui/outline.py +120 -98
- novelwriter/gui/projtree.py +114 -112
- novelwriter/gui/search.py +362 -0
- novelwriter/gui/sidebar.py +36 -45
- novelwriter/gui/statusbar.py +14 -14
- novelwriter/gui/theme.py +116 -34
- novelwriter/guimain.py +216 -207
- novelwriter/shared.py +31 -6
- novelwriter/text/counting.py +138 -0
- novelwriter/tools/dictionaries.py +15 -14
- novelwriter/tools/lipsum.py +20 -17
- novelwriter/tools/manusbuild.py +43 -35
- novelwriter/tools/manuscript.py +381 -104
- novelwriter/tools/manussettings.py +263 -125
- novelwriter/tools/noveldetails.py +21 -19
- novelwriter/tools/welcome.py +59 -57
- novelwriter/tools/writingstats.py +61 -55
- novelwriter/types.py +90 -0
- novelWriter-2.3rc1.dist-info/entry_points.txt +0 -5
- novelwriter/core/__init__.py +0 -3
- novelwriter/dialogs/__init__.py +0 -3
- novelwriter/extensions/__init__.py +0 -3
- novelwriter/gui/__init__.py +0 -3
- novelwriter/tools/__init__.py +0 -3
- {novelWriter-2.3rc1.dist-info → novelWriter-2.4.dist-info}/LICENSE.md +0 -0
- {novelWriter-2.3rc1.dist-info → novelWriter-2.4.dist-info}/top_level.txt +0 -0
novelwriter/gui/dochighlight.py
CHANGED
@@ -44,16 +44,21 @@ logger = logging.getLogger(__name__)
|
|
44
44
|
|
45
45
|
SPELLRX = QRegularExpression(r"\b[^\s\-\+\/–—\[\]:]+\b")
|
46
46
|
SPELLRX.setPatternOptions(QRegularExpression.UseUnicodePropertiesOption)
|
47
|
+
SPELLSC = QRegularExpression(nwRegEx.FMT_SC)
|
48
|
+
SPELLSC.setPatternOptions(QRegularExpression.UseUnicodePropertiesOption)
|
49
|
+
SPELLSV = QRegularExpression(nwRegEx.FMT_SV)
|
50
|
+
SPELLSV.setPatternOptions(QRegularExpression.UseUnicodePropertiesOption)
|
47
51
|
|
52
|
+
BLOCK_NONE = 0
|
53
|
+
BLOCK_TEXT = 1
|
54
|
+
BLOCK_META = 2
|
55
|
+
BLOCK_TITLE = 4
|
48
56
|
|
49
|
-
class GuiDocHighlighter(QSyntaxHighlighter):
|
50
57
|
|
51
|
-
|
58
|
+
class GuiDocHighlighter(QSyntaxHighlighter):
|
52
59
|
|
53
|
-
|
54
|
-
|
55
|
-
BLOCK_META = 2
|
56
|
-
BLOCK_TITLE = 4
|
60
|
+
__slots__ = ("_tHandle", "_isInactive", "_spellCheck", "_spellErr",
|
61
|
+
"_hRules", "_hStyles", "_rxRules")
|
57
62
|
|
58
63
|
def __init__(self, document: QTextDocument) -> None:
|
59
64
|
super().__init__(document)
|
@@ -67,6 +72,7 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
|
67
72
|
|
68
73
|
self._hRules: list[tuple[str, dict]] = []
|
69
74
|
self._hStyles: dict[str, QTextCharFormat] = {}
|
75
|
+
self._rxRules: list[tuple[QRegularExpression, dict[str, QTextCharFormat]]] = []
|
70
76
|
|
71
77
|
self.initHighlighter()
|
72
78
|
|
@@ -90,10 +96,10 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
|
90
96
|
"header2": self._makeFormat(SHARED.theme.colHead, "bold", 1.6),
|
91
97
|
"header3": self._makeFormat(SHARED.theme.colHead, "bold", 1.4),
|
92
98
|
"header4": self._makeFormat(SHARED.theme.colHead, "bold", 1.2),
|
93
|
-
"
|
94
|
-
"
|
95
|
-
"
|
96
|
-
"
|
99
|
+
"head1h": self._makeFormat(SHARED.theme.colHeadH, "bold", 1.8),
|
100
|
+
"head2h": self._makeFormat(SHARED.theme.colHeadH, "bold", 1.6),
|
101
|
+
"head3h": self._makeFormat(SHARED.theme.colHeadH, "bold", 1.4),
|
102
|
+
"head4h": self._makeFormat(SHARED.theme.colHeadH, "bold", 1.2),
|
97
103
|
"bold": self._makeFormat(colEmph, "bold"),
|
98
104
|
"italic": self._makeFormat(colEmph, "italic"),
|
99
105
|
"strike": self._makeFormat(SHARED.theme.colHidden, "strike"),
|
@@ -116,7 +122,7 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
|
116
122
|
# Cache Spell Error Format
|
117
123
|
self._spellErr = QTextCharFormat()
|
118
124
|
self._spellErr.setUnderlineColor(SHARED.theme.colSpell)
|
119
|
-
self._spellErr.setUnderlineStyle(QTextCharFormat.SpellCheckUnderline)
|
125
|
+
self._spellErr.setUnderlineStyle(QTextCharFormat.UnderlineStyle.SpellCheckUnderline)
|
120
126
|
|
121
127
|
# Multiple or Trailing Spaces
|
122
128
|
if CONFIG.showMultiSpaces:
|
@@ -218,11 +224,11 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
|
218
224
|
))
|
219
225
|
|
220
226
|
# Build a QRegExp for each highlight pattern
|
221
|
-
self.
|
227
|
+
self._rxRules = []
|
222
228
|
for regEx, regRules in self._hRules:
|
223
229
|
hReg = QRegularExpression(regEx)
|
224
230
|
hReg.setPatternOptions(QRegularExpression.UseUnicodePropertiesOption)
|
225
|
-
self.
|
231
|
+
self._rxRules.append((hReg, regRules))
|
226
232
|
|
227
233
|
return
|
228
234
|
|
@@ -272,12 +278,12 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
|
272
278
|
is significantly faster than running the regex checks used for
|
273
279
|
text paragraphs.
|
274
280
|
"""
|
275
|
-
self.setCurrentBlockState(
|
281
|
+
self.setCurrentBlockState(BLOCK_NONE)
|
276
282
|
if self._tHandle is None or not text:
|
277
283
|
return
|
278
284
|
|
279
285
|
if text.startswith("@"): # Keywords and commands
|
280
|
-
self.setCurrentBlockState(
|
286
|
+
self.setCurrentBlockState(BLOCK_META)
|
281
287
|
index = SHARED.project.index
|
282
288
|
isValid, bits, pos = index.scanThis(text)
|
283
289
|
isGood = index.checkThese(bits, self._tHandle)
|
@@ -300,35 +306,39 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
|
300
306
|
# so we force a return here
|
301
307
|
return
|
302
308
|
|
303
|
-
elif text.startswith(("# ", "#! ", "## ", "##! ", "### ", "#### ")):
|
304
|
-
self.setCurrentBlockState(
|
309
|
+
elif text.startswith(("# ", "#! ", "## ", "##! ", "### ", "###! ", "#### ")):
|
310
|
+
self.setCurrentBlockState(BLOCK_TITLE)
|
305
311
|
|
306
|
-
if text.startswith("# "): #
|
307
|
-
self.setFormat(0, 1, self._hStyles["
|
312
|
+
if text.startswith("# "): # Heading 1
|
313
|
+
self.setFormat(0, 1, self._hStyles["head1h"])
|
308
314
|
self.setFormat(1, len(text), self._hStyles["header1"])
|
309
315
|
|
310
|
-
elif text.startswith("## "): #
|
311
|
-
self.setFormat(0, 2, self._hStyles["
|
316
|
+
elif text.startswith("## "): # Heading 2
|
317
|
+
self.setFormat(0, 2, self._hStyles["head2h"])
|
312
318
|
self.setFormat(2, len(text), self._hStyles["header2"])
|
313
319
|
|
314
|
-
elif text.startswith("### "): #
|
315
|
-
self.setFormat(0, 3, self._hStyles["
|
320
|
+
elif text.startswith("### "): # Heading 3
|
321
|
+
self.setFormat(0, 3, self._hStyles["head3h"])
|
316
322
|
self.setFormat(3, len(text), self._hStyles["header3"])
|
317
323
|
|
318
|
-
elif text.startswith("#### "): #
|
319
|
-
self.setFormat(0, 4, self._hStyles["
|
324
|
+
elif text.startswith("#### "): # Heading 4
|
325
|
+
self.setFormat(0, 4, self._hStyles["head4h"])
|
320
326
|
self.setFormat(4, len(text), self._hStyles["header4"])
|
321
327
|
|
322
328
|
elif text.startswith("#! "): # Title
|
323
|
-
self.setFormat(0, 2, self._hStyles["
|
329
|
+
self.setFormat(0, 2, self._hStyles["head1h"])
|
324
330
|
self.setFormat(2, len(text), self._hStyles["header1"])
|
325
331
|
|
326
332
|
elif text.startswith("##! "): # Unnumbered
|
327
|
-
self.setFormat(0, 3, self._hStyles["
|
333
|
+
self.setFormat(0, 3, self._hStyles["head2h"])
|
328
334
|
self.setFormat(3, len(text), self._hStyles["header2"])
|
329
335
|
|
336
|
+
elif text.startswith("###! "): # Alternative Scene
|
337
|
+
self.setFormat(0, 4, self._hStyles["head3h"])
|
338
|
+
self.setFormat(4, len(text), self._hStyles["header3"])
|
339
|
+
|
330
340
|
elif text.startswith("%"): # Comments
|
331
|
-
self.setCurrentBlockState(
|
341
|
+
self.setCurrentBlockState(BLOCK_TEXT)
|
332
342
|
cStyle, _, cPos = processComment(text)
|
333
343
|
if cStyle == nwComment.PLAIN:
|
334
344
|
self.setFormat(0, len(text), self._hStyles["hidden"])
|
@@ -353,8 +363,8 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
|
353
363
|
return
|
354
364
|
|
355
365
|
# Regular Text
|
356
|
-
self.setCurrentBlockState(
|
357
|
-
for rX, xFmt in self.
|
366
|
+
self.setCurrentBlockState(BLOCK_TEXT)
|
367
|
+
for rX, xFmt in self._rxRules:
|
358
368
|
rxItt = rX.globalMatch(text, 0)
|
359
369
|
while rxItt.hasNext():
|
360
370
|
rxMatch = rxItt.next()
|
@@ -398,16 +408,16 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
|
398
408
|
if style is not None:
|
399
409
|
styles = style.split(",")
|
400
410
|
if "bold" in styles:
|
401
|
-
charFormat.setFontWeight(QFont.Bold)
|
411
|
+
charFormat.setFontWeight(QFont.Weight.Bold)
|
402
412
|
if "italic" in styles:
|
403
413
|
charFormat.setFontItalic(True)
|
404
414
|
if "strike" in styles:
|
405
415
|
charFormat.setFontStrikeOut(True)
|
406
416
|
if "errline" in styles:
|
407
417
|
charFormat.setUnderlineColor(SHARED.theme.colError)
|
408
|
-
charFormat.setUnderlineStyle(QTextCharFormat.SpellCheckUnderline)
|
418
|
+
charFormat.setUnderlineStyle(QTextCharFormat.UnderlineStyle.SpellCheckUnderline)
|
409
419
|
if "background" in styles and color is not None:
|
410
|
-
charFormat.setBackground(QBrush(color, Qt.SolidPattern))
|
420
|
+
charFormat.setBackground(QBrush(color, Qt.BrushStyle.SolidPattern))
|
411
421
|
|
412
422
|
if size is not None:
|
413
423
|
charFormat.setFontPointSize(int(round(size*CONFIG.textSize)))
|
@@ -435,6 +445,17 @@ class TextBlockData(QTextBlockUserData):
|
|
435
445
|
"""Run the spell checker and cache the result, and return the
|
436
446
|
list of spell check errors.
|
437
447
|
"""
|
448
|
+
if "[" in text:
|
449
|
+
# Strip shortcodes
|
450
|
+
for rX in [SPELLSC, SPELLSV]:
|
451
|
+
rxItt = rX.globalMatch(text, 0)
|
452
|
+
while rxItt.hasNext():
|
453
|
+
rxMatch = rxItt.next()
|
454
|
+
xPos = rxMatch.capturedStart(0)
|
455
|
+
xLen = rxMatch.capturedLength(0)
|
456
|
+
xEnd = rxMatch.capturedEnd(0)
|
457
|
+
text = text[:xPos] + " "*xLen + text[xEnd:]
|
458
|
+
|
438
459
|
self._spellErrors = []
|
439
460
|
rxSpell = SPELLRX.globalMatch(text.replace("_", " "), 0)
|
440
461
|
while rxSpell.hasNext():
|