Fix bugs in the document viewer (#2014)
This commit is contained in:
@@ -832,7 +832,7 @@ class Tokenizer(ABC):
|
|||||||
sAlign |= self.A_IND_R
|
sAlign |= self.A_IND_R
|
||||||
|
|
||||||
# Process formats
|
# Process formats
|
||||||
tLine, tFmt = self._extractFormats(aLine)
|
tLine, tFmt = self._extractFormats(aLine, hDialog=self._isNovel)
|
||||||
tokens.append((
|
tokens.append((
|
||||||
self.T_TEXT, nHead, tLine, tFmt, sAlign
|
self.T_TEXT, nHead, tLine, tFmt, sAlign
|
||||||
))
|
))
|
||||||
@@ -1098,8 +1098,13 @@ class Tokenizer(ABC):
|
|||||||
# Internal Functions
|
# Internal Functions
|
||||||
##
|
##
|
||||||
|
|
||||||
def _extractFormats(self, text: str, skip: int = 0) -> tuple[str, T_Formats]:
|
def _extractFormats(
|
||||||
"""Extract format markers from a text paragraph."""
|
self, text: str, skip: int = 0, hDialog: bool = False
|
||||||
|
) -> tuple[str, T_Formats]:
|
||||||
|
"""Extract format markers from a text paragraph. In order to
|
||||||
|
also process dialogue highlighting, the hDialog flag must be set
|
||||||
|
to True. See issues #2011 and #2013.
|
||||||
|
"""
|
||||||
temp: list[tuple[int, int, int, str]] = []
|
temp: list[tuple[int, int, int, str]] = []
|
||||||
|
|
||||||
# Match Markdown
|
# Match Markdown
|
||||||
@@ -1137,7 +1142,7 @@ class Tokenizer(ABC):
|
|||||||
))
|
))
|
||||||
|
|
||||||
# Match Dialogue
|
# Match Dialogue
|
||||||
if self._rxDialogue:
|
if self._rxDialogue and hDialog:
|
||||||
for regEx, fmtB, fmtE in self._rxDialogue:
|
for regEx, fmtB, fmtE in self._rxDialogue:
|
||||||
rxItt = regEx.globalMatch(text, 0)
|
rxItt = regEx.globalMatch(text, 0)
|
||||||
while rxItt.hasNext():
|
while rxItt.hasNext():
|
||||||
@@ -1150,8 +1155,9 @@ class Tokenizer(ABC):
|
|||||||
formats = []
|
formats = []
|
||||||
for pos, n, fmt, key in reversed(sorted(temp, key=lambda x: x[0])):
|
for pos, n, fmt, key in reversed(sorted(temp, key=lambda x: x[0])):
|
||||||
if fmt > 0:
|
if fmt > 0:
|
||||||
result = result[:pos] + result[pos+n:]
|
if n > 0:
|
||||||
formats = [(p-n, f, k) for p, f, k in formats]
|
result = result[:pos] + result[pos+n:]
|
||||||
|
formats = [(p-n if p > pos else p, f, k) for p, f, k in formats]
|
||||||
formats.insert(0, (pos, fmt, key))
|
formats.insert(0, (pos, fmt, key))
|
||||||
|
|
||||||
return result, formats
|
return result, formats
|
||||||
|
|||||||
@@ -229,15 +229,13 @@ class GuiDocViewer(QTextBrowser):
|
|||||||
QApplication.restoreOverrideCursor()
|
QApplication.restoreOverrideCursor()
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Refresh the tab stops
|
# Must be before setDocument
|
||||||
self.setTabStopDistance(CONFIG.getTabWidth())
|
|
||||||
|
|
||||||
# Must be before setHtml
|
|
||||||
if updateHistory:
|
if updateHistory:
|
||||||
self.docHistory.append(tHandle)
|
self.docHistory.append(tHandle)
|
||||||
|
|
||||||
self.setDocumentTitle(tHandle)
|
self.setDocumentTitle(tHandle)
|
||||||
self.setDocument(qDoc.document)
|
self.setDocument(qDoc.document)
|
||||||
|
self.setTabStopDistance(CONFIG.getTabWidth())
|
||||||
|
|
||||||
if self._docHandle == tHandle:
|
if self._docHandle == tHandle:
|
||||||
# This is a refresh, so we set the scrollbar back to where it was
|
# This is a refresh, so we set the scrollbar back to where it was
|
||||||
|
|||||||
@@ -823,6 +823,7 @@ class _PreviewWidget(QTextBrowser):
|
|||||||
|
|
||||||
document.setDocumentMargin(CONFIG.getTextMargin())
|
document.setDocumentMargin(CONFIG.getTextMargin())
|
||||||
self.setDocument(document)
|
self.setDocument(document)
|
||||||
|
self.setTabStopDistance(CONFIG.getTabWidth())
|
||||||
|
|
||||||
self._docTime = int(time())
|
self._docTime = int(time())
|
||||||
self._updateBuildAge()
|
self._updateBuildAge()
|
||||||
|
|||||||
@@ -1100,6 +1100,7 @@ def testCoreToken_Dialogue(mockGUI):
|
|||||||
project = NWProject()
|
project = NWProject()
|
||||||
tokens = BareTokenizer(project)
|
tokens = BareTokenizer(project)
|
||||||
tokens.setDialogueHighlight(True)
|
tokens.setDialogueHighlight(True)
|
||||||
|
tokens._isNovel = True
|
||||||
|
|
||||||
# Single quotes
|
# Single quotes
|
||||||
tokens._text = "Text with \u2018dialogue one,\u2019 and \u2018dialogue two.\u2019\n"
|
tokens._text = "Text with \u2018dialogue one,\u2019 and \u2018dialogue two.\u2019\n"
|
||||||
@@ -1161,6 +1162,24 @@ def testCoreToken_Dialogue(mockGUI):
|
|||||||
Tokenizer.A_NONE
|
Tokenizer.A_NONE
|
||||||
)]
|
)]
|
||||||
|
|
||||||
|
# Special Cases
|
||||||
|
# =============
|
||||||
|
|
||||||
|
# Dialogue + formatting on same index (Issue #2012)
|
||||||
|
tokens._text = "[i]\u201cDialogue text.\u201d[/i]\n"
|
||||||
|
tokens.tokenizeText()
|
||||||
|
assert tokens._tokens == [(
|
||||||
|
Tokenizer.T_TEXT, 0,
|
||||||
|
"\u201cDialogue text.\u201d",
|
||||||
|
[
|
||||||
|
(0, Tokenizer.FMT_I_B, ""),
|
||||||
|
(0, Tokenizer.FMT_DL_B, ""),
|
||||||
|
(16, Tokenizer.FMT_I_E, ""),
|
||||||
|
(16, Tokenizer.FMT_DL_E, ""),
|
||||||
|
],
|
||||||
|
Tokenizer.A_NONE
|
||||||
|
)]
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
def testCoreToken_SpecialFormat(mockGUI):
|
def testCoreToken_SpecialFormat(mockGUI):
|
||||||
|
|||||||
Reference in New Issue
Block a user