Add support for mentions references (#2064)

This commit is contained in:
Veronica Berglyd Olsen
2024-10-25 23:17:36 +02:00
committed by GitHub
13 changed files with 190 additions and 131 deletions
+3
View File
@@ -118,6 +118,9 @@ The root folders are closely tied to the tags and reference system. Each folder
the categories of tags that can be used to reference them. For more information about the tags the categories of tags that can be used to reference them. For more information about the tags
listed, see :ref:`a_references_references`. listed, see :ref:`a_references_references`.
There is also a ``@mention`` keyword that can be used to reference any tag.
See :ref:`a_references_references` for more details.
.. note:: .. note::
You can rename root folders to whatever you want. However, this doesn't change the reference You can rename root folders to whatever you want. However, this doesn't change the reference
keyword or what they do. keyword or what they do.
+6
View File
@@ -162,6 +162,12 @@ reference keywords allow multiple values.
Custom references in the current section. The target must be a note tag in a **Custom** type Custom references in the current section. The target must be a note tag in a **Custom** type
root folder. The custom folder are for any other category of notes you may want to use. root folder. The custom folder are for any other category of notes you may want to use.
``@mention``
Anything mentioned, but not present in the current section. It is intended for those cases where
you reveal details about a character or place in a scene without it being otherwise a part of
it. This can be useful when checking for consistency later. Any tag in any root note folder can
be listed under mentions.
The syntax highlighter will alert the user that the tags and references are used correctly, and The syntax highlighter will alert the user that the tags and references are used correctly, and
that the tags referenced exist. that the tags referenced exist.
+1
View File
@@ -165,6 +165,7 @@ a key or key combination for the inserted content.
":kbd:`Ctrl+K`, :kbd:`G`", "Insert a ``@tag`` keyword" ":kbd:`Ctrl+K`, :kbd:`G`", "Insert a ``@tag`` keyword"
":kbd:`Ctrl+K`, :kbd:`H`", "Insert a short description comment" ":kbd:`Ctrl+K`, :kbd:`H`", "Insert a short description comment"
":kbd:`Ctrl+K`, :kbd:`L`", "Insert a ``@location`` keyword" ":kbd:`Ctrl+K`, :kbd:`L`", "Insert a ``@location`` keyword"
":kbd:`Ctrl+K`, :kbd:`M`", "Insert a ``@mention`` keyword"
":kbd:`Ctrl+K`, :kbd:`O`", "Insert an ``@object`` keyword" ":kbd:`Ctrl+K`, :kbd:`O`", "Insert an ``@object`` keyword"
":kbd:`Ctrl+K`, :kbd:`P`", "Insert a ``@plot`` keyword" ":kbd:`Ctrl+K`, :kbd:`P`", "Insert a ``@plot`` keyword"
":kbd:`Ctrl+K`, :kbd:`S`", "Insert a synopsis comment" ":kbd:`Ctrl+K`, :kbd:`S`", "Insert a synopsis comment"
+50 -47
View File
@@ -145,34 +145,35 @@ class nwFiles:
class nwKeyWords: class nwKeyWords:
TAG_KEY = "@tag" TAG_KEY = "@tag"
POV_KEY = "@pov" POV_KEY = "@pov"
FOCUS_KEY = "@focus" FOCUS_KEY = "@focus"
CHAR_KEY = "@char" CHAR_KEY = "@char"
PLOT_KEY = "@plot" PLOT_KEY = "@plot"
TIME_KEY = "@time" TIME_KEY = "@time"
WORLD_KEY = "@location" WORLD_KEY = "@location"
OBJECT_KEY = "@object" OBJECT_KEY = "@object"
ENTITY_KEY = "@entity" ENTITY_KEY = "@entity"
CUSTOM_KEY = "@custom" CUSTOM_KEY = "@custom"
MENTION_KEY = "@mention"
# Set of Valid Keys # Set of Valid Keys
VALID_KEYS = { VALID_KEYS = {
TAG_KEY, POV_KEY, FOCUS_KEY, CHAR_KEY, PLOT_KEY, TIME_KEY, TAG_KEY, POV_KEY, FOCUS_KEY, CHAR_KEY, PLOT_KEY, TIME_KEY,
WORLD_KEY, OBJECT_KEY, ENTITY_KEY, CUSTOM_KEY WORLD_KEY, OBJECT_KEY, ENTITY_KEY, CUSTOM_KEY, MENTION_KEY
} }
# Map from Keys to Item Class # Map from Keys to Item Class
KEY_CLASS = { KEY_CLASS = {
POV_KEY: nwItemClass.CHARACTER, POV_KEY: nwItemClass.CHARACTER,
FOCUS_KEY: nwItemClass.CHARACTER, FOCUS_KEY: nwItemClass.CHARACTER,
CHAR_KEY: nwItemClass.CHARACTER, CHAR_KEY: nwItemClass.CHARACTER,
PLOT_KEY: nwItemClass.PLOT, PLOT_KEY: nwItemClass.PLOT,
TIME_KEY: nwItemClass.TIMELINE, TIME_KEY: nwItemClass.TIMELINE,
WORLD_KEY: nwItemClass.WORLD, WORLD_KEY: nwItemClass.WORLD,
OBJECT_KEY: nwItemClass.OBJECT, OBJECT_KEY: nwItemClass.OBJECT,
ENTITY_KEY: nwItemClass.ENTITY, ENTITY_KEY: nwItemClass.ENTITY,
CUSTOM_KEY: nwItemClass.CUSTOM, CUSTOM_KEY: nwItemClass.CUSTOM,
} }
@@ -236,35 +237,37 @@ class nwLabels:
"note": QT_TRANSLATE_NOOP("Constant", "Project Note"), "note": QT_TRANSLATE_NOOP("Constant", "Project Note"),
} }
KEY_NAME = { KEY_NAME = {
nwKeyWords.TAG_KEY: QT_TRANSLATE_NOOP("Constant", "Tag"), nwKeyWords.TAG_KEY: QT_TRANSLATE_NOOP("Constant", "Tag"),
nwKeyWords.POV_KEY: QT_TRANSLATE_NOOP("Constant", "Point of View"), nwKeyWords.POV_KEY: QT_TRANSLATE_NOOP("Constant", "Point of View"),
nwKeyWords.FOCUS_KEY: QT_TRANSLATE_NOOP("Constant", "Focus"), nwKeyWords.FOCUS_KEY: QT_TRANSLATE_NOOP("Constant", "Focus"),
nwKeyWords.CHAR_KEY: QT_TRANSLATE_NOOP("Constant", "Characters"), nwKeyWords.CHAR_KEY: QT_TRANSLATE_NOOP("Constant", "Characters"),
nwKeyWords.PLOT_KEY: QT_TRANSLATE_NOOP("Constant", "Plot"), nwKeyWords.PLOT_KEY: QT_TRANSLATE_NOOP("Constant", "Plot"),
nwKeyWords.TIME_KEY: QT_TRANSLATE_NOOP("Constant", "Timeline"), nwKeyWords.TIME_KEY: QT_TRANSLATE_NOOP("Constant", "Timeline"),
nwKeyWords.WORLD_KEY: QT_TRANSLATE_NOOP("Constant", "Locations"), nwKeyWords.WORLD_KEY: QT_TRANSLATE_NOOP("Constant", "Locations"),
nwKeyWords.OBJECT_KEY: QT_TRANSLATE_NOOP("Constant", "Objects"), nwKeyWords.OBJECT_KEY: QT_TRANSLATE_NOOP("Constant", "Objects"),
nwKeyWords.ENTITY_KEY: QT_TRANSLATE_NOOP("Constant", "Entities"), nwKeyWords.ENTITY_KEY: QT_TRANSLATE_NOOP("Constant", "Entities"),
nwKeyWords.CUSTOM_KEY: QT_TRANSLATE_NOOP("Constant", "Custom"), nwKeyWords.CUSTOM_KEY: QT_TRANSLATE_NOOP("Constant", "Custom"),
nwKeyWords.MENTION_KEY: QT_TRANSLATE_NOOP("Constant", "Mentions"),
} }
OUTLINE_COLS = { OUTLINE_COLS = {
nwOutline.TITLE: QT_TRANSLATE_NOOP("Constant", "Title"), nwOutline.TITLE: QT_TRANSLATE_NOOP("Constant", "Title"),
nwOutline.LEVEL: QT_TRANSLATE_NOOP("Constant", "Level"), nwOutline.LEVEL: QT_TRANSLATE_NOOP("Constant", "Level"),
nwOutline.LABEL: QT_TRANSLATE_NOOP("Constant", "Document"), nwOutline.LABEL: QT_TRANSLATE_NOOP("Constant", "Document"),
nwOutline.LINE: QT_TRANSLATE_NOOP("Constant", "Line"), nwOutline.LINE: QT_TRANSLATE_NOOP("Constant", "Line"),
nwOutline.CCOUNT: QT_TRANSLATE_NOOP("Constant", "Chars"), nwOutline.CCOUNT: QT_TRANSLATE_NOOP("Constant", "Chars"),
nwOutline.WCOUNT: QT_TRANSLATE_NOOP("Constant", "Words"), nwOutline.WCOUNT: QT_TRANSLATE_NOOP("Constant", "Words"),
nwOutline.PCOUNT: QT_TRANSLATE_NOOP("Constant", "Pars"), nwOutline.PCOUNT: QT_TRANSLATE_NOOP("Constant", "Pars"),
nwOutline.POV: QT_TRANSLATE_NOOP("Constant", "POV"), nwOutline.POV: QT_TRANSLATE_NOOP("Constant", "POV"),
nwOutline.FOCUS: QT_TRANSLATE_NOOP("Constant", "Focus"), nwOutline.FOCUS: QT_TRANSLATE_NOOP("Constant", "Focus"),
nwOutline.CHAR: KEY_NAME[nwKeyWords.CHAR_KEY], nwOutline.CHAR: KEY_NAME[nwKeyWords.CHAR_KEY],
nwOutline.PLOT: KEY_NAME[nwKeyWords.PLOT_KEY], nwOutline.PLOT: KEY_NAME[nwKeyWords.PLOT_KEY],
nwOutline.WORLD: KEY_NAME[nwKeyWords.WORLD_KEY], nwOutline.WORLD: KEY_NAME[nwKeyWords.WORLD_KEY],
nwOutline.TIME: KEY_NAME[nwKeyWords.TIME_KEY], nwOutline.TIME: KEY_NAME[nwKeyWords.TIME_KEY],
nwOutline.OBJECT: KEY_NAME[nwKeyWords.OBJECT_KEY], nwOutline.OBJECT: KEY_NAME[nwKeyWords.OBJECT_KEY],
nwOutline.ENTITY: KEY_NAME[nwKeyWords.ENTITY_KEY], nwOutline.ENTITY: KEY_NAME[nwKeyWords.ENTITY_KEY],
nwOutline.CUSTOM: KEY_NAME[nwKeyWords.CUSTOM_KEY], nwOutline.CUSTOM: KEY_NAME[nwKeyWords.CUSTOM_KEY],
nwOutline.SYNOP: QT_TRANSLATE_NOOP("Constant", "Synopsis"), nwOutline.MENTION: KEY_NAME[nwKeyWords.MENTION_KEY],
nwOutline.SYNOP: QT_TRANSLATE_NOOP("Constant", "Synopsis"),
} }
BUILD_FMT = { BUILD_FMT = {
nwBuildFmt.ODT: QT_TRANSLATE_NOOP("Constant", "Open Document (.odt)"), nwBuildFmt.ODT: QT_TRANSLATE_NOOP("Constant", "Open Document (.odt)"),
+24 -13
View File
@@ -487,13 +487,14 @@ class NWIndex:
if nBits == 0: if nBits == 0:
return [] return []
# Check that the key is valid # Check that the keyword is valid
isGood[0] = tBits[0] in nwKeyWords.VALID_KEYS kBit = tBits[0]
isGood[0] = kBit in nwKeyWords.VALID_KEYS
if not isGood[0] or nBits == 1: if not isGood[0] or nBits == 1:
return isGood return isGood
# For a tag, only the first value is accepted, the rest are ignored # For a tag, only the first value is accepted, the rest are ignored
if tBits[0] == nwKeyWords.TAG_KEY and nBits > 1: if kBit == nwKeyWords.TAG_KEY and nBits > 1:
check, _ = self.parseValue(tBits[1]) check, _ = self.parseValue(tBits[1])
if check in self._tagsIndex: if check in self._tagsIndex:
isGood[1] = self._tagsIndex.tagHandle(check) == tHandle isGood[1] = self._tagsIndex.tagHandle(check) == tHandle
@@ -501,12 +502,16 @@ class NWIndex:
isGood[1] = True isGood[1] = True
return isGood return isGood
if kBit == nwKeyWords.MENTION_KEY and nBits > 1:
isGood[1:nBits] = [aBit in self._tagsIndex for aBit in tBits[1:nBits]]
return isGood
# If we're still here, we check that the references exist # If we're still here, we check that the references exist
# Class references cannot have the | symbol in them # Class references cannot have the | symbol in them
refKey = nwKeyWords.KEY_CLASS[tBits[0]].name if rClass := nwKeyWords.KEY_CLASS.get(kBit):
for n in range(1, nBits): for n in range(1, nBits):
if (aBit := tBits[n]) in self._tagsIndex: if (aBit := tBits[n]) in self._tagsIndex:
isGood[n] = self._tagsIndex.tagClass(aBit) == refKey and "|" not in aBit isGood[n] = self._tagsIndex.tagClass(aBit) == rClass.name and "|" not in aBit
return isGood return isGood
@@ -681,9 +686,10 @@ class NWIndex:
"""Return all tags used by a specific document.""" """Return all tags used by a specific document."""
return self._itemIndex.allItemTags(tHandle) if tHandle else [] return self._itemIndex.allItemTags(tHandle) if tHandle else []
def getClassTags(self, itemClass: nwItemClass) -> list[str]: def getClassTags(self, itemClass: nwItemClass | None) -> list[str]:
"""Return all tags based on itemClass.""" """Return all tags based on itemClass."""
return self._tagsIndex.filterTagNames(itemClass.name) name = None if itemClass is None else itemClass.name
return self._tagsIndex.filterTagNames(name)
def getTagsData( def getTagsData(
self, activeOnly: bool = True self, activeOnly: bool = True
@@ -780,11 +786,16 @@ class TagsIndex:
"""Get the class of a given tag.""" """Get the class of a given tag."""
return self._tags.get(tagKey.lower(), {}).get("class", None) return self._tags.get(tagKey.lower(), {}).get("class", None)
def filterTagNames(self, className: str) -> list[str]: def filterTagNames(self, className: str | None) -> list[str]:
"""Get a list of tag names for a given class.""" """Get a list of tag names for a given class."""
return [ if className is None:
x.get("name", "") for x in self._tags.values() if x.get("class", "") == className return [
] x.get("name", "") for x in self._tags.values()
]
else:
return [
x.get("name", "") for x in self._tags.values() if x.get("class", "") == className
]
## ##
# Pack/Unpack # Pack/Unpack
+18 -17
View File
@@ -158,23 +158,24 @@ class nwFocus(Enum):
class nwOutline(Enum): class nwOutline(Enum):
TITLE = 0 TITLE = 0
LEVEL = 1 LEVEL = 1
LABEL = 2 LABEL = 2
LINE = 3 LINE = 3
CCOUNT = 4 CCOUNT = 4
WCOUNT = 5 WCOUNT = 5
PCOUNT = 6 PCOUNT = 6
POV = 7 POV = 7
FOCUS = 8 FOCUS = 8
CHAR = 9 CHAR = 9
PLOT = 10 PLOT = 10
TIME = 11 TIME = 11
WORLD = 12 WORLD = 12
OBJECT = 13 OBJECT = 13
ENTITY = 14 ENTITY = 14
CUSTOM = 15 CUSTOM = 15
SYNOP = 16 MENTION = 16
SYNOP = 17
class nwBuildFmt(Enum): class nwBuildFmt(Enum):
+1 -1
View File
@@ -2176,7 +2176,7 @@ class MetaCompleter(QMenu):
suffix = "" suffix = ""
options = list(filter( options = list(filter(
lambda x: lookup in x.lower(), SHARED.project.index.getClassTags( lambda x: lookup in x.lower(), SHARED.project.index.getClassTags(
nwKeyWords.KEY_CLASS.get(kw.strip(), nwItemClass.NO_CLASS) nwKeyWords.KEY_CLASS.get(kw.strip())
) )
))[:15] ))[:15]
+11 -10
View File
@@ -535,16 +535,17 @@ class GuiMainMenu(QMenuBar):
# Insert > Tags and References # Insert > Tags and References
self.mInsKeywords = self.insMenu.addMenu(self.tr("Tags and References")) self.mInsKeywords = self.insMenu.addMenu(self.tr("Tags and References"))
self.mInsKWItems = {} self.mInsKWItems = {}
self.mInsKWItems[nwKeyWords.TAG_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, G") self.mInsKWItems[nwKeyWords.TAG_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, G")
self.mInsKWItems[nwKeyWords.POV_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, V") self.mInsKWItems[nwKeyWords.POV_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, V")
self.mInsKWItems[nwKeyWords.FOCUS_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, F") self.mInsKWItems[nwKeyWords.FOCUS_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, F")
self.mInsKWItems[nwKeyWords.CHAR_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, C") self.mInsKWItems[nwKeyWords.CHAR_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, C")
self.mInsKWItems[nwKeyWords.PLOT_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, P") self.mInsKWItems[nwKeyWords.PLOT_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, P")
self.mInsKWItems[nwKeyWords.TIME_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, T") self.mInsKWItems[nwKeyWords.TIME_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, T")
self.mInsKWItems[nwKeyWords.WORLD_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, L") self.mInsKWItems[nwKeyWords.WORLD_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, L")
self.mInsKWItems[nwKeyWords.OBJECT_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, O") self.mInsKWItems[nwKeyWords.OBJECT_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, O")
self.mInsKWItems[nwKeyWords.ENTITY_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, E") self.mInsKWItems[nwKeyWords.ENTITY_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, E")
self.mInsKWItems[nwKeyWords.CUSTOM_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, X") self.mInsKWItems[nwKeyWords.CUSTOM_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, X")
self.mInsKWItems[nwKeyWords.MENTION_KEY] = (QAction(self.mInsKeywords), "Ctrl+K, M")
for n, keyWord in enumerate(self.mInsKWItems): for n, keyWord in enumerate(self.mInsKWItems):
self.mInsKWItems[keyWord][0].setText(trConst(nwLabels.KEY_NAME[keyWord])) self.mInsKWItems[keyWord][0].setText(trConst(nwLabels.KEY_NAME[keyWord]))
self.mInsKWItems[keyWord][0].setShortcut(self.mInsKWItems[keyWord][1]) self.mInsKWItems[keyWord][0].setShortcut(self.mInsKWItems[keyWord][1])
+36 -34
View File
@@ -312,43 +312,45 @@ class GuiOutlineToolBar(QToolBar):
class GuiOutlineTree(QTreeWidget): class GuiOutlineTree(QTreeWidget):
DEF_WIDTH = { DEF_WIDTH = {
nwOutline.TITLE: 200, nwOutline.TITLE: 200,
nwOutline.LEVEL: 40, nwOutline.LEVEL: 40,
nwOutline.LABEL: 150, nwOutline.LABEL: 150,
nwOutline.LINE: 40, nwOutline.LINE: 40,
nwOutline.CCOUNT: 50, nwOutline.CCOUNT: 50,
nwOutline.WCOUNT: 50, nwOutline.WCOUNT: 50,
nwOutline.PCOUNT: 50, nwOutline.PCOUNT: 50,
nwOutline.POV: 100, nwOutline.POV: 100,
nwOutline.FOCUS: 100, nwOutline.FOCUS: 100,
nwOutline.CHAR: 100, nwOutline.CHAR: 100,
nwOutline.PLOT: 100, nwOutline.PLOT: 100,
nwOutline.TIME: 100, nwOutline.TIME: 100,
nwOutline.WORLD: 100, nwOutline.WORLD: 100,
nwOutline.OBJECT: 100, nwOutline.OBJECT: 100,
nwOutline.ENTITY: 100, nwOutline.ENTITY: 100,
nwOutline.CUSTOM: 100, nwOutline.CUSTOM: 100,
nwOutline.SYNOP: 200, nwOutline.MENTION: 100,
nwOutline.SYNOP: 200,
} }
DEF_HIDDEN = { DEF_HIDDEN = {
nwOutline.TITLE: False, nwOutline.TITLE: False,
nwOutline.LEVEL: True, nwOutline.LEVEL: True,
nwOutline.LABEL: False, nwOutline.LABEL: False,
nwOutline.LINE: True, nwOutline.LINE: True,
nwOutline.CCOUNT: True, nwOutline.CCOUNT: True,
nwOutline.WCOUNT: False, nwOutline.WCOUNT: False,
nwOutline.PCOUNT: False, nwOutline.PCOUNT: False,
nwOutline.POV: False, nwOutline.POV: False,
nwOutline.FOCUS: True, nwOutline.FOCUS: True,
nwOutline.CHAR: False, nwOutline.CHAR: False,
nwOutline.PLOT: False, nwOutline.PLOT: False,
nwOutline.TIME: True, nwOutline.TIME: True,
nwOutline.WORLD: False, nwOutline.WORLD: False,
nwOutline.OBJECT: True, nwOutline.OBJECT: True,
nwOutline.ENTITY: True, nwOutline.ENTITY: True,
nwOutline.CUSTOM: True, nwOutline.CUSTOM: True,
nwOutline.SYNOP: False, nwOutline.MENTION: True,
nwOutline.SYNOP: False,
} }
D_HANDLE = QtUserRole D_HANDLE = QtUserRole
+3 -2
View File
@@ -1,13 +1,14 @@
%%~name: Making a Scene %%~name: Making a Scene
%%~path: 6a2d6d5f4f401/636b6aa9b697b %%~path: 6a2d6d5f4f401/636b6aa9b697b
%%~kind: NOVEL/DOCUMENT %%~kind: NOVEL/DOCUMENT
%%~hash: c7e664867218b3a9aac5c12119ef0ec63da2e5cc %%~hash: 349d9ce3d59ad241d63b01380c53a7fb26ce9f19
%%~date: Unknown/2024-04-18 17:56:30 %%~date: Unknown/2024-10-24 23:44:27
### Making a Scene ### Making a Scene
@pov: Jane @pov: Jane
@char: John, Jane @char: John, Jane
@location: Earth @location: Earth
@mention: Bob, Space
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. The scene document can be sorted after the chapter document, or as a child of the chapter. Both result in the same output in the end, so it is a matter of preference. 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. The scene document can be sorted after the chapter document, or as a child of the chapter. Both result in the same output in the end, so it is a matter of preference.
+4 -4
View File
@@ -1,6 +1,6 @@
<?xml version='1.0' encoding='utf-8'?> <?xml version='1.0' encoding='utf-8'?>
<novelWriterXML appVersion="2.6a2" hexVersion="0x020600a2" fileVersion="1.5" fileRevision="4" timeStamp="2024-10-24 16:26:12"> <novelWriterXML appVersion="2.6a2" hexVersion="0x020600a2" fileVersion="1.5" fileRevision="4" timeStamp="2024-10-24 23:58:23">
<project id="e2be99af-f9bf-4403-857a-c3d1ac25abea" saveCount="2077" autoCount="279" editTime="93511"> <project id="e2be99af-f9bf-4403-857a-c3d1ac25abea" saveCount="2088" autoCount="280" editTime="93793">
<name>Sample Project</name> <name>Sample Project</name>
<author>Jane Smith</author> <author>Jane Smith</author>
</project> </project>
@@ -58,11 +58,11 @@
<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="520" paraCount="15" cursorPos="4" /> <meta expanded="no" heading="H3" charCount="2937" wordCount="520" paraCount="15" cursorPos="19" />
<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">
<meta expanded="no" heading="H3" charCount="563" wordCount="108" paraCount="3" cursorPos="691" /> <meta expanded="no" heading="H3" charCount="548" wordCount="108" paraCount="3" cursorPos="650" />
<name status="s90e6c9" import="ia857f0" active="yes">Another Scene</name> <name status="s90e6c9" import="ia857f0" active="yes">Another Scene</name>
</item> </item>
<item handle="ba8a28a246524" parent="7031beac91f75" root="7031beac91f75" order="4" type="FILE" class="NOVEL" layout="DOCUMENT"> <item handle="ba8a28a246524" parent="7031beac91f75" root="7031beac91f75" order="4" type="FILE" class="NOVEL" layout="DOCUMENT">
+31 -1
View File
@@ -224,13 +224,17 @@ def testCoreIndex_CheckThese(mockGUI, fncPath, mockRnd):
nHandle = project.newFile("Hello", C.hNovelRoot) nHandle = project.newFile("Hello", C.hNovelRoot)
cHandle = project.newFile("Jane", C.hCharRoot) cHandle = project.newFile("Jane", C.hCharRoot)
wHandle = project.newFile("Earth", C.hWorldRoot)
assert isinstance(nHandle, str) assert isinstance(nHandle, str)
assert isinstance(cHandle, str) assert isinstance(cHandle, str)
assert isinstance(wHandle, str)
nItem = project.tree[nHandle] nItem = project.tree[nHandle]
cItem = project.tree[cHandle] cItem = project.tree[cHandle]
wItem = project.tree[wHandle]
assert isinstance(nItem, NWItem) assert isinstance(nItem, NWItem)
assert isinstance(cItem, NWItem) assert isinstance(cItem, NWItem)
assert isinstance(wItem, NWItem)
assert index.rootChangedSince(C.hNovelRoot, 0) is False assert index.rootChangedSince(C.hNovelRoot, 0) is False
assert index.rootChangedSince(None, 0) is False assert index.rootChangedSince(None, 0) is False
@@ -242,21 +246,31 @@ def testCoreIndex_CheckThese(mockGUI, fncPath, mockRnd):
"@tag:\n" "@tag:\n"
"@:\n" "@:\n"
)) ))
assert index.scanText(wHandle, (
"# Earth\n"
"@tag: Earth\n"
))
assert index.scanText(nHandle, ( assert index.scanText(nHandle, (
"# Hello World!\n" "# Hello World!\n"
"@pov: Jane\n" "@pov: Jane\n"
"@location: Earth\n"
"@invalid: John\n" # Checks for issue #688 "@invalid: John\n" # Checks for issue #688
)) ))
assert index._tagsIndex.tagHandle("Earth") == wHandle
assert index._tagsIndex.tagHeading("Earth") == "T0001"
assert index._tagsIndex.tagClass("Earth") == "WORLD"
assert index._tagsIndex.tagHandle("Jane") == cHandle assert index._tagsIndex.tagHandle("Jane") == cHandle
assert index._tagsIndex.tagHeading("Jane") == "T0001" assert index._tagsIndex.tagHeading("Jane") == "T0001"
assert index._tagsIndex.tagClass("Jane") == "CHARACTER" assert index._tagsIndex.tagClass("Jane") == "CHARACTER"
assert index.getItemHeading(nHandle, "T0001").title == "Hello World!" # type: ignore assert index.getItemHeading(nHandle, "T0001").title == "Hello World!" # type: ignore
assert index.getReferences(nHandle, "T0001") == { assert index.getReferences(nHandle, "T0001") == {
"@char": [], "@char": [],
"@custom": [], "@custom": [],
"@entity": [], "@entity": [],
"@focus": [], "@focus": [],
"@location": [], "@location": ["Earth"],
"@object": [], "@object": [],
"@plot": [], "@plot": [],
"@pov": ["Jane"], "@pov": ["Jane"],
@@ -283,13 +297,29 @@ def testCoreIndex_CheckThese(mockGUI, fncPath, mockRnd):
assert index.checkThese(["@tag", "John"], nHandle) == [True, True] assert index.checkThese(["@tag", "John"], nHandle) == [True, True]
assert index.checkThese(["@pov", "John"], nHandle) == [True, False] assert index.checkThese(["@pov", "John"], nHandle) == [True, False]
assert index.checkThese(["@pov", "Jane"], nHandle) == [True, True] assert index.checkThese(["@pov", "Jane"], nHandle) == [True, True]
assert index.checkThese(["@mention", "Jane"], nHandle) == [True, True]
assert index.checkThese(["@ pov", "Jane"], nHandle) == [False, False] assert index.checkThese(["@ pov", "Jane"], nHandle) == [False, False]
assert index.checkThese(["@what", "Jane"], nHandle) == [False, False] assert index.checkThese(["@what", "Jane"], nHandle) == [False, False]
# Two w/Class Check
assert index.checkThese(["@pov", "Earth"], nHandle) == [True, False]
assert index.checkThese(["@focus", "Earth"], nHandle) == [True, False]
assert index.checkThese(["@char", "Earth"], nHandle) == [True, False]
assert index.checkThese(["@plot", "Earth"], nHandle) == [True, False]
assert index.checkThese(["@time", "Earth"], nHandle) == [True, False]
assert index.checkThese(["@location", "Earth"], nHandle) == [True, True]
assert index.checkThese(["@object", "Earth"], nHandle) == [True, False]
assert index.checkThese(["@entity", "Earth"], nHandle) == [True, False]
assert index.checkThese(["@custom", "Earth"], nHandle) == [True, False]
assert index.checkThese(["@mention", "Earth"], nHandle) == [True, True]
# Three Items # Three Items
assert index.checkThese(["@tag", "Jane", "John"], cHandle) == [True, True, False] assert index.checkThese(["@tag", "Jane", "John"], cHandle) == [True, True, False]
assert index.checkThese(["@who", "Jane", "John"], cHandle) == [False, False, False] assert index.checkThese(["@who", "Jane", "John"], cHandle) == [False, False, False]
assert index.checkThese(["@pov", "Jane", "John"], nHandle) == [True, True, False] assert index.checkThese(["@pov", "Jane", "John"], nHandle) == [True, True, False]
assert index.checkThese(["@pov", "Jane", "Earth"], nHandle) == [True, True, False]
assert index.checkThese(["@mention", "Jane", "Earth"], nHandle) == [True, True, True]
assert index.checkThese(["@mention", "Jane", "Stuff"], nHandle) == [True, True, False]
# Parse a Checked Value # Parse a Checked Value
assert index.parseValue("Jane | Jane Smith") == ("Jane", "Jane Smith") assert index.parseValue("Jane | Jane Smith") == ("Jane", "Jane Smith")
+2 -2
View File
@@ -165,12 +165,12 @@ def testGuiOutline_Main(qtbot, monkeypatch, nwGUI, projPath):
# Current Order # Current Order
order = [outlineTree._colIdx[col] for col in outlineTree._treeOrder] order = [outlineTree._colIdx[col] for col in outlineTree._treeOrder]
assert order == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] assert order == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]
# Move 3 to 0 # Move 3 to 0
outlineTree._columnMoved(0, 3, 0) outlineTree._columnMoved(0, 3, 0)
order = [outlineTree._colIdx[col] for col in outlineTree._treeOrder] order = [outlineTree._colIdx[col] for col in outlineTree._treeOrder]
assert order == [3, 0, 1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] assert order == [3, 0, 1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]
# qtbot.stop() # qtbot.stop()