Add working meta data blocks

This commit is contained in:
Veronica Berglyd Olsen
2024-05-23 20:48:42 +02:00
parent c8017a1f42
commit e998cb634e
3 changed files with 79 additions and 38 deletions
+4 -1
View File
@@ -597,7 +597,10 @@ class Tokenizer(ABC):
# are automatically skipped. # are automatically skipped.
valid, bits, _ = self._project.index.scanThis(aLine) valid, bits, _ = self._project.index.scanThis(aLine)
if valid and bits and bits[0] not in self._skipKeywords: if (
valid and bits and bits[0] in nwLabels.KEY_NAME
and bits[0] not in self._skipKeywords
):
tokens.append(( tokens.append((
self.T_KEYWORD, nHead, aLine[1:].strip(), [], sAlign self.T_KEYWORD, nHead, aLine[1:].strip(), [], sAlign
)) ))
+68 -30
View File
@@ -26,12 +26,12 @@ from __future__ import annotations
import logging import logging
from PyQt5.QtGui import ( from PyQt5.QtGui import (
QColor, QFont, QFontMetrics, QTextBlockFormat, QTextCharFormat, QFont, QFontMetrics, QTextBlockFormat, QTextCharFormat, QTextCursor,
QTextCursor, QTextDocument QTextDocument
) )
from novelwriter import SHARED from novelwriter import SHARED
from novelwriter.constants import nwHeaders from novelwriter.constants import nwHeaders, nwHeadFmt, nwKeyWords, nwLabels, nwUnicode
from novelwriter.core.project import NWProject from novelwriter.core.project import NWProject
from novelwriter.core.tokenizer import T_Formats, Tokenizer from novelwriter.core.tokenizer import T_Formats, Tokenizer
from novelwriter.types import ( from novelwriter.types import (
@@ -99,6 +99,24 @@ class ToQTextDocument(Tokenizer):
self._defaultChar = QTextCharFormat() self._defaultChar = QTextCharFormat()
self._defaultChar.setForeground(SHARED.theme.colText) self._defaultChar.setForeground(SHARED.theme.colText)
self._comChar = QTextCharFormat()
self._comChar.setForeground(SHARED.theme.colHidden)
self._noteChar = QTextCharFormat()
self._noteChar.setForeground(SHARED.theme.colNote)
self._modChar = QTextCharFormat()
self._modChar.setForeground(SHARED.theme.colMod)
self._keyChar = QTextCharFormat()
self._keyChar.setForeground(SHARED.theme.colKey)
self._tagChar = QTextCharFormat()
self._tagChar.setForeground(SHARED.theme.colTag)
self._optChar = QTextCharFormat()
self._optChar.setForeground(SHARED.theme.colOpt)
self._defaultBlock = QTextBlockFormat() self._defaultBlock = QTextBlockFormat()
self._defaultBlock.setTopMargin(self._mText[0]) self._defaultBlock.setTopMargin(self._mText[0])
self._defaultBlock.setBottomMargin(self._mText[1]) self._defaultBlock.setBottomMargin(self._mText[1])
@@ -139,7 +157,7 @@ class ToQTextDocument(Tokenizer):
else: else:
cursor.setBlockFormat(bFmt) cursor.setBlockFormat(bFmt)
for tType, _, tText, tFormat, tStyle in self._tokens: for tType, nHead, tText, tFormat, tStyle in self._tokens:
# Styles # Styles
bFmt = QTextBlockFormat(self._defaultBlock) bFmt = QTextBlockFormat(self._defaultBlock)
@@ -173,9 +191,9 @@ class ToQTextDocument(Tokenizer):
self._insertFragments(tText, tFormat, cursor, self._defaultChar) self._insertFragments(tText, tFormat, cursor, self._defaultChar)
elif tType in self.L_HEADINGS: elif tType in self.L_HEADINGS:
bFmt, cFmt = self._genHeadStyle(tType, bFmt) bFmt, cFmt = self._genHeadStyle(tType, nHead, bFmt)
newBlock(bFmt) newBlock(bFmt)
cursor.insertText(tText, cFmt) cursor.insertText(tText.replace(nwHeadFmt.BR, "\n"), cFmt)
elif tType == self.T_SEP: elif tType == self.T_SEP:
newBlock(bFmt) newBlock(bFmt)
@@ -183,20 +201,30 @@ class ToQTextDocument(Tokenizer):
elif tType == self.T_SKIP: elif tType == self.T_SKIP:
newBlock(bFmt) newBlock(bFmt)
cursor.insertText(nwUnicode.U_NBSP, self._defaultChar)
elif tType == self.T_SYNOPSIS and self._doSynopsis: elif tType == self.T_SYNOPSIS and self._doSynopsis:
pass newBlock(bFmt)
prefix = self._localLookup("Synopsis")
cursor.insertText(f"{prefix}: ", self._modChar)
self._insertFragments(tText, tFormat, cursor, self._noteChar)
elif tType == self.T_SHORT and self._doSynopsis: elif tType == self.T_SHORT and self._doSynopsis:
pass newBlock(bFmt)
prefix = self._localLookup("Short Description")
cursor.insertText(f"{prefix}: ", self._modChar)
self._insertFragments(tText, tFormat, cursor, self._noteChar)
elif tType == self.T_COMMENT and self._doComments: elif tType == self.T_COMMENT and self._doComments:
pass newBlock(bFmt)
self._insertFragments(tText, tFormat, cursor, self._comChar)
elif tType == self.T_KEYWORD and self._doKeywords: elif tType == self.T_KEYWORD and self._doKeywords:
pass newBlock(bFmt)
self._insertKeywords(tText, cursor)
self._document.blockSignals(False) self._document.blockSignals(False)
print(self._document.toHtml())
return return
@@ -226,16 +254,16 @@ class ToQTextDocument(Tokenizer):
## ##
def _insertFragments( def _insertFragments(
self, text: str, tFmt: T_Formats, cursor: QTextCursor, self, text: str, tFmt: T_Formats, cursor: QTextCursor, dFmt: QTextCharFormat
dFmt: QTextCharFormat, bgCol: QColor = QtTransparent
) -> None: ) -> None:
"""Apply formatting tags to text.""" """Apply formatting tags to text."""
cFmt = QTextCharFormat(dFmt) cFmt = QTextCharFormat(dFmt)
start = 0 start = 0
temp = text.replace("\n", nwUnicode.U_LSEP)
for pos, fmt, data in tFmt: for pos, fmt, data in tFmt:
# Insert buffer with previous format # Insert buffer with previous format
cursor.insertText(text[start:pos], cFmt) cursor.insertText(temp[start:pos], cFmt)
# Construct next format # Construct next format
if fmt == self.FMT_B_B: if fmt == self.FMT_B_B:
@@ -257,7 +285,7 @@ class ToQTextDocument(Tokenizer):
elif fmt == self.FMT_M_B: elif fmt == self.FMT_M_B:
cFmt.setBackground(SHARED.theme.colMark) cFmt.setBackground(SHARED.theme.colMark)
elif fmt == self.FMT_M_E: elif fmt == self.FMT_M_E:
cFmt.setBackground(bgCol) cFmt.setBackground(QtTransparent)
elif fmt == self.FMT_SUP_B: elif fmt == self.FMT_SUP_B:
cFmt.setVerticalAlignment(QtVAlignSuper) cFmt.setVerticalAlignment(QtVAlignSuper)
elif fmt == self.FMT_SUP_E: elif fmt == self.FMT_SUP_E:
@@ -280,27 +308,35 @@ class ToQTextDocument(Tokenizer):
start = pos start = pos
# Insert whatever is left in the buffer # Insert whatever is left in the buffer
cursor.insertText(text[start:], cFmt) cursor.insertText(temp[start:], cFmt)
return return
def _formatKeywords(self, text: str, style: int) -> str: def _insertKeywords(self, text: str, cursor: QTextCursor) -> None:
"""Apply Markdown formatting to keywords.""" """Apply Markdown formatting to keywords."""
# valid, bits, _ = self._project.index.scanThis("@"+text) valid, bits, _ = self._project.index.scanThis("@"+text)
# if not valid or not bits: if valid and bits:
# return "" key = f"{self._localLookup(nwLabels.KEY_NAME[bits[0]])}: "
cursor.insertText(key, self._keyChar)
if (num := len(bits)) > 1:
if bits[0] == nwKeyWords.TAG_KEY:
one, two = self._project.index.parseValue(bits[1])
cursor.insertText(one, self._tagChar)
if two:
cursor.insertText(" | ", self._defaultChar)
cursor.insertText(two, self._optChar)
else:
for n, bit in enumerate(bits[1:], 2):
cFmt = QTextCharFormat(self._tagChar)
cFmt.setFontUnderline(True)
cFmt.setAnchor(True)
cFmt.setAnchorHref(f"#{bits[0][1:]}={bit}")
cursor.insertText(bit, cFmt)
if n < num:
cursor.insertText(", ", self._defaultChar)
return
result = "" def _genHeadStyle(self, level: int, nHead: int, rFmt: QTextBlockFormat) -> T_TextStyle:
# if bits[0] in nwLabels.KEY_NAME:
# result += f"**{self._localLookup(nwLabels.KEY_NAME[bits[0]])}:** "
# if len(bits) > 1:
# result += ", ".join(bits[1:])
# result += " \n" if style & self.A_Z_BTMMRG else "\n\n"
return result
def _genHeadStyle(self, level: int, rFmt: QTextBlockFormat) -> T_TextStyle:
"""Generate a heading style set.""" """Generate a heading style set."""
mTop, mBottom = self._mHead.get(level, (0.0, 0.0)) mTop, mBottom = self._mHead.get(level, (0.0, 0.0))
@@ -312,5 +348,7 @@ class ToQTextDocument(Tokenizer):
cFmt.setForeground(SHARED.theme.colHead) cFmt.setForeground(SHARED.theme.colHead)
cFmt.setFontWeight(QFont.Weight.Bold) cFmt.setFontWeight(QFont.Weight.Bold)
cFmt.setFontPointSize(self._sHead.get(level, 1.0)) cFmt.setFontPointSize(self._sHead.get(level, 1.0))
cFmt.setAnchorNames([f"{self._handle}:T{nHead:04d}"])
cFmt.setAnchor(True)
return bFmt, cFmt return bFmt, cFmt
+7 -7
View File
@@ -27,7 +27,7 @@ from PyQt5.QtGui import QMouseEvent, QTextCursor
from PyQt5.QtWidgets import QAction, QApplication, QMenu from PyQt5.QtWidgets import QAction, QApplication, QMenu
from novelwriter import CONFIG, SHARED from novelwriter import CONFIG, SHARED
from novelwriter.core.tohtml import ToHtml from novelwriter.core.toqdoc import ToQTextDocument
from novelwriter.enum import nwDocAction from novelwriter.enum import nwDocAction
from novelwriter.gui.docviewer import GuiDocViewer from novelwriter.gui.docviewer import GuiDocViewer
from novelwriter.types import QtModeNone, QtMouseLeft from novelwriter.types import QtModeNone, QtMouseLeft
@@ -119,7 +119,7 @@ def testGuiViewer_Main(qtbot, monkeypatch, nwGUI, prjLipsum):
# Select All # Select All
assert docViewer.docAction(nwDocAction.SEL_ALL) is True assert docViewer.docAction(nwDocAction.SEL_ALL) is True
cursor = docViewer.textCursor() cursor = docViewer.textCursor()
assert len(cursor.selectedText()) == 3061 assert len(cursor.selectedText()) == 3060
# Other actions # Other actions
assert docViewer.docAction(nwDocAction.NO_ACTION) is False assert docViewer.docAction(nwDocAction.NO_ACTION) is False
@@ -196,19 +196,19 @@ def testGuiViewer_Main(qtbot, monkeypatch, nwGUI, prjLipsum):
# Document footer show/hide synopsis # Document footer show/hide synopsis
assert nwGUI.viewDocument("f96ec11c6a3da") is True assert nwGUI.viewDocument("f96ec11c6a3da") is True
assert len(docViewer.toPlainText()) == 4315 assert len(docViewer.toPlainText()) == 4314
docViewer.docFooter._doToggleSynopsis(False) docViewer.docFooter._doToggleSynopsis(False)
assert len(docViewer.toPlainText()) == 4099 assert len(docViewer.toPlainText()) == 4098
# Document footer show/hide comments # Document footer show/hide comments
assert nwGUI.viewDocument("846352075de7d") is True assert nwGUI.viewDocument("846352075de7d") is True
assert len(docViewer.toPlainText()) == 675 assert len(docViewer.toPlainText()) == 674
docViewer.docFooter._doToggleComments(False) docViewer.docFooter._doToggleComments(False)
assert len(docViewer.toPlainText()) == 635 assert len(docViewer.toPlainText()) == 634
# Crash the HTML rendering # Crash the HTML rendering
with monkeypatch.context() as mp: with monkeypatch.context() as mp:
mp.setattr(ToHtml, "doConvert", causeException) mp.setattr(ToQTextDocument, "doConvert", causeException)
assert docViewer.loadText("846352075de7d") is False assert docViewer.loadText("846352075de7d") is False
assert docViewer.toPlainText() == "An error occurred while generating the preview." assert docViewer.toPlainText() == "An error occurred while generating the preview."