From 489eae2e0d2deeb03f19d76254e21d22adcb6ee3 Mon Sep 17 00:00:00 2001
From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com>
Date: Tue, 29 Oct 2019 14:49:11 +0100
Subject: [PATCH] Adding non-breaking space support for editor and html, latex
export
---
nw/constants.py | 68 +++++++++++++++++++++-----------------
nw/convert/file/html.py | 25 +++++++-------
nw/convert/file/text.py | 1 +
nw/convert/text/tohtml.py | 15 +++++----
nw/convert/text/tolatex.py | 15 +++++++++
nw/convert/text/totext.py | 12 +++++++
nw/convert/tokenizer.py | 3 ++
nw/gui/doceditor.py | 15 ++++++---
nw/gui/docviewer.py | 1 +
nw/project/document.py | 3 +-
10 files changed, 104 insertions(+), 54 deletions(-)
diff --git a/nw/constants.py b/nw/constants.py
index e06942c8..92c693dc 100644
--- a/nw/constants.py
+++ b/nw/constants.py
@@ -149,7 +149,9 @@ class nwUnicode:
"""Suppoted unicode character constants and translation maps.
"""
- # Quotation Marks
+ # Unicode Constants
+
+ ## Quotation Marks
U_QUOT = "\u0022" # Quotation mark
U_APOS = "\u0027" # Apostrophe
U_LAQUO = "\u00ab" # Left-pointing double angle quotation mark
@@ -170,38 +172,44 @@ class nwUnicode:
U_LWCQUO = "\u300e" # Left white corner bracket
U_RECQUO = "\u300f" # Right white corner bracket
- # Punctuation
- U_NDASH = "\u2013" # Short dash
- U_MDASH = "\u2014" # Long dash
+ ## Punctuation
+ U_ENDASH = "\u2013" # Short dash
+ U_EMDASH = "\u2014" # Long dash
U_HELLIP = "\u2026" # Ellipsis
- # Other
+ ## Other
U_NBSP = "\u00a0" # Non-breaking space
+ U_PARA = "\u2029" # Paragraph separator
- HTML = {
- U_QUOT : """,
- U_APOS : "'",
- U_LAQUO : "«",
- U_RAQUO : "»",
- U_LSQUO : "‘",
- U_RSQUO : "’",
- U_SBQUO : "‚",
- U_SUQUO : "‛",
- U_LDQUO : "“",
- U_RDQUO : "”",
- U_BDQUO : "„",
- U_UDQUO : "‟",
- U_LSAQUO : "‹",
- U_RSAQUO : "›",
- U_BDRQUO : "⹂",
- U_LCQUO : "「",
- U_RCQUO : "」",
- U_LWCQUO : "『",
- U_LWCQUO : "『",
- U_NDASH : "–",
- U_MDASH : "—",
- U_HELLIP : "…",
- U_NBSP : " ",
- }
+ # HTML Equivalents
+
+ ## Quotes
+ H_QUOT = """
+ H_APOS = "'"
+ H_LAQUO = "«"
+ H_RAQUO = "»"
+ H_LSQUO = "‘"
+ H_RSQUO = "’"
+ H_SBQUO = "‚"
+ H_SUQUO = "‛"
+ H_LDQUO = "“"
+ H_RDQUO = "”"
+ H_BDQUO = "„"
+ H_UDQUO = "‟"
+ H_LSAQUO = "‹"
+ H_RSAQUO = "›"
+ H_BDRQUO = "⹂"
+ H_LCQUO = "「"
+ H_RCQUO = "」"
+ H_LWCQUO = "『"
+ H_LWCQUO = "『"
+
+ ## Punctuation
+ H_ENDASH = "–"
+ H_EMDASH = "—"
+ H_HELLIP = "…"
+
+ ## Other
+ H_NBSP = " "
# END Class nwUnicode
diff --git a/nw/convert/file/html.py b/nw/convert/file/html.py
index 278acab7..1dc89b39 100644
--- a/nw/convert/file/html.py
+++ b/nw/convert/file/html.py
@@ -38,18 +38,19 @@ class HtmlFile(TextFile):
self.outFile.write("\n")
self.outFile.write("\n")
self.outFile.write("
\n")
- self.outFile.write("\n")
+ self.outFile.write(" \n")
+ self.outFile.write(" \n")
self.outFile.write("\n")
self.outFile.write("\n")
self.outFile.write("\n")
diff --git a/nw/convert/file/text.py b/nw/convert/file/text.py
index 9c490b3d..9301a823 100644
--- a/nw/convert/file/text.py
+++ b/nw/convert/file/text.py
@@ -138,6 +138,7 @@ class TextFile():
self.theConv.tokenizeText()
self.theConv.doHeaders()
self.theConv.doConvert()
+ self.theConv.doPostProcessing()
if self.theConv.theResult is not None and self.outFile is not None:
self.outFile.write(self.theConv.theResult)
diff --git a/nw/convert/text/tohtml.py b/nw/convert/text/tohtml.py
index 0c086a68..64ddbbb7 100644
--- a/nw/convert/text/tohtml.py
+++ b/nw/convert/text/tohtml.py
@@ -15,6 +15,7 @@ import re
import nw
from nw.convert.tokenizer import Tokenizer
+from nw.constants import nwUnicode
logger = logging.getLogger(__name__)
@@ -28,13 +29,13 @@ class ToHtml(Tokenizer):
Tokenizer.doAutoReplace(self)
repDict = {
- "<" : "<",
- ">" : ">",
- "&" : "&",
- "\u2013" : "&endash;",
- "\u2014" : "$emdash;",
- "\u2500" : "$emdash;",
- "\u2026" : "…",
+ "<" : "<",
+ ">" : ">",
+ "&" : "&",
+ nwUnicode.U_ENDASH : nwUnicode.H_ENDASH,
+ nwUnicode.U_EMDASH : nwUnicode.H_EMDASH,
+ nwUnicode.U_HELLIP : nwUnicode.H_HELLIP,
+ nwUnicode.U_NBSP : nwUnicode.H_NBSP,
}
xRep = re.compile("|".join([re.escape(k) for k in repDict.keys()]), flags=re.DOTALL)
self.theText = xRep.sub(lambda x: repDict[x.group(0)], self.theText)
diff --git a/nw/convert/text/tolatex.py b/nw/convert/text/tolatex.py
index cfcec012..435fee84 100644
--- a/nw/convert/text/tolatex.py
+++ b/nw/convert/text/tolatex.py
@@ -16,6 +16,7 @@ import re
import nw
from nw.convert.tokenizer import Tokenizer
+from nw.constants import nwUnicode
logger = logging.getLogger(__name__)
@@ -26,6 +27,20 @@ class ToLaTeX(Tokenizer):
self.texCodecFail = False
return
+ def doPostProcessing(self):
+ """The latexcodec misses dashes and non-breaking spaces, so we do those here.
+ """
+
+ repDict = {
+ nwUnicode.U_ENDASH : "--",
+ nwUnicode.U_EMDASH : "---",
+ nwUnicode.U_NBSP : "~",
+ }
+ xRep = re.compile("|".join([re.escape(k) for k in repDict.keys()]), flags=re.DOTALL)
+ self.theResult = xRep.sub(lambda x: repDict[x.group(0)], self.theResult)
+
+ return
+
def doConvert(self):
texTags = {
diff --git a/nw/convert/text/totext.py b/nw/convert/text/totext.py
index fc21163e..5b226999 100644
--- a/nw/convert/text/totext.py
+++ b/nw/convert/text/totext.py
@@ -16,6 +16,7 @@ import re
import nw
from nw.convert.tokenizer import Tokenizer
+from nw.constants import nwUnicode
logger = logging.getLogger(__name__)
@@ -25,6 +26,17 @@ class ToText(Tokenizer):
Tokenizer.__init__(self, theProject, theParent)
return
+ def doAutoReplace(self):
+ Tokenizer.doAutoReplace(self)
+
+ repDict = {
+ nwUnicode.U_NBSP : " ",
+ }
+ xRep = re.compile("|".join([re.escape(k) for k in repDict.keys()]), flags=re.DOTALL)
+ self.theText = xRep.sub(lambda x: repDict[x.group(0)], self.theText)
+
+ return
+
def doConvert(self):
"""Converts the tokenized text into plain text.
"""
diff --git a/nw/convert/tokenizer.py b/nw/convert/tokenizer.py
index 63abc1ae..7be25952 100644
--- a/nw/convert/tokenizer.py
+++ b/nw/convert/tokenizer.py
@@ -149,6 +149,9 @@ class Tokenizer():
self.theText = xRep.sub(lambda x: repDict[x.group(0)], self.theText)
return
+ def doPostProcessing(self):
+ return
+
def tokenizeText(self):
"""Scan the text for either lines starting with specific characters that indicate headers,
comments, commands etc, or just contains plain text. in the case of plain text, apply the
diff --git a/nw/gui/doceditor.py b/nw/gui/doceditor.py
index e2ca9237..1d0c35ac 100644
--- a/nw/gui/doceditor.py
+++ b/nw/gui/doceditor.py
@@ -218,7 +218,14 @@ class GuiDocEditor(QTextEdit):
return self.docChanged
def getText(self):
- theText = self.toPlainText()
+ """Get the text content of the current document. This method uses QTextEdit->toPlainText for
+ Qt versions lower than 5.9, and the QDocument->toRawText for higher version. The latter
+ preserves non-breaking spaces, which the former does not.
+ """
+ if self.mainConf.verQtValue >= 50900:
+ theText = self.qDocument.toRawText().replace(nwUnicode.U_PARA,"\n")
+ else:
+ theText = self.toPlainText()
return theText
def setCursorPosition(self, thePosition):
@@ -466,11 +473,11 @@ class GuiDocEditor(QTextEdit):
elif self.mainConf.doReplaceDash and theTwo == "--":
theCursor.movePosition(QTextCursor.Left, QTextCursor.KeepAnchor, 2)
- theCursor.insertText(nwUnicode.U_NDASH)
+ theCursor.insertText(nwUnicode.U_ENDASH)
- elif self.mainConf.doReplaceDash and theTwo == nwUnicode.U_NDASH+"-":
+ elif self.mainConf.doReplaceDash and theTwo == nwUnicode.U_ENDASH+"-":
theCursor.movePosition(QTextCursor.Left, QTextCursor.KeepAnchor, 2)
- theCursor.insertText(nwUnicode.U_MDASH)
+ theCursor.insertText(nwUnicode.U_EMDASH)
elif self.mainConf.doReplaceDots and theThree == "...":
theCursor.movePosition(QTextCursor.Left, QTextCursor.KeepAnchor, 3)
diff --git a/nw/gui/docviewer.py b/nw/gui/docviewer.py
index 72c85ee4..76c57e67 100644
--- a/nw/gui/docviewer.py
+++ b/nw/gui/docviewer.py
@@ -106,6 +106,7 @@ class GuiDocViewer(QTextBrowser):
aDoc.doAutoReplace()
aDoc.tokenizeText()
aDoc.doConvert()
+ aDoc.doPostProcessing()
self.setHtml(aDoc.theResult)
if self.theHandle == tHandle:
self.verticalScrollBar().setValue(sPos)
diff --git a/nw/project/document.py b/nw/project/document.py
index 7f5b550a..923f5c9e 100644
--- a/nw/project/document.py
+++ b/nw/project/document.py
@@ -100,7 +100,8 @@ class NWDoc():
self.makeAlert(["Could not save document.",str(e)], nwAlert.ERROR)
return False
- if path.isfile(docTemp): unlink(docTemp)
+ if path.isfile(docTemp):
+ unlink(docTemp)
self.theParent.statusBar.setStatus("Saved Document: %s" % self.theItem.itemName)