Move comment processing to a separate file

This commit is contained in:
Veronica Berglyd Olsen
2025-02-09 15:39:48 +01:00
parent 9bae8f762f
commit 05feaf7d2d
6 changed files with 182 additions and 132 deletions
+1 -45
View File
@@ -43,6 +43,7 @@ from novelwriter.common import (
from novelwriter.constants import nwFiles, nwKeyWords, nwStyles from novelwriter.constants import nwFiles, nwKeyWords, nwStyles
from novelwriter.enum import nwComment, nwItemClass, nwItemLayout, nwItemType from novelwriter.enum import nwComment, nwItemClass, nwItemLayout, nwItemType
from novelwriter.error import logException from novelwriter.error import logException
from novelwriter.text.comments import processComment
from novelwriter.text.counting import standardCounter from novelwriter.text.counting import standardCounter
if TYPE_CHECKING: # pragma: no cover if TYPE_CHECKING: # pragma: no cover
@@ -1343,48 +1344,3 @@ class IndexHeading:
else: else:
raise ValueError("The itemIndex contains an invalid reference type") raise ValueError("The itemIndex contains an invalid reference type")
return return
# Text Processing Functions
# =========================
MODIFIERS = {
"synopsis": nwComment.SYNOPSIS,
"short": nwComment.SHORT,
"note": nwComment.NOTE,
"footnote": nwComment.FOOTNOTE,
}
KEY_REQ = {
"synopsis": 0, # Key not allowed
"short": 0, # Key not allowed
"note": 1, # Key optional
"footnote": 2, # Key required
}
def _checkModKey(modifier: str, key: str) -> bool:
"""Check if a modifier and key set are ok."""
if modifier in MODIFIERS:
if key == "":
return KEY_REQ[modifier] < 2
elif key.replace("_", "").isalnum():
return KEY_REQ[modifier] > 0
return False
def processComment(text: str) -> tuple[nwComment, str, str, int, int]:
"""Extract comment style, key and text. Should only be called on
text starting with a %.
"""
if text[:2] == "%~":
return nwComment.IGNORE, "", text[2:].lstrip(), 0, 0
check = text[1:].strip()
start, _, content = check.partition(":")
modifier, _, key = start.rstrip().partition(".")
if content and (clean := modifier.lower()) and _checkModKey(clean, key):
col = text.find(":") + 1
dot = text.find(".", 0, col) + 1
return MODIFIERS[clean], key, content.lstrip(), dot, col
return nwComment.PLAIN, "", check, 0, 0
+1 -1
View File
@@ -40,12 +40,12 @@ from novelwriter.constants import (
nwHeadFmt, nwKeyWords, nwLabels, nwShortcode, nwStats, nwStyles, nwUnicode, nwHeadFmt, nwKeyWords, nwLabels, nwShortcode, nwStats, nwStyles, nwUnicode,
trConst trConst
) )
from novelwriter.core.index import processComment
from novelwriter.core.project import NWProject from novelwriter.core.project import NWProject
from novelwriter.enum import nwComment, nwItemLayout from novelwriter.enum import nwComment, nwItemLayout
from novelwriter.formats.shared import ( from novelwriter.formats.shared import (
BlockFmt, BlockTyp, T_Block, T_Formats, T_Note, TextDocumentTheme, TextFmt BlockFmt, BlockTyp, T_Block, T_Formats, T_Note, TextDocumentTheme, TextFmt
) )
from novelwriter.text.comments import processComment
from novelwriter.text.patterns import REGEX_PATTERNS, DialogParser from novelwriter.text.patterns import REGEX_PATTERNS, DialogParser
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
+1 -1
View File
@@ -38,8 +38,8 @@ from PyQt6.QtGui import (
from novelwriter import CONFIG, SHARED from novelwriter import CONFIG, SHARED
from novelwriter.common import checkInt from novelwriter.common import checkInt
from novelwriter.constants import nwStyles, nwUnicode from novelwriter.constants import nwStyles, nwUnicode
from novelwriter.core.index import processComment
from novelwriter.enum import nwComment from novelwriter.enum import nwComment
from novelwriter.text.comments import processComment
from novelwriter.text.patterns import REGEX_PATTERNS, DialogParser from novelwriter.text.patterns import REGEX_PATTERNS, DialogParser
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
+68
View File
@@ -0,0 +1,68 @@
"""
novelWriter Text Comments
===========================
File History:
Created: 2023-11-23 [2.2b1]
Moved: 2025-02-09 [2.7b1]
This file is a part of novelWriter
Copyright (C) 2025 Veronica Berglyd Olsen and novelWriter contributors
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
from __future__ import annotations
from novelwriter.enum import nwComment
MODIFIERS = {
"synopsis": nwComment.SYNOPSIS,
"short": nwComment.SHORT,
"note": nwComment.NOTE,
"footnote": nwComment.FOOTNOTE,
}
KEY_REQ = {
"synopsis": 0, # Key not allowed
"short": 0, # Key not allowed
"note": 1, # Key optional
"footnote": 2, # Key required
}
def _checkModKey(modifier: str, key: str) -> bool:
"""Check if a modifier and key set are ok."""
if modifier in MODIFIERS:
if key == "":
return KEY_REQ[modifier] < 2
elif key.replace("_", "").isalnum():
return KEY_REQ[modifier] > 0
return False
def processComment(text: str) -> tuple[nwComment, str, str, int, int]:
"""Extract comment style, key and text. Should only be called on
text starting with a %.
"""
if text[:2] == "%~":
return nwComment.IGNORE, "", text[2:].lstrip(), 0, 0
check = text[1:].strip()
start, _, content = check.partition(":")
modifier, _, key = start.rstrip().partition(".")
if content and (clean := modifier.lower()) and _checkModKey(clean, key):
col = text.find(":") + 1
dot = text.find(".", 0, col) + 1
return MODIFIERS[clean], key, content.lstrip(), dot, col
return nwComment.PLAIN, "", check, 0, 0
+1 -85
View File
@@ -28,7 +28,7 @@ import pytest
from novelwriter import SHARED from novelwriter import SHARED
from novelwriter.constants import nwFiles from novelwriter.constants import nwFiles
from novelwriter.core.index import IndexItem, NWIndex, TagsIndex, _checkModKey, processComment from novelwriter.core.index import IndexItem, NWIndex, TagsIndex
from novelwriter.core.item import NWItem from novelwriter.core.item import NWItem
from novelwriter.core.project import NWProject from novelwriter.core.project import NWProject
from novelwriter.enum import nwComment, nwItemClass, nwItemLayout from novelwriter.enum import nwComment, nwItemClass, nwItemLayout
@@ -1419,87 +1419,3 @@ def testCoreIndex_ItemIndex(mockGUI, fncPath, mockRnd):
"notes": {"footnotes": ["fkey"], "comments": ["ckey"]}, "notes": {"footnotes": ["fkey"], "comments": ["ckey"]},
} }
}) })
@pytest.mark.core
def testCoreIndex_checkModKey():
"""Test the _checkModKey function."""
# Check Requirements
# Synopsis
assert _checkModKey("synopsis", "") is True
assert _checkModKey("synopsis", "a") is False
# Short
assert _checkModKey("short", "") is True
assert _checkModKey("short", "a") is False
# Note
assert _checkModKey("note", "") is True
assert _checkModKey("note", "a") is True
# Footnote
assert _checkModKey("footnote", "") is False
assert _checkModKey("footnote", "a") is True
# Invalid
assert _checkModKey("stuff", "") is False
assert _checkModKey("stuff", "a") is False
# Check Keys
assert _checkModKey("note", "a") is True
assert _checkModKey("note", "a1") is True
assert _checkModKey("note", "a1.2") is False
assert _checkModKey("note", "a1_2") is True
@pytest.mark.core
def testCoreIndex_processComment():
"""Test the comment processing function."""
# Plain
assert processComment("%Hi") == (nwComment.PLAIN, "", "Hi", 0, 0)
assert processComment("% Hi") == (nwComment.PLAIN, "", "Hi", 0, 0)
assert processComment("% Hi:You") == (nwComment.PLAIN, "", "Hi:You", 0, 0)
assert processComment("% Hi.You:There") == (nwComment.PLAIN, "", "Hi.You:There", 0, 0)
# Ignore
assert processComment("%~Hi") == (nwComment.IGNORE, "", "Hi", 0, 0)
assert processComment("%~ Hi") == (nwComment.IGNORE, "", "Hi", 0, 0)
# Invalid
assert processComment("") == (nwComment.PLAIN, "", "", 0, 0)
# Short : Term not allowed
assert processComment("%short: Hi") == (nwComment.SHORT, "", "Hi", 0, 7)
assert processComment("%short.a: Hi") == (nwComment.PLAIN, "", "short.a: Hi", 0, 0)
# Synopsis : Term not allowed
assert processComment("%synopsis: Hi") == (nwComment.SYNOPSIS, "", "Hi", 0, 10)
assert processComment("%synopsis.a: Hi") == (nwComment.PLAIN, "", "synopsis.a: Hi", 0, 0)
# Note : Term optional
assert processComment("%note: Hi") == (nwComment.NOTE, "", "Hi", 0, 6)
assert processComment("%note.a: Hi") == (nwComment.NOTE, "a", "Hi", 6, 8)
# Footnote : Term required
assert processComment("%footnote: Hi") == (nwComment.PLAIN, "", "footnote: Hi", 0, 0)
assert processComment("%footnote.a: Hi") == (nwComment.FOOTNOTE, "a", "Hi", 10, 12)
# Check Case
assert processComment("%Footnote.a: Hi") == (nwComment.FOOTNOTE, "a", "Hi", 10, 12)
assert processComment("%FOOTNOTE.A: Hi") == (nwComment.FOOTNOTE, "A", "Hi", 10, 12)
assert processComment("%FootNote.A_a: Hi") == (nwComment.FOOTNOTE, "A_a", "Hi", 10, 14)
# Padding without term
assert processComment("%short: Hi") == (nwComment.SHORT, "", "Hi", 0, 7)
assert processComment("% short: Hi") == (nwComment.SHORT, "", "Hi", 0, 8)
assert processComment("% short : Hi") == (nwComment.SHORT, "", "Hi", 0, 10)
assert processComment("% short : Hi") == (nwComment.SHORT, "", "Hi", 0, 12)
assert processComment("% \t short : Hi") == (nwComment.SHORT, "", "Hi", 0, 13)
# Padding with term
assert processComment("%note.term: Hi") == (nwComment.NOTE, "term", "Hi", 6, 11)
assert processComment("% note.term: Hi") == (nwComment.NOTE, "term", "Hi", 7, 12)
assert processComment("% note.term : Hi") == (nwComment.NOTE, "term", "Hi", 7, 13)
assert processComment("% note. term : Hi") == (nwComment.PLAIN, "", "note. term : Hi", 0, 0)
assert processComment("% note . term : Hi") == (nwComment.PLAIN, "", "note . term : Hi", 0, 0)
+110
View File
@@ -0,0 +1,110 @@
"""
novelWriter NWIndex Class Tester
==================================
This file is a part of novelWriter
Copyright (C) 2020 Veronica Berglyd Olsen and novelWriter contributors
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
from __future__ import annotations
import pytest
from novelwriter.enum import nwComment
from novelwriter.text.comments import _checkModKey, processComment
@pytest.mark.core
def testTextComments_checkModKey():
"""Test the _checkModKey function."""
# Check Requirements
# Synopsis
assert _checkModKey("synopsis", "") is True
assert _checkModKey("synopsis", "a") is False
# Short
assert _checkModKey("short", "") is True
assert _checkModKey("short", "a") is False
# Note
assert _checkModKey("note", "") is True
assert _checkModKey("note", "a") is True
# Footnote
assert _checkModKey("footnote", "") is False
assert _checkModKey("footnote", "a") is True
# Invalid
assert _checkModKey("stuff", "") is False
assert _checkModKey("stuff", "a") is False
# Check Keys
assert _checkModKey("note", "a") is True
assert _checkModKey("note", "a1") is True
assert _checkModKey("note", "a1.2") is False
assert _checkModKey("note", "a1_2") is True
@pytest.mark.core
def testTextComments_processComment():
"""Test the comment processing function."""
# Plain
assert processComment("%Hi") == (nwComment.PLAIN, "", "Hi", 0, 0)
assert processComment("% Hi") == (nwComment.PLAIN, "", "Hi", 0, 0)
assert processComment("% Hi:You") == (nwComment.PLAIN, "", "Hi:You", 0, 0)
assert processComment("% Hi.You:There") == (nwComment.PLAIN, "", "Hi.You:There", 0, 0)
# Ignore
assert processComment("%~Hi") == (nwComment.IGNORE, "", "Hi", 0, 0)
assert processComment("%~ Hi") == (nwComment.IGNORE, "", "Hi", 0, 0)
# Invalid
assert processComment("") == (nwComment.PLAIN, "", "", 0, 0)
# Short : Term not allowed
assert processComment("%short: Hi") == (nwComment.SHORT, "", "Hi", 0, 7)
assert processComment("%short.a: Hi") == (nwComment.PLAIN, "", "short.a: Hi", 0, 0)
# Synopsis : Term not allowed
assert processComment("%synopsis: Hi") == (nwComment.SYNOPSIS, "", "Hi", 0, 10)
assert processComment("%synopsis.a: Hi") == (nwComment.PLAIN, "", "synopsis.a: Hi", 0, 0)
# Note : Term optional
assert processComment("%note: Hi") == (nwComment.NOTE, "", "Hi", 0, 6)
assert processComment("%note.a: Hi") == (nwComment.NOTE, "a", "Hi", 6, 8)
# Footnote : Term required
assert processComment("%footnote: Hi") == (nwComment.PLAIN, "", "footnote: Hi", 0, 0)
assert processComment("%footnote.a: Hi") == (nwComment.FOOTNOTE, "a", "Hi", 10, 12)
# Check Case
assert processComment("%Footnote.a: Hi") == (nwComment.FOOTNOTE, "a", "Hi", 10, 12)
assert processComment("%FOOTNOTE.A: Hi") == (nwComment.FOOTNOTE, "A", "Hi", 10, 12)
assert processComment("%FootNote.A_a: Hi") == (nwComment.FOOTNOTE, "A_a", "Hi", 10, 14)
# Padding without term
assert processComment("%short: Hi") == (nwComment.SHORT, "", "Hi", 0, 7)
assert processComment("% short: Hi") == (nwComment.SHORT, "", "Hi", 0, 8)
assert processComment("% short : Hi") == (nwComment.SHORT, "", "Hi", 0, 10)
assert processComment("% short : Hi") == (nwComment.SHORT, "", "Hi", 0, 12)
assert processComment("% \t short : Hi") == (nwComment.SHORT, "", "Hi", 0, 13)
# Padding with term
assert processComment("%note.term: Hi") == (nwComment.NOTE, "term", "Hi", 6, 11)
assert processComment("% note.term: Hi") == (nwComment.NOTE, "term", "Hi", 7, 12)
assert processComment("% note.term : Hi") == (nwComment.NOTE, "term", "Hi", 7, 13)
assert processComment("% note. term : Hi") == (nwComment.PLAIN, "", "note. term : Hi", 0, 0)
assert processComment("% note . term : Hi") == (nwComment.PLAIN, "", "note . term : Hi", 0, 0)