From c7e953fc249486844a35e9f8214c357d3c3b1cfc Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Wed, 13 Mar 2024 11:08:49 +0100 Subject: [PATCH] Fix chapter numbering in refactored tokenizer and add test coverage --- novelwriter/core/tokenizer.py | 44 ++++++++++++-------------- tests/test_core/test_core_tokenizer.py | 9 ++++++ 2 files changed, 30 insertions(+), 23 deletions(-) diff --git a/novelwriter/core/tokenizer.py b/novelwriter/core/tokenizer.py index 39565383..3d52e19a 100644 --- a/novelwriter/core/tokenizer.py +++ b/novelwriter/core/tokenizer.py @@ -573,20 +573,19 @@ class Tokenizer(ABC): # Partition headings are only formatted in novel documents, and # otherwise unchanged. Scene separators are disabled # immediately after partitions, and scene numbers are reset. - isPart = aLine.startswith("# ") + isPlain = aLine.startswith("# ") nHead += 1 - nSkip = 2 if isPart else 3 - tText = aLine[nSkip:].strip() - tType = self.T_HEAD1 if isPart else self.T_TITLE - tStyle = self.A_NONE if isPart else (self.A_PBB | self.A_CENTRE) - if self._isNovel and isPart: - tText = self._hFormatter.apply(self._fmtTitle, tText, nHead) - tStyle = self._titleStyle - self._hFormatter.resetScene() - self._noSep = True - elif self._isNovel and not isPart: - self._hFormatter.resetAll() + tText = aLine[2:].strip() + tType = self.T_HEAD1 if isPlain else self.T_TITLE + tStyle = self.A_NONE if isPlain else (self.A_PBB | self.A_CENTRE) + if self._isNovel: + if isPlain: + tText = self._hFormatter.apply(self._fmtTitle, tText, nHead) + tStyle = self._titleStyle + self._hFormatter.resetScene() + else: + self._hFormatter.resetAll() self._noSep = True self._tokens.append(( @@ -604,18 +603,18 @@ class Tokenizer(ABC): # immediately after chapter headings, and scene numbers are # reset. Unnumbered chapters are only meaningful in Novel docs, # so if we're in a note, we keep them as level 2 headings. - isUnNum = aLine.startswith("##! ") + isPlain = aLine.startswith("## ") nHead += 1 - nSkip = 4 if isUnNum else 3 - tText = aLine[nSkip:].strip() + tText = aLine[3:].strip() tType = self.T_HEAD2 tStyle = self.A_NONE - tFormat = self._fmtUnNum if isUnNum else self._fmtChapter + tFormat = self._fmtChapter if isPlain else self._fmtUnNum if self._isNovel: - self._hFormatter.incChapter() + if isPlain: + self._hFormatter.incChapter() tText = self._hFormatter.apply(tFormat, tText, nHead) - tType = self.T_UNNUM if isUnNum else tType + tType = self.T_HEAD2 if isPlain else self.T_UNNUM tStyle = self._chapterStyle self._noSep = True self._hFormatter.resetScene() @@ -637,15 +636,14 @@ class Tokenizer(ABC): # separators immediately after other titles. Scene numbers are # always incremented before formatting. For notes, the heading # is unchanged. - isHard = aLine.startswith("###! ") + isPlain = aLine.startswith("### ") nHead += 1 - nSkip = 5 if isHard else 4 - tText = aLine[nSkip:].strip() + tText = aLine[4:].strip() tType = self.T_HEAD3 tStyle = self.A_NONE - sHide = self._hideHScene if isHard else self._hideScene - tFormat = self._fmtHScene if isHard else self._fmtScene + sHide = self._hideScene if isPlain else self._hideHScene + tFormat = self._fmtScene if isPlain else self._fmtHScene if self._isNovel: self._hFormatter.incScene() tText = self._hFormatter.apply(tFormat, tText, nHead) diff --git a/tests/test_core/test_core_tokenizer.py b/tests/test_core/test_core_tokenizer.py index 0d722500..03343d0c 100644 --- a/tests/test_core/test_core_tokenizer.py +++ b/tests/test_core/test_core_tokenizer.py @@ -1843,9 +1843,12 @@ def testCoreToken_HeaderCounterAndVisibility(mockGUI): # Counter Handling, Novel Titles # ============================== + # This also checks that only numbered chapters bump the counter md._text = ( "#! Novel One\n\n" + "##! Prologue\n\n" + "Text\n\n" "## Chapter One\n\n" "### Scene One\n\n" "Text\n\n" @@ -1857,6 +1860,8 @@ def testCoreToken_HeaderCounterAndVisibility(mockGUI): "###! Scene Four\n\n" "Text\n\n" "#! Novel Two\n\n" + "##! Prologue\n\n" + "Text\n\n" "## Chapter One\n\n" "### Scene One\n\n" "Text\n\n" @@ -1883,6 +1888,8 @@ def testCoreToken_HeaderCounterAndVisibility(mockGUI): md.doConvert() assert md.result == ( "# Novel One\n\n" + "## Prologue\n\n" + "Text\n\n" "## C 1: Chapter One\n\n" "### S 1.1 (1): Scene One\n\n" "Text\n\n" @@ -1894,6 +1901,8 @@ def testCoreToken_HeaderCounterAndVisibility(mockGUI): "### H 2.2 (4): Scene Four\n\n" "Text\n\n" "# Novel Two\n\n" + "## Prologue\n\n" + "Text\n\n" "## C 1: Chapter One\n\n" "### S 1.1 (1): Scene One\n\n" "Text\n\n"