Fix highlighting of multiple dialogue sections

This commit is contained in:
Veronica Berglyd Olsen
2024-06-10 23:50:59 +02:00
parent 0b3488c265
commit 416c580a45
3 changed files with 129 additions and 68 deletions
+1 -1
View File
@@ -457,7 +457,7 @@ class ToHtml(Tokenizer):
else: else:
html = "<sup>ERR</sup>" html = "<sup>ERR</sup>"
else: else:
html = HTML5_TAGS.get(fmt, "ERR") html = HTML5_TAGS.get(fmt, "")
temp = f"{temp[:pos]}{html}{temp[pos:]}" temp = f"{temp[:pos]}{html}{temp[pos:]}"
temp = temp.replace("\n", "<br>") temp = temp.replace("\n", "<br>")
return stripEscape(temp) return stripEscape(temp)
+3 -1
View File
@@ -1139,7 +1139,9 @@ class Tokenizer(ABC):
# Match Dialogue # Match Dialogue
if self._rxDialogue: if self._rxDialogue:
for regEx, fmtB, fmtE in self._rxDialogue: for regEx, fmtB, fmtE in self._rxDialogue:
if (rxMatch := regEx.match(text, 0)).hasMatch(): rxItt = regEx.globalMatch(text, 0)
while rxItt.hasNext():
rxMatch = rxItt.next()
temp.append((rxMatch.capturedStart(0), 0, fmtB, "")) temp.append((rxMatch.capturedStart(0), 0, fmtB, ""))
temp.append((rxMatch.capturedEnd(0), 0, fmtE, "")) temp.append((rxMatch.capturedEnd(0), 0, fmtE, ""))
+125 -66
View File
@@ -26,6 +26,7 @@ import pytest
from PyQt5.QtGui import QFont from PyQt5.QtGui import QFont
from novelwriter import CONFIG
from novelwriter.constants import nwHeadFmt from novelwriter.constants import nwHeadFmt
from novelwriter.core.project import NWProject from novelwriter.core.project import NWProject
from novelwriter.core.tokenizer import HeadingFormatter, Tokenizer, stripEscape from novelwriter.core.tokenizer import HeadingFormatter, Tokenizer, stripEscape
@@ -1016,88 +1017,151 @@ def testCoreToken_TextFormat(mockGUI):
# Text Emphasis # Text Emphasis
tokens._text = "Some **bolded text** on this lines\n" tokens._text = "Some **bolded text** on this lines\n"
tokens.tokenizeText() tokens.tokenizeText()
assert tokens._tokens == [ assert tokens._tokens == [(
( Tokenizer.T_TEXT, 0, "Some bolded text on this lines",
Tokenizer.T_TEXT, 0, [
"Some bolded text on this lines", (5, Tokenizer.FMT_B_B, ""),
[ (16, Tokenizer.FMT_B_E, ""),
(5, Tokenizer.FMT_B_B, ""), ],
(16, Tokenizer.FMT_B_E, ""), Tokenizer.A_NONE
], )]
Tokenizer.A_NONE
),
]
assert tokens.allMarkdown[-1] == "Some **bolded text** on this lines\n\n" assert tokens.allMarkdown[-1] == "Some **bolded text** on this lines\n\n"
tokens._text = "Some _italic text_ on this lines\n" tokens._text = "Some _italic text_ on this lines\n"
tokens.tokenizeText() tokens.tokenizeText()
assert tokens._tokens == [ assert tokens._tokens == [(
( Tokenizer.T_TEXT, 0, "Some italic text on this lines",
Tokenizer.T_TEXT, 0, [
"Some italic text on this lines", (5, Tokenizer.FMT_I_B, ""),
[ (16, Tokenizer.FMT_I_E, ""),
(5, Tokenizer.FMT_I_B, ""), ],
(16, Tokenizer.FMT_I_E, ""), Tokenizer.A_NONE
], )]
Tokenizer.A_NONE
),
]
assert tokens.allMarkdown[-1] == "Some _italic text_ on this lines\n\n" assert tokens.allMarkdown[-1] == "Some _italic text_ on this lines\n\n"
tokens._text = "Some **_bold italic text_** on this lines\n" tokens._text = "Some **_bold italic text_** on this lines\n"
tokens.tokenizeText() tokens.tokenizeText()
assert tokens._tokens == [ assert tokens._tokens == [(
( Tokenizer.T_TEXT, 0, "Some bold italic text on this lines",
Tokenizer.T_TEXT, 0, [
"Some bold italic text on this lines", (5, Tokenizer.FMT_B_B, ""),
[ (5, Tokenizer.FMT_I_B, ""),
(5, Tokenizer.FMT_B_B, ""), (21, Tokenizer.FMT_I_E, ""),
(5, Tokenizer.FMT_I_B, ""), (21, Tokenizer.FMT_B_E, ""),
(21, Tokenizer.FMT_I_E, ""), ],
(21, Tokenizer.FMT_B_E, ""), Tokenizer.A_NONE
], )]
Tokenizer.A_NONE
),
]
assert tokens.allMarkdown[-1] == "Some **_bold italic text_** on this lines\n\n" assert tokens.allMarkdown[-1] == "Some **_bold italic text_** on this lines\n\n"
tokens._text = "Some ~~strikethrough text~~ on this lines\n" tokens._text = "Some ~~strikethrough text~~ on this lines\n"
tokens.tokenizeText() tokens.tokenizeText()
assert tokens._tokens == [ assert tokens._tokens == [(
( Tokenizer.T_TEXT, 0, "Some strikethrough text on this lines",
Tokenizer.T_TEXT, 0, [
"Some strikethrough text on this lines", (5, Tokenizer.FMT_D_B, ""),
[ (23, Tokenizer.FMT_D_E, ""),
(5, Tokenizer.FMT_D_B, ""), ],
(23, Tokenizer.FMT_D_E, ""), Tokenizer.A_NONE
], )]
Tokenizer.A_NONE
),
]
assert tokens.allMarkdown[-1] == "Some ~~strikethrough text~~ on this lines\n\n" assert tokens.allMarkdown[-1] == "Some ~~strikethrough text~~ on this lines\n\n"
tokens._text = "Some **nested bold and _italic_ and ~~strikethrough~~ text** here\n" tokens._text = "Some **nested bold and _italic_ and ~~strikethrough~~ text** here\n"
tokens.tokenizeText() tokens.tokenizeText()
assert tokens._tokens == [ assert tokens._tokens == [(
( Tokenizer.T_TEXT, 0, "Some nested bold and italic and strikethrough text here",
Tokenizer.T_TEXT, 0, [
"Some nested bold and italic and strikethrough text here", (5, Tokenizer.FMT_B_B, ""),
[ (21, Tokenizer.FMT_I_B, ""),
(5, Tokenizer.FMT_B_B, ""), (27, Tokenizer.FMT_I_E, ""),
(21, Tokenizer.FMT_I_B, ""), (32, Tokenizer.FMT_D_B, ""),
(27, Tokenizer.FMT_I_E, ""), (45, Tokenizer.FMT_D_E, ""),
(32, Tokenizer.FMT_D_B, ""), (50, Tokenizer.FMT_B_E, ""),
(45, Tokenizer.FMT_D_E, ""), ],
(50, Tokenizer.FMT_B_E, ""), Tokenizer.A_NONE
], )]
Tokenizer.A_NONE
),
]
assert tokens.allMarkdown[-1] == ( assert tokens.allMarkdown[-1] == (
"Some **nested bold and _italic_ and ~~strikethrough~~ text** here\n\n" "Some **nested bold and _italic_ and ~~strikethrough~~ text** here\n\n"
) )
@pytest.mark.core
def testCoreToken_Dialogue(mockGUI):
"""Test the tokenization of dialogue in the Tokenizer class."""
CONFIG.fmtDQuoteOpen = "\u201c"
CONFIG.fmtDQuoteClose = "\u201d"
CONFIG.fmtSQuoteOpen = "\u2018"
CONFIG.fmtSQuoteClose = "\u2019"
CONFIG.dialogStyle = 3
CONFIG.altDialogOpen = "::"
CONFIG.altDialogClose = "::"
CONFIG.dialogLine = "\u2013"
CONFIG.narratorBreak = "\u2013"
project = NWProject()
tokens = BareTokenizer(project)
tokens.setDialogueHighlight(True)
# Single quotes
tokens._text = "Text with \u2018dialogue one,\u2019 and \u2018dialogue two.\u2019\n"
tokens.tokenizeText()
assert tokens._tokens == [(
Tokenizer.T_TEXT, 0,
"Text with \u2018dialogue one,\u2019 and \u2018dialogue two.\u2019",
[
(10, Tokenizer.FMT_DL_B, ""),
(25, Tokenizer.FMT_DL_E, ""),
(30, Tokenizer.FMT_DL_B, ""),
(45, Tokenizer.FMT_DL_E, ""),
],
Tokenizer.A_NONE
)]
# Double quotes
tokens._text = "Text with \u201cdialogue one,\u201d and \u201cdialogue two.\u201d\n"
tokens.tokenizeText()
assert tokens._tokens == [(
Tokenizer.T_TEXT, 0,
"Text with \u201cdialogue one,\u201d and \u201cdialogue two.\u201d",
[
(10, Tokenizer.FMT_DL_B, ""),
(25, Tokenizer.FMT_DL_E, ""),
(30, Tokenizer.FMT_DL_B, ""),
(45, Tokenizer.FMT_DL_E, ""),
],
Tokenizer.A_NONE
)]
# Alt quotes
tokens._text = "Text with ::dialogue one,:: and ::dialogue two.::\n"
tokens.tokenizeText()
assert tokens._tokens == [(
Tokenizer.T_TEXT, 0,
"Text with ::dialogue one,:: and ::dialogue two.::",
[
(10, Tokenizer.FMT_ADL_B, ""),
(27, Tokenizer.FMT_ADL_E, ""),
(32, Tokenizer.FMT_ADL_B, ""),
(49, Tokenizer.FMT_ADL_E, ""),
],
Tokenizer.A_NONE
)]
# Dialogue line with narrator break
tokens._text = "\u2013 Dialogue with a narrator break, \u2013he said,\u2013 see?\n"
tokens.tokenizeText()
assert tokens._tokens == [(
Tokenizer.T_TEXT, 0,
"\u2013 Dialogue with a narrator break, \u2013he said,\u2013 see?",
[
(0, Tokenizer.FMT_DL_B, ""),
(34, Tokenizer.FMT_DL_E, ""),
(44, Tokenizer.FMT_DL_B, ""),
(49, Tokenizer.FMT_DL_E, ""),
],
Tokenizer.A_NONE
)]
@pytest.mark.core @pytest.mark.core
def testCoreToken_SpecialFormat(mockGUI): def testCoreToken_SpecialFormat(mockGUI):
"""Test the tokenization of special formats in the Tokenizer class.""" """Test the tokenization of special formats in the Tokenizer class."""
@@ -1267,11 +1331,6 @@ def testCoreToken_ProcessHeaders(mockGUI):
project.data.setLanguage("en") project.data.setLanguage("en")
project._loadProjectLocalisation() project._loadProjectLocalisation()
tokens = BareTokenizer(project) tokens = BareTokenizer(project)
##
# Story Files
##
tokens._isNovel = True tokens._isNovel = True
# Titles # Titles