diff --git a/novelwriter/formats/shared.py b/novelwriter/formats/shared.py index 12c65020..0eba6698 100644 --- a/novelwriter/formats/shared.py +++ b/novelwriter/formats/shared.py @@ -105,20 +105,17 @@ class BlockTyp(IntEnum): EMPTY = 1 # Empty line (new paragraph) TITLE = 2 # Title PART = 3 # Partition - CHAPTER = 4 # Chapter - SCENE = 5 # Scene - SECTION = 6 # Section - HEAD1 = 7 # Heading 1 - HEAD2 = 8 # Heading 2 - HEAD3 = 9 # Heading 3 - HEAD4 = 10 # Heading 4 - TEXT = 11 # Text line - SEP = 12 # Scene separator - SKIP = 13 # Paragraph break - SUMMARY = 14 # Synopsis/short comment - NOTE = 15 # Note - COMMENT = 16 # Comment - KEYWORD = 17 # Tag/reference keywords + HEAD1 = 4 # Heading 1 or Chapter + HEAD2 = 5 # Heading 2 or Scene + HEAD3 = 6 # Heading 3 or Section + HEAD4 = 7 # Heading 4 + TEXT = 8 # Text line + SEP = 9 # Scene separator + SKIP = 10 # Paragraph break + SUMMARY = 11 # Synopsis/short comment + NOTE = 12 # Note + COMMENT = 13 # Comment + KEYWORD = 14 # Tag/reference keywords class BlockFmt(Flag): diff --git a/novelwriter/formats/tohtml.py b/novelwriter/formats/tohtml.py index 3aae33be..9db18616 100644 --- a/novelwriter/formats/tohtml.py +++ b/novelwriter/formats/tohtml.py @@ -203,15 +203,15 @@ class ToHtml(Tokenizer): tHead = tText.replace("\n", "
") lines.append(f"

{aNm}{tHead}

\n") - elif tType in (BlockTyp.HEAD1, BlockTyp.CHAPTER): + elif tType == BlockTyp.HEAD1: tHead = tText.replace("\n", "
") lines.append(f"{aNm}{tHead}\n") - elif tType in (BlockTyp.HEAD2, BlockTyp.SCENE): + elif tType == BlockTyp.HEAD2: tHead = tText.replace("\n", "
") lines.append(f"{aNm}{tHead}\n") - elif tType in (BlockTyp.HEAD3, BlockTyp.SECTION): + elif tType == BlockTyp.HEAD3: tHead = tText.replace("\n", "
") lines.append(f"{aNm}{tHead}\n") diff --git a/novelwriter/formats/tokenizer.py b/novelwriter/formats/tokenizer.py index 19839096..e01b51e7 100644 --- a/novelwriter/formats/tokenizer.py +++ b/novelwriter/formats/tokenizer.py @@ -68,18 +68,9 @@ COMMENT_STYLE = { nwComment.COMMENT: ComStyle(), nwComment.STORY: ComStyle("", "modifier", "note"), } -OUTLINE_CODE = { - BlockTyp.TITLE: "TT", - BlockTyp.PART: "PT", - BlockTyp.CHAPTER: "CH", - BlockTyp.SCENE: "SC", - BlockTyp.HEAD1: "H1", - BlockTyp.HEAD2: "H2", - BlockTyp.HEAD3: "H3", -} HEADINGS = [ - BlockTyp.TITLE, BlockTyp.PART, BlockTyp.CHAPTER, BlockTyp.SCENE, BlockTyp.SECTION, - BlockTyp.HEAD1, BlockTyp.HEAD2, BlockTyp.HEAD3, BlockTyp.HEAD4, + BlockTyp.TITLE, BlockTyp.PART, BlockTyp.HEAD1, + BlockTyp.HEAD2, BlockTyp.HEAD3, BlockTyp.HEAD4, ] SKIP_INDENT = HEADINGS + [BlockTyp.SEP, BlockTyp.SKIP] B_EMPTY: T_Block = (BlockTyp.EMPTY, "", "", [], BlockFmt.NONE) @@ -697,7 +688,7 @@ class Tokenizer(ABC): sHide = self._hideChapter if isPlain else self._hideUnNum tFormat = self._fmtChapter if isPlain else self._fmtUnNum if isNovel: - tType = BlockTyp.CHAPTER + tType = BlockTyp.HEAD1 # Promote if isPlain: self._hFormatter.incChapter() if sHide: @@ -732,7 +723,7 @@ class Tokenizer(ABC): sHide = self._hideScene if isPlain else self._hideHScene tFormat = self._fmtScene if isPlain else self._fmtHScene if isNovel: - tType = BlockTyp.SCENE + tType = BlockTyp.HEAD2 # Promote self._hFormatter.incScene() if sHide: tText = "" @@ -764,7 +755,7 @@ class Tokenizer(ABC): tText = aLine[5:].strip() tType = BlockTyp.HEAD4 if isNovel: - tType = BlockTyp.SECTION + tType = BlockTyp.HEAD3 # Promote if self._hideSection: tText = "" tType = BlockTyp.EMPTY @@ -936,10 +927,24 @@ class Tokenizer(ABC): def buildOutline(self) -> None: """Build an outline of the text up to level 3 headings.""" + isNovel = self._isNovel for tType, tKey, tText, _, _ in self._blocks: - if prefix := OUTLINE_CODE.get(tType): - text = tText.replace(nwHeadFmt.BR, " ").replace("&", "&") - self._outline[tKey] = f"{prefix}|{text}" + if tType == BlockTyp.TITLE: + prefix = "TT" + elif tType == BlockTyp.PART: + prefix = "PT" + elif tType == BlockTyp.HEAD1: + prefix = "CH" if isNovel else "H1" + elif tType == BlockTyp.HEAD2: + prefix = "SC" if isNovel else "H2" + elif tType == BlockTyp.HEAD3 and not isNovel: + prefix = "H3" + else: + continue + + text = tText.replace(nwHeadFmt.BR, " ").replace("&", "&") + self._outline[tKey] = f"{prefix}|{text}" + return def countStats(self) -> None: diff --git a/novelwriter/formats/tomarkdown.py b/novelwriter/formats/tomarkdown.py index 0fe28fc6..e1f67b06 100644 --- a/novelwriter/formats/tomarkdown.py +++ b/novelwriter/formats/tomarkdown.py @@ -113,15 +113,15 @@ class ToMarkdown(Tokenizer): tTemp = self._formatText(tText, tFormat, mTags).replace("\n", " \n") lines.append(f"{tTemp}\n\n") - elif tType in (BlockTyp.TITLE, BlockTyp.HEAD1, BlockTyp.PART, BlockTyp.CHAPTER): + elif tType in (BlockTyp.TITLE, BlockTyp.PART, BlockTyp.HEAD1): tHead = tText.replace("\n", " - ") lines.append(f"# {tHead}\n\n") - elif tType in (BlockTyp.HEAD2, BlockTyp.SCENE): + elif tType == BlockTyp.HEAD2: tHead = tText.replace("\n", " - ") lines.append(f"## {tHead}\n\n") - elif tType in (BlockTyp.HEAD3, BlockTyp.SECTION): + elif tType == BlockTyp.HEAD3: tHead = tText.replace("\n", " - ") lines.append(f"### {tHead}\n\n") diff --git a/novelwriter/formats/toqdoc.py b/novelwriter/formats/toqdoc.py index 260592f6..12fdb305 100644 --- a/novelwriter/formats/toqdoc.py +++ b/novelwriter/formats/toqdoc.py @@ -156,28 +156,22 @@ class ToQTextDocument(Tokenizer): mPx = fPx * self._dpi/96.0 self._mHead = { - BlockTyp.TITLE: (fPx * self._marginTitle[0], fPx * self._marginTitle[1]), - BlockTyp.PART: (fPx * self._marginTitle[0], fPx * self._marginTitle[1]), - BlockTyp.HEAD1: (fPx * self._marginHead1[0], fPx * self._marginHead1[1]), - BlockTyp.CHAPTER: (fPx * self._marginHead1[0], fPx * self._marginHead1[1]), - BlockTyp.HEAD2: (fPx * self._marginHead2[0], fPx * self._marginHead2[1]), - BlockTyp.SCENE: (fPx * self._marginHead2[0], fPx * self._marginHead2[1]), - BlockTyp.HEAD3: (fPx * self._marginHead3[0], fPx * self._marginHead3[1]), - BlockTyp.SECTION: (fPx * self._marginHead3[0], fPx * self._marginHead3[1]), - BlockTyp.HEAD4: (fPx * self._marginHead4[0], fPx * self._marginHead4[1]), + BlockTyp.TITLE: (fPx * self._marginTitle[0], fPx * self._marginTitle[1]), + BlockTyp.PART: (fPx * self._marginTitle[0], fPx * self._marginTitle[1]), + BlockTyp.HEAD1: (fPx * self._marginHead1[0], fPx * self._marginHead1[1]), + BlockTyp.HEAD2: (fPx * self._marginHead2[0], fPx * self._marginHead2[1]), + BlockTyp.HEAD3: (fPx * self._marginHead3[0], fPx * self._marginHead3[1]), + BlockTyp.HEAD4: (fPx * self._marginHead4[0], fPx * self._marginHead4[1]), } hScale = self._scaleHeads self._sHead = { - BlockTyp.TITLE: (nwStyles.H_SIZES.get(0, 1.0) * fPt) if hScale else fPt, - BlockTyp.PART: (nwStyles.H_SIZES.get(0, 1.0) * fPt) if hScale else fPt, - BlockTyp.HEAD1: (nwStyles.H_SIZES.get(1, 1.0) * fPt) if hScale else fPt, - BlockTyp.CHAPTER: (nwStyles.H_SIZES.get(1, 1.0) * fPt) if hScale else fPt, - BlockTyp.HEAD2: (nwStyles.H_SIZES.get(2, 1.0) * fPt) if hScale else fPt, - BlockTyp.SCENE: (nwStyles.H_SIZES.get(2, 1.0) * fPt) if hScale else fPt, - BlockTyp.HEAD3: (nwStyles.H_SIZES.get(3, 1.0) * fPt) if hScale else fPt, - BlockTyp.SECTION: (nwStyles.H_SIZES.get(3, 1.0) * fPt) if hScale else fPt, - BlockTyp.HEAD4: (nwStyles.H_SIZES.get(4, 1.0) * fPt) if hScale else fPt, + BlockTyp.TITLE: (nwStyles.H_SIZES.get(0, 1.0) * fPt) if hScale else fPt, + BlockTyp.PART: (nwStyles.H_SIZES.get(0, 1.0) * fPt) if hScale else fPt, + BlockTyp.HEAD1: (nwStyles.H_SIZES.get(1, 1.0) * fPt) if hScale else fPt, + BlockTyp.HEAD2: (nwStyles.H_SIZES.get(2, 1.0) * fPt) if hScale else fPt, + BlockTyp.HEAD3: (nwStyles.H_SIZES.get(3, 1.0) * fPt) if hScale else fPt, + BlockTyp.HEAD4: (nwStyles.H_SIZES.get(4, 1.0) * fPt) if hScale else fPt, } self._mText = (fPx * self._marginText[0], fPx * self._marginText[1]) diff --git a/tests/test_formats/test_fmt_tohtml.py b/tests/test_formats/test_fmt_tohtml.py index aaba1c95..5ec08385 100644 --- a/tests/test_formats/test_fmt_tohtml.py +++ b/tests/test_formats/test_fmt_tohtml.py @@ -410,7 +410,7 @@ def testFmtToHtml_ConvertDirect(mockGUI): # Unnumbered html._blocks = [ - (BlockTyp.CHAPTER, tMeta, "Prologue", [], BlockFmt.PBB), + (BlockTyp.HEAD1, tMeta, "Prologue", [], BlockFmt.PBB), ] html.doConvert() assert html._pages[-1] == ( diff --git a/tests/test_formats/test_fmt_tokenizer.py b/tests/test_formats/test_fmt_tokenizer.py index 585ae734..5bc4491f 100644 --- a/tests/test_formats/test_fmt_tokenizer.py +++ b/tests/test_formats/test_fmt_tokenizer.py @@ -313,7 +313,7 @@ def testFmtToken_HeaderFormat(mockGUI): tokens.tokenizeText() assert tokens._blocks == [ - (BlockTyp.CHAPTER, TM1, "Chapter One", [], BlockFmt.PBB), + (BlockTyp.HEAD1, TM1, "Chapter One", [], BlockFmt.PBB), ] # Note File @@ -334,7 +334,7 @@ def testFmtToken_HeaderFormat(mockGUI): tokens.tokenizeText() assert tokens._blocks == [ - (BlockTyp.SCENE, TM1, "Scene One", [], BlockFmt.NONE), + (BlockTyp.HEAD2, TM1, "Scene One", [], BlockFmt.NONE), ] # Note File @@ -355,7 +355,7 @@ def testFmtToken_HeaderFormat(mockGUI): tokens.tokenizeText() assert tokens._blocks == [ - (BlockTyp.SECTION, TM1, "A Section", [], BlockFmt.NONE), + (BlockTyp.HEAD3, TM1, "A Section", [], BlockFmt.NONE), ] # Note File @@ -399,7 +399,7 @@ def testFmtToken_HeaderFormat(mockGUI): tokens.tokenizeText() assert tokens._blocks == [ - (BlockTyp.CHAPTER, TM1, "Prologue", [], BlockFmt.PBB), + (BlockTyp.HEAD1, TM1, "Prologue", [], BlockFmt.PBB), ] # Note File @@ -1639,7 +1639,7 @@ def testFmtToken_ProcessHeaders(mockGUI): tokens.setChapterFormat(f"C: {nwHeadFmt.TITLE}") tokens.tokenizeText() assert tokens._blocks == [ - (BlockTyp.CHAPTER, TM1, "C: Chapter One", [], BlockFmt.PBB), + (BlockTyp.HEAD1, TM1, "C: Chapter One", [], BlockFmt.PBB), ] # H2: Unnumbered Chapter @@ -1647,7 +1647,7 @@ def testFmtToken_ProcessHeaders(mockGUI): tokens.setUnNumberedFormat(f"U: {nwHeadFmt.TITLE}") tokens.tokenizeText() assert tokens._blocks == [ - (BlockTyp.CHAPTER, TM1, "U: Prologue", [], BlockFmt.PBB), + (BlockTyp.HEAD1, TM1, "U: Prologue", [], BlockFmt.PBB), ] # H2: Chapter Word Number @@ -1656,7 +1656,7 @@ def testFmtToken_ProcessHeaders(mockGUI): tokens._hFormatter._chCount = 0 tokens.tokenizeText() assert tokens._blocks == [ - (BlockTyp.CHAPTER, TM1, "Chapter One", [], BlockFmt.PBB), + (BlockTyp.HEAD1, TM1, "Chapter One", [], BlockFmt.PBB), ] # H2: Chapter Roman Number Upper Case @@ -1664,7 +1664,7 @@ def testFmtToken_ProcessHeaders(mockGUI): tokens.setChapterFormat(f"Chapter {nwHeadFmt.CH_ROMU}") tokens.tokenizeText() assert tokens._blocks == [ - (BlockTyp.CHAPTER, TM1, "Chapter II", [], BlockFmt.PBB), + (BlockTyp.HEAD1, TM1, "Chapter II", [], BlockFmt.PBB), ] # H2: Chapter Roman Number Lower Case @@ -1672,7 +1672,7 @@ def testFmtToken_ProcessHeaders(mockGUI): tokens.setChapterFormat(f"Chapter {nwHeadFmt.CH_ROML}") tokens.tokenizeText() assert tokens._blocks == [ - (BlockTyp.CHAPTER, TM1, "Chapter iii", [], BlockFmt.PBB), + (BlockTyp.HEAD1, TM1, "Chapter iii", [], BlockFmt.PBB), ] # Scenes @@ -1683,7 +1683,7 @@ def testFmtToken_ProcessHeaders(mockGUI): tokens.setSceneFormat(f"S: {nwHeadFmt.TITLE}", False) tokens.tokenizeText() assert tokens._blocks == [ - (BlockTyp.SCENE, TM1, "S: Scene One", [], BlockFmt.NONE), + (BlockTyp.HEAD2, TM1, "S: Scene One", [], BlockFmt.NONE), ] # H3: Scene Hidden wo/Format @@ -1731,7 +1731,7 @@ def testFmtToken_ProcessHeaders(mockGUI): tokens._hFormatter._scChCount = 0 tokens.tokenizeText() assert tokens._blocks == [ - (BlockTyp.SCENE, TM1, "Scene 1", [], BlockFmt.NONE), + (BlockTyp.HEAD2, TM1, "Scene 1", [], BlockFmt.NONE), ] # H3: Scene w/Chapter Number @@ -1741,7 +1741,7 @@ def testFmtToken_ProcessHeaders(mockGUI): tokens._hFormatter._scChCount = 1 tokens.tokenizeText() assert tokens._blocks == [ - (BlockTyp.SCENE, TM1, "Scene 3.2", [], BlockFmt.NONE), + (BlockTyp.HEAD2, TM1, "Scene 3.2", [], BlockFmt.NONE), ] # Sections @@ -1766,7 +1766,7 @@ def testFmtToken_ProcessHeaders(mockGUI): tokens.setSectionFormat(f"X: {nwHeadFmt.TITLE}", False) tokens.tokenizeText() assert tokens._blocks == [ - (BlockTyp.SECTION, TM1, "X: A Section", [], BlockFmt.NONE), + (BlockTyp.HEAD3, TM1, "X: A Section", [], BlockFmt.NONE), ] # H4: Section Separator diff --git a/tests/test_formats/test_fmt_toqdoc.py b/tests/test_formats/test_fmt_toqdoc.py index 07110308..e48bb44d 100644 --- a/tests/test_formats/test_fmt_toqdoc.py +++ b/tests/test_formats/test_fmt_toqdoc.py @@ -90,33 +90,33 @@ def testFmtToQTextDocument_ConvertHeaders(mockGUI): block = doc.document.findBlockByNumber(2) assert block.text() == "Chapter" bFmt = block.blockFormat() - assert bFmt.topMargin() == doc._mHead[BlockTyp.CHAPTER][0] - assert bFmt.bottomMargin() == doc._mHead[BlockTyp.CHAPTER][1] + assert bFmt.topMargin() == doc._mHead[BlockTyp.HEAD1][0] + assert bFmt.bottomMargin() == doc._mHead[BlockTyp.HEAD1][1] cFmt = charFmtInBlock(block, 1) assert cFmt.fontWeight() == QFont.Weight.Bold - assert cFmt.fontPointSize() == doc._sHead[BlockTyp.CHAPTER] + assert cFmt.fontPointSize() == doc._sHead[BlockTyp.HEAD1] assert cFmt.foreground().color() == THEME.head # Scene block = doc.document.findBlockByNumber(3) assert block.text() == "Scene" bFmt = block.blockFormat() - assert bFmt.topMargin() == doc._mHead[BlockTyp.SCENE][0] - assert bFmt.bottomMargin() == doc._mHead[BlockTyp.SCENE][1] + assert bFmt.topMargin() == doc._mHead[BlockTyp.HEAD2][0] + assert bFmt.bottomMargin() == doc._mHead[BlockTyp.HEAD2][1] cFmt = charFmtInBlock(block, 1) assert cFmt.fontWeight() == QFont.Weight.Bold - assert cFmt.fontPointSize() == doc._sHead[BlockTyp.SCENE] + assert cFmt.fontPointSize() == doc._sHead[BlockTyp.HEAD2] assert cFmt.foreground().color() == THEME.head # Section block = doc.document.findBlockByNumber(4) assert block.text() == "Section" bFmt = block.blockFormat() - assert bFmt.topMargin() == doc._mHead[BlockTyp.SECTION][0] - assert bFmt.bottomMargin() == doc._mHead[BlockTyp.SECTION][1] + assert bFmt.topMargin() == doc._mHead[BlockTyp.HEAD3][0] + assert bFmt.bottomMargin() == doc._mHead[BlockTyp.HEAD3][1] cFmt = charFmtInBlock(block, 1) assert cFmt.fontWeight() == QFont.Weight.Bold - assert cFmt.fontPointSize() == doc._sHead[BlockTyp.SECTION] + assert cFmt.fontPointSize() == doc._sHead[BlockTyp.HEAD3] assert cFmt.foreground().color() == THEME.head