From ceadfe1e5c51df02e386e0875c7998df4faf7719 Mon Sep 17 00:00:00 2001
From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com>
Date: Mon, 29 Jun 2020 12:15:49 +0200
Subject: [PATCH 1/5] Improved regex, highlighting and HTML conversion of bold
and italic text. Reverting to old syntax for italic.
---
nw/constants/constants.py | 7 ++--
nw/core/tohtml.py | 5 +--
nw/core/tokenizer.py | 22 +++++++++----
nw/core/tools.py | 8 +++++
nw/gui/dochighlight.py | 68 ++++++++++++++++++---------------------
5 files changed, 59 insertions(+), 51 deletions(-)
diff --git a/nw/constants/constants.py b/nw/constants/constants.py
index 18443c1d..d78cd5c6 100644
--- a/nw/constants/constants.py
+++ b/nw/constants/constants.py
@@ -37,10 +37,9 @@ class nwConst():
class nwRegEx():
- FMT_B = r"(?",
self.FMT_I_B : "",
self.FMT_I_E : "",
- self.FMT_S_B : "",
- self.FMT_S_E : "",
self.FMT_D_B : "",
self.FMT_D_E : "",
}
@@ -136,8 +135,6 @@ class ToHtml(Tokenizer):
self.FMT_B_E : "",
self.FMT_I_B : "",
self.FMT_I_E : "",
- self.FMT_S_B : "",
- self.FMT_S_E : "",
self.FMT_D_B : "",
self.FMT_D_E : "",
}
diff --git a/nw/core/tokenizer.py b/nw/core/tokenizer.py
index 09345e09..eba1ab65 100644
--- a/nw/core/tokenizer.py
+++ b/nw/core/tokenizer.py
@@ -44,10 +44,8 @@ class Tokenizer():
FMT_B_E = 2 # End bold
FMT_I_B = 3 # Begin italics
FMT_I_E = 4 # End italics
- FMT_S_B = 5 # Begin bold italic
- FMT_S_E = 6 # End bold italic
- FMT_D_B = 7 # Begin strikeout
- FMT_D_E = 8 # End strikeout
+ FMT_D_B = 5 # Begin strikeout
+ FMT_D_E = 6 # End strikeout
T_EMPTY = 1 # Empty line (new paragraph)
T_SYNOPSIS = 2 # Synopsis comment
@@ -269,7 +267,6 @@ class Tokenizer():
def doAutoReplace(self):
"""Run through the user's auto-replace dictionary.
"""
-
if len(self.theProject.autoReplace) > 0:
repDict = {}
for aKey, aVal in self.theProject.autoReplace.items():
@@ -280,8 +277,20 @@ class Tokenizer():
return
def doPostProcessing(self):
- """Do some postprocessing. Overloaded by subclasses.
+ """Do some postprocessing. Overloaded by subclasses. This just
+ does the standard escaped characters.
"""
+ escapeDict = {
+ "\*" : "*",
+ "\~" : "~",
+ "\_" : "_",
+ }
+ escReplace = re.compile(
+ "|".join([re.escape(k) for k in escapeDict.keys()]), flags=re.DOTALL
+ )
+ self.theResult = escReplace.sub(
+ lambda x: escapeDict[x.group(0)], self.theResult
+ )
return
def tokenizeText(self):
@@ -304,7 +313,6 @@ class Tokenizer():
rxFormats = [
(QRegularExpression(nwRegEx.FMT_I), [None, self.FMT_I_B, None, self.FMT_I_E]),
(QRegularExpression(nwRegEx.FMT_B), [None, self.FMT_B_B, None, self.FMT_B_E]),
- (QRegularExpression(nwRegEx.FMT_BI), [None, self.FMT_S_B, None, self.FMT_S_E]),
(QRegularExpression(nwRegEx.FMT_ST), [None, self.FMT_D_B, None, self.FMT_D_E]),
]
diff --git a/nw/core/tools.py b/nw/core/tools.py
index 8115105d..5c352fe7 100644
--- a/nw/core/tools.py
+++ b/nw/core/tools.py
@@ -34,6 +34,10 @@ from os import path, unlink, rmdir
logger = logging.getLogger(__name__)
+# =========================================================================== #
+# Simple Word Counter
+# =========================================================================== #
+
def countWords(theText):
"""Count words in a piece of text, skipping special syntax and
comments.
@@ -80,6 +84,10 @@ def countWords(theText):
return charCount, wordCount, paraCount
+# =========================================================================== #
+# Convert an Integer to a Word Number
+# =========================================================================== #
+
def numberToWord(numVal, theLanguage):
"""Wrapper for converting numbers to words for chapter headings.
"""
diff --git a/nw/gui/dochighlight.py b/nw/gui/dochighlight.py
index 4acc0e7a..deb646b2 100644
--- a/nw/gui/dochighlight.py
+++ b/nw/gui/dochighlight.py
@@ -107,7 +107,6 @@ class GuiDocHighlighter(QSyntaxHighlighter):
"header4h" : self._makeFormat(self.colHeadH, "bold", 1.2),
"bold" : self._makeFormat(self.colEmph, "bold"),
"italic" : self._makeFormat(self.colEmph, "italic"),
- "bolditalic" : self._makeFormat(self.colEmph, ("bold","italic")),
"strike" : self._makeFormat(self.colEmph, "strike"),
"trailing" : self._makeFormat(self.colTrail, "background"),
"nobreak" : self._makeFormat(self.colTrail, "background"),
@@ -137,36 +136,6 @@ class GuiDocHighlighter(QSyntaxHighlighter):
}
))
- # Markdown
- self.hRules.append((
- nwRegEx.FMT_I, {
- 1 : self.hStyles["hidden"],
- 2 : self.hStyles["italic"],
- 3 : self.hStyles["hidden"],
- }
- ))
- self.hRules.append((
- nwRegEx.FMT_B, {
- 1 : self.hStyles["hidden"],
- 2 : self.hStyles["bold"],
- 3 : self.hStyles["hidden"],
- }
- ))
- self.hRules.append((
- nwRegEx.FMT_BI, {
- 1 : self.hStyles["hidden"],
- 2 : self.hStyles["bolditalic"],
- 3 : self.hStyles["hidden"],
- }
- ))
- self.hRules.append((
- nwRegEx.FMT_ST, {
- 1 : self.hStyles["hidden"],
- 2 : self.hStyles["strike"],
- 3 : self.hStyles["hidden"],
- }
- ))
-
# Quoted Strings
if self.mainConf.highlightQuotes:
self.hRules.append((
@@ -185,6 +154,29 @@ class GuiDocHighlighter(QSyntaxHighlighter):
}
))
+ # Markdown
+ self.hRules.append((
+ nwRegEx.FMT_I, {
+ 1 : self.hStyles["hidden"],
+ 2 : self.hStyles["italic"],
+ 3 : self.hStyles["hidden"],
+ }
+ ))
+ self.hRules.append((
+ nwRegEx.FMT_B, {
+ 1 : self.hStyles["hidden"],
+ 2 : self.hStyles["bold"],
+ 3 : self.hStyles["hidden"],
+ }
+ ))
+ self.hRules.append((
+ nwRegEx.FMT_ST, {
+ 1 : self.hStyles["hidden"],
+ 2 : self.hStyles["strike"],
+ 3 : self.hStyles["hidden"],
+ }
+ ))
+
# Auto-Replace Tags
self.hRules.append((
r"<(\S+?)>", {
@@ -302,10 +294,14 @@ class GuiDocHighlighter(QSyntaxHighlighter):
rxItt = rX.globalMatch(theText, 0)
while rxItt.hasNext():
rxMatch = rxItt.next()
- for xM in xFmt.keys():
+ for xM in xFmt:
xPos = rxMatch.capturedStart(xM)
xLen = rxMatch.capturedLength(xM)
- self.setFormat(xPos, xLen, xFmt[xM])
+ for x in range(xPos, xPos+xLen):
+ spFmt = self.format(x)
+ if spFmt != self.hStyles["hidden"]:
+ spFmt.merge(xFmt[xM])
+ self.setFormat(x, 1, spFmt)
if self.theDict is None or not self.spellCheck:
return
@@ -318,11 +314,11 @@ class GuiDocHighlighter(QSyntaxHighlighter):
continue
xPos = rxMatch.capturedStart(0)
xLen = rxMatch.capturedLength(0)
- for x in range(xLen):
- spFmt = self.format(xPos+x)
+ for x in range(xPos, xPos+xLen):
+ spFmt = self.format(x)
spFmt.setUnderlineColor(self.colSpell)
spFmt.setUnderlineStyle(QTextCharFormat.SpellCheckUnderline)
- self.setFormat(xPos+x, 1, spFmt)
+ self.setFormat(x, 1, spFmt)
return
From 564a15968c031013ebd2dcf5be14831550250259 Mon Sep 17 00:00:00 2001
From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com>
Date: Mon, 29 Jun 2020 12:52:56 +0200
Subject: [PATCH 2/5] Fixed menu and shortcut action for bold/italic
---
nw/constants/enum.py | 37 +++++++++--------
nw/gui/doceditor.py | 96 ++++++++++++--------------------------------
nw/gui/mainmenu.py | 7 ----
nw/guimain.py | 1 -
4 files changed, 44 insertions(+), 97 deletions(-)
diff --git a/nw/constants/enum.py b/nw/constants/enum.py
index d068cb8e..4a377d7b 100644
--- a/nw/constants/enum.py
+++ b/nw/constants/enum.py
@@ -76,25 +76,24 @@ class nwDocAction(Enum):
PASTE = 5
EMPH = 6
STRONG = 7
- STRONGEMPH = 8
- STRIKE = 9
- S_QUOTE = 10
- D_QUOTE = 11
- SEL_ALL = 12
- SEL_PARA = 13
- FIND = 14
- REPLACE = 15
- GO_NEXT = 16
- GO_PREV = 17
- REPL_NEXT = 18
- BLOCK_H1 = 19
- BLOCK_H2 = 20
- BLOCK_H3 = 21
- BLOCK_H4 = 22
- BLOCK_COM = 23
- BLOCK_TXT = 24
- REPL_SNG = 25
- REPL_DBL = 26
+ STRIKE = 8
+ S_QUOTE = 9
+ D_QUOTE = 10
+ SEL_ALL = 11
+ SEL_PARA = 12
+ FIND = 13
+ REPLACE = 14
+ GO_NEXT = 15
+ GO_PREV = 16
+ REPL_NEXT = 17
+ BLOCK_H1 = 18
+ BLOCK_H2 = 19
+ BLOCK_H3 = 20
+ BLOCK_H4 = 21
+ BLOCK_COM = 22
+ BLOCK_TXT = 23
+ REPL_SNG = 24
+ REPL_DBL = 25
# END Enum nwDocAction
diff --git a/nw/gui/doceditor.py b/nw/gui/doceditor.py
index fce3d01c..7fd84a28 100644
--- a/nw/gui/doceditor.py
+++ b/nw/gui/doceditor.py
@@ -515,13 +515,11 @@ class GuiDocEditor(QTextEdit):
elif theAction == nwDocAction.PASTE:
self.paste()
elif theAction == nwDocAction.EMPH:
- self._toggleEmph(1)
+ self._toggleFormat(1, "_")
elif theAction == nwDocAction.STRONG:
- self._toggleEmph(2)
- elif theAction == nwDocAction.STRONGEMPH:
- self._toggleEmph(3)
+ self._toggleFormat(2, "*")
elif theAction == nwDocAction.STRIKE:
- self._toggleStrike()
+ self._toggleFormat(2, "~")
elif theAction == nwDocAction.S_QUOTE:
self._wrapSelection(self.typSQOpen, self.typSQClose)
elif theAction == nwDocAction.D_QUOTE:
@@ -998,69 +996,27 @@ class GuiDocEditor(QTextEdit):
theCursor = self.textCursor()
if self.mainConf.autoSelect and not theCursor.hasSelection():
theCursor.select(QTextCursor.WordUnderCursor)
- self.setTextCursor(theCursor)
- return theCursor
-
- def _toggleEmph(self, eLevel):
- """Toggle emphasis of a given level between 1 and 3, where 1 is
- italic, 2 is bold, and 3 is bold italic. The current level in
- the text is cLevel. The rules are as follows:
-
- cLevel | eLevel | Result
- ============+============+============
- None | Italic | Italic
- None | Bold | Bold
- None | BoldItalic | BoldItalic
- ------------+------------+------------
- Italic | Italic | None
- Italic | Bold | BoldItalic
- Italic | BoldItalic | BoldItalic
- ------------+------------+------------
- Bold | Italic | BoldItalic
- Bold | Bold | None
- Bold | BoldItalic | BoldItalic
- ------------+------------+------------
- BoldItalic | Italic | Bold
- BoldItalic | Bold | Italic
- BoldItalic | BoldItalic | None
-
- """
- theCursor = self._autoSelect()
- if theCursor.hasSelection():
posS = theCursor.selectionStart()
posE = theCursor.selectionEnd()
- numB = 0
- for n in range(3):
- if self.qDocument.characterAt(posS-n-1) == "*":
- numB += 1
- else:
- break
+ # Underscore counts as a part of the word, so check that the
+ # selection isn't wrapped in italics markers.
+ reSelect = False
+ if self.qDocument.characterAt(posS) == "_":
+ posS += 1
+ reSelect = True
+ if self.qDocument.characterAt(posE) == "_":
+ posE -= 1
+ reSelect = True
+ if reSelect:
+ theCursor.clearSelection()
+ theCursor.setPosition(posE-1)
+ theCursor.movePosition(QTextCursor.Left, QTextCursor.KeepAnchor, posE-posS-1)
- numA = 0
- for n in range(3):
- if self.qDocument.characterAt(posE+n) == "*":
- numA += 1
- else:
- break
+ self.setTextCursor(theCursor)
+ return theCursor
- cLevel = min(numB, numA)
- if cLevel == 0:
- # Has no emphasis, set to desired level
- self._wrapSelection("*"*eLevel)
- elif cLevel == 3:
- # Has max, so reduce by desired level
- self._clearSurrounding(theCursor, eLevel)
- elif cLevel == eLevel:
- # Toggle mode, so clear what we had set
- self._clearSurrounding(theCursor, cLevel)
- else:
- # Already at 1 or 2, increase to 3
- self._wrapSelection("*"*(3 - cLevel))
-
- return
-
- def _toggleStrike(self):
+ def _toggleFormat(self, fLen, fChar):
"""Toggle strikethrough text.
"""
theCursor = self._autoSelect()
@@ -1069,24 +1025,24 @@ class GuiDocEditor(QTextEdit):
posE = theCursor.selectionEnd()
numB = 0
- for n in range(2):
- if self.qDocument.characterAt(posS-n-1) == "~":
+ for n in range(fLen):
+ if self.qDocument.characterAt(posS-n-1) == fChar:
numB += 1
else:
break
numA = 0
- for n in range(2):
- if self.qDocument.characterAt(posE+n) == "~":
+ for n in range(fLen):
+ if self.qDocument.characterAt(posE+n) == fChar:
numA += 1
else:
break
cLevel = min(numB, numA)
- if cLevel == 2:
- self._clearSurrounding(theCursor, 2)
+ if cLevel == fLen:
+ self._clearSurrounding(theCursor, fLen)
else:
- self._wrapSelection("~~")
+ self._wrapSelection(fChar*fLen)
return
diff --git a/nw/gui/mainmenu.py b/nw/gui/mainmenu.py
index 2d2ecf01..5cdbf55a 100644
--- a/nw/gui/mainmenu.py
+++ b/nw/gui/mainmenu.py
@@ -540,13 +540,6 @@ class GuiMainMenu(QMenuBar):
self.aFmtStrong.triggered.connect(lambda: self._docAction(nwDocAction.STRONG))
self.fmtMenu.addAction(self.aFmtStrong)
- # Format > Very Strong Emphasis
- self.aFmtStrongEmph = QAction("Very Strong Emphasis", self)
- self.aFmtStrongEmph.setStatusTip("Add very strong emphasis to selected text (bold and italic)")
- self.aFmtStrongEmph.setShortcut("Ctrl+Shift+B")
- self.aFmtStrongEmph.triggered.connect(lambda: self._docAction(nwDocAction.STRONGEMPH))
- self.fmtMenu.addAction(self.aFmtStrongEmph)
-
# Format > Strikethrough
self.aFmtStrike = QAction("Strikethrough", self)
self.aFmtStrike.setStatusTip("Add strikethrough to selected text")
diff --git a/nw/guimain.py b/nw/guimain.py
index 8a115f0d..7681089c 100644
--- a/nw/guimain.py
+++ b/nw/guimain.py
@@ -1008,7 +1008,6 @@ class GuiMain(QMainWindow):
# Format
self.addAction(self.mainMenu.aFmtEmph)
self.addAction(self.mainMenu.aFmtStrong)
- self.addAction(self.mainMenu.aFmtStrongEmph)
self.addAction(self.mainMenu.aFmtStrike)
self.addAction(self.mainMenu.aFmtDQuote)
self.addAction(self.mainMenu.aFmtSQuote)
From 70078be1455e515bd405f1eb6e97733037f386ad Mon Sep 17 00:00:00 2001
From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com>
Date: Mon, 29 Jun 2020 12:56:36 +0200
Subject: [PATCH 3/5] Fixed tests and updated sample
---
sample/content/636b6aa9b697b.nwd | 6 +++---
sample/nwProject.nwx | 22 +++++++++----------
tests/lipsum/content/88d59a277361b.nwd | 2 +-
tests/reference/build/1_LoremIpsum.nwd | 2 +-
tests/reference/build/2_LoremIpsum.nwd | 2 +-
tests/test_gui.py | 30 +-------------------------
6 files changed, 18 insertions(+), 46 deletions(-)
diff --git a/sample/content/636b6aa9b697b.nwd b/sample/content/636b6aa9b697b.nwd
index 0ab145f1..4809096d 100644
--- a/sample/content/636b6aa9b697b.nwd
+++ b/sample/content/636b6aa9b697b.nwd
@@ -7,13 +7,13 @@
A scene is defined by a level three heading, like the one at the top of this page. The scene will be assigned to the chapter preceding it in the project tree.
-Each paragraph in the scene is separated by a blank line. The text supports minimal formatting, like **bold**, *italic* and ***bold italic***. You can also ~~strike through~~ text.
+Each paragraph in the scene is separated by a blank line. The text supports minimal formatting, like **bold**, _italic_ and **_bold italic_**. You can also ~~strike through~~ text. There is **some support for _nested_ emphasis**, but it isn’t fully Markdown compliant. If the syntax highlighter doesn’t show it correctly, the export tool will not either.
-In addition, the editor supports automatic formatting of “quotes”, both double and ‘single’. Depending on the syntax highlighter, these can be in different colours.
+In addition, the editor supports automatic formatting of “quotes”, both double and ‘single’. Depending on the syntax highlighter, these can be in different colours. “You can of course use **bold** and _italic_ text inside of quotes too.”
If you have the need for it, you can also add text that can be automatically replaced by other text when you generate a preview or export the project. Now, let’s auto-replace this A with , and this C with . While is just . Press Ctrl+R to see what this looks like in the view pane.
-The editor also supports non breaking spaces, and the spell checker accepts long dashes—like this—as valid word separators. Regular dashes are also supported – and can be automatically inserted when typing two hyphens.
+The editor also supports non breaking spaces, and the spell checker accepts long dashes—like this—as valid word separators. Regular dashes are also supported – and can be automatically inserted when typing two hyphens.
Thin spaces and thin non-breaking spaces are also supported from the Insert menu, and can be used to separate numbers from their units, like: 25 kg.
diff --git a/sample/nwProject.nwx b/sample/nwProject.nwx
index c5a194a5..e7e4a731 100644
--- a/sample/nwProject.nwx
+++ b/sample/nwProject.nwx
@@ -1,22 +1,22 @@
-
+
Sample Project
Sample Project
Jane Smith
Jay Doh
- 593
- 103
- 24563
+ 651
+ 122
+ 32698
False
- True
+ False
True
636b6aa9b697b
- b3e74dbc1f584
- 982
- 606
+ 636b6aa9b697b
+ 1022
+ 646
376
B
@@ -116,10 +116,10 @@
1st Draft
True
SCENE
- 1564
- 278
+ 1811
+ 318
8
- 1633
+ 851
-
Another Scene
diff --git a/tests/lipsum/content/88d59a277361b.nwd b/tests/lipsum/content/88d59a277361b.nwd
index a67f49f1..f6ac2810 100644
--- a/tests/lipsum/content/88d59a277361b.nwd
+++ b/tests/lipsum/content/88d59a277361b.nwd
@@ -3,4 +3,4 @@
% Synopsis:Explanation from the lipsum.com website.
-*Lorem Ipsum* is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
+_Lorem Ipsum_ is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
diff --git a/tests/reference/build/1_LoremIpsum.nwd b/tests/reference/build/1_LoremIpsum.nwd
index fbe4f132..010f3a80 100644
--- a/tests/reference/build/1_LoremIpsum.nwd
+++ b/tests/reference/build/1_LoremIpsum.nwd
@@ -14,7 +14,7 @@ The standard chunk of Lorem Ipsum used since the 1500s is reproduced below for t
## Prologue
-*Lorem Ipsum* is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
+_Lorem Ipsum_ is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
# Act One
diff --git a/tests/reference/build/2_LoremIpsum.nwd b/tests/reference/build/2_LoremIpsum.nwd
index f2a26740..d58f1021 100644
--- a/tests/reference/build/2_LoremIpsum.nwd
+++ b/tests/reference/build/2_LoremIpsum.nwd
@@ -16,7 +16,7 @@ The standard chunk of Lorem Ipsum used since the 1500s is reproduced below for t
% Synopsis:Explanation from the lipsum.com website.
-*Lorem Ipsum* is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
+_Lorem Ipsum_ is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
# Act One
diff --git a/tests/test_gui.py b/tests/test_gui.py
index 5c8bf2ac..7660497f 100644
--- a/tests/test_gui.py
+++ b/tests/test_gui.py
@@ -746,17 +746,6 @@ def testDocAction(qtbot, nwTempGUI, nwLipsum, nwRef, nwTemp):
assert nwGUI.openProject(nwLipsum)
qtbot.wait(stepDelay)
- # CUT = 3
- # COPY = 4
- # PASTE = 5
- # SEL_ALL = 12
- # SEL_PARA = 13
- # FIND = 14
- # REPLACE = 15
- # GO_NEXT = 16
- # GO_PREV = 17
- # REPL_NEXT = 18
-
# Split By Chapter
assert nwGUI.openDocument("4c4f28287af27")
assert nwGUI.docEditor.setCursorPosition(30)
@@ -773,20 +762,12 @@ def testDocAction(qtbot, nwTempGUI, nwLipsum, nwRef, nwTemp):
# Italic
assert nwGUI.passDocumentAction(nwDocAction.EMPH)
- assert nwGUI.docEditor.getText()[27:76] == "*Pellentesque* nec erat ut nulla posuere commodo."
+ assert nwGUI.docEditor.getText()[27:76] == "_Pellentesque_ nec erat ut nulla posuere commodo."
qtbot.wait(stepDelay)
assert nwGUI.passDocumentAction(nwDocAction.EMPH)
assert nwGUI.docEditor.getText()[27:74] == cleanText
qtbot.wait(stepDelay)
- # Bold-Italic
- assert nwGUI.passDocumentAction(nwDocAction.STRONGEMPH)
- assert nwGUI.docEditor.getText()[27:80] == "***Pellentesque*** nec erat ut nulla posuere commodo."
- qtbot.wait(stepDelay)
- assert nwGUI.passDocumentAction(nwDocAction.STRONGEMPH)
- assert nwGUI.docEditor.getText()[27:74] == cleanText
- qtbot.wait(stepDelay)
-
# Strikethrough
assert nwGUI.passDocumentAction(nwDocAction.STRIKE)
assert nwGUI.docEditor.getText()[27:78] == "~~Pellentesque~~ nec erat ut nulla posuere commodo."
@@ -806,15 +787,6 @@ def testDocAction(qtbot, nwTempGUI, nwLipsum, nwRef, nwTemp):
assert nwGUI.docEditor.getText()[27:74] == cleanText
qtbot.wait(stepDelay)
- # Equivalent of the above
- assert nwGUI.passDocumentAction(nwDocAction.STRONGEMPH)
- qtbot.wait(stepDelay)
- assert nwGUI.passDocumentAction(nwDocAction.EMPH)
- qtbot.wait(stepDelay)
- assert nwGUI.passDocumentAction(nwDocAction.STRONG)
- assert nwGUI.docEditor.getText()[27:74] == cleanText
- qtbot.wait(stepDelay)
-
# Double Quotes
assert nwGUI.passDocumentAction(nwDocAction.D_QUOTE)
assert nwGUI.docEditor.getText()[27:76] == "“Pellentesque” nec erat ut nulla posuere commodo."
From fdf7f58d5f823d31474138956978e06778a2f864 Mon Sep 17 00:00:00 2001
From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com>
Date: Mon, 29 Jun 2020 13:14:47 +0200
Subject: [PATCH 4/5] Updated docs
---
docs/source/interface.rst | 19 +++++++++++--------
1 file changed, 11 insertions(+), 8 deletions(-)
diff --git a/docs/source/interface.rst b/docs/source/interface.rst
index 99e5b663..0a8dfd79 100644
--- a/docs/source/interface.rst
+++ b/docs/source/interface.rst
@@ -33,8 +33,9 @@ Markdown Format
===============
The document editor uses a simplified markdown format.
-That is, it supports basic formatting like bold, italics and strikethrough, as well as four levels of headings.
-The preference of novelWriter is to use `*` for wrapping emphasised text, but `_` is partially supported when typed, but not by the automatic formatting features and keyboard shortcuts.
+That is, it supports basic formatting like emphasis (italic), strong emphasis (bold) and strikethrough text, as well as four levels of headings.
+It is commonly recommended style to differentiate between strong emphasis and emphasis by using ``**`` for strong emphasis and ``_`` for emphasis, although Markdown generally supports also ``__`` for strong emphasis and ``*`` fdr emphasis.
+However, since the differentiation makes the highlighting and conversion significantly simpler and faster, in novelWriter this is a rule, not just a recommendation.
In addition to these standard markdown features, the editor also allows for comments, that is text that is ignored by the word counter and not exported or, optionally, hidden in the document viewer.
If the first word of a comment is "Synopsis:" (with the colon), the comment is treated specially, and will show up in the Outline View.
@@ -48,19 +49,21 @@ The editor also has a minimal set of keywords used for setting tags and referenc
"``## Title``", "Heading level two. The space after the # is mandatory."
"``### Title``", "Heading level three. The space after the # is mandatory."
"``#### Title``", "Heading level four. The space after the # is mandatory."
- "``*text*``", "The text is rendered as emphasised text (italicised)."
+ "``_text_``", "The text is rendered as emphasised text (italicised)."
"``**text**``", "The text is rendered as strongly emphasised text (bold)."
- "``***text***``", "The text is rendered as very strongly emphasised text (italicised, bold)."
- "``_text_``", "Alternative format for emphasised text."
- "``__text__``", "Alternative format for strongly emphasised text."
"``~~text~~``", "Strikethrough text."
"``% text...``", "A comment. The text is not exported by default, seen in viewer, or counted towards word counts."
"``% Synopsis: text...``", "A synopsis comment. Shows up in the Synopsis column of the Outline View, but is otherwise treated as a comment."
"``@keyword: value``", "A keyword argument followed by a value, or a comma separated list of values."
-.. note::
- The emphasis and strikethrough formatting tags do not allow spaces between the words and the tag itself.
+Some additional rules:
+
+1. The emphasis and strikethrough formatting tags do not allow spaces between the words and the tag itself.
That is, ``**text**`` is valid, ``**text **`` is not.
+2. More generally, the delimiters must be on the outer edge of words.
+ That is, ``some **text in bold** here`` is valid, ``some** text in bold** here`` is not.
+3. If using both ``**`` and ``_`` to wrap the same text, the underscore must be the inner wrapper.
+ This is due to the underscore also being a valid word character, so if they are on the outside, they violate rule 2.
The editor and viewer also supports markdown standard hard line breaks, and preserves non-breaking spaces.
A hard line break is achieved by leaving two or more spaces at the end of the line.
From 4355d5fd77489b074b8dd1ef9a92091b3015404b Mon Sep 17 00:00:00 2001
From: "Veronica K. B. Olsen" <1619840+vkbo@users.noreply.github.com>
Date: Mon, 29 Jun 2020 13:28:15 +0200
Subject: [PATCH 5/5] Put back the non-breaking space in the sample
---
sample/content/636b6aa9b697b.nwd | 2 +-
sample/nwProject.nwx | 8 ++++----
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/sample/content/636b6aa9b697b.nwd b/sample/content/636b6aa9b697b.nwd
index 4809096d..5936fbd3 100644
--- a/sample/content/636b6aa9b697b.nwd
+++ b/sample/content/636b6aa9b697b.nwd
@@ -13,7 +13,7 @@ In addition, the editor supports automatic formatting of “quotes”, both doub
If you have the need for it, you can also add text that can be automatically replaced by other text when you generate a preview or export the project. Now, let’s auto-replace this A with , and this C with . While is just . Press Ctrl+R to see what this looks like in the view pane.
-The editor also supports non breaking spaces, and the spell checker accepts long dashes—like this—as valid word separators. Regular dashes are also supported – and can be automatically inserted when typing two hyphens.
+The editor also supports non breaking spaces, and the spell checker accepts long dashes—like this—as valid word separators. Regular dashes are also supported – and can be automatically inserted when typing two hyphens.
Thin spaces and thin non-breaking spaces are also supported from the Insert menu, and can be used to separate numbers from their units, like: 25 kg.
diff --git a/sample/nwProject.nwx b/sample/nwProject.nwx
index e7e4a731..82c542c6 100644
--- a/sample/nwProject.nwx
+++ b/sample/nwProject.nwx
@@ -1,13 +1,13 @@
-
+
Sample Project
Sample Project
Jane Smith
Jay Doh
- 651
+ 652
122
- 32698
+ 32716
False
@@ -119,7 +119,7 @@
1811
318
8
- 851
+ 1143
-
Another Scene