Improve comment processing

This commit is contained in:
Veronica Berglyd Olsen
2024-04-26 22:25:08 +02:00
parent b585b8ecd1
commit b722224863
2 changed files with 99 additions and 31 deletions
+32 -13
View File
@@ -40,8 +40,8 @@ from novelwriter import SHARED
from novelwriter.common import (
checkInt, isHandle, isItemClass, isListInstance, isTitleTag, jsonEncode
)
from novelwriter.constants import nwFiles, nwKeyWords, nwHeaders
from novelwriter.enum import nwComment, nwItemClass, nwItemType, nwItemLayout
from novelwriter.constants import nwFiles, nwHeaders, nwKeyWords
from novelwriter.enum import nwComment, nwItemClass, nwItemLayout, nwItemType
from novelwriter.error import logException
from novelwriter.text.counting import standardCounter
@@ -1360,24 +1360,43 @@ class IndexHeading:
# Text Processing Functions
# =============================================================================================== #
CLASSIFIERS = {
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
}
TERMS = ["note", "footnote"]
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 and text. Should only be called on text
starting with a %.
"""Extract comment style, key and text. Should only be called on
text starting with a %.
"""
check = text[1:].lstrip()
classifier, _, content = check.partition(":")
classifier, _, term = classifier.partition(".")
if content and (clean := classifier.strip().lower()) in CLASSIFIERS:
term = "ERR" if term and clean not in TERMS else term.strip()
return CLASSIFIERS[clean], term, content.strip(), text.find(".") + 1, text.find(":") + 1
return nwComment.IGNORE if text.startswith("%~") else nwComment.PLAIN, "", check, 0, 0
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
+67 -18
View File
@@ -26,16 +26,16 @@ from shutil import copyfile
import pytest
from mocked import causeException
from tools import C, buildTestProject, cmpFiles, writeFile
from novelwriter import SHARED
from novelwriter.constants import nwFiles
from novelwriter.core.index import IndexItem, NWIndex, TagsIndex, processComment
from novelwriter.core.index import IndexItem, NWIndex, TagsIndex, _checkModKey, processComment
from novelwriter.core.item import NWItem
from novelwriter.core.project import NWProject
from novelwriter.enum import nwComment, nwItemClass, nwItemLayout
from tests.mocked import causeException
from tests.tools import C, buildTestProject, cmpFiles, writeFile
@pytest.mark.core
def testCoreIndex_LoadSave(qtbot, monkeypatch, prjLipsum, mockGUI, tstPaths):
@@ -1319,39 +1319,88 @@ def testCoreIndex_ItemIndex(mockGUI, fncPath, mockRnd):
# END Test testCoreIndex_ItemIndex
@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
# END Test testCoreIndex_checkModKey
@pytest.mark.core
def testCoreIndex_processComment():
"""Test the comment processing function."""
# Regular comment
# 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)
# Check Non-Term
# 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.term: Hi") == (nwComment.SHORT, "ERR", "Hi", 7, 12)
assert processComment("%short.a: Hi") == (nwComment.PLAIN, "", "short.a: Hi", 0, 0)
# Check Term
# 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.term: Hi") == (nwComment.NOTE, "term", "Hi", 6, 11)
assert processComment("%note.a: Hi") == (nwComment.NOTE, "a", "Hi", 6, 8)
# Check Padding
# 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", 9, 16)
assert processComment("% note . term : Hi") == (nwComment.NOTE, "term", "Hi", 11, 20)
# Check Classifiers
assert processComment("%short: Hi") == (nwComment.SHORT, "", "Hi", 0, 7)
assert processComment("%synopsis: Hi") == (nwComment.SYNOPSIS, "", "Hi", 0, 10)
assert processComment("%note.term: Hi") == (nwComment.NOTE, "term", "Hi", 6, 11)
assert processComment("%footnote.term: Hi") == (nwComment.FOOTNOTE, "term", "Hi", 10, 15)
assert processComment("% note. term : Hi") == (nwComment.PLAIN, "", "note. term : Hi", 0, 0)
assert processComment("% note . term : Hi") == (nwComment.PLAIN, "", "note . term : Hi", 0, 0)
# END Test testCoreIndex_processComment