Merge pull request #355 from vkbo/markdown-fixes

Markdown fixes
This commit is contained in:
Veronica K. Berglyd Olsen
2020-06-29 17:04:12 +02:00
committed by GitHub
16 changed files with 131 additions and 201 deletions
+11 -8
View File
@@ -33,8 +33,9 @@ Markdown Format
=============== ===============
The document editor uses a simplified 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. That is, it supports basic formatting like emphasis (italic), strong emphasis (bold) and strikethrough text, 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. 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. 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. 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 two. The space after the # is mandatory."
"``### Title``", "Heading level three. 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." "``#### 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 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~~``", "Strikethrough text."
"``% text...``", "A comment. The text is not exported by default, seen in viewer, or counted towards word counts." "``% 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." "``% 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." "``@keyword: value``", "A keyword argument followed by a value, or a comma separated list of values."
.. note:: Some additional rules:
The emphasis and strikethrough formatting tags do not allow spaces between the words and the tag itself.
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. 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. 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. A hard line break is achieved by leaving two or more spaces at the end of the line.
+3 -4
View File
@@ -37,10 +37,9 @@ class nwConst():
class nwRegEx(): class nwRegEx():
FMT_B = r"(?<![\w|\*|_|\\])([\*|_]{2})(?!\s|\*|_)(.+?)(?<![\s|\\])(\1)(?!\w)" FMT_I = r"(?<![\w\\])(_)(?![\s_])(.+?)(?<![\s\\])(\1)(?!\w)"
FMT_I = r"(?<![\w|\*|_|\\])([\*|_])(?!\s|\*|_)(.+?)(?<![\s|\\])(\1)(?!\w)" FMT_B = r"(?<![\w\\])([\*]{2})(?![\s\*])(.+?)(?<![\s\\])(\1)(?!\w)"
FMT_BI = r"(?<![\w|\*|\\])([\*]{3})(?!\s|\*)(.+?)(?<![\s|\\])(\1)(?!\w)" FMT_ST = r"(?<![\w\\])([~]{2})(?![\s~])(.+?)(?<![\s\\])(\1)(?!\w)"
FMT_ST = r"(?<![\w|~|\\])([~]{2})(?!\s|~)(.+?)(?<![\s|\\])(\1)(?!\w)"
# END Class nwRegEx # END Class nwRegEx
+18 -19
View File
@@ -76,25 +76,24 @@ class nwDocAction(Enum):
PASTE = 5 PASTE = 5
EMPH = 6 EMPH = 6
STRONG = 7 STRONG = 7
STRONGEMPH = 8 STRIKE = 8
STRIKE = 9 S_QUOTE = 9
S_QUOTE = 10 D_QUOTE = 10
D_QUOTE = 11 SEL_ALL = 11
SEL_ALL = 12 SEL_PARA = 12
SEL_PARA = 13 FIND = 13
FIND = 14 REPLACE = 14
REPLACE = 15 GO_NEXT = 15
GO_NEXT = 16 GO_PREV = 16
GO_PREV = 17 REPL_NEXT = 17
REPL_NEXT = 18 BLOCK_H1 = 18
BLOCK_H1 = 19 BLOCK_H2 = 19
BLOCK_H2 = 20 BLOCK_H3 = 20
BLOCK_H3 = 21 BLOCK_H4 = 21
BLOCK_H4 = 22 BLOCK_COM = 22
BLOCK_COM = 23 BLOCK_TXT = 23
BLOCK_TXT = 24 REPL_SNG = 24
REPL_SNG = 25 REPL_DBL = 25
REPL_DBL = 26
# END Enum nwDocAction # END Enum nwDocAction
+1 -4
View File
@@ -107,6 +107,7 @@ class ToHtml(Tokenizer):
"""Reverse the html entities replacement on the markdown text. """Reverse the html entities replacement on the markdown text.
Otherwise, all the &something; bits will also be in there. Otherwise, all the &something; bits will also be in there.
""" """
Tokenizer.doPostProcessing(self)
if self.genMode == self.M_PREVIEW: if self.genMode == self.M_PREVIEW:
# Doesn't matter for preview as we don't use the markdown # Doesn't matter for preview as we don't use the markdown
return return
@@ -125,8 +126,6 @@ class ToHtml(Tokenizer):
self.FMT_B_E : "</b>", self.FMT_B_E : "</b>",
self.FMT_I_B : "<i>", self.FMT_I_B : "<i>",
self.FMT_I_E : "</i>", self.FMT_I_E : "</i>",
self.FMT_S_B : "<b><i>",
self.FMT_S_E : "</i></b>",
self.FMT_D_B : "<span style='text-decoration: line-through;'>", self.FMT_D_B : "<span style='text-decoration: line-through;'>",
self.FMT_D_E : "</span>", self.FMT_D_E : "</span>",
} }
@@ -136,8 +135,6 @@ class ToHtml(Tokenizer):
self.FMT_B_E : "</strong>", self.FMT_B_E : "</strong>",
self.FMT_I_B : "<em>", self.FMT_I_B : "<em>",
self.FMT_I_E : "</em>", self.FMT_I_E : "</em>",
self.FMT_S_B : "<strong><em>",
self.FMT_S_E : "</em></strong>",
self.FMT_D_B : "<del>", self.FMT_D_B : "<del>",
self.FMT_D_E : "</del>", self.FMT_D_E : "</del>",
} }
+15 -7
View File
@@ -44,10 +44,8 @@ class Tokenizer():
FMT_B_E = 2 # End bold FMT_B_E = 2 # End bold
FMT_I_B = 3 # Begin italics FMT_I_B = 3 # Begin italics
FMT_I_E = 4 # End italics FMT_I_E = 4 # End italics
FMT_S_B = 5 # Begin bold italic FMT_D_B = 5 # Begin strikeout
FMT_S_E = 6 # End bold italic FMT_D_E = 6 # End strikeout
FMT_D_B = 7 # Begin strikeout
FMT_D_E = 8 # End strikeout
T_EMPTY = 1 # Empty line (new paragraph) T_EMPTY = 1 # Empty line (new paragraph)
T_SYNOPSIS = 2 # Synopsis comment T_SYNOPSIS = 2 # Synopsis comment
@@ -269,7 +267,6 @@ class Tokenizer():
def doAutoReplace(self): def doAutoReplace(self):
"""Run through the user's auto-replace dictionary. """Run through the user's auto-replace dictionary.
""" """
if len(self.theProject.autoReplace) > 0: if len(self.theProject.autoReplace) > 0:
repDict = {} repDict = {}
for aKey, aVal in self.theProject.autoReplace.items(): for aKey, aVal in self.theProject.autoReplace.items():
@@ -280,8 +277,20 @@ class Tokenizer():
return return
def doPostProcessing(self): 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 return
def tokenizeText(self): def tokenizeText(self):
@@ -304,7 +313,6 @@ class Tokenizer():
rxFormats = [ rxFormats = [
(QRegularExpression(nwRegEx.FMT_I), [None, self.FMT_I_B, None, self.FMT_I_E]), (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_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]), (QRegularExpression(nwRegEx.FMT_ST), [None, self.FMT_D_B, None, self.FMT_D_E]),
] ]
+8
View File
@@ -34,6 +34,10 @@ from os import path, unlink, rmdir
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# =========================================================================== #
# Simple Word Counter
# =========================================================================== #
def countWords(theText): def countWords(theText):
"""Count words in a piece of text, skipping special syntax and """Count words in a piece of text, skipping special syntax and
comments. comments.
@@ -80,6 +84,10 @@ def countWords(theText):
return charCount, wordCount, paraCount return charCount, wordCount, paraCount
# =========================================================================== #
# Convert an Integer to a Word Number
# =========================================================================== #
def numberToWord(numVal, theLanguage): def numberToWord(numVal, theLanguage):
"""Wrapper for converting numbers to words for chapter headings. """Wrapper for converting numbers to words for chapter headings.
""" """
+26 -70
View File
@@ -515,13 +515,11 @@ class GuiDocEditor(QTextEdit):
elif theAction == nwDocAction.PASTE: elif theAction == nwDocAction.PASTE:
self.paste() self.paste()
elif theAction == nwDocAction.EMPH: elif theAction == nwDocAction.EMPH:
self._toggleEmph(1) self._toggleFormat(1, "_")
elif theAction == nwDocAction.STRONG: elif theAction == nwDocAction.STRONG:
self._toggleEmph(2) self._toggleFormat(2, "*")
elif theAction == nwDocAction.STRONGEMPH:
self._toggleEmph(3)
elif theAction == nwDocAction.STRIKE: elif theAction == nwDocAction.STRIKE:
self._toggleStrike() self._toggleFormat(2, "~")
elif theAction == nwDocAction.S_QUOTE: elif theAction == nwDocAction.S_QUOTE:
self._wrapSelection(self.typSQOpen, self.typSQClose) self._wrapSelection(self.typSQOpen, self.typSQClose)
elif theAction == nwDocAction.D_QUOTE: elif theAction == nwDocAction.D_QUOTE:
@@ -998,69 +996,27 @@ class GuiDocEditor(QTextEdit):
theCursor = self.textCursor() theCursor = self.textCursor()
if self.mainConf.autoSelect and not theCursor.hasSelection(): if self.mainConf.autoSelect and not theCursor.hasSelection():
theCursor.select(QTextCursor.WordUnderCursor) 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() posS = theCursor.selectionStart()
posE = theCursor.selectionEnd() posE = theCursor.selectionEnd()
numB = 0 # Underscore counts as a part of the word, so check that the
for n in range(3): # selection isn't wrapped in italics markers.
if self.qDocument.characterAt(posS-n-1) == "*": reSelect = False
numB += 1 if self.qDocument.characterAt(posS) == "_":
else: posS += 1
break 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 self.setTextCursor(theCursor)
for n in range(3): return theCursor
if self.qDocument.characterAt(posE+n) == "*":
numA += 1
else:
break
cLevel = min(numB, numA) def _toggleFormat(self, fLen, fChar):
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):
"""Toggle strikethrough text. """Toggle strikethrough text.
""" """
theCursor = self._autoSelect() theCursor = self._autoSelect()
@@ -1069,24 +1025,24 @@ class GuiDocEditor(QTextEdit):
posE = theCursor.selectionEnd() posE = theCursor.selectionEnd()
numB = 0 numB = 0
for n in range(2): for n in range(fLen):
if self.qDocument.characterAt(posS-n-1) == "~": if self.qDocument.characterAt(posS-n-1) == fChar:
numB += 1 numB += 1
else: else:
break break
numA = 0 numA = 0
for n in range(2): for n in range(fLen):
if self.qDocument.characterAt(posE+n) == "~": if self.qDocument.characterAt(posE+n) == fChar:
numA += 1 numA += 1
else: else:
break break
cLevel = min(numB, numA) cLevel = min(numB, numA)
if cLevel == 2: if cLevel == fLen:
self._clearSurrounding(theCursor, 2) self._clearSurrounding(theCursor, fLen)
else: else:
self._wrapSelection("~~") self._wrapSelection(fChar*fLen)
return return
+32 -36
View File
@@ -107,7 +107,6 @@ class GuiDocHighlighter(QSyntaxHighlighter):
"header4h" : self._makeFormat(self.colHeadH, "bold", 1.2), "header4h" : self._makeFormat(self.colHeadH, "bold", 1.2),
"bold" : self._makeFormat(self.colEmph, "bold"), "bold" : self._makeFormat(self.colEmph, "bold"),
"italic" : self._makeFormat(self.colEmph, "italic"), "italic" : self._makeFormat(self.colEmph, "italic"),
"bolditalic" : self._makeFormat(self.colEmph, ("bold","italic")),
"strike" : self._makeFormat(self.colEmph, "strike"), "strike" : self._makeFormat(self.colEmph, "strike"),
"trailing" : self._makeFormat(self.colTrail, "background"), "trailing" : self._makeFormat(self.colTrail, "background"),
"nobreak" : 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 # Quoted Strings
if self.mainConf.highlightQuotes: if self.mainConf.highlightQuotes:
self.hRules.append(( 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 # Auto-Replace Tags
self.hRules.append(( self.hRules.append((
r"<(\S+?)>", { r"<(\S+?)>", {
@@ -302,10 +294,14 @@ class GuiDocHighlighter(QSyntaxHighlighter):
rxItt = rX.globalMatch(theText, 0) rxItt = rX.globalMatch(theText, 0)
while rxItt.hasNext(): while rxItt.hasNext():
rxMatch = rxItt.next() rxMatch = rxItt.next()
for xM in xFmt.keys(): for xM in xFmt:
xPos = rxMatch.capturedStart(xM) xPos = rxMatch.capturedStart(xM)
xLen = rxMatch.capturedLength(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: if self.theDict is None or not self.spellCheck:
return return
@@ -318,11 +314,11 @@ class GuiDocHighlighter(QSyntaxHighlighter):
continue continue
xPos = rxMatch.capturedStart(0) xPos = rxMatch.capturedStart(0)
xLen = rxMatch.capturedLength(0) xLen = rxMatch.capturedLength(0)
for x in range(xLen): for x in range(xPos, xPos+xLen):
spFmt = self.format(xPos+x) spFmt = self.format(x)
spFmt.setUnderlineColor(self.colSpell) spFmt.setUnderlineColor(self.colSpell)
spFmt.setUnderlineStyle(QTextCharFormat.SpellCheckUnderline) spFmt.setUnderlineStyle(QTextCharFormat.SpellCheckUnderline)
self.setFormat(xPos+x, 1, spFmt) self.setFormat(x, 1, spFmt)
return return
-7
View File
@@ -540,13 +540,6 @@ class GuiMainMenu(QMenuBar):
self.aFmtStrong.triggered.connect(lambda: self._docAction(nwDocAction.STRONG)) self.aFmtStrong.triggered.connect(lambda: self._docAction(nwDocAction.STRONG))
self.fmtMenu.addAction(self.aFmtStrong) 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 # Format > Strikethrough
self.aFmtStrike = QAction("Strikethrough", self) self.aFmtStrike = QAction("Strikethrough", self)
self.aFmtStrike.setStatusTip("Add strikethrough to selected text") self.aFmtStrike.setStatusTip("Add strikethrough to selected text")
-1
View File
@@ -1008,7 +1008,6 @@ class GuiMain(QMainWindow):
# Format # Format
self.addAction(self.mainMenu.aFmtEmph) self.addAction(self.mainMenu.aFmtEmph)
self.addAction(self.mainMenu.aFmtStrong) self.addAction(self.mainMenu.aFmtStrong)
self.addAction(self.mainMenu.aFmtStrongEmph)
self.addAction(self.mainMenu.aFmtStrike) self.addAction(self.mainMenu.aFmtStrike)
self.addAction(self.mainMenu.aFmtDQuote) self.addAction(self.mainMenu.aFmtDQuote)
self.addAction(self.mainMenu.aFmtSQuote) self.addAction(self.mainMenu.aFmtSQuote)
+2 -2
View File
@@ -7,9 +7,9 @@
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. 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 isnt fully Markdown compliant. If the syntax highlighter doesnt 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, lets auto-replace this A with <A>, and this C with <C>. While <E> is just <E>. Press Ctrl+R to see what this looks like in the view pane. 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, lets auto-replace this A with <A>, and this C with <C>. While <E> is just <E>. Press Ctrl+R to see what this looks like in the view pane.
+11 -11
View File
@@ -1,22 +1,22 @@
<?xml version='1.0' encoding='utf-8'?> <?xml version='1.0' encoding='utf-8'?>
<novelWriterXML appVersion="0.10.0rc1" hexVersion="0x001000c1" fileVersion="1.2" timeStamp="2020-06-27 17:29:20"> <novelWriterXML appVersion="0.10.0rc1" hexVersion="0x001000c1" fileVersion="1.2" timeStamp="2020-06-29 13:27:47">
<project> <project>
<name>Sample Project</name> <name>Sample Project</name>
<title>Sample Project</title> <title>Sample Project</title>
<author>Jane Smith</author> <author>Jane Smith</author>
<author>Jay Doh</author> <author>Jay Doh</author>
<saveCount>593</saveCount> <saveCount>652</saveCount>
<autoCount>103</autoCount> <autoCount>122</autoCount>
<editTime>24563</editTime> <editTime>32716</editTime>
</project> </project>
<settings> <settings>
<doBackup>False</doBackup> <doBackup>False</doBackup>
<spellCheck>True</spellCheck> <spellCheck>False</spellCheck>
<autoOutline>True</autoOutline> <autoOutline>True</autoOutline>
<lastEdited>636b6aa9b697b</lastEdited> <lastEdited>636b6aa9b697b</lastEdited>
<lastViewed>b3e74dbc1f584</lastViewed> <lastViewed>636b6aa9b697b</lastViewed>
<lastWordCount>982</lastWordCount> <lastWordCount>1022</lastWordCount>
<novelWordCount>606</novelWordCount> <novelWordCount>646</novelWordCount>
<notesWordCount>376</notesWordCount> <notesWordCount>376</notesWordCount>
<autoReplace> <autoReplace>
<entry key="A">B</entry> <entry key="A">B</entry>
@@ -116,10 +116,10 @@
<status>1st Draft</status> <status>1st Draft</status>
<exported>True</exported> <exported>True</exported>
<layout>SCENE</layout> <layout>SCENE</layout>
<charCount>1564</charCount> <charCount>1811</charCount>
<wordCount>278</wordCount> <wordCount>318</wordCount>
<paraCount>8</paraCount> <paraCount>8</paraCount>
<cursorPos>1633</cursorPos> <cursorPos>1143</cursorPos>
</item> </item>
<item handle="bc0cbd2a407f3" order="2" parent="e7ded148d6e4a"> <item handle="bc0cbd2a407f3" order="2" parent="e7ded148d6e4a">
<name>Another Scene</name> <name>Another Scene</name>
+1 -1
View File
@@ -3,4 +3,4 @@
% Synopsis:Explanation from the lipsum.com website. % 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.
+1 -1
View File
@@ -14,7 +14,7 @@ The standard chunk of Lorem Ipsum used since the 1500s is reproduced below for t
## Prologue ## 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 # Act One
+1 -1
View File
@@ -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. % 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 # Act One
+1 -29
View File
@@ -746,17 +746,6 @@ def testDocAction(qtbot, nwTempGUI, nwLipsum, nwRef, nwTemp):
assert nwGUI.openProject(nwLipsum) assert nwGUI.openProject(nwLipsum)
qtbot.wait(stepDelay) 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 # Split By Chapter
assert nwGUI.openDocument("4c4f28287af27") assert nwGUI.openDocument("4c4f28287af27")
assert nwGUI.docEditor.setCursorPosition(30) assert nwGUI.docEditor.setCursorPosition(30)
@@ -773,20 +762,12 @@ def testDocAction(qtbot, nwTempGUI, nwLipsum, nwRef, nwTemp):
# Italic # Italic
assert nwGUI.passDocumentAction(nwDocAction.EMPH) 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) qtbot.wait(stepDelay)
assert nwGUI.passDocumentAction(nwDocAction.EMPH) assert nwGUI.passDocumentAction(nwDocAction.EMPH)
assert nwGUI.docEditor.getText()[27:74] == cleanText assert nwGUI.docEditor.getText()[27:74] == cleanText
qtbot.wait(stepDelay) 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 # Strikethrough
assert nwGUI.passDocumentAction(nwDocAction.STRIKE) assert nwGUI.passDocumentAction(nwDocAction.STRIKE)
assert nwGUI.docEditor.getText()[27:78] == "~~Pellentesque~~ nec erat ut nulla posuere commodo." 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 assert nwGUI.docEditor.getText()[27:74] == cleanText
qtbot.wait(stepDelay) 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 # Double Quotes
assert nwGUI.passDocumentAction(nwDocAction.D_QUOTE) assert nwGUI.passDocumentAction(nwDocAction.D_QUOTE)
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."