diff --git a/README.md b/README.md index 067e4f6b..0325cb84 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![codecov](https://codecov.io/gh/vkbo/novelWriter/branch/master/graph/badge.svg)](https://codecov.io/gh/vkbo/novelWriter) [![Documentation Status](https://readthedocs.org/projects/novelwriter/badge/?version=latest)](https://novelwriter.readthedocs.io/en/latest/?badge=latest) -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 for writing novels and larger projects of many smaller plain text documents. The documentation is available here: [novelwriter.readthedocs.io](https://novelwriter.readthedocs.io/). @@ -20,6 +20,34 @@ If you do use it for real projects, please run backups frequently to avoid data 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. +## Markdown Flavour + +novelWriter is **not** a full-feature Markdown editor. +It allows for a minimal set of formatting needed for writing text documents for novels. +These are currently limited to: + +* Headings level 1 to 4 using the `#` syntax only. +* Bold, italic and underline text. +* Hard line breaks using two or more spaces at the end of a line. + +That is it. +Features not supported in the editor are also not exported when using the export tool. + +In addition, novelWriter adds the following, which is otherwise not supported by Markdown: + +* A line starting with `%` is treated as a comment and not rendered on exports unless requested. + Comments do not count towards the word count. +* A set of meta data keyword/value sets starting with the character `@`. + This is used for tagging and inter-linking documents. +* Non-breaking spaces are supported as long as your system is using at least Qt 5.9. + For earlier version, non-breaking spaces are converted to normal spaces when saving the document. + This is done by the Qt library. +* Tabs may be rendered, depending on export format. + +The core export format that should render properly all supported features is the HTML export. +This format also forms the basis of conversion to Office type document formats with Pandoc. +Note that Pandoc itself strips some formatting from the document during conversion, so the final result may be different than expected. + ## Implementation The application is written in Python3 using Qt5 via PyQt5. diff --git a/nw/convert/text/tomarkdown.py b/nw/convert/text/tomarkdown.py index c9ea57b7..da65d863 100644 --- a/nw/convert/text/tomarkdown.py +++ b/nw/convert/text/tomarkdown.py @@ -85,7 +85,8 @@ class ToMarkdown(Tokenizer): # indicating a new paragraph. if tType == self.T_EMPTY: if len(thisPar) > 0: - self.theResult += "%s\n\n" % " ".join(thisPar) + tTemp = "\n".join(thisPar) + self.theResult += "%s\n\n" % tTemp.rstrip() thisPar = [] elif tType == self.T_HEAD1: @@ -104,7 +105,7 @@ class ToMarkdown(Tokenizer): self.theResult += "%s\n\n" % tText elif tType == self.T_SKIP: - self.theResult += "\n\n\n\n" + self.theResult += "\n\n\n" elif tType == self.T_TEXT: thisPar.append(tText) diff --git a/nw/convert/text/totext.py b/nw/convert/text/totext.py index fa528199..1f98d5e2 100644 --- a/nw/convert/text/totext.py +++ b/nw/convert/text/totext.py @@ -122,8 +122,8 @@ class ToText(Tokenizer): tText = self._centreText(tText,self.wordWrap) self.theResult += "%s\n\n" % tText - elif tType == self.T_SEP: - self.theResult += "\n\n\n\n" + elif tType == self.T_SKIP: + self.theResult += "\n\n\n" elif tType == self.T_TEXT: thisPar.append(tText) diff --git a/nw/gui/dialogs/configeditor.py b/nw/gui/dialogs/configeditor.py index 8d3d4b0f..89bf6992 100644 --- a/nw/gui/dialogs/configeditor.py +++ b/nw/gui/dialogs/configeditor.py @@ -44,7 +44,6 @@ class GuiConfigEditor(QDialog): self.setWindowTitle("Preferences") self.guiDeco = self.theParent.theTheme.loadDecoration("settings",(64,64)) - self.theProject.countStatus() self.tabMain = GuiConfigEditGeneral(self.theParent) self.tabEditor = GuiConfigEditEditor(self.theParent) diff --git a/nw/gui/dialogs/export.py b/nw/gui/dialogs/export.py index 15a8ed7a..8d580f87 100644 --- a/nw/gui/dialogs/export.py +++ b/nw/gui/dialogs/export.py @@ -50,7 +50,6 @@ class GuiExport(QDialog): self.guiDeco = self.theParent.theTheme.loadDecoration("export",(64,64)) - self.theProject.countStatus() self.tabMain = GuiExportMain(self.theParent, self.theProject, self.optState) self.tabPandoc = GuiExportPandoc(self.theParent, self.theProject, self.optState) diff --git a/nw/gui/elements/doceditor.py b/nw/gui/elements/doceditor.py index c8b69df7..3e0aba3c 100644 --- a/nw/gui/elements/doceditor.py +++ b/nw/gui/elements/doceditor.py @@ -229,6 +229,14 @@ class GuiDocEditor(QTextEdit): return True + def replaceText(self, theText): + """Replaces the text of the current document with the provided + text. This also clears undo history. + """ + self.setPlainText(theText) + self.setDocumentChanged(True) + return + def saveText(self): if self.nwDocument.theItem is None: diff --git a/nw/guimain.py b/nw/guimain.py index 853b3e33..95e0c6a3 100644 --- a/nw/guimain.py +++ b/nw/guimain.py @@ -417,17 +417,20 @@ class GuiMain(QMainWindow): ) if inPath: loadFile = inPath[0] - self.mainConf.setLastPath(loadFile) else: return False + if loadFile.strip() == "": + return False + theText = None try: with open(loadFile,mode="rt",encoding="utf8") as inFile: theText = inFile.read() + self.mainConf.setLastPath(loadFile) except Exception as e: self.makeAlert( - ["Could not read file. The file cannot be a binary file.",str(e)], + ["Could not read file. The file must be an existing text file.",str(e)], nwAlert.ERROR ) return False @@ -451,7 +454,7 @@ class GuiMain(QMainWindow): else: return False - self.docEditor.setText(theText) + self.docEditor.replaceText(theText) return True diff --git a/nw/project/project.py b/nw/project/project.py index 49105ce8..041029a1 100644 --- a/nw/project/project.py +++ b/nw/project/project.py @@ -582,6 +582,9 @@ class NWProject(): return True def countStatus(self): + """Count how many times the various status flags are used in the + project tree. + """ self.statusItems.resetCounts() self.importItems.resetCounts() for nwItem in self.projTree.values(): diff --git a/nw/project/status.py b/nw/project/status.py index 3edd417a..6e15f5b9 100644 --- a/nw/project/status.py +++ b/nw/project/status.py @@ -41,6 +41,8 @@ class NWStatus(): return True def lookupEntry(self, theLabel): + if theLabel is None: + return None theLabel = theLabel.strip() if theLabel in self.theMap.keys(): return self.theMap[theLabel]