Update tests and word counter

This commit is contained in:
Veronica Berglyd Olsen
2023-11-06 11:49:26 +01:00
parent 5e41dd9a92
commit b03603cc9b
8 changed files with 81 additions and 53 deletions
+6 -1
View File
@@ -23,6 +23,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
""" """
from __future__ import annotations from __future__ import annotations
import re
from PyQt5.QtCore import QCoreApplication, QT_TRANSLATE_NOOP from PyQt5.QtCore import QCoreApplication, QT_TRANSLATE_NOOP
from novelwriter.enum import nwBuildFmt, nwItemClass, nwItemLayout, nwOutline from novelwriter.enum import nwBuildFmt, nwItemClass, nwItemLayout, nwOutline
@@ -59,9 +61,12 @@ class nwRegEx:
FMT_EI = r"(?<![\w\\])(_)(?![\s_])(.+?)(?<![\s\\])(\1)(?!\w)" FMT_EI = r"(?<![\w\\])(_)(?![\s_])(.+?)(?<![\s\\])(\1)(?!\w)"
FMT_EB = r"(?<![\w\\])([\*]{2})(?![\s\*])(.+?)(?<![\s\\])(\1)(?!\w)" FMT_EB = r"(?<![\w\\])([\*]{2})(?![\s\*])(.+?)(?<![\s\\])(\1)(?!\w)"
FMT_ST = r"(?<![\w\\])([~]{2})(?![\s~])(.+?)(?<![\s\\])(\1)(?!\w)" FMT_ST = r"(?<![\w\\])([~]{2})(?![\s~])(.+?)(?<![\s\\])(\1)(?!\w)"
FMT_SC = r"(?<!\\)(\[[\/\!]?(?i)(?:i|b|s|u|sup|sub)\])" FMT_SC = r"(?i)(?<!\\)(\[[\/\!]?(?:i|b|s|u|sup|sub)\])"
FMT_SV = r"(?<!\\)(\[(?i)(?:fn|footnote):)(.+?)(?<!\\)(\])" FMT_SV = r"(?<!\\)(\[(?i)(?:fn|footnote):)(.+?)(?<!\\)(\])"
# Pre-Compiled RegEx
RX_SC = re.compile(FMT_SC)
# END Class nwRegEx # END Class nwRegEx
+8 -3
View File
@@ -38,7 +38,7 @@ from pathlib import Path
from novelwriter.enum import nwItemClass, nwItemType, nwItemLayout from novelwriter.enum import nwItemClass, nwItemType, nwItemLayout
from novelwriter.error import logException from novelwriter.error import logException
from novelwriter.common import checkInt, isHandle, isItemClass, isTitleTag, jsonEncode from novelwriter.common import checkInt, isHandle, isItemClass, isTitleTag, jsonEncode
from novelwriter.constants import nwFiles, nwKeyWords, nwUnicode, nwHeaders from novelwriter.constants import nwFiles, nwKeyWords, nwRegEx, nwUnicode, nwHeaders
if TYPE_CHECKING: # pragma: no cover if TYPE_CHECKING: # pragma: no cover
from novelwriter.core.item import NWItem from novelwriter.core.item import NWItem
@@ -1229,6 +1229,10 @@ def countWords(text: str) -> tuple[int, int, int]:
if nwUnicode.U_EMDASH in text: if nwUnicode.U_EMDASH in text:
text = text.replace(nwUnicode.U_EMDASH, " ") text = text.replace(nwUnicode.U_EMDASH, " ")
# Strip shortcodes
if "[" in text:
text = nwRegEx.RX_SC.sub("", text)
for line in text.splitlines(): for line in text.splitlines():
countPara = True countPara = True
@@ -1241,9 +1245,10 @@ def countWords(text: str) -> tuple[int, int, int]:
continue continue
if line[0] == "[": if line[0] == "[":
if line.startswith(("[NEWPAGE]", "[NEW PAGE]", "[VSPACE]")): check = line.lower()
if check.startswith(("[newpage]", "[new page]", "[vspace]")):
continue continue
elif line.startswith("[VSPACE:") and line.endswith("]"): elif check.startswith("[vspace:") and line.endswith("]"):
continue continue
elif line[0] == "#": elif line[0] == "#":
+15 -22
View File
@@ -55,6 +55,7 @@ from novelwriter.enum import nwDocAction, nwDocInsert, nwDocMode, nwItemClass
from novelwriter.common import minmax, transferCase from novelwriter.common import minmax, transferCase
from novelwriter.constants import nwKeyWords, nwUnicode from novelwriter.constants import nwKeyWords, nwUnicode
from novelwriter.core.index import countWords from novelwriter.core.index import countWords
from novelwriter.core.document import NWDocument
from novelwriter.gui.dochighlight import GuiDocHighlighter from novelwriter.gui.dochighlight import GuiDocHighlighter
from novelwriter.gui.editordocument import GuiTextDocument from novelwriter.gui.editordocument import GuiTextDocument
from novelwriter.extensions.wheeleventfilter import WheelEventFilter from novelwriter.extensions.wheeleventfilter import WheelEventFilter
@@ -408,12 +409,6 @@ class GuiDocEditor(QPlainTextEdit):
self._qDocument.syntaxHighlighter.rehighlightByType(GuiDocHighlighter.BLOCK_META) self._qDocument.syntaxHighlighter.rehighlightByType(GuiDocHighlighter.BLOCK_META)
return return
def redrawText(self) -> None:
"""Redraw the text by marking the document content as dirty."""
self._qDocument.markContentsDirty(0, self._qDocument.characterCount())
self.updateDocMargins()
return
def replaceText(self, text: str) -> None: def replaceText(self, text: str) -> None:
"""Replace the text of the current document with the provided """Replace the text of the current document with the provided
text. This also clears undo history. text. This also clears undo history.
@@ -735,19 +730,17 @@ class GuiDocEditor(QPlainTextEdit):
"""Tell the user where on the file system the file in the editor """Tell the user where on the file system the file in the editor
is saved. is saved.
""" """
if self._nwDocument is None: if isinstance(self._nwDocument, NWDocument):
logger.error("No document open") SHARED.info(
return "<br>".join([
SHARED.info( self.tr("Document Details"),
"<br>".join([ ""*40,
self.tr("Document Details"), self.tr("Created: {0}").format(self._nwDocument.createdDate),
""*40, self.tr("Updated: {0}").format(self._nwDocument.updatedDate),
self.tr("Created: {0}").format(self._nwDocument.createdDate), ]),
self.tr("Updated: {0}").format(self._nwDocument.updatedDate), details=self.tr("File Location: {0}").format(self._nwDocument.fileLocation),
]), log=False
details=self.tr("File Location: {0}").format(self._nwDocument.fileLocation), )
log=False
)
return return
def insertText(self, insert: str | nwDocInsert) -> bool: def insertText(self, insert: str | nwDocInsert) -> bool:
@@ -775,15 +768,15 @@ class GuiDocEditor(QPlainTextEdit):
newBlock = True newBlock = True
goAfter = True goAfter = True
elif insert == nwDocInsert.NEW_PAGE: elif insert == nwDocInsert.NEW_PAGE:
text = "[NEW PAGE]" text = "[newpage]"
newBlock = True newBlock = True
goAfter = False goAfter = False
elif insert == nwDocInsert.VSPACE_S: elif insert == nwDocInsert.VSPACE_S:
text = "[VSPACE]" text = "[vspace]"
newBlock = True newBlock = True
goAfter = False goAfter = False
elif insert == nwDocInsert.VSPACE_M: elif insert == nwDocInsert.VSPACE_M:
text = "[VSPACE:2]" text = "[vspace:2]"
newBlock = True newBlock = True
goAfter = False goAfter = False
else: else:
+5 -5
View File
@@ -1,11 +1,11 @@
%%~name: Page %%~name: Page
%%~path: 7031beac91f75/974e400180a99 %%~path: 7031beac91f75/974e400180a99
%%~kind: NOVEL/DOCUMENT %%~kind: NOVEL/DOCUMENT
%%~hash: 7547809e972205eb2a55dd988595e0aa1d01e139 %%~hash: a0b0719e19763bf505bcf797bea0968c505c9b4a
%%~date: Unknown/2023-08-25 16:51:54 %%~date: Unknown/2023-11-06 11:19:33
[NEW PAGE] [newpage]
[VSPACE:2] [vspace:2]
This is a plain page with some text on it. This is a plain page with some text on it.
If you want the text to start on a fresh page, add the [NEW PAGE] code above the text. You can also add empty paragraphs with the [VSPACE] code. The above code adds two empty paragraphs before the text starts. If you want the text to start on a fresh page, add the [newpage] code above the text. You can also add empty paragraphs with the [vspace] code. The above code adds two empty paragraphs before the text starts.
+5 -5
View File
@@ -1,6 +1,6 @@
<?xml version='1.0' encoding='utf-8'?> <?xml version='1.0' encoding='utf-8'?>
<novelWriterXML appVersion="2.2-alpha1" hexVersion="0x020200a1" fileVersion="1.5" fileRevision="1" timeStamp="2023-10-20 22:58:21"> <novelWriterXML appVersion="2.2-alpha1" hexVersion="0x020200a1" fileVersion="1.5" fileRevision="1" timeStamp="2023-11-06 11:44:21">
<project id="e2be99af-f9bf-4403-857a-c3d1ac25abea" saveCount="1605" autoCount="254" editTime="80970"> <project id="e2be99af-f9bf-4403-857a-c3d1ac25abea" saveCount="1609" autoCount="255" editTime="81165">
<name>Sample Project</name> <name>Sample Project</name>
<title>Sample Project</title> <title>Sample Project</title>
<author>Jane Smith</author> <author>Jane Smith</author>
@@ -36,7 +36,7 @@
<entry key="i56be10" count="1" red="117" green="0" blue="175">Main</entry> <entry key="i56be10" count="1" red="117" green="0" blue="175">Main</entry>
</importance> </importance>
</settings> </settings>
<content items="27" novelWords="988" notesWords="409"> <content items="27" novelWords="989" notesWords="409">
<item handle="7031beac91f75" parent="None" root="7031beac91f75" order="0" type="ROOT" class="NOVEL"> <item handle="7031beac91f75" parent="None" root="7031beac91f75" order="0" type="ROOT" class="NOVEL">
<meta expanded="yes" /> <meta expanded="yes" />
<name status="sc24b8f" import="ia857f0">Novel</name> <name status="sc24b8f" import="ia857f0">Novel</name>
@@ -46,7 +46,7 @@
<name status="sc24b8f" import="ia857f0" active="yes">Title Page</name> <name status="sc24b8f" import="ia857f0" active="yes">Title Page</name>
</item> </item>
<item handle="974e400180a99" parent="7031beac91f75" root="7031beac91f75" order="1" type="FILE" class="NOVEL" layout="DOCUMENT"> <item handle="974e400180a99" parent="7031beac91f75" root="7031beac91f75" order="1" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta expanded="no" heading="H0" charCount="251" wordCount="50" paraCount="2" cursorPos="10" /> <meta expanded="no" heading="H0" charCount="269" wordCount="51" paraCount="3" cursorPos="275" />
<name status="sf12341" import="ia857f0" active="yes">Page</name> <name status="sf12341" import="ia857f0" active="yes">Page</name>
</item> </item>
<item handle="edca4be2fcaf8" parent="7031beac91f75" root="7031beac91f75" order="2" type="FILE" class="NOVEL" layout="DOCUMENT"> <item handle="edca4be2fcaf8" parent="7031beac91f75" root="7031beac91f75" order="2" type="FILE" class="NOVEL" layout="DOCUMENT">
@@ -58,7 +58,7 @@
<name status="sf24ce6" import="ia857f0" active="yes">Chapter One</name> <name status="sf24ce6" import="ia857f0" active="yes">Chapter One</name>
</item> </item>
<item handle="636b6aa9b697b" parent="6a2d6d5f4f401" root="7031beac91f75" order="0" type="FILE" class="NOVEL" layout="DOCUMENT"> <item handle="636b6aa9b697b" parent="6a2d6d5f4f401" root="7031beac91f75" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta expanded="no" heading="H3" charCount="2937" wordCount="513" paraCount="15" cursorPos="19" /> <meta expanded="no" heading="H3" charCount="2901" wordCount="513" paraCount="15" cursorPos="749" />
<name status="s90e6c9" import="ia857f0" active="yes">Making a Scene</name> <name status="s90e6c9" import="ia857f0" active="yes">Making a Scene</name>
</item> </item>
<item handle="bc0cbd2a407f3" parent="6a2d6d5f4f401" root="7031beac91f75" order="1" type="FILE" class="NOVEL" layout="DOCUMENT"> <item handle="bc0cbd2a407f3" parent="6a2d6d5f4f401" root="7031beac91f75" order="1" type="FILE" class="NOVEL" layout="DOCUMENT">
+26 -1
View File
@@ -1281,7 +1281,7 @@ def testCoreIndex_CountWords():
assert wC == 9 assert wC == 9
assert pC == 4 assert pC == 4
# Formatting Codes # Formatting Codes, Upper Case (Old Implementation)
cC, wC, pC = countWords(( cC, wC, pC = countWords((
"Some text\n\n" "Some text\n\n"
"[NEWPAGE]\n\n" "[NEWPAGE]\n\n"
@@ -1297,4 +1297,29 @@ def testCoreIndex_CountWords():
assert wC == 13 assert wC == 13
assert pC == 5 assert pC == 5
# Formatting Codes, Lower Case (Current Implementation)
cC, wC, pC = countWords((
"Some text\n\n"
"[newpage]\n\n"
"more text\n\n"
"[new page]]\n\n"
"even more text\n\n"
"[vspace]\n\n"
"and some final text\n\n"
"[vspace:4]\n\n"
"THE END\n\n"
))
assert cC == 58
assert wC == 13
assert pC == 5
# Check ShortCodes
cC, wC, pC = countWords((
"Text with [b]bold[/b] text and padded [b] bold [/b] text.\n\n"
"Text with [b][i] nested [/i] emphasis [/b] in it.\n\n"
))
assert cC == 78
assert wC == 14
assert pC == 2
# END Test testCoreIndex_CountWords # END Test testCoreIndex_CountWords
+13 -13
View File
@@ -789,7 +789,7 @@ def testCoreToken_SpecialFormat(mockGUI):
tokens._isFirst = True tokens._isFirst = True
tokens._text = ( tokens._text = (
"# Title One\n\n" "# Title One\n\n"
"[NEWPAGE]\n\n" "[newpage]\n\n"
"# Title Two\n\n" "# Title Two\n\n"
) )
tokens.tokenizeText() tokens.tokenizeText()
@@ -799,7 +799,7 @@ def testCoreToken_SpecialFormat(mockGUI):
tokens._isFirst = True tokens._isFirst = True
tokens._text = ( tokens._text = (
"# Title One\n\n" "# Title One\n\n"
"[NEW PAGE]\n\n" "[new page]\n\n"
"# Title Two\n\n" "# Title Two\n\n"
) )
tokens.tokenizeText() tokens.tokenizeText()
@@ -809,7 +809,7 @@ def testCoreToken_SpecialFormat(mockGUI):
tokens._isFirst = True tokens._isFirst = True
tokens._text = ( tokens._text = (
"# Title One\n\n" "# Title One\n\n"
"[NEW PAGE] \t\n\n" "[new page] \t\n\n"
"# Title Two\n\n" "# Title Two\n\n"
) )
tokens.tokenizeText() tokens.tokenizeText()
@@ -820,7 +820,7 @@ def testCoreToken_SpecialFormat(mockGUI):
tokens._text = ( tokens._text = (
"# Title One\n\n" "# Title One\n\n"
"[VSPACE] \n\n" "[vspace] \n\n"
"Some text to go here ...\n\n" "Some text to go here ...\n\n"
) )
tokens.tokenizeText() tokens.tokenizeText()
@@ -840,7 +840,7 @@ def testCoreToken_SpecialFormat(mockGUI):
# One Skip # One Skip
tokens._text = ( tokens._text = (
"# Title One\n\n" "# Title One\n\n"
"[VSPACE:1] \n\n" "[vspace:1] \n\n"
"Some text to go here ...\n\n" "Some text to go here ...\n\n"
) )
tokens.tokenizeText() tokens.tokenizeText()
@@ -857,7 +857,7 @@ def testCoreToken_SpecialFormat(mockGUI):
# Three Skips # Three Skips
tokens._text = ( tokens._text = (
"# Title One\n\n" "# Title One\n\n"
"[VSPACE:3] \n\n" "[vspace:3] \n\n"
"Some text to go here ...\n\n" "Some text to go here ...\n\n"
) )
tokens.tokenizeText() tokens.tokenizeText()
@@ -876,7 +876,7 @@ def testCoreToken_SpecialFormat(mockGUI):
# Malformed Command, Case 1 # Malformed Command, Case 1
tokens._text = ( tokens._text = (
"# Title One\n\n" "# Title One\n\n"
"[VSPACE:3xa] \n\n" "[vspace:3xa] \n\n"
"Some text to go here ...\n\n" "Some text to go here ...\n\n"
) )
tokens.tokenizeText() tokens.tokenizeText()
@@ -892,7 +892,7 @@ def testCoreToken_SpecialFormat(mockGUI):
# Malformed Command, Case 2 # Malformed Command, Case 2
tokens._text = ( tokens._text = (
"# Title One\n\n" "# Title One\n\n"
"[VSPACE:3.5]\n\n" "[vspace:3.5]\n\n"
"Some text to go here ...\n\n" "Some text to go here ...\n\n"
) )
tokens.tokenizeText() tokens.tokenizeText()
@@ -908,7 +908,7 @@ def testCoreToken_SpecialFormat(mockGUI):
# Malformed Command, Case 3 # Malformed Command, Case 3
tokens._text = ( tokens._text = (
"# Title One\n\n" "# Title One\n\n"
"[VSPACE:-1]\n\n" "[vspace:-1]\n\n"
"Some text to go here ...\n\n" "Some text to go here ...\n\n"
) )
tokens.tokenizeText() tokens.tokenizeText()
@@ -927,8 +927,8 @@ def testCoreToken_SpecialFormat(mockGUI):
# Single Skip # Single Skip
tokens._text = ( tokens._text = (
"# Title One\n\n" "# Title One\n\n"
"[NEW PAGE]\n\n" "[new page]\n\n"
"[VSPACE]\n\n" "[vspace]\n\n"
"Some text to go here ...\n\n" "Some text to go here ...\n\n"
) )
tokens.tokenizeText() tokens.tokenizeText()
@@ -946,8 +946,8 @@ def testCoreToken_SpecialFormat(mockGUI):
# Multiple Skip # Multiple Skip
tokens._text = ( tokens._text = (
"# Title One\n\n" "# Title One\n\n"
"[NEW PAGE]\n\n" "[new page]\n\n"
"[VSPACE:3]\n\n" "[vspace:3]\n\n"
"Some text to go here ...\n\n" "Some text to go here ...\n\n"
) )
tokens.tokenizeText() tokens.tokenizeText()
+3 -3
View File
@@ -600,15 +600,15 @@ def testGuiMenu_Insert(qtbot, monkeypatch, nwGUI, fncPath, projPath, mockRnd):
nwGUI.docEditor.setPlainText("### Stuff\n") nwGUI.docEditor.setPlainText("### Stuff\n")
nwGUI.mainMenu.aInsNewPage.activate(QAction.Trigger) nwGUI.mainMenu.aInsNewPage.activate(QAction.Trigger)
assert nwGUI.docEditor.getText() == "[NEW PAGE]\n### Stuff\n" assert nwGUI.docEditor.getText() == "[newpage]\n### Stuff\n"
nwGUI.docEditor.setPlainText("### Stuff\n") nwGUI.docEditor.setPlainText("### Stuff\n")
nwGUI.mainMenu.aInsVSpaceS.activate(QAction.Trigger) nwGUI.mainMenu.aInsVSpaceS.activate(QAction.Trigger)
assert nwGUI.docEditor.getText() == "[VSPACE]\n### Stuff\n" assert nwGUI.docEditor.getText() == "[vspace]\n### Stuff\n"
nwGUI.docEditor.setPlainText("### Stuff\n") nwGUI.docEditor.setPlainText("### Stuff\n")
nwGUI.mainMenu.aInsVSpaceM.activate(QAction.Trigger) nwGUI.mainMenu.aInsVSpaceM.activate(QAction.Trigger)
assert nwGUI.docEditor.getText() == "[VSPACE:2]\n### Stuff\n" assert nwGUI.docEditor.getText() == "[vspace:2]\n### Stuff\n"
nwGUI.docEditor.clear() nwGUI.docEditor.clear()