@@ -6,13 +6,25 @@
|
|||||||
|
|
||||||
novelWriter is a markdown-like text editor designed fro writing novels and larger projects of many smaller plain text documents.
|
novelWriter is a markdown-like text editor designed fro writing novels and larger projects of many smaller plain text documents.
|
||||||
|
|
||||||
It is under initial development, and not all planned features are included, but it is perfectly usable in the current state.
|
The documentation is available here: [novelwriter.readthedocs.io](https://novelwriter.readthedocs.io/).
|
||||||
|
|
||||||
|
### Note
|
||||||
|
|
||||||
|
The application is under initial development, and not all planned features are included.
|
||||||
|
The core functionality is, however, in place and has been used for a while by the author and collaborators.
|
||||||
|
|
||||||
|
New features are being added regularly, until the core toolset is complete.
|
||||||
|
When all planned initial features are in place, a release 1.0 will be made.
|
||||||
|
Until then, novelWriter is in a pre-release alpha state, and should be considered experimental.
|
||||||
|
If you do use it for real projects, please run backups frequently to avoid data losses.
|
||||||
|
There is a built in backup feature that can pack the entire project into a zip file on close.
|
||||||
|
Please check the documentation for further details.
|
||||||
|
|
||||||
|
## Implementation
|
||||||
|
|
||||||
The application is written in Python3 using Qt5 via PyQt5.
|
The application is written in Python3 using Qt5 via PyQt5.
|
||||||
It is developed on Linux, but it should in principle work fine on other operating systems as well as long as dependencies are met.
|
It is developed on Linux, but it should in principle work fine on other operating systems as well as long as dependencies are met.
|
||||||
|
|
||||||
The documentation is available here: [novelwriter.readthedocs.io](https://novelwriter.readthedocs.io/).
|
|
||||||
|
|
||||||
The application can be started from the source folder with the command:
|
The application can be started from the source folder with the command:
|
||||||
```
|
```
|
||||||
./novelWriter.py
|
./novelWriter.py
|
||||||
@@ -22,7 +34,7 @@ It also takes a few parameters for debugging and such, which can be listed with
|
|||||||
|
|
||||||
There are no launcher icons yet.
|
There are no launcher icons yet.
|
||||||
Consult your operating system documentation for how to make those.
|
Consult your operating system documentation for how to make those.
|
||||||
I will add those later, and would appreciate any assistance from people working on Windows and MacOS as I don't use either of those operating systems.
|
These will be added at some point, and I would appreciate any assistance from people working on Windows and MacOS as I don't use either of those operating systems.
|
||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
@@ -38,6 +50,7 @@ These are optional, but recommended:
|
|||||||
* `python3-enchant` for spell checking
|
* `python3-enchant` for spell checking
|
||||||
* `python3-pycountry` for translating language codes to language names
|
* `python3-pycountry` for translating language codes to language names
|
||||||
* `python3-latexcodec` for escaping unicode characters in LaTeX export
|
* `python3-latexcodec` for escaping unicode characters in LaTeX export
|
||||||
|
* `python3-pandoc` for additional exports to Word, Open Office, eBooks, etc.
|
||||||
|
|
||||||
Alternatively, the packages can be installed with `pip` by running
|
Alternatively, the packages can be installed with `pip` by running
|
||||||
```
|
```
|
||||||
@@ -53,13 +66,15 @@ python3 -m pip install lxml
|
|||||||
python3 -m pip install pyenchant
|
python3 -m pip install pyenchant
|
||||||
python3 -m pip install pycountry
|
python3 -m pip install pycountry
|
||||||
python3 -m pip install latexcodec
|
python3 -m pip install latexcodec
|
||||||
|
python3 -m pip install pypandoc
|
||||||
```
|
```
|
||||||
This may be necessary on Windows, as `pyenchant` may cause problems.
|
On Windows,`pyenchant` may cause problems.
|
||||||
I'm looking for a good alternative for spell checking.
|
I'm looking for a good alternative for spell checking.
|
||||||
|
|
||||||
Note: On Windows, make sure Python3 is in your PATH if you want to launch novelWriter from command line.
|
Note: On Windows, make sure Python3 is in your PATH if you want to launch novelWriter from command line.
|
||||||
You can also right click the `novelWriter.py` file, create a shortcut.
|
You can also right click the `novelWriter.py` file, create a shortcut, then right click again, select "Properties" and change the target to your python executable and `novelWriter.py`.
|
||||||
Then right click again, select "Properties" and change the target to your python executable and `novelWriter.py`.
|
|
||||||
|
It should look something like this:
|
||||||
```
|
```
|
||||||
C:\...\AppData\Local\Programs\Python\Python38\python.exe novelWriter.py
|
C:\...\AppData\Local\Programs\Python\Python38\python.exe novelWriter.py
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -105,3 +105,11 @@ def splitVersionNumber(vString):
|
|||||||
vInt = vMajor*10000 + vMinor*100 + vPatch
|
vInt = vMajor*10000 + vMinor*100 + vPatch
|
||||||
|
|
||||||
return [vMajor, vMinor, vPatch, vInt]
|
return [vMajor, vMinor, vPatch, vInt]
|
||||||
|
|
||||||
|
def packageRefURL(packName):
|
||||||
|
from nw.constants import nwDependencies
|
||||||
|
if packName in nwDependencies.PACKS.keys():
|
||||||
|
return "<a href=\"%s\">%s</a>" % (
|
||||||
|
nwDependencies.PACKS[packName]["site"], packName
|
||||||
|
)
|
||||||
|
return packName
|
||||||
|
|||||||
+2
-2
@@ -74,11 +74,11 @@ class Config:
|
|||||||
## Text Editor
|
## Text Editor
|
||||||
self.textFont = None
|
self.textFont = None
|
||||||
self.textSize = 12
|
self.textSize = 12
|
||||||
self.textFixedW = True
|
self.textFixedW = False
|
||||||
self.textWidth = 600
|
self.textWidth = 600
|
||||||
self.textMargin = 40
|
self.textMargin = 40
|
||||||
self.tabWidth = 40
|
self.tabWidth = 40
|
||||||
self.doJustify = True
|
self.doJustify = False
|
||||||
self.autoSelect = True
|
self.autoSelect = True
|
||||||
self.doReplace = True
|
self.doReplace = True
|
||||||
self.doReplaceSQuote = True
|
self.doReplaceSQuote = True
|
||||||
|
|||||||
@@ -80,6 +80,42 @@ class nwLabels():
|
|||||||
|
|
||||||
# END Class nwLabels
|
# END Class nwLabels
|
||||||
|
|
||||||
|
class nwDependencies():
|
||||||
|
"""Python package dependencies and their reference links.
|
||||||
|
"""
|
||||||
|
PACKS = {
|
||||||
|
"pyqt5" : {
|
||||||
|
"site" : "",
|
||||||
|
"docs" : "",
|
||||||
|
},
|
||||||
|
"appdirs" : {
|
||||||
|
"site" : "",
|
||||||
|
"docs" : "",
|
||||||
|
},
|
||||||
|
"lxml" : {
|
||||||
|
"site" : "",
|
||||||
|
"docs" : "",
|
||||||
|
},
|
||||||
|
"pyenchant" : {
|
||||||
|
"site" : "",
|
||||||
|
"docs" : "",
|
||||||
|
},
|
||||||
|
"pycountry" : {
|
||||||
|
"site" : "",
|
||||||
|
"docs" : "",
|
||||||
|
},
|
||||||
|
"latexcodec" : {
|
||||||
|
"site" : "https://pypi.org/project/latexcodec/",
|
||||||
|
"docs" : "https://latexcodec.readthedocs.io/en/latest/",
|
||||||
|
},
|
||||||
|
"pypandoc" : {
|
||||||
|
"site" : "https://pypi.org/project/pypandoc/",
|
||||||
|
"docs" : "https://pypi.org/project/pypandoc/",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
# END Class nwDependencies
|
||||||
|
|
||||||
class nwQuotes():
|
class nwQuotes():
|
||||||
"""Allowed quotation marks.
|
"""Allowed quotation marks.
|
||||||
Source: https://en.wikipedia.org/wiki/Quotation_mark
|
Source: https://en.wikipedia.org/wiki/Quotation_mark
|
||||||
|
|||||||
+9
-4
@@ -31,6 +31,7 @@ from nw.convert.file.html import HtmlFile
|
|||||||
from nw.convert.file.markdown import MarkdownFile
|
from nw.convert.file.markdown import MarkdownFile
|
||||||
from nw.convert.file.latex import LaTeXFile
|
from nw.convert.file.latex import LaTeXFile
|
||||||
from nw.convert.file.concat import ConcatFile
|
from nw.convert.file.concat import ConcatFile
|
||||||
|
from nw.common import packageRefURL
|
||||||
from nw.constants import nwFiles
|
from nw.constants import nwFiles
|
||||||
from nw.enum import nwItemType, nwAlert
|
from nw.enum import nwItemType, nwAlert
|
||||||
|
|
||||||
@@ -191,9 +192,11 @@ class GuiExport(QDialog):
|
|||||||
# Check that encoding was successful
|
# Check that encoding was successful
|
||||||
if outFile.texCodecFail:
|
if outFile.texCodecFail:
|
||||||
self.theParent.makeAlert((
|
self.theParent.makeAlert((
|
||||||
"Failed to escape unicode characters while writing LaTeX file. "
|
"Failed to escape unicode characters while writing LaTeX file. The generated "
|
||||||
"The genrated .tex file may not build properly. "
|
".tex file may not build properly. Make sure the python package '{package:s}' "
|
||||||
"Make sure the python package 'latexcodec' is installed and working."
|
"is installed and working."
|
||||||
|
).format(
|
||||||
|
package = packageRefURL("latexcodec")
|
||||||
), nwAlert.WARN)
|
), nwAlert.WARN)
|
||||||
|
|
||||||
if eFormat != GuiExportMain.FMT_PDOC:
|
if eFormat != GuiExportMain.FMT_PDOC:
|
||||||
@@ -227,8 +230,10 @@ class GuiExport(QDialog):
|
|||||||
import pypandoc
|
import pypandoc
|
||||||
except:
|
except:
|
||||||
self.theParent.makeAlert((
|
self.theParent.makeAlert((
|
||||||
"Could not load the 'pypandoc' package. "
|
"Could not load the '{package:s}' package. "
|
||||||
"Make sure it is installed, and try again."
|
"Make sure it is installed, and try again."
|
||||||
|
).format(
|
||||||
|
package = packageRefURL("pypandoc")
|
||||||
), nwAlert.ERROR)
|
), nwAlert.ERROR)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|||||||
+8
-8
@@ -76,7 +76,7 @@ class GuiMainMenu(QMenuBar):
|
|||||||
for n in range(len(self.mainConf.recentList)):
|
for n in range(len(self.mainConf.recentList)):
|
||||||
recentProject = self.mainConf.recentList[n]
|
recentProject = self.mainConf.recentList[n]
|
||||||
if recentProject == "": continue
|
if recentProject == "": continue
|
||||||
menuItem = QAction("%d: %s" % (n,recentProject), self.projMenu)
|
menuItem = QAction("%s" % recentProject, self.projMenu)
|
||||||
menuItem.triggered.connect(lambda menuItem, n=n : self.openRecentProject(menuItem, n))
|
menuItem.triggered.connect(lambda menuItem, n=n : self.openRecentProject(menuItem, n))
|
||||||
self.recentMenu.addAction(menuItem)
|
self.recentMenu.addAction(menuItem)
|
||||||
return
|
return
|
||||||
@@ -216,13 +216,13 @@ class GuiMainMenu(QMenuBar):
|
|||||||
# Project > New Root
|
# Project > New Root
|
||||||
rootMenu = self.projMenu.addMenu("Create Root Folder")
|
rootMenu = self.projMenu.addMenu("Create Root Folder")
|
||||||
self.rootItems = {}
|
self.rootItems = {}
|
||||||
self.rootItems[nwItemClass.NOVEL] = QAction("Novel Root", rootMenu)
|
self.rootItems[nwItemClass.NOVEL] = QAction("Novel Root", rootMenu)
|
||||||
self.rootItems[nwItemClass.PLOT] = QAction("Plot Root", rootMenu)
|
self.rootItems[nwItemClass.PLOT] = QAction("Plot Root", rootMenu)
|
||||||
self.rootItems[nwItemClass.CHARACTER] = QAction("Character Root", rootMenu)
|
self.rootItems[nwItemClass.CHARACTER] = QAction("Character Root", rootMenu)
|
||||||
self.rootItems[nwItemClass.WORLD] = QAction("Location Root", rootMenu)
|
self.rootItems[nwItemClass.WORLD] = QAction("Location Root", rootMenu)
|
||||||
self.rootItems[nwItemClass.TIMELINE] = QAction("Timeline Root", rootMenu)
|
self.rootItems[nwItemClass.TIMELINE] = QAction("Timeline Root", rootMenu)
|
||||||
self.rootItems[nwItemClass.OBJECT] = QAction("Object Root", rootMenu)
|
self.rootItems[nwItemClass.OBJECT] = QAction("Object Root", rootMenu)
|
||||||
self.rootItems[nwItemClass.CUSTOM] = QAction("Custom Root", rootMenu)
|
self.rootItems[nwItemClass.CUSTOM] = QAction("Custom Root", rootMenu)
|
||||||
nCount = 0
|
nCount = 0
|
||||||
for itemClass in self.rootItems.keys():
|
for itemClass in self.rootItems.keys():
|
||||||
nCount += 1 # This forces the lambdas to be unique
|
nCount += 1 # This forces the lambdas to be unique
|
||||||
|
|||||||
@@ -4,3 +4,4 @@ lxml
|
|||||||
pyenchant
|
pyenchant
|
||||||
pycountry
|
pycountry
|
||||||
latexcodec
|
latexcodec
|
||||||
|
pypandoc
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
[Main]
|
[Main]
|
||||||
timestamp = 2019-06-27 20:26:43
|
timestamp = 2019-10-29 10:40:19
|
||||||
theme = default
|
theme = default
|
||||||
syntax = default_light
|
syntax = default_light
|
||||||
|
|
||||||
@@ -16,11 +16,11 @@ autosavedoc = 30
|
|||||||
[Editor]
|
[Editor]
|
||||||
textfont = None
|
textfont = None
|
||||||
textsize = 12
|
textsize = 12
|
||||||
fixedwidth = True
|
fixedwidth = False
|
||||||
width = 600
|
width = 600
|
||||||
margin = 40
|
margin = 40
|
||||||
tabwidth = 40
|
tabwidth = 40
|
||||||
justify = True
|
justify = False
|
||||||
autoselect = True
|
autoselect = True
|
||||||
autoreplace = True
|
autoreplace = True
|
||||||
repsquotes = True
|
repsquotes = True
|
||||||
|
|||||||
Reference in New Issue
Block a user