novelWriter 2.4.2__py3-none-any.whl → 2.5b1__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.4.2.dist-info → novelWriter-2.5b1.dist-info}/METADATA +4 -5
- {novelWriter-2.4.2.dist-info → novelWriter-2.5b1.dist-info}/RECORD +109 -101
- novelwriter/__init__.py +33 -39
- novelwriter/assets/i18n/project_en_GB.json +1 -0
- novelwriter/assets/icons/typicons_dark/icons.conf +2 -0
- novelwriter/assets/icons/typicons_dark/nw_font.svg +4 -0
- novelwriter/assets/icons/typicons_dark/nw_quote.svg +4 -0
- novelwriter/assets/icons/typicons_light/icons.conf +2 -0
- novelwriter/assets/icons/typicons_light/nw_font.svg +4 -0
- novelwriter/assets/icons/typicons_light/nw_quote.svg +4 -0
- novelwriter/assets/manual.pdf +0 -0
- novelwriter/assets/sample.zip +0 -0
- novelwriter/assets/syntax/cyberpunk_night.conf +5 -3
- novelwriter/assets/syntax/default_dark.conf +32 -18
- novelwriter/assets/syntax/default_light.conf +24 -10
- novelwriter/assets/syntax/dracula.conf +44 -0
- novelwriter/assets/syntax/grey_dark.conf +5 -4
- novelwriter/assets/syntax/grey_light.conf +5 -4
- novelwriter/assets/syntax/light_owl.conf +7 -6
- novelwriter/assets/syntax/night_owl.conf +7 -6
- novelwriter/assets/syntax/snazzy.conf +42 -0
- novelwriter/assets/syntax/solarized_dark.conf +4 -3
- novelwriter/assets/syntax/solarized_light.conf +4 -3
- novelwriter/assets/syntax/tango.conf +27 -11
- novelwriter/assets/syntax/tomorrow.conf +6 -5
- novelwriter/assets/syntax/tomorrow_night.conf +7 -6
- novelwriter/assets/syntax/tomorrow_night_blue.conf +6 -5
- novelwriter/assets/syntax/tomorrow_night_bright.conf +6 -5
- novelwriter/assets/syntax/tomorrow_night_eighties.conf +6 -5
- novelwriter/assets/text/credits_en.htm +4 -1
- novelwriter/assets/themes/cyberpunk_night.conf +2 -0
- novelwriter/assets/themes/default_dark.conf +1 -0
- novelwriter/assets/themes/default_light.conf +1 -0
- novelwriter/assets/themes/dracula.conf +47 -0
- novelwriter/assets/themes/solarized_dark.conf +1 -0
- novelwriter/assets/themes/solarized_light.conf +1 -0
- novelwriter/common.py +31 -9
- novelwriter/config.py +118 -84
- novelwriter/constants.py +40 -26
- novelwriter/core/buildsettings.py +63 -66
- novelwriter/core/coretools.py +2 -22
- novelwriter/core/docbuild.py +51 -40
- novelwriter/core/document.py +3 -5
- novelwriter/core/index.py +115 -45
- novelwriter/core/item.py +8 -19
- novelwriter/core/options.py +2 -4
- novelwriter/core/project.py +23 -57
- novelwriter/core/projectdata.py +1 -3
- novelwriter/core/projectxml.py +12 -15
- novelwriter/core/sessions.py +3 -5
- novelwriter/core/spellcheck.py +4 -9
- novelwriter/core/status.py +211 -164
- novelwriter/core/storage.py +0 -8
- novelwriter/core/tohtml.py +94 -100
- novelwriter/core/tokenizer.py +199 -112
- novelwriter/core/{tomd.py → tomarkdown.py} +97 -78
- novelwriter/core/toodt.py +212 -148
- novelwriter/core/toqdoc.py +403 -0
- novelwriter/core/tree.py +5 -7
- novelwriter/dialogs/about.py +3 -5
- novelwriter/dialogs/docmerge.py +1 -3
- novelwriter/dialogs/docsplit.py +1 -3
- novelwriter/dialogs/editlabel.py +0 -2
- novelwriter/dialogs/preferences.py +111 -88
- novelwriter/dialogs/projectsettings.py +216 -180
- novelwriter/dialogs/quotes.py +3 -4
- novelwriter/dialogs/wordlist.py +3 -9
- novelwriter/enum.py +31 -25
- novelwriter/error.py +8 -15
- novelwriter/extensions/circularprogress.py +5 -6
- novelwriter/extensions/configlayout.py +18 -18
- novelwriter/extensions/eventfilters.py +1 -5
- novelwriter/extensions/modified.py +50 -13
- novelwriter/extensions/novelselector.py +1 -3
- novelwriter/extensions/pagedsidebar.py +9 -12
- novelwriter/extensions/simpleprogress.py +1 -3
- novelwriter/extensions/statusled.py +1 -3
- novelwriter/extensions/switch.py +4 -6
- novelwriter/extensions/switchbox.py +7 -6
- novelwriter/extensions/versioninfo.py +3 -9
- novelwriter/gui/doceditor.py +132 -133
- novelwriter/gui/dochighlight.py +237 -183
- novelwriter/gui/docviewer.py +61 -97
- novelwriter/gui/docviewerpanel.py +3 -10
- novelwriter/gui/editordocument.py +1 -3
- novelwriter/gui/itemdetails.py +7 -11
- novelwriter/gui/mainmenu.py +11 -7
- novelwriter/gui/noveltree.py +11 -24
- novelwriter/gui/outline.py +11 -23
- novelwriter/gui/projtree.py +26 -43
- novelwriter/gui/search.py +1 -3
- novelwriter/gui/sidebar.py +2 -6
- novelwriter/gui/statusbar.py +6 -10
- novelwriter/gui/theme.py +26 -51
- novelwriter/guimain.py +50 -71
- novelwriter/shared.py +30 -15
- novelwriter/tools/dictionaries.py +12 -15
- novelwriter/tools/lipsum.py +2 -4
- novelwriter/tools/manusbuild.py +1 -3
- novelwriter/tools/manuscript.py +71 -144
- novelwriter/tools/manussettings.py +67 -73
- novelwriter/tools/noveldetails.py +6 -11
- novelwriter/tools/welcome.py +2 -16
- novelwriter/tools/writingstats.py +6 -9
- novelwriter/types.py +45 -3
- {novelWriter-2.4.2.dist-info → novelWriter-2.5b1.dist-info}/LICENSE.md +0 -0
- {novelWriter-2.4.2.dist-info → novelWriter-2.5b1.dist-info}/WHEEL +0 -0
- {novelWriter-2.4.2.dist-info → novelWriter-2.5b1.dist-info}/entry_points.txt +0 -0
- {novelWriter-2.4.2.dist-info → novelWriter-2.5b1.dist-info}/top_level.txt +0 -0
@@ -29,11 +29,50 @@ from pathlib import Path
|
|
29
29
|
|
30
30
|
from novelwriter.constants import nwHeadFmt, nwLabels, nwUnicode
|
31
31
|
from novelwriter.core.project import NWProject
|
32
|
-
from novelwriter.core.tokenizer import Tokenizer
|
32
|
+
from novelwriter.core.tokenizer import T_Formats, Tokenizer
|
33
33
|
|
34
34
|
logger = logging.getLogger(__name__)
|
35
35
|
|
36
36
|
|
37
|
+
# Standard Markdown
|
38
|
+
STD_MD = {
|
39
|
+
Tokenizer.FMT_B_B: "**",
|
40
|
+
Tokenizer.FMT_B_E: "**",
|
41
|
+
Tokenizer.FMT_I_B: "_",
|
42
|
+
Tokenizer.FMT_I_E: "_",
|
43
|
+
Tokenizer.FMT_D_B: "",
|
44
|
+
Tokenizer.FMT_D_E: "",
|
45
|
+
Tokenizer.FMT_U_B: "",
|
46
|
+
Tokenizer.FMT_U_E: "",
|
47
|
+
Tokenizer.FMT_M_B: "",
|
48
|
+
Tokenizer.FMT_M_E: "",
|
49
|
+
Tokenizer.FMT_SUP_B: "",
|
50
|
+
Tokenizer.FMT_SUP_E: "",
|
51
|
+
Tokenizer.FMT_SUB_B: "",
|
52
|
+
Tokenizer.FMT_SUB_E: "",
|
53
|
+
Tokenizer.FMT_STRIP: "",
|
54
|
+
}
|
55
|
+
|
56
|
+
# Extended Markdown
|
57
|
+
EXT_MD = {
|
58
|
+
Tokenizer.FMT_B_B: "**",
|
59
|
+
Tokenizer.FMT_B_E: "**",
|
60
|
+
Tokenizer.FMT_I_B: "_",
|
61
|
+
Tokenizer.FMT_I_E: "_",
|
62
|
+
Tokenizer.FMT_D_B: "~~",
|
63
|
+
Tokenizer.FMT_D_E: "~~",
|
64
|
+
Tokenizer.FMT_U_B: "",
|
65
|
+
Tokenizer.FMT_U_E: "",
|
66
|
+
Tokenizer.FMT_M_B: "==",
|
67
|
+
Tokenizer.FMT_M_E: "==",
|
68
|
+
Tokenizer.FMT_SUP_B: "^",
|
69
|
+
Tokenizer.FMT_SUP_E: "^",
|
70
|
+
Tokenizer.FMT_SUB_B: "~",
|
71
|
+
Tokenizer.FMT_SUB_E: "~",
|
72
|
+
Tokenizer.FMT_STRIP: "",
|
73
|
+
}
|
74
|
+
|
75
|
+
|
37
76
|
class ToMarkdown(Tokenizer):
|
38
77
|
"""Core: Markdown Document Writer
|
39
78
|
|
@@ -42,14 +81,11 @@ class ToMarkdown(Tokenizer):
|
|
42
81
|
supports concatenating novelWriter markup files.
|
43
82
|
"""
|
44
83
|
|
45
|
-
M_STD = 0 # Standard Markdown
|
46
|
-
M_EXT = 1 # Extended Markdown
|
47
|
-
|
48
84
|
def __init__(self, project: NWProject) -> None:
|
49
85
|
super().__init__(project)
|
50
|
-
self._genMode = self.M_STD
|
51
86
|
self._fullMD: list[str] = []
|
52
|
-
self.
|
87
|
+
self._usedNotes: dict[str, int] = {}
|
88
|
+
self._extended = True
|
53
89
|
return
|
54
90
|
|
55
91
|
##
|
@@ -65,19 +101,9 @@ class ToMarkdown(Tokenizer):
|
|
65
101
|
# Setters
|
66
102
|
##
|
67
103
|
|
68
|
-
def
|
69
|
-
"""Set the converter to use standard Markdown formatting."""
|
70
|
-
self._genMode = self.M_STD
|
71
|
-
return
|
72
|
-
|
73
|
-
def setExtendedMarkdown(self) -> None:
|
104
|
+
def setExtendedMarkdown(self, state: bool) -> None:
|
74
105
|
"""Set the converter to use Extended Markdown formatting."""
|
75
|
-
self.
|
76
|
-
return
|
77
|
-
|
78
|
-
def setPreserveBreaks(self, state: bool) -> None:
|
79
|
-
"""Preserve line breaks in paragraphs."""
|
80
|
-
self._preserveBreaks = state
|
106
|
+
self._extended = state
|
81
107
|
return
|
82
108
|
|
83
109
|
##
|
@@ -90,58 +116,21 @@ class ToMarkdown(Tokenizer):
|
|
90
116
|
|
91
117
|
def doConvert(self) -> None:
|
92
118
|
"""Convert the list of text tokens into a Markdown document."""
|
93
|
-
if self._genMode == self.M_STD:
|
94
|
-
# Standard Markdown
|
95
|
-
mdTags = {
|
96
|
-
self.FMT_B_B: "**",
|
97
|
-
self.FMT_B_E: "**",
|
98
|
-
self.FMT_I_B: "_",
|
99
|
-
self.FMT_I_E: "_",
|
100
|
-
self.FMT_D_B: "",
|
101
|
-
self.FMT_D_E: "",
|
102
|
-
self.FMT_U_B: "",
|
103
|
-
self.FMT_U_E: "",
|
104
|
-
self.FMT_M_B: "",
|
105
|
-
self.FMT_M_E: "",
|
106
|
-
self.FMT_SUP_B: "",
|
107
|
-
self.FMT_SUP_E: "",
|
108
|
-
self.FMT_SUB_B: "",
|
109
|
-
self.FMT_SUB_E: "",
|
110
|
-
}
|
111
|
-
cSkip = ""
|
112
|
-
else:
|
113
|
-
# Extended Markdown
|
114
|
-
mdTags = {
|
115
|
-
self.FMT_B_B: "**",
|
116
|
-
self.FMT_B_E: "**",
|
117
|
-
self.FMT_I_B: "_",
|
118
|
-
self.FMT_I_E: "_",
|
119
|
-
self.FMT_D_B: "~~",
|
120
|
-
self.FMT_D_E: "~~",
|
121
|
-
self.FMT_U_B: "",
|
122
|
-
self.FMT_U_E: "",
|
123
|
-
self.FMT_M_B: "==",
|
124
|
-
self.FMT_M_E: "==",
|
125
|
-
self.FMT_SUP_B: "^",
|
126
|
-
self.FMT_SUP_E: "^",
|
127
|
-
self.FMT_SUB_B: "~",
|
128
|
-
self.FMT_SUB_E: "~",
|
129
|
-
}
|
130
|
-
cSkip = nwUnicode.U_MMSP
|
131
|
-
|
132
119
|
self._result = ""
|
133
120
|
|
134
|
-
|
135
|
-
|
136
|
-
|
121
|
+
if self._extended:
|
122
|
+
mTags = EXT_MD
|
123
|
+
cSkip = nwUnicode.U_MMSP
|
124
|
+
else:
|
125
|
+
mTags = STD_MD
|
126
|
+
cSkip = ""
|
137
127
|
|
128
|
+
lines = []
|
138
129
|
for tType, _, tText, tFormat, tStyle in self._tokens:
|
139
130
|
|
140
|
-
if tType == self.
|
141
|
-
|
142
|
-
|
143
|
-
lines.append(f"{tTemp}\n\n")
|
144
|
-
para = []
|
131
|
+
if tType == self.T_TEXT:
|
132
|
+
tTemp = self._formatText(tText, tFormat, mTags).replace("\n", " \n")
|
133
|
+
lines.append(f"{tTemp}\n\n")
|
145
134
|
|
146
135
|
elif tType == self.T_TITLE:
|
147
136
|
tHead = tText.replace(nwHeadFmt.BR, "\n")
|
@@ -169,23 +158,17 @@ class ToMarkdown(Tokenizer):
|
|
169
158
|
elif tType == self.T_SKIP:
|
170
159
|
lines.append(f"{cSkip}\n\n")
|
171
160
|
|
172
|
-
elif tType == self.T_TEXT:
|
173
|
-
tTemp = tText
|
174
|
-
for pos, fmt in reversed(tFormat):
|
175
|
-
tTemp = f"{tTemp[:pos]}{mdTags[fmt]}{tTemp[pos:]}"
|
176
|
-
para.append(tTemp.rstrip())
|
177
|
-
|
178
161
|
elif tType == self.T_SYNOPSIS and self._doSynopsis:
|
179
162
|
label = self._localLookup("Synopsis")
|
180
|
-
lines.append(f"**{label}:** {tText}\n\n")
|
163
|
+
lines.append(f"**{label}:** {self._formatText(tText, tFormat, mTags)}\n\n")
|
181
164
|
|
182
165
|
elif tType == self.T_SHORT and self._doSynopsis:
|
183
166
|
label = self._localLookup("Short Description")
|
184
|
-
lines.append(f"**{label}:** {tText}\n\n")
|
167
|
+
lines.append(f"**{label}:** {self._formatText(tText, tFormat, mTags)}\n\n")
|
185
168
|
|
186
169
|
elif tType == self.T_COMMENT and self._doComments:
|
187
170
|
label = self._localLookup("Comment")
|
188
|
-
lines.append(f"**{label}:** {tText}\n\n")
|
171
|
+
lines.append(f"**{label}:** {self._formatText(tText, tFormat, mTags)}\n\n")
|
189
172
|
|
190
173
|
elif tType == self.T_KEYWORD and self._doKeywords:
|
191
174
|
lines.append(self._formatKeywords(tText, tStyle))
|
@@ -195,6 +178,27 @@ class ToMarkdown(Tokenizer):
|
|
195
178
|
|
196
179
|
return
|
197
180
|
|
181
|
+
def appendFootnotes(self) -> None:
|
182
|
+
"""Append the footnotes in the buffer."""
|
183
|
+
if self._usedNotes:
|
184
|
+
tags = EXT_MD if self._extended else STD_MD
|
185
|
+
footnotes = self._localLookup("Footnotes")
|
186
|
+
|
187
|
+
lines = []
|
188
|
+
lines.append(f"### {footnotes}\n\n")
|
189
|
+
for key, index in self._usedNotes.items():
|
190
|
+
if content := self._footnotes.get(key):
|
191
|
+
marker = f"{index}. "
|
192
|
+
text = self._formatText(*content, tags)
|
193
|
+
lines.append(f"{marker}{text}\n")
|
194
|
+
lines.append("\n")
|
195
|
+
|
196
|
+
result = "".join(lines)
|
197
|
+
self._result += result
|
198
|
+
self._fullMD.append(result)
|
199
|
+
|
200
|
+
return
|
201
|
+
|
198
202
|
def saveMarkdown(self, path: str | Path) -> None:
|
199
203
|
"""Save the data to a plain text file."""
|
200
204
|
with open(path, mode="w", encoding="utf-8") as outFile:
|
@@ -206,14 +210,31 @@ class ToMarkdown(Tokenizer):
|
|
206
210
|
"""Replace tabs with spaces."""
|
207
211
|
spaces = spaceChar*nSpaces
|
208
212
|
self._fullMD = [p.replace("\t", spaces) for p in self._fullMD]
|
209
|
-
if self.
|
210
|
-
self.
|
213
|
+
if self._keepMD:
|
214
|
+
self._markdown = [p.replace("\t", spaces) for p in self._markdown]
|
211
215
|
return
|
212
216
|
|
213
217
|
##
|
214
218
|
# Internal Functions
|
215
219
|
##
|
216
220
|
|
221
|
+
def _formatText(self, text: str, tFmt: T_Formats, tags: dict[int, str]) -> str:
|
222
|
+
"""Apply formatting tags to text."""
|
223
|
+
temp = text
|
224
|
+
for pos, fmt, data in reversed(tFmt):
|
225
|
+
md = ""
|
226
|
+
if fmt == self.FMT_FNOTE:
|
227
|
+
if data in self._footnotes:
|
228
|
+
index = len(self._usedNotes) + 1
|
229
|
+
self._usedNotes[data] = index
|
230
|
+
md = f"[{index}]"
|
231
|
+
else:
|
232
|
+
md = "[ERR]"
|
233
|
+
else:
|
234
|
+
md = tags.get(fmt, "")
|
235
|
+
temp = f"{temp[:pos]}{md}{temp[pos:]}"
|
236
|
+
return temp
|
237
|
+
|
217
238
|
def _formatKeywords(self, text: str, style: int) -> str:
|
218
239
|
"""Apply Markdown formatting to keywords."""
|
219
240
|
valid, bits, _ = self._project.index.scanThis("@"+text)
|
@@ -229,5 +250,3 @@ class ToMarkdown(Tokenizer):
|
|
229
250
|
result += " \n" if style & self.A_Z_BTMMRG else "\n\n"
|
230
251
|
|
231
252
|
return result
|
232
|
-
|
233
|
-
# END Class ToMarkdown
|