Add story structure comment parsing (#2284)

This commit is contained in:
Veronica Berglyd Olsen
2025-04-09 21:25:23 +02:00
committed by GitHub
11 changed files with 124 additions and 79 deletions
@@ -3,6 +3,7 @@
"Short Description": "Short Description",
"Footnotes": "Footnotes",
"Comment": "Comment",
"Story Structure": "Story Structure",
"Notes": "Notes",
"Tag": "Tag",
"Point of View": "Point of View",
+29 -11
View File
@@ -387,10 +387,10 @@ class Index:
elif line.startswith("%"):
cStyle, cKey, cText, _, _ = processComment(line)
if cStyle in (nwComment.SYNOPSIS, nwComment.SHORT):
self._itemIndex.setHeadingSynopsis(tHandle, cTitle, cText)
elif cStyle == nwComment.FOOTNOTE:
if cStyle == nwComment.FOOTNOTE:
self._itemIndex.addNoteKey(tHandle, "footnotes", cKey)
else:
self._itemIndex.setHeadingComment(tHandle, cTitle, cStyle, cKey, cText)
# Count words for remaining text after last heading
if pTitle != TT_NONE:
@@ -894,6 +894,21 @@ class TagsIndex:
return
class IndexCache:
"""Core: Item Index Lookup Data Class
A small data class passed between all objects of the Item Index
which provides lookup capabilities and caching for shared data.
"""
__slots__ = ("story", "tags")
def __init__(self, tagsIndex: TagsIndex) -> None:
self.tags: TagsIndex = tagsIndex
self.story: set[str] = set()
return
# The Item Index Objects
# ======================
@@ -907,11 +922,11 @@ class ItemIndex:
IndexHeading object for each heading of the text.
"""
__slots__ = ("_items", "_project", "_tags")
__slots__ = ("_cache", "_items", "_project")
def __init__(self, project: NWProject, tagsIndex: TagsIndex) -> None:
self._project = project
self._tags = tagsIndex
self._cache = IndexCache(tagsIndex)
self._items: dict[str, IndexNode] = {}
return
@@ -938,7 +953,7 @@ class ItemIndex:
"""Add a new item to the index. This will overwrite the item if
it already exists.
"""
self._items[tHandle] = IndexNode(self._tags, tHandle, nwItem)
self._items[tHandle] = IndexNode(self._cache, tHandle, nwItem)
return
def allItemTags(self, tHandle: str) -> list[str]:
@@ -996,7 +1011,7 @@ class ItemIndex:
if tHandle in self._items:
tItem = self._items[tHandle]
sTitle = tItem.nextHeading()
tItem.addHeading(IndexHeading(self._tags, sTitle, lineNo, level, text))
tItem.addHeading(IndexHeading(self._cache, sTitle, lineNo, level, text))
return sTitle
return TT_NONE
@@ -1008,10 +1023,13 @@ class ItemIndex:
self._items[tHandle].setHeadingCounts(sTitle, cC, wC, pC)
return
def setHeadingSynopsis(self, tHandle: str, sTitle: str, text: str) -> None:
"""Set the synopsis text for a heading on a given item."""
def setHeadingComment(
self, tHandle: str, sTitle: str,
comment: nwComment, key: str, text: str,
) -> None:
"""Set a story comment for a heading on a given item."""
if tHandle in self._items:
self._items[tHandle].setHeadingSynopsis(sTitle, text)
self._items[tHandle].setHeadingComment(sTitle, comment, key, text)
return
def setHeadingTag(self, tHandle: str, sTitle: str, tagKey: str) -> None:
@@ -1067,7 +1085,7 @@ class ItemIndex:
nwItem = self._project.tree[tHandle]
if nwItem is not None:
tItem = IndexNode(self._tags, tHandle, nwItem)
tItem = IndexNode(self._cache, tHandle, nwItem)
tItem.unpackData(tData)
self._items[tHandle] = tItem
+31 -20
View File
@@ -31,14 +31,15 @@ import logging
from typing import TYPE_CHECKING, Literal
from novelwriter import CONFIG
from novelwriter.common import checkInt, isListInstance, isTitleTag
from novelwriter.common import checkInt, compact, isListInstance, isTitleTag
from novelwriter.constants import nwKeyWords, nwStyles
if TYPE_CHECKING:
from collections.abc import ItemsView, Sequence
from novelwriter.core.index import TagsIndex
from novelwriter.core.index import IndexCache
from novelwriter.core.item import NWItem
from novelwriter.enum import nwComment
logger = logging.getLogger(__name__)
@@ -58,13 +59,13 @@ class IndexNode:
must be reset each time the item is re-indexed.
"""
__slots__ = ("_count", "_handle", "_headings", "_item", "_notes", "_tags")
__slots__ = ("_cache", "_count", "_handle", "_headings", "_item", "_notes")
def __init__(self, tagsIndex: TagsIndex, tHandle: str, nwItem: NWItem) -> None:
self._tags = tagsIndex
def __init__(self, cache: IndexCache, tHandle: str, nwItem: NWItem) -> None:
self._cache = cache
self._handle = tHandle
self._item = nwItem
self._headings: dict[str, IndexHeading] = {TT_NONE: IndexHeading(self._tags, TT_NONE)}
self._headings: dict[str, IndexHeading] = {TT_NONE: IndexHeading(self._cache, TT_NONE)}
self._notes: dict[str, set[str]] = {}
self._count = 0
return
@@ -114,10 +115,10 @@ class IndexNode:
self._headings[sTitle].setCounts([cCount, wCount, pCount])
return
def setHeadingSynopsis(self, sTitle: str, text: str) -> None:
"""Set the synopsis text of a heading."""
def setHeadingComment(self, sTitle: str, comment: nwComment, key: str, text: str) -> None:
"""Set the comment text of a heading."""
if sTitle in self._headings:
self._headings[sTitle].setSynopsis(text)
self._headings[sTitle].setComment(comment.name, key, text)
return
def setHeadingTag(self, sTitle: str, tag: str) -> None:
@@ -182,7 +183,7 @@ class IndexNode:
"""Unpack an item entry from the data."""
for key, entry in data.items():
if isTitleTag(key):
heading = IndexHeading(self._tags, key)
heading = IndexHeading(self._cache, key)
heading.unpackData(entry)
self.addHeading(heading)
elif key == "document":
@@ -206,15 +207,15 @@ class IndexHeading:
"""
__slots__ = (
"_comments", "_counts", "_key", "_level", "_line", "_refs", "_tag",
"_tags", "_title",
"_cache", "_comments", "_counts", "_key", "_level", "_line", "_refs",
"_tag", "_title",
)
def __init__(
self, tagsIndex: TagsIndex, key: str, line: int = 0,
self, cache: IndexCache, key: str, line: int = 0,
level: str = "H0", title: str = "",
) -> None:
self._tags = tagsIndex
self._cache = cache
self._key = key
self._line = line
self._level = level
@@ -268,6 +269,10 @@ class IndexHeading:
def synopsis(self) -> str:
return self._comments.get("summary", "")
@property
def comments(self) -> dict[str, str]:
return self._comments
@property
def tag(self) -> str:
return self._tag
@@ -303,9 +308,14 @@ class IndexHeading:
)
return
def setSynopsis(self, text: str) -> None:
"""Set the synopsis text and make sure it is a string."""
self._comments["summary"] = str(text)
def setComment(self, comment: str, key: str, text: str) -> None:
"""Set the text for a comment and make sure it is a string."""
match comment.lower():
case "short" | "synopsis" | "summary":
self._comments["summary"] = str(text)
case "story" if key:
self._cache.story.add(key)
self._comments[f"story.{key}"] = str(text)
return
def setTag(self, tag: str) -> None:
@@ -333,7 +343,7 @@ class IndexHeading:
refs = {x: [] for x in nwKeyWords.VALID_KEYS}
for tag, types in self._refs.items():
for keyword in types:
if keyword in refs and (name := self._tags.tagName(tag)):
if keyword in refs and (name := self._cache.tags.tagName(tag)):
refs[keyword].append(name)
return refs
@@ -341,7 +351,7 @@ class IndexHeading:
"""Extract all references for this heading."""
refs = []
for tag, types in self._refs.items():
if keyword in types and (name := self._tags.tagName(tag)):
if keyword in types and (name := self._cache.tags.tagName(tag)):
refs.append(name)
return refs
@@ -386,7 +396,8 @@ class IndexHeading:
else:
raise ValueError("Heading reference contains an invalid keyword")
elif key == "summary" or key.startswith("story"):
self._comments[str(key)] = str(entry)
comment, _, kind = str(key).partition(".")
self.setComment(comment, compact(kind), str(entry))
else:
raise KeyError("Unknown key in heading entry")
return
+7 -5
View File
@@ -64,12 +64,12 @@ class ComStyle(NamedTuple):
COMMENT_STYLE = {
nwComment.PLAIN: ComStyle("Comment", "comment", "comment"),
nwComment.IGNORE: ComStyle(),
nwComment.SYNOPSIS: ComStyle("Synopsis", "modifier", "synopsis"),
nwComment.SHORT: ComStyle("Short Description", "modifier", "synopsis"),
nwComment.SYNOPSIS: ComStyle("Synopsis", "modifier", "note"),
nwComment.SHORT: ComStyle("Short Description", "modifier", "note"),
nwComment.NOTE: ComStyle("Note", "modifier", "note"),
nwComment.FOOTNOTE: ComStyle("", "modifier", "note"),
nwComment.COMMENT: ComStyle(),
nwComment.STORY: ComStyle("", "modifier", "note"),
nwComment.STORY: ComStyle("Story Structure", "modifier", "note"),
}
HEADINGS = [
BlockTyp.TITLE, BlockTyp.PART, BlockTyp.HEAD1,
@@ -440,7 +440,7 @@ class Tokenizer(ABC):
def initDocument(self) -> None:
"""Initialise data after settings."""
self._classes["modifier"] = self._theme.modifier
self._classes["synopsis"] = self._theme.note
self._classes["note"] = self._theme.note
self._classes["comment"] = self._theme.comment
self._classes["dialog"] = self._theme.dialog
self._classes["altdialog"] = self._theme.altdialog
@@ -615,7 +615,9 @@ class Tokenizer(ABC):
if doJustify and not tStyle & BlockFmt.ALIGNED:
tStyle |= BlockFmt.JUSTIFY
if cStyle in (nwComment.SYNOPSIS, nwComment.SHORT, nwComment.PLAIN):
if cStyle in (
nwComment.SYNOPSIS, nwComment.SHORT, nwComment.PLAIN, nwComment.STORY
):
bStyle = COMMENT_STYLE[cStyle]
tLine, tFmt = self._formatComment(bStyle, cKey, cText)
tBlocks.append((
+2
View File
@@ -31,12 +31,14 @@ MODIFIERS = {
"short": nwComment.SHORT,
"note": nwComment.NOTE,
"footnote": nwComment.FOOTNOTE,
"story": nwComment.STORY,
}
KEY_REQ = {
"synopsis": 0, # Key not allowed
"short": 0, # Key not allowed
"note": 1, # Key optional
"footnote": 2, # Key required
"story": 2, # Key required
}
+4 -2
View File
@@ -1,8 +1,8 @@
%%~name: Making a Scene
%%~path: 6a2d6d5f4f401/636b6aa9b697b
%%~kind: NOVEL/DOCUMENT
%%~hash: 8d245fa740926779d19741ff7f75ef387b55130c
%%~date: Unknown/2024-10-25 23:54:52
%%~hash: c057a5e9309b0e764c367b0fe9ab0607e3308622
%%~date: Unknown/2025-04-08 20:10:33
### Making a Scene
@pov: Jane
@@ -10,6 +10,8 @@
@location: Earth
@mention: Space
%Story.Resolution: You can describe the scene structure with story comments.
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.
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 there are some known limitations. If the syntax highlighter doesnt show it correctly, the export tool will not either.
+3 -3
View File
@@ -1,6 +1,6 @@
<?xml version='1.0' encoding='utf-8'?>
<novelWriterXML appVersion="2.7a3" hexVersion="0x020700a3" fileVersion="1.5" fileRevision="4" timeStamp="2025-03-23 22:26:31">
<project id="e2be99af-f9bf-4403-857a-c3d1ac25abea" saveCount="2166" autoCount="282" editTime="96058">
<novelWriterXML appVersion="2.7a3" hexVersion="0x020700a3" fileVersion="1.5" fileRevision="4" timeStamp="2025-04-08 20:12:28">
<project id="e2be99af-f9bf-4403-857a-c3d1ac25abea" saveCount="2176" autoCount="285" editTime="96579">
<name>Sample Project</name>
<author>Jane Smith</author>
</project>
@@ -58,7 +58,7 @@
<name status="sf24ce6" import="ia857f0" active="yes">Chapter One</name>
</item>
<item handle="636b6aa9b697b" parent="6a2d6d5f4f401" root="7031beac91f75" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta expanded="no" heading="H3" charCount="2999" wordCount="530" paraCount="16" cursorPos="1035" />
<meta expanded="no" heading="H3" charCount="2999" wordCount="530" paraCount="16" cursorPos="159" />
<name status="s90e6c9" import="ia857f0" active="yes">Making a Scene</name>
</item>
<item handle="bc0cbd2a407f3" parent="6a2d6d5f4f401" root="7031beac91f75" order="1" type="FILE" class="NOVEL" layout="DOCUMENT">
+1 -1
View File
@@ -1196,7 +1196,7 @@ def testCoreIndex_ItemIndex(nwGUI, fncPath, mockRnd):
# Set the remaining data values
itemIndex.setHeadingCounts(cHandle, "T0001", 60, 10, 2)
itemIndex.setHeadingSynopsis(cHandle, "T0001", "In the beginning ...")
itemIndex.setHeadingComment(cHandle, "T0001", nwComment.SYNOPSIS, "", "In the beginning ...")
itemIndex.setHeadingTag(cHandle, "T0001", "One")
itemIndex.addHeadingRef(cHandle, "T0001", ["Jane"], "@pov")
itemIndex.addHeadingRef(cHandle, "T0001", ["Jane"], "@focus")
+40 -31
View File
@@ -23,10 +23,11 @@ from __future__ import annotations
import pytest
from novelwriter import CONFIG
from novelwriter.core.index import TagsIndex
from novelwriter.core.index import IndexCache, TagsIndex
from novelwriter.core.indexdata import IndexHeading, IndexNode
from novelwriter.core.item import NWItem
from novelwriter.core.project import NWProject
from novelwriter.enum import nwComment
@pytest.mark.core
@@ -35,10 +36,10 @@ def testCoreIndexData_IndexNode(mockGUI):
handle = "0123456789abc"
project = NWProject()
item = NWItem(project, handle)
tags = TagsIndex()
cache = IndexCache(TagsIndex())
# Defaults
node = IndexNode(tags, handle, item)
node = IndexNode(cache, handle, item)
assert node.handle == handle
assert node.item is item
assert str(node) == f"<IndexNode handle='{handle}'>"
@@ -47,8 +48,8 @@ def testCoreIndexData_IndexNode(mockGUI):
assert "T0000" in node # Placeholder heading
# Add a heading
head1 = IndexHeading(tags, node.nextHeading(), line=1, level="H1", title="Heading 1")
head2 = IndexHeading(tags, node.nextHeading(), line=10, level="H2", title="Heading 2")
head1 = IndexHeading(cache, node.nextHeading(), line=1, level="H1", title="Heading 1")
head2 = IndexHeading(cache, node.nextHeading(), line=10, level="H2", title="Heading 2")
node.addHeading(head1)
node.addHeading(head2)
assert len(node) == 2
@@ -74,12 +75,12 @@ def testCoreIndexData_IndexNode(mockGUI):
assert head2.paraCount == 6
# Set synopsis
node.setHeadingSynopsis("T0001", "The first")
node.setHeadingSynopsis("T0002", "The second")
node.setHeadingComment("T0001", nwComment.SYNOPSIS, "", "The first")
node.setHeadingComment("T0002", nwComment.SYNOPSIS, "", "The second")
assert head1.synopsis == "The first"
assert head2.synopsis == "The second"
# Set tags
# Set cache
node.setHeadingTag("T0001", "part1")
node.setHeadingTag("T0002", "part2")
assert head1.tag == "part1"
@@ -108,12 +109,12 @@ def testCoreIndexData_IndexNodePackUnpack(mockGUI):
handle = "0123456789abc"
project = NWProject()
item = NWItem(project, handle)
tags = TagsIndex()
node = IndexNode(tags, handle, item)
cache = IndexCache(TagsIndex())
node = IndexNode(cache, handle, item)
# Add some headings and notes
head1 = IndexHeading(tags, node.nextHeading(), line=1, level="H1", title="Heading 1")
head2 = IndexHeading(tags, node.nextHeading(), line=10, level="H2", title="Heading 2")
head1 = IndexHeading(cache, node.nextHeading(), line=1, level="H1", title="Heading 1")
head2 = IndexHeading(cache, node.nextHeading(), line=10, level="H2", title="Heading 2")
node.addHeading(head1)
node.addHeading(head2)
node.setHeadingCounts("T0001", 42, 13, 3)
@@ -132,7 +133,7 @@ def testCoreIndexData_IndexNodePackUnpack(mockGUI):
assert set(data["document"]["footnotes"]) == {"key1", "key2"}
# Create a new node
new = IndexNode(tags, handle, item)
new = IndexNode(cache, handle, item)
# Unpack heading one
data = {"T0001": {"meta": {
@@ -169,8 +170,8 @@ def testCoreIndexData_IndexNodePackUnpack(mockGUI):
def testCoreIndexData_IndexHeading():
"""Test the IndexHeading class."""
# Defaults
tags = TagsIndex()
head = IndexHeading(tags, "T0001")
cache = IndexCache(TagsIndex())
head = IndexHeading(cache, "T0001")
assert str(head) == "<IndexHeading key='T0001'>"
assert repr(head) == "<IndexHeading key='T0001'>"
assert head.key == "T0001"
@@ -213,9 +214,16 @@ def testCoreIndexData_IndexHeading():
assert head.mainCount == 42
# Set Summary
head.setSynopsis("In the beginning ...")
head.setComment(nwComment.SYNOPSIS.name, "", "In the beginning ...")
assert head.synopsis == "In the beginning ..."
# Set Story Structure Comment
head.setComment(nwComment.STORY.name, "crisis", "It exploded!")
assert head.comments == {
"summary": "In the beginning ...",
"story.crisis": "It exploded!",
}
# Set Tag
head.setTag("Stuff")
assert head.tag == "stuff" # Case insensitive
@@ -231,6 +239,7 @@ def testCoreIndexData_IndexHeading():
"meta": {"level": "H1", "title": "", "line": 42, "tag": "stuff", "counts": (42, 4, 2)},
"refs": {"stuff": "@object"},
"summary": "In the beginning ...",
"story.crisis": "It exploded!",
}
# Unpack KeyError
@@ -245,8 +254,8 @@ def testCoreIndexData_IndexHeading():
@pytest.mark.core
def testCoreIndexData_IndexHeadingReferences():
"""Test the IndexHeading references handling."""
tags = TagsIndex()
head = IndexHeading(tags, "T0001")
cache = IndexCache(TagsIndex())
head = IndexHeading(cache, "T0001")
# Add some references
head.addReference("Jane", "@pov")
@@ -272,10 +281,10 @@ def testCoreIndexData_IndexHeadingReferences():
}
# Set names
tags.add("Jane", "Jane", "0000000000000", "T00001", "CHARACTER")
tags.add("John", "John", "0000000000000", "T00001", "CHARACTER")
tags.add("Main", "Main", "0000000000000", "T00001", "PLOT")
tags.add("Gun", "Gun", "0000000000000", "T00001", "OBJECT")
cache.tags.add("Jane", "Jane", "0000000000000", "T00001", "CHARACTER")
cache.tags.add("John", "John", "0000000000000", "T00001", "CHARACTER")
cache.tags.add("Main", "Main", "0000000000000", "T00001", "PLOT")
cache.tags.add("Gun", "Gun", "0000000000000", "T00001", "OBJECT")
# Now they should be populated
assert head.getReferences() == {
@@ -311,13 +320,13 @@ def testCoreIndexData_IndexHeadingReferences():
@pytest.mark.core
def testCoreIndexData_IndexHeadingUnpackMeta():
"""Test IndexHeading class meta unpacking."""
tags = TagsIndex()
cache = IndexCache(TagsIndex())
# Valid
data = {"meta": {
"level": "H1", "title": "So it Begins", "line": 1, "tag": "begins", "counts": [95, 18, 1]
}}
head = IndexHeading(tags, "T0001")
head = IndexHeading(cache, "T0001")
head.unpackData(data)
assert head.level == "H1"
assert head.title == "So it Begins"
@@ -331,7 +340,7 @@ def testCoreIndexData_IndexHeadingUnpackMeta():
data = {"meta": {
"level": "H9", "title": None, "line": None, "tag": None, "counts": [42]
}}
head = IndexHeading(tags, "T0001")
head = IndexHeading(cache, "T0001")
head.unpackData(data)
assert head.level == "H0"
assert head.title == "None"
@@ -343,7 +352,7 @@ def testCoreIndexData_IndexHeadingUnpackMeta():
# Empty
data = {"meta": {}}
head = IndexHeading(tags, "T0001")
head = IndexHeading(cache, "T0001")
head.unpackData(data)
assert head.level == "H0"
assert head.title == ""
@@ -357,13 +366,13 @@ def testCoreIndexData_IndexHeadingUnpackMeta():
@pytest.mark.core
def testCoreIndexData_IndexHeadingUnpackRefs():
"""Test IndexHeading class refs unpacking."""
tags = TagsIndex()
cache = IndexCache(TagsIndex())
# Valid
data = {"refs": {
"jane": "@char,@pov", "john": "@char", "earth": "@location", "space": "@mention,@location"
}}
head = IndexHeading(tags, "T0001")
head = IndexHeading(cache, "T0001")
head.unpackData(data)
assert head.references["jane"] == {"@char", "@pov"}
assert head.references["john"] == {"@char"}
@@ -372,18 +381,18 @@ def testCoreIndexData_IndexHeadingUnpackRefs():
# Invalid key
data = {"refs": {0: "@char,@pov"}}
head = IndexHeading(tags, "T0001")
head = IndexHeading(cache, "T0001")
with pytest.raises(ValueError, match="Heading reference key must be a string"):
head.unpackData(data)
# Invalid value
data = {"refs": {"jane": None}}
head = IndexHeading(tags, "T0001")
head = IndexHeading(cache, "T0001")
with pytest.raises(ValueError, match="Heading reference value must be a string"):
head.unpackData(data)
# Invalid keyword
data = {"refs": {"jane": "@char,@pov,@stuff"}}
head = IndexHeading(tags, "T0001")
head = IndexHeading(cache, "T0001")
with pytest.raises(ValueError, match="Heading reference contains an invalid keyword"):
head.unpackData(data)
+2 -2
View File
@@ -156,8 +156,8 @@ def testCoreNovelModel_Data(nwGUI, fncPath, mockRnd):
model.append(scene)
# Add headings to scene
scene.addHeading(IndexHeading(scene._tags, "T0002", 10, "H4", "A Section"))
scene.addHeading(IndexHeading(scene._tags, "T0003", 10, "H4", "Another Section"))
scene.addHeading(IndexHeading(scene._cache, "T0002", 10, "H4", "A Section"))
scene.addHeading(IndexHeading(scene._cache, "T0003", 10, "H4", "Another Section"))
assert model.refresh(scene) is True
assert [
model.data(model.createIndex(i, 0), Qt.ItemDataRole.DisplayRole)
+4 -4
View File
@@ -785,7 +785,7 @@ def testFmtToken_MetaFormat(mockGUI):
BlockTyp.COMMENT, "", "Synopsis: The synopsis", [
(0, TextFmt.B_B, ""), (0, TextFmt.COL_B, "modifier"),
(9, TextFmt.COL_E, ""), (9, TextFmt.B_E, ""),
(10, TextFmt.COL_B, "synopsis"), (22, TextFmt.COL_E, "")
(10, TextFmt.COL_B, "note"), (22, TextFmt.COL_E, "")
], BlockFmt.NONE
)]
@@ -802,7 +802,7 @@ def testFmtToken_MetaFormat(mockGUI):
BlockTyp.COMMENT, "", "Short Description: A short description", [
(0, TextFmt.B_B, ""), (0, TextFmt.COL_B, "modifier"),
(18, TextFmt.COL_E, ""), (18, TextFmt.B_E, ""),
(19, TextFmt.COL_B, "synopsis"), (38, TextFmt.COL_E, ""),
(19, TextFmt.COL_B, "note"), (38, TextFmt.COL_E, ""),
], BlockFmt.NONE
)]
@@ -1553,7 +1553,7 @@ def testFmtToken_TextIndent(mockGUI):
tokens.tokenizeText()
tFmt = [
(0, TextFmt.B_B, ""), (0, TextFmt.COL_B, "modifier"), (9, TextFmt.COL_E, ""),
(9, TextFmt.B_E, ""), (10, TextFmt.COL_B, "synopsis"), (24, TextFmt.COL_E, ""),
(9, TextFmt.B_E, ""), (10, TextFmt.COL_B, "note"), (24, TextFmt.COL_E, ""),
]
assert tokens._blocks == [
(BlockTyp.HEAD3, TM1, "Scene Two", [], BlockFmt.NONE),
@@ -1814,7 +1814,7 @@ def testFmtToken_FormatComment(mockGUI):
"Synopsis: Hello world!", [
(0, TextFmt.B_B, ""), (0, TextFmt.COL_B, "modifier"),
(9, TextFmt.COL_E, ""), (9, TextFmt.B_E, ""),
(10, TextFmt.COL_B, "synopsis"), (22, TextFmt.COL_E, ""),
(10, TextFmt.COL_B, "note"), (22, TextFmt.COL_E, ""),
]
)