Merge pull request #310 from vkbo/tidy_formatting
Standard Markdown Text Emphasis
This commit is contained in:
@@ -2,9 +2,15 @@
|
||||
|
||||
## Version 0.9rc1 [2020-xx-xx]
|
||||
|
||||
**Core Functionality**
|
||||
|
||||
* Underline text formatting has been removed. It is not standard HTML5, not Markdown, and was previously implemented using the double underscore notation that in standard Markdown is renderred as bold text. Instead, novelWriter now renders a single `*` or `-` wrapping a piece of text *within* a paragraphs as italicised text, and a double `**` or `__` as bold text. The keyboard shortcuts and automatic features **only** support the `*` notation. A triple set of `***` are treated as both bold and italicised. PR #310.
|
||||
* Strikethrough formatting has been added back into novelWriter using the standard Markdown `~~` wrapping. PR #310.
|
||||
|
||||
**User Interface**
|
||||
|
||||
* The Open Project dialog will now ask before removing an entry from the recent projects list. PR #309.
|
||||
* The text emphasis functions, either selected from the menu or via keyboard shortcuts, will now try to respond to the command in a more meaningful way. That is, the text editor will try to toggle the bold or italics features independently of eachother on the selected text. A feature to apply both at the same time has also been added. PR #310.
|
||||
|
||||
**Other Changes**
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ It allows for a minimal set of formatting needed for writing text documents for
|
||||
These are currently limited to:
|
||||
|
||||
* Headings level 1 to 4 using the `#` syntax only.
|
||||
* Bold, italic and underline text.
|
||||
* Bold, italic and strikethrough text.
|
||||
* Hard line breaks using two or more spaces at the end of a line.
|
||||
|
||||
That is it.
|
||||
|
||||
@@ -33,8 +33,8 @@ Markdown Format
|
||||
===============
|
||||
|
||||
The document editor uses a simplified markdown format.
|
||||
That is, it supports basic formatting like bold, italics and underline, as well as four levels of headings.
|
||||
The formats are listed below.
|
||||
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.
|
||||
|
||||
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,9 +48,12 @@ 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 italicised text."
|
||||
"``**text**``", "The text is rendered as bold text."
|
||||
"``_text_``", "The text is rendered as italicized text."
|
||||
"``__text__``", "The text is rendered as underlined text."
|
||||
"``***text***``", "The text is rendered as bold italicised text."
|
||||
"``_text_``", "Alternative format for italicised text."
|
||||
"``__text__``", "Alternative format for bold 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."
|
||||
@@ -110,6 +113,7 @@ These are as following:
|
||||
":kbd:`Ctrl-.`", "Correct word under cursor."
|
||||
":kbd:`Ctrl-,`", "Open the Preferences dialog."
|
||||
":kbd:`Ctrl-/`", "Change block format to comment."
|
||||
":kbd:`Ctrl--`", "Strikethrough selected text, or word under cursor."
|
||||
":kbd:`Ctrl-0`", "Remove block formatting for block under cursor."
|
||||
":kbd:`Ctrl-1`", "Change block format to header level 1."
|
||||
":kbd:`Ctrl-2`", "Change block format to header level 2."
|
||||
@@ -122,7 +126,7 @@ These are as following:
|
||||
":kbd:`Ctrl-E`", "If in tree view, edit a document or folder settings. (Same as :kbd:`F2`)"
|
||||
":kbd:`Ctrl-F`", "Open the search bar and search for selected word, if any is selected."
|
||||
":kbd:`Ctrl-G`", "Find next occurrence of word in current document. (Same as :kbd:`F3`)"
|
||||
":kbd:`Ctrl-H`", "Open the search and replace bar and search for selected word, if any is selected. (On Mac, this is :kbd:`Cmd+=`)"
|
||||
":kbd:`Ctrl-H`", "Open the search and replace bar and search for selected word, if any is selected. (On Mac, this is :kbd:`Cmd-=`)"
|
||||
":kbd:`Ctrl-I`", "Format selected text, or word under cursor, as italic."
|
||||
":kbd:`Ctrl-N`", "Create new document."
|
||||
":kbd:`Ctrl-O`", "Open selected document."
|
||||
@@ -143,6 +147,7 @@ These are as following:
|
||||
":kbd:`Ctrl-Shift-/`", "Remove block formatting for block under cursor."
|
||||
":kbd:`Ctrl-Shift-1`", "Replace occurrence of word in current document, and search for next occurrence."
|
||||
":kbd:`Ctrl-Shift-A`", "Select all text in current paragraph."
|
||||
":kbd:`Ctrl-Shift-B`", "Format selected text, or word under cursor, as bold and italic."
|
||||
":kbd:`Ctrl-Shift-D`", "Wrap selected text, or word under cursor, in single quotes."
|
||||
":kbd:`Ctrl-Shift-G`", "Find previous occurrence of word in current document. (Same as :kbd:`Shift-F3`"
|
||||
":kbd:`Ctrl-Shift-I`", "Import text to the current document from a text file."
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from nw.constants.iso import isoLanguage, isoCountry
|
||||
from nw.constants.constants import (
|
||||
nwConst, nwFiles, nwKeyWords, nwLabels, nwQuotes, nwUnicode
|
||||
nwConst, nwRegEx, nwFiles, nwKeyWords, nwLabels, nwQuotes, nwUnicode
|
||||
)
|
||||
from nw.constants.enum import (
|
||||
nwAlert, nwDocAction, nwItemClass, nwItemLayout, nwItemType, nwOutline
|
||||
@@ -11,6 +11,7 @@ __all__ = [
|
||||
"isoLanguage",
|
||||
"isoCountry",
|
||||
"nwConst",
|
||||
"nwRegEx",
|
||||
"nwFiles",
|
||||
"nwKeyWords",
|
||||
"nwLabels",
|
||||
|
||||
@@ -34,6 +34,15 @@ class nwConst():
|
||||
|
||||
# END 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)"
|
||||
|
||||
# END Class nwRegEx
|
||||
|
||||
class nwFiles():
|
||||
|
||||
PROJ_FILE = "nwProject.nwx"
|
||||
|
||||
+25
-24
@@ -68,30 +68,31 @@ class nwItemLayout(Enum):
|
||||
|
||||
class nwDocAction(Enum):
|
||||
|
||||
NO_ACTION = 0
|
||||
UNDO = 1
|
||||
REDO = 2
|
||||
CUT = 3
|
||||
COPY = 4
|
||||
PASTE = 5
|
||||
BOLD = 6
|
||||
ITALIC = 7
|
||||
U_LINE = 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
|
||||
NO_ACTION = 0
|
||||
UNDO = 1
|
||||
REDO = 2
|
||||
CUT = 3
|
||||
COPY = 4
|
||||
PASTE = 5
|
||||
ITALIC = 6
|
||||
BOLD = 7
|
||||
BOLDITALIC = 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
|
||||
|
||||
# END Enum nwDocAction
|
||||
|
||||
|
||||
+3
-2
@@ -305,11 +305,12 @@ class NWIndex():
|
||||
|
||||
elif aLine.startswith(r"%"):
|
||||
if nTitle > 0:
|
||||
toCheck = aLine[1:].lstrip().lower()
|
||||
toCheck = aLine[1:].lstrip()
|
||||
synTag = toCheck[:9].lower()
|
||||
tLen = len(aLine)
|
||||
cLen = len(toCheck)
|
||||
cOff = tLen - cLen
|
||||
if toCheck.startswith("synopsis:"):
|
||||
if synTag == "synopsis:":
|
||||
self._indexSynopsis(tHandle, isNovel, aLine[cOff+9:].strip(), nTitle)
|
||||
|
||||
# Count words for remaining text after last heading
|
||||
|
||||
+22
-8
@@ -116,14 +116,28 @@ class ToHtml(Tokenizer):
|
||||
"""Convert the list of text tokens into a HTML document saved
|
||||
to theResult.
|
||||
"""
|
||||
htmlTags = {
|
||||
self.FMT_B_B : "<strong>",
|
||||
self.FMT_B_E : "</strong>",
|
||||
self.FMT_I_B : "<em>",
|
||||
self.FMT_I_E : "</em>",
|
||||
self.FMT_U_B : "<u>",
|
||||
self.FMT_U_E : "</u>",
|
||||
}
|
||||
if self.genMode == self.M_PREVIEW:
|
||||
htmlTags = { # HTML4 + CSS2
|
||||
self.FMT_B_B : "<b>",
|
||||
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>",
|
||||
}
|
||||
else:
|
||||
htmlTags = { # HTML5
|
||||
self.FMT_B_B : "<strong>",
|
||||
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>",
|
||||
}
|
||||
|
||||
if self.isNovel and self.genMode != self.M_PREVIEW:
|
||||
# For novel files for export, we bump the titles one level
|
||||
|
||||
+18
-19
@@ -34,7 +34,7 @@ from PyQt5.QtCore import QRegularExpression
|
||||
|
||||
from nw.core.document import NWDoc
|
||||
from nw.core.tools import numberToWord
|
||||
from nw.constants import nwItemLayout, nwItemType
|
||||
from nw.constants import nwItemLayout, nwItemType, nwRegEx
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -44,8 +44,10 @@ class Tokenizer():
|
||||
FMT_B_E = 2 # End bold
|
||||
FMT_I_B = 3 # Begin italics
|
||||
FMT_I_E = 4 # End italics
|
||||
FMT_U_B = 5 # Begin underline
|
||||
FMT_U_E = 6 # End underline
|
||||
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
|
||||
|
||||
T_EMPTY = 1 # Empty line (new paragraph)
|
||||
T_SYNOPSIS = 2 # Synopsis comment
|
||||
@@ -292,23 +294,19 @@ class Tokenizer():
|
||||
The format of the token list is an entry with a four-tuple for
|
||||
each line in the file. The tuple is as follows:
|
||||
1: The type of the block, self.T_*
|
||||
2: The text content of the block, without leading tags
|
||||
3: The internal formatting map of the text, self.FMT_*
|
||||
4: The style of the block, self.A_*
|
||||
2: The line in file where this block occurred
|
||||
3: The text content of the block, without leading tags
|
||||
4: The internal formatting map of the text, self.FMT_*
|
||||
5: The style of the block, self.A_*
|
||||
"""
|
||||
|
||||
# RegExes for adding formatting tags within text lines
|
||||
# Keep in sync with the DocHighlighter class
|
||||
rxFormats = [(
|
||||
QRegularExpression(r"(?<![\w|\\])([\*]{2})(?!\s)(?m:(.+?))(?<![\s|\\])(\1)(?!\w)"),
|
||||
[None, self.FMT_B_B, None, self.FMT_B_E]
|
||||
),(
|
||||
QRegularExpression(r"(?<![\w|_|\\])([_])(?!\s|\1)(?m:(.+?))(?<![\s|\\])(\1)(?!\w)"),
|
||||
[None, self.FMT_I_B, None, self.FMT_I_E]
|
||||
),(
|
||||
QRegularExpression(r"(?<![\w|\\])([_]{2})(?!\s)(?m:(.+?))(?<![\s|\\])(\1)(?!\w)"),
|
||||
[None, self.FMT_U_B, None, self.FMT_U_E]
|
||||
)]
|
||||
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]),
|
||||
]
|
||||
|
||||
self.theTokens = []
|
||||
self.theMarkdown = ""
|
||||
@@ -329,8 +327,9 @@ class Tokenizer():
|
||||
tmpMarkdown.append("\n")
|
||||
|
||||
elif aLine[0] == "%":
|
||||
cLine = aLine[1:].strip()
|
||||
if cLine.lower().startswith("synopsis:"):
|
||||
cLine = aLine[1:].lstrip()
|
||||
synTag = cLine[:9].lower()
|
||||
if synTag == "synopsis:":
|
||||
self.theTokens.append((
|
||||
self.T_SYNOPSIS,
|
||||
nLine,
|
||||
|
||||
+3
-1
@@ -982,7 +982,9 @@ class GuiBuildNovelDocView(QTextBrowser):
|
||||
"""
|
||||
if isinstance(theText, list):
|
||||
theText = "".join(theText)
|
||||
theText = theText.replace(" "," "*4)
|
||||
theText = theText.replace(" ", " "*4)
|
||||
theText = theText.replace("<del>", "<span style='text-decoration: line-through;'>")
|
||||
theText = theText.replace("</del>", "</span>")
|
||||
self.setHtml(theText)
|
||||
return
|
||||
|
||||
|
||||
+139
-11
@@ -509,16 +509,18 @@ class GuiDocEditor(QTextEdit):
|
||||
self.copy()
|
||||
elif theAction == nwDocAction.PASTE:
|
||||
self.paste()
|
||||
elif theAction == nwDocAction.BOLD:
|
||||
self._wrapSelection("**","**")
|
||||
elif theAction == nwDocAction.ITALIC:
|
||||
self._wrapSelection("_","_")
|
||||
elif theAction == nwDocAction.U_LINE:
|
||||
self._wrapSelection("__","__")
|
||||
self._toggleEmph(1)
|
||||
elif theAction == nwDocAction.BOLD:
|
||||
self._toggleEmph(2)
|
||||
elif theAction == nwDocAction.BOLDITALIC:
|
||||
self._toggleEmph(3)
|
||||
elif theAction == nwDocAction.STRIKE:
|
||||
self._toggleStrike()
|
||||
elif theAction == nwDocAction.S_QUOTE:
|
||||
self._wrapSelection(self.typSQOpen,self.typSQClose)
|
||||
self._wrapSelection(self.typSQOpen, self.typSQClose)
|
||||
elif theAction == nwDocAction.D_QUOTE:
|
||||
self._wrapSelection(self.typDQOpen,self.typDQClose)
|
||||
self._wrapSelection(self.typDQOpen, self.typDQClose)
|
||||
elif theAction == nwDocAction.SEL_ALL:
|
||||
self._makeSelection(QTextCursor.Document)
|
||||
elif theAction == nwDocAction.SEL_PARA:
|
||||
@@ -881,18 +883,20 @@ class GuiDocEditor(QTextEdit):
|
||||
self.bigDoc = False
|
||||
return
|
||||
|
||||
def _wrapSelection(self, tBefore, tAfter):
|
||||
def _wrapSelection(self, tBefore, tAfter=None):
|
||||
"""Wraps the selected text in whatever is in tBefore and tAfter.
|
||||
If there is no selection, the autoSelect setting decides the
|
||||
action. AutoSelect will select the word under the cursor before
|
||||
wrapping it. If this feature is disabled, nothing is done.
|
||||
"""
|
||||
theCursor = self.textCursor()
|
||||
if self.mainConf.autoSelect and not theCursor.hasSelection():
|
||||
theCursor.select(QTextCursor.WordUnderCursor)
|
||||
if tAfter is None:
|
||||
tAfter = tBefore
|
||||
|
||||
theCursor = self._autoSelect()
|
||||
if theCursor.hasSelection():
|
||||
posS = theCursor.selectionStart()
|
||||
posE = theCursor.selectionEnd()
|
||||
|
||||
theCursor.clearSelection()
|
||||
theCursor.beginEditBlock()
|
||||
theCursor.setPosition(posE)
|
||||
@@ -900,10 +904,134 @@ class GuiDocEditor(QTextEdit):
|
||||
theCursor.setPosition(posS)
|
||||
theCursor.insertText(tBefore)
|
||||
theCursor.endEditBlock()
|
||||
|
||||
theCursor.setPosition(posE + len(tBefore))
|
||||
theCursor.movePosition(QTextCursor.Left, QTextCursor.KeepAnchor, posE-posS)
|
||||
self.setTextCursor(theCursor)
|
||||
|
||||
else:
|
||||
logger.warning("No selection made, nothing to do")
|
||||
return
|
||||
|
||||
def _clearSurrounding(self, theCursor, nChars):
|
||||
"""Clears n characters before and after the cursor.
|
||||
"""
|
||||
if theCursor.hasSelection():
|
||||
posS = theCursor.selectionStart()
|
||||
posE = theCursor.selectionEnd()
|
||||
theCursor.clearSelection()
|
||||
theCursor.beginEditBlock()
|
||||
theCursor.setPosition(posS)
|
||||
for i in range(nChars):
|
||||
theCursor.deletePreviousChar()
|
||||
theCursor.setPosition(posE)
|
||||
for i in range(nChars):
|
||||
theCursor.deletePreviousChar()
|
||||
theCursor.endEditBlock()
|
||||
theCursor.clearSelection()
|
||||
else:
|
||||
logger.warning("No selection made, nothing to do")
|
||||
return
|
||||
|
||||
def _autoSelect(self):
|
||||
"""Returns a cursor which may or may not have a selection based
|
||||
on user settings and document action.
|
||||
"""
|
||||
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
|
||||
|
||||
numA = 0
|
||||
for n in range(3):
|
||||
if self.qDocument.characterAt(posE+n) == "*":
|
||||
numA += 1
|
||||
else:
|
||||
break
|
||||
|
||||
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):
|
||||
"""Toggle strikethrough text.
|
||||
"""
|
||||
theCursor = self._autoSelect()
|
||||
if theCursor.hasSelection():
|
||||
posS = theCursor.selectionStart()
|
||||
posE = theCursor.selectionEnd()
|
||||
|
||||
numB = 0
|
||||
for n in range(2):
|
||||
if self.qDocument.characterAt(posS-n-1) == "~":
|
||||
numB += 1
|
||||
else:
|
||||
break
|
||||
|
||||
numA = 0
|
||||
for n in range(2):
|
||||
if self.qDocument.characterAt(posE+n) == "~":
|
||||
numA += 1
|
||||
else:
|
||||
break
|
||||
|
||||
cLevel = min(numB, numA)
|
||||
if cLevel == 2:
|
||||
self._clearSurrounding(theCursor, 2)
|
||||
else:
|
||||
self._wrapSelection("~~")
|
||||
|
||||
return
|
||||
|
||||
def _formatBlock(self, docAction):
|
||||
"""Changes the block format of the block under the cursor.
|
||||
"""
|
||||
|
||||
+51
-43
@@ -33,7 +33,7 @@ from PyQt5.QtGui import (
|
||||
QColor, QTextCharFormat, QFont, QSyntaxHighlighter, QBrush
|
||||
)
|
||||
|
||||
from nw.constants import nwUnicode
|
||||
from nw.constants import nwUnicode, nwRegEx
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -78,7 +78,6 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
||||
"""Initialise the syntax highlighter, setting all the colour
|
||||
rules and building the regexes.
|
||||
"""
|
||||
|
||||
logger.debug("Setting up highlighting rules")
|
||||
|
||||
self.colHead = QColor(*self.theTheme.colHead)
|
||||
@@ -98,28 +97,28 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
||||
self.colTrail.setAlpha(64)
|
||||
|
||||
self.hStyles = {
|
||||
"header1" : self._makeFormat(self.colHead, "bold",1.8),
|
||||
"header2" : self._makeFormat(self.colHead, "bold",1.6),
|
||||
"header3" : self._makeFormat(self.colHead, "bold",1.4),
|
||||
"header4" : self._makeFormat(self.colHead, "bold",1.2),
|
||||
"header1h" : self._makeFormat(self.colHeadH,"bold",1.8),
|
||||
"header2h" : self._makeFormat(self.colHeadH,"bold",1.6),
|
||||
"header3h" : self._makeFormat(self.colHeadH,"bold",1.4),
|
||||
"header4h" : self._makeFormat(self.colHeadH,"bold",1.2),
|
||||
"bold" : self._makeFormat(self.colEmph, "bold"),
|
||||
"italic" : self._makeFormat(self.colEmph, "italic"),
|
||||
"strike" : self._makeFormat(self.colEmph, "strike"),
|
||||
"underline" : self._makeFormat(self.colEmph, "underline"),
|
||||
"trailing" : self._makeFormat(self.colTrail,"background"),
|
||||
"nobreak" : self._makeFormat(self.colTrail,"background"),
|
||||
"dialogue1" : self._makeFormat(self.colDialN),
|
||||
"dialogue2" : self._makeFormat(self.colDialD),
|
||||
"dialogue3" : self._makeFormat(self.colDialS),
|
||||
"replace" : self._makeFormat(self.colRepTag),
|
||||
"hidden" : self._makeFormat(self.colComm),
|
||||
"keyword" : self._makeFormat(self.colKey),
|
||||
"modifier" : self._makeFormat(self.colMod),
|
||||
"value" : self._makeFormat(self.colVal),
|
||||
"header1" : self._makeFormat(self.colHead, "bold", 1.8),
|
||||
"header2" : self._makeFormat(self.colHead, "bold", 1.6),
|
||||
"header3" : self._makeFormat(self.colHead, "bold", 1.4),
|
||||
"header4" : self._makeFormat(self.colHead, "bold", 1.2),
|
||||
"header1h" : self._makeFormat(self.colHeadH, "bold", 1.8),
|
||||
"header2h" : self._makeFormat(self.colHeadH, "bold", 1.6),
|
||||
"header3h" : self._makeFormat(self.colHeadH, "bold", 1.4),
|
||||
"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"),
|
||||
"dialogue1" : self._makeFormat(self.colDialN),
|
||||
"dialogue2" : self._makeFormat(self.colDialD),
|
||||
"dialogue3" : self._makeFormat(self.colDialS),
|
||||
"replace" : self._makeFormat(self.colRepTag),
|
||||
"hidden" : self._makeFormat(self.colComm),
|
||||
"keyword" : self._makeFormat(self.colKey),
|
||||
"modifier" : self._makeFormat(self.colMod),
|
||||
"value" : self._makeFormat(self.colVal, "underline"),
|
||||
}
|
||||
|
||||
self.hRules = []
|
||||
@@ -131,7 +130,7 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
||||
}
|
||||
))
|
||||
|
||||
# Non-breaking Space
|
||||
# Non-Breaking Spaces
|
||||
self.hRules.append((
|
||||
"[%s]+" % nwUnicode.U_NBSP, {
|
||||
0 : self.hStyles["nobreak"],
|
||||
@@ -140,23 +139,30 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
||||
|
||||
# Markdown
|
||||
self.hRules.append((
|
||||
r"(?<![\w|\\])([\*]{2})(?!\s)(?m:(.+?))(?<![\s|\\])(\1)(?!\w)", {
|
||||
1 : self.hStyles["hidden"],
|
||||
2 : self.hStyles["bold"],
|
||||
3 : self.hStyles["hidden"],
|
||||
}
|
||||
))
|
||||
self.hRules.append((
|
||||
r"(?<![\w|_|\\])([_])(?!\s|\1)(?m:(.+?))(?<![\s|\\])(\1)(?!\w)", {
|
||||
nwRegEx.FMT_I, {
|
||||
1 : self.hStyles["hidden"],
|
||||
2 : self.hStyles["italic"],
|
||||
3 : self.hStyles["hidden"],
|
||||
}
|
||||
))
|
||||
self.hRules.append((
|
||||
r"(?<![\w|\\])([_]{2})(?!\s)(?m:(.+?))(?<![\s|\\])(\1)(?!\w)", {
|
||||
nwRegEx.FMT_B, {
|
||||
1 : self.hStyles["hidden"],
|
||||
2 : self.hStyles["underline"],
|
||||
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"],
|
||||
}
|
||||
))
|
||||
@@ -196,9 +202,10 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
||||
# Build a QRegExp for spell checker
|
||||
# Include additional characters that the highlighter should
|
||||
# consider to be word separators
|
||||
wordSep = "_+"
|
||||
wordSep = r"_\+"
|
||||
wordSep += nwUnicode.U_ENDASH
|
||||
wordSep += nwUnicode.U_EMDASH
|
||||
self.spellRx = QRegularExpression("\\b[^\\s%s]+\\b" % wordSep)
|
||||
self.spellRx = QRegularExpression(r"\b[^\s"+wordSep+r"]+\b")
|
||||
self.spellRx.setPatternOptions(QRegularExpression.UseUnicodePropertiesOption)
|
||||
|
||||
return True
|
||||
@@ -233,7 +240,7 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
||||
def highlightBlock(self, theText):
|
||||
"""Highlight a single block. Prefer to check first character for
|
||||
all formats that are defined by their initial characters. This
|
||||
is significantly faster than running the regex checks we use for
|
||||
is significantly faster than running the regex checks used for
|
||||
text paragraphs.
|
||||
"""
|
||||
if self.theHandle is None or not theText:
|
||||
@@ -244,9 +251,9 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
||||
isValid, theBits, thePos = self.theIndex.scanThis(theText)
|
||||
isGood = self.theIndex.checkThese(theBits, tItem)
|
||||
if isValid:
|
||||
for n in range(len(theBits)):
|
||||
for n, theBit in enumerate(theBits):
|
||||
xPos = thePos[n]
|
||||
xLen = len(theBits[n])
|
||||
xLen = len(theBit)
|
||||
if isGood[n]:
|
||||
if n == 0:
|
||||
self.setFormat(xPos, xLen, self.hStyles["keyword"])
|
||||
@@ -279,11 +286,12 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
||||
self.setFormat(4, len(theText), self.hStyles["header4"])
|
||||
|
||||
elif theText.startswith("%"): # Comments
|
||||
toCheck = theText[1:].lstrip().lower()
|
||||
toCheck = theText[1:].lstrip()
|
||||
synTag = toCheck[:9].lower()
|
||||
tLen = len(theText)
|
||||
cLen = len(toCheck)
|
||||
cOff = tLen - cLen
|
||||
if toCheck.startswith("synopsis:"):
|
||||
if synTag == "synopsis:":
|
||||
self.setFormat(0, cOff+9, self.hStyles["modifier"])
|
||||
self.setFormat(cOff+9, tLen, self.hStyles["hidden"])
|
||||
else:
|
||||
@@ -341,7 +349,7 @@ class GuiDocHighlighter(QSyntaxHighlighter):
|
||||
if "underline" in fmtStyle:
|
||||
theFormat.setFontUnderline(True)
|
||||
if "background" in fmtStyle:
|
||||
theFormat.setBackground(QBrush(fmtCol,Qt.SolidPattern))
|
||||
theFormat.setBackground(QBrush(fmtCol, Qt.SolidPattern))
|
||||
|
||||
if fmtSize is not None:
|
||||
theFormat.setFontPointSize(round(fmtSize*self.mainConf.textSize))
|
||||
|
||||
+19
-12
@@ -515,13 +515,6 @@ class GuiMainMenu(QMenuBar):
|
||||
# Format
|
||||
self.fmtMenu = self.addMenu("&Format")
|
||||
|
||||
# Format > Bold Text
|
||||
self.aFmtBold = QAction("Bold Text", self)
|
||||
self.aFmtBold.setStatusTip("Make selected text bold")
|
||||
self.aFmtBold.setShortcut("Ctrl+B")
|
||||
self.aFmtBold.triggered.connect(lambda: self._docAction(nwDocAction.BOLD))
|
||||
self.fmtMenu.addAction(self.aFmtBold)
|
||||
|
||||
# Format > Italic Text
|
||||
self.aFmtItalic = QAction("Italic Text", self)
|
||||
self.aFmtItalic.setStatusTip("Make selected text italic")
|
||||
@@ -529,12 +522,26 @@ class GuiMainMenu(QMenuBar):
|
||||
self.aFmtItalic.triggered.connect(lambda: self._docAction(nwDocAction.ITALIC))
|
||||
self.fmtMenu.addAction(self.aFmtItalic)
|
||||
|
||||
# Format > Bold Text
|
||||
self.aFmtBold = QAction("Bold Text", self)
|
||||
self.aFmtBold.setStatusTip("Make selected text bold")
|
||||
self.aFmtBold.setShortcut("Ctrl+B")
|
||||
self.aFmtBold.triggered.connect(lambda: self._docAction(nwDocAction.BOLD))
|
||||
self.fmtMenu.addAction(self.aFmtBold)
|
||||
|
||||
# Format > Underline Text
|
||||
self.aFmtULine = QAction("Underline Text", self)
|
||||
self.aFmtULine.setStatusTip("Underline selected text")
|
||||
self.aFmtULine.setShortcut("Ctrl+U")
|
||||
self.aFmtULine.triggered.connect(lambda: self._docAction(nwDocAction.U_LINE))
|
||||
self.fmtMenu.addAction(self.aFmtULine)
|
||||
self.aFmtBoldIt = QAction("Bold Italic Text", self)
|
||||
self.aFmtBoldIt.setStatusTip("Make selected text bold and italic")
|
||||
self.aFmtBoldIt.setShortcut("Ctrl+Shift+B")
|
||||
self.aFmtBoldIt.triggered.connect(lambda: self._docAction(nwDocAction.BOLDITALIC))
|
||||
self.fmtMenu.addAction(self.aFmtBoldIt)
|
||||
|
||||
# Format > Strikethrough
|
||||
self.aFmtStrike = QAction("Strikethrough Text", self)
|
||||
self.aFmtStrike.setStatusTip("Strikethrough selected text")
|
||||
self.aFmtStrike.setShortcut("Ctrl+-")
|
||||
self.aFmtStrike.triggered.connect(lambda: self._docAction(nwDocAction.STRIKE))
|
||||
self.fmtMenu.addAction(self.aFmtStrike)
|
||||
|
||||
# Edit > Separator
|
||||
self.fmtMenu.addSeparator()
|
||||
|
||||
+2
-2
@@ -961,9 +961,9 @@ class GuiMain(QMainWindow):
|
||||
self.addAction(self.mainMenu.aEditPaste)
|
||||
self.addAction(self.mainMenu.aSelectAll)
|
||||
self.addAction(self.mainMenu.aSelectPar)
|
||||
self.addAction(self.mainMenu.aFmtBold)
|
||||
self.addAction(self.mainMenu.aFmtItalic)
|
||||
self.addAction(self.mainMenu.aFmtULine)
|
||||
self.addAction(self.mainMenu.aFmtBold)
|
||||
self.addAction(self.mainMenu.aFmtBoldIt)
|
||||
self.addAction(self.mainMenu.aFmtDQuote)
|
||||
self.addAction(self.mainMenu.aFmtSQuote)
|
||||
self.addAction(self.mainMenu.aFmtHead1)
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
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 __underscore__.
|
||||
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.
|
||||
|
||||
In addition, the editor supports automatic formatting of “quotes”, both double and ‘single’. Depending on the syntax highlighter, these can be in different colours.
|
||||
|
||||
|
||||
@@ -14,6 +14,3 @@ In fact, if you wish, you can add all the scenes in the chapter file too. All no
|
||||
@location: Earth
|
||||
|
||||
This is a second scene in the same file as the previous scene. You can always split the files up later.
|
||||
|
||||
|
||||
|
||||
|
||||
+11
-11
@@ -1,21 +1,21 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<novelWriterXML appVersion="0.9.0rc1" hexVersion="0x000900c1" fileVersion="1.1" timeStamp="2020-06-12 17:13:30">
|
||||
<novelWriterXML appVersion="0.9.0rc1" hexVersion="0x000900c1" fileVersion="1.1" timeStamp="2020-06-13 10:26:35">
|
||||
<project>
|
||||
<name>Sample Project</name>
|
||||
<title>Sample Project</title>
|
||||
<author>Jane Smith</author>
|
||||
<author>Jay Doh</author>
|
||||
<saveCount>280</saveCount>
|
||||
<autoCount>41</autoCount>
|
||||
<editTime>4312</editTime>
|
||||
<saveCount>332</saveCount>
|
||||
<autoCount>56</autoCount>
|
||||
<editTime>10692</editTime>
|
||||
</project>
|
||||
<settings>
|
||||
<doBackup>False</doBackup>
|
||||
<spellCheck>True</spellCheck>
|
||||
<autoOutline>True</autoOutline>
|
||||
<lastEdited>bc0cbd2a407f3</lastEdited>
|
||||
<lastViewed>b3e74dbc1f584</lastViewed>
|
||||
<lastWordCount>920</lastWordCount>
|
||||
<lastEdited>636b6aa9b697b</lastEdited>
|
||||
<lastViewed>636b6aa9b697b</lastViewed>
|
||||
<lastWordCount>927</lastWordCount>
|
||||
<autoReplace>
|
||||
<A>B</A>
|
||||
<B>E</B>
|
||||
@@ -114,10 +114,10 @@
|
||||
<status>1st Draft</status>
|
||||
<exported>True</exported>
|
||||
<layout>SCENE</layout>
|
||||
<charCount>1199</charCount>
|
||||
<wordCount>216</wordCount>
|
||||
<charCount>1240</charCount>
|
||||
<wordCount>223</wordCount>
|
||||
<paraCount>7</paraCount>
|
||||
<cursorPos>950</cursorPos>
|
||||
<cursorPos>403</cursorPos>
|
||||
</item>
|
||||
<item handle="bc0cbd2a407f3" order="2" parent="e7ded148d6e4a">
|
||||
<name>Another Scene</name>
|
||||
@@ -129,7 +129,7 @@
|
||||
<charCount>476</charCount>
|
||||
<wordCount>93</wordCount>
|
||||
<paraCount>3</paraCount>
|
||||
<cursorPos>551</cursorPos>
|
||||
<cursorPos>428</cursorPos>
|
||||
</item>
|
||||
<item handle="ba8a28a246524" order="3" parent="e7ded148d6e4a">
|
||||
<name>Interlude</name>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
%%~ 04468803b92e1:60bdf227455cc:Ancient Europe
|
||||
%%~ 04468803b92e1:60bdf227455cc:WORLD:NOTE:Ancient Europe
|
||||
# Ancient Europe
|
||||
|
||||
@tag: Europe
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
%%~ 2426c6f0ca922:6c6afb1247750:Main
|
||||
%%~ 2426c6f0ca922:6c6afb1247750:PLOT:NOTE:Main
|
||||
# Main Plot
|
||||
|
||||
@tag: Main
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
%%~ 441420a886d82:6bd935d2490cd:b3643d0f92e32:Chapter Two
|
||||
%%~ 441420a886d82:6bd935d2490cd:b3643d0f92e32:NOVEL:CHAPTER:Chapter Two
|
||||
## Chapter Two
|
||||
|
||||
@pov: Bod
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
%%~ 47666c91c7ccf:6bd935d2490cd:b3643d0f92e32:Scene Five
|
||||
%%~ 47666c91c7ccf:6bd935d2490cd:b3643d0f92e32:NOVEL:SCENE:Scene Five
|
||||
### Scene Five
|
||||
|
||||
@pov: Bod
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
%%~ 4c4f28287af27:67a8707f2f249:Mr. Nobody
|
||||
%%~ 4c4f28287af27:67a8707f2f249:CHARACTER:NOTE:Mr. Nobody
|
||||
# Nobody Owens
|
||||
|
||||
@tag: Bod
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
%%~ 7a992350f3eb6:b3643d0f92e32:Lorem Ipusm
|
||||
%%~ 7a992350f3eb6:b3643d0f92e32:NOVEL:TITLE:Lorem Ipusm
|
||||
# Lorem Ipsum
|
||||
|
||||
**By lipsum.com**
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
%%~ 846352075de7d:b3643d0f92e32:Interlude
|
||||
%%~ 846352075de7d:b3643d0f92e32:NOVEL:BOOK:Interlude
|
||||
## Why do we use it?
|
||||
|
||||
% Exctracted from the lipsum.com website.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
%%~ 88243afbe5ed8:45e6b01ca35c1:b3643d0f92e32:Scene One
|
||||
%%~ 88243afbe5ed8:45e6b01ca35c1:b3643d0f92e32:NOVEL:SCENE:Scene One
|
||||
### Scene One
|
||||
|
||||
@pov: Bod
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
%%~ 88d59a277361b:b3643d0f92e32:Prologue
|
||||
%%~ 88d59a277361b:b3643d0f92e32:NOVEL:UNNUMBERED:Prologue
|
||||
## Prologue
|
||||
|
||||
% 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,4 +1,4 @@
|
||||
%%~ 8c58a65414c23:b3643d0f92e32:Front Matter
|
||||
%%~ 8c58a65414c23:b3643d0f92e32:NOVEL:PAGE:Front Matter
|
||||
% Exctracted from the lipsum.com website.
|
||||
|
||||
Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of “de Finibus Bonorum et Malorum” (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, “Lorem ipsum dolor sit amet..”, comes from a line in section 1.10.32.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
%%~ db7e733775d4d:b3643d0f92e32:Act One
|
||||
%%~ db7e733775d4d:b3643d0f92e32:NOVEL:PARTITION:Act One
|
||||
# Act One
|
||||
|
||||
“Fusce maximus felis libero”
|
||||
@@ -1,4 +1,4 @@
|
||||
%%~ eb103bc70c90c:6bd935d2490cd:b3643d0f92e32:Scene Three
|
||||
%%~ eb103bc70c90c:6bd935d2490cd:b3643d0f92e32:NOVEL:SCENE:Scene Three
|
||||
### Scene Three
|
||||
|
||||
@pov: Bod
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
%%~ f8c0562e50f1b:6bd935d2490cd:b3643d0f92e32:Scene Four
|
||||
%%~ f8c0562e50f1b:6bd935d2490cd:b3643d0f92e32:NOVEL:SCENE:Scene Four
|
||||
### Scene Four
|
||||
|
||||
@pov: Bod
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
%%~ f96ec11c6a3da:45e6b01ca35c1:b3643d0f92e32:Scene Two
|
||||
%%~ f96ec11c6a3da:45e6b01ca35c1:b3643d0f92e32:NOVEL:SCENE:Scene Two
|
||||
### Scene Two
|
||||
|
||||
@pov: Bod
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
%%~ fb609cd8319dc:45e6b01ca35c1:b3643d0f92e32:Chapter One
|
||||
%%~ fb609cd8319dc:45e6b01ca35c1:b3643d0f92e32:NOVEL:CHAPTER:Chapter One
|
||||
## Chapter One
|
||||
|
||||
@pov: Bod
|
||||
|
||||
+14
-14
@@ -1,17 +1,20 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<novelWriterXML appVersion="0.7.0rc1" hexVersion="0x000700c1" fileVersion="1.1" saveCount="6" autoCount="20" timeStamp="2020-05-30 12:03:01" editTime="1408">
|
||||
<novelWriterXML appVersion="0.9.0rc1" hexVersion="0x000900c1" fileVersion="1.1" timeStamp="2020-06-13 00:37:49">
|
||||
<project>
|
||||
<name>Lorem Ipsum</name>
|
||||
<title>Lorem Ipsum</title>
|
||||
<author>lipsum.com</author>
|
||||
<backup>False</backup>
|
||||
<saveCount>7</saveCount>
|
||||
<autoCount>21</autoCount>
|
||||
<editTime>1459</editTime>
|
||||
</project>
|
||||
<settings>
|
||||
<doBackup>False</doBackup>
|
||||
<spellCheck>False</spellCheck>
|
||||
<autoOutline>True</autoOutline>
|
||||
<lastEdited>88d59a277361b</lastEdited>
|
||||
<lastEdited>04468803b92e1</lastEdited>
|
||||
<lastViewed>None</lastViewed>
|
||||
<lastWordCount>3397</lastWordCount>
|
||||
<lastWordCount>3847</lastWordCount>
|
||||
<autoReplace>
|
||||
<Rep1>Replace Text 1</Rep1>
|
||||
<Rep2>Replace Text 2</Rep2>
|
||||
@@ -22,9 +25,6 @@
|
||||
<unnumbered>%title%</unnumbered>
|
||||
<scene>* * *</scene>
|
||||
<section></section>
|
||||
<withSynopsis>False</withSynopsis>
|
||||
<withComments>False</withComments>
|
||||
<withKeywords>False</withKeywords>
|
||||
</titleFormat>
|
||||
<status>
|
||||
<entry blue="100" green="100" red="100">New</entry>
|
||||
@@ -81,7 +81,7 @@
|
||||
<charCount>584</charCount>
|
||||
<wordCount>92</wordCount>
|
||||
<paraCount>1</paraCount>
|
||||
<cursorPos>35</cursorPos>
|
||||
<cursorPos>79</cursorPos>
|
||||
</item>
|
||||
<item handle="db7e733775d4d" order="3" parent="b3643d0f92e32">
|
||||
<name>Act One</name>
|
||||
@@ -238,9 +238,9 @@
|
||||
<status>Main</status>
|
||||
<exported>True</exported>
|
||||
<layout>NOTE</layout>
|
||||
<charCount>9</charCount>
|
||||
<wordCount>2</wordCount>
|
||||
<paraCount>0</paraCount>
|
||||
<charCount>1369</charCount>
|
||||
<wordCount>195</wordCount>
|
||||
<paraCount>2</paraCount>
|
||||
<cursorPos>1387</cursorPos>
|
||||
</item>
|
||||
<item handle="60bdf227455cc" order="3" parent="None">
|
||||
@@ -257,9 +257,9 @@
|
||||
<status>Minor</status>
|
||||
<exported>True</exported>
|
||||
<layout>NOTE</layout>
|
||||
<charCount>14</charCount>
|
||||
<wordCount>2</wordCount>
|
||||
<paraCount>0</paraCount>
|
||||
<charCount>1770</charCount>
|
||||
<wordCount>259</wordCount>
|
||||
<paraCount>3</paraCount>
|
||||
<cursorPos>1792</cursorPos>
|
||||
</item>
|
||||
</content>
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user