@@ -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.
|
||||
|
||||
@@ -37,10 +37,9 @@ class nwConst():
|
||||
|
||||
class nwRegEx():
|
||||
|
||||
FMT_B = r"(?<![\w|\*|_|\\])([\*|_]{2})(?!\s|\*|_)(.+?)(?<![\s|\\])(\1)(?!\w)"
|
||||
FMT_I = r"(?<![\w|\*|_|\\])([\*|_])(?!\s|\*|_)(.+?)(?<![\s|\\])(\1)(?!\w)"
|
||||
FMT_BI = r"(?<![\w|\*|\\])([\*]{3})(?!\s|\*)(.+?)(?<![\s|\\])(\1)(?!\w)"
|
||||
FMT_ST = r"(?<![\w|~|\\])([~]{2})(?!\s|~)(.+?)(?<![\s|\\])(\1)(?!\w)"
|
||||
FMT_I = r"(?<![\w\\])(_)(?![\s_])(.+?)(?<![\s\\])(\1)(?!\w)"
|
||||
FMT_B = r"(?<![\w\\])([\*]{2})(?![\s\*])(.+?)(?<![\s\\])(\1)(?!\w)"
|
||||
FMT_ST = r"(?<![\w\\])([~]{2})(?![\s~])(.+?)(?<![\s\\])(\1)(?!\w)"
|
||||
|
||||
# END Class nwRegEx
|
||||
|
||||
|
||||
+18
-19
@@ -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
|
||||
|
||||
|
||||
+1
-4
@@ -107,6 +107,7 @@ class ToHtml(Tokenizer):
|
||||
"""Reverse the html entities replacement on the markdown text.
|
||||
Otherwise, all the &something; bits will also be in there.
|
||||
"""
|
||||
Tokenizer.doPostProcessing(self)
|
||||
if self.genMode == self.M_PREVIEW:
|
||||
# Doesn't matter for preview as we don't use the markdown
|
||||
return
|
||||
@@ -125,8 +126,6 @@ class ToHtml(Tokenizer):
|
||||
self.FMT_B_E : "</b>",
|
||||
self.FMT_I_B : "<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_E : "</span>",
|
||||
}
|
||||
@@ -136,8 +135,6 @@ class ToHtml(Tokenizer):
|
||||
self.FMT_B_E : "</strong>",
|
||||
self.FMT_I_B : "<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_E : "</del>",
|
||||
}
|
||||
|
||||
+15
-7
@@ -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]),
|
||||
]
|
||||
|
||||
|
||||
@@ -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.
|
||||
"""
|
||||
|
||||
+26
-70
@@ -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
|
||||
|
||||
|
||||
+32
-36
@@ -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
|
||||
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
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 <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
@@ -1,22 +1,22 @@
|
||||
<?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>
|
||||
<name>Sample Project</name>
|
||||
<title>Sample Project</title>
|
||||
<author>Jane Smith</author>
|
||||
<author>Jay Doh</author>
|
||||
<saveCount>593</saveCount>
|
||||
<autoCount>103</autoCount>
|
||||
<editTime>24563</editTime>
|
||||
<saveCount>652</saveCount>
|
||||
<autoCount>122</autoCount>
|
||||
<editTime>32716</editTime>
|
||||
</project>
|
||||
<settings>
|
||||
<doBackup>False</doBackup>
|
||||
<spellCheck>True</spellCheck>
|
||||
<spellCheck>False</spellCheck>
|
||||
<autoOutline>True</autoOutline>
|
||||
<lastEdited>636b6aa9b697b</lastEdited>
|
||||
<lastViewed>b3e74dbc1f584</lastViewed>
|
||||
<lastWordCount>982</lastWordCount>
|
||||
<novelWordCount>606</novelWordCount>
|
||||
<lastViewed>636b6aa9b697b</lastViewed>
|
||||
<lastWordCount>1022</lastWordCount>
|
||||
<novelWordCount>646</novelWordCount>
|
||||
<notesWordCount>376</notesWordCount>
|
||||
<autoReplace>
|
||||
<entry key="A">B</entry>
|
||||
@@ -116,10 +116,10 @@
|
||||
<status>1st Draft</status>
|
||||
<exported>True</exported>
|
||||
<layout>SCENE</layout>
|
||||
<charCount>1564</charCount>
|
||||
<wordCount>278</wordCount>
|
||||
<charCount>1811</charCount>
|
||||
<wordCount>318</wordCount>
|
||||
<paraCount>8</paraCount>
|
||||
<cursorPos>1633</cursorPos>
|
||||
<cursorPos>1143</cursorPos>
|
||||
</item>
|
||||
<item handle="bc0cbd2a407f3" order="2" parent="e7ded148d6e4a">
|
||||
<name>Another Scene</name>
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
+1
-29
@@ -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."
|
||||
|
||||
Reference in New Issue
Block a user