Remove HTML preview mode and manuscript cache

This commit is contained in:
Veronica Berglyd Olsen
2024-05-24 20:12:13 +02:00
parent 6cc046c65c
commit e74c1057a4
4 changed files with 41 additions and 176 deletions
+5 -15
View File
@@ -55,7 +55,7 @@ class NWBuildDocument:
__slots__ = (
"_project", "_build", "_queue", "_error", "_cache", "_count",
"_outline", "_preview"
"_outline",
)
def __init__(self, project: NWProject, build: BuildSettings) -> None:
@@ -66,7 +66,6 @@ class NWBuildDocument:
self._cache = None
self._count = False
self._outline = False
self._preview = False
return
##
@@ -100,15 +99,6 @@ class NWBuildDocument:
self._outline = state
return
def setPreviewMode(self, state: bool) -> None:
"""Set the preview mode of the build. This also enables stats
count and outline mode.
"""
self._preview = state
self._outline = state
self._count = state
return
##
# Special Methods
##
@@ -140,10 +130,12 @@ class NWBuildDocument:
makeObj = ToQTextDocument(self._project)
filtered = self._setupBuild(makeObj)
self._outline = True
self._count = True
font = QFont()
font.fromString(self._build.getStr("format.textFont"))
makeObj.setLinkHeadings(self._preview)
makeObj.initDocument(font, theme)
for i, tHandle in enumerate(self._queue):
self._error = None
@@ -207,8 +199,6 @@ class NWBuildDocument:
makeObj = ToHtml(self._project)
filtered = self._setupBuild(makeObj)
makeObj.setPreview(self._preview)
makeObj.setLinkHeadings(self._preview)
for i, tHandle in enumerate(self._queue):
self._error = None
if filtered.get(tHandle, (False, 0))[0]:
@@ -218,7 +208,7 @@ class NWBuildDocument:
makeObj.appendFootnotes()
if not (self._build.getBool("html.preserveTabs") or self._preview):
if not self._build.getBool("html.preserveTabs"):
makeObj.replaceTabs()
self._error = None
+14 -55
View File
@@ -38,24 +38,6 @@ from novelwriter.types import FONT_STYLE, FONT_WEIGHTS
logger = logging.getLogger(__name__)
HTML4_TAGS = {
Tokenizer.FMT_B_B: "<b>",
Tokenizer.FMT_B_E: "</b>",
Tokenizer.FMT_I_B: "<i>",
Tokenizer.FMT_I_E: "</i>",
Tokenizer.FMT_D_B: "<span style='text-decoration: line-through;'>",
Tokenizer.FMT_D_E: "</span>",
Tokenizer.FMT_U_B: "<u>",
Tokenizer.FMT_U_E: "</u>",
Tokenizer.FMT_M_B: "<mark>",
Tokenizer.FMT_M_E: "</mark>",
Tokenizer.FMT_SUP_B: "<sup>",
Tokenizer.FMT_SUP_E: "</sup>",
Tokenizer.FMT_SUB_B: "<sub>",
Tokenizer.FMT_SUB_E: "</sub>",
Tokenizer.FMT_STRIP: "",
}
HTML5_TAGS = {
Tokenizer.FMT_B_B: "<strong>",
Tokenizer.FMT_B_E: "</strong>",
@@ -82,14 +64,9 @@ class ToHtml(Tokenizer):
also used by the Document Viewer, and Manuscript Build Preview.
"""
M_PREVIEW = 0 # Tweak output for the DocViewer
M_EXPORT = 1 # Tweak output for saving to HTML or printing
M_EBOOK = 2 # Tweak output for converting to epub
def __init__(self, project: NWProject) -> None:
super().__init__(project)
self._genMode = self.M_EXPORT
self._cssStyles = True
self._fullHTML: list[str] = []
@@ -112,11 +89,6 @@ class ToHtml(Tokenizer):
# Setters
##
def setPreview(self, state: bool) -> None:
"""Set to preview generator mode."""
self._genMode = self.M_PREVIEW if state else self.M_EXPORT
return
def setStyles(self, cssStyles: bool) -> None:
"""Enable or disable CSS styling. Some elements may still have
class tags.
@@ -157,8 +129,7 @@ class ToHtml(Tokenizer):
"""Convert the list of text tokens into an HTML document."""
self._result = ""
hTags = HTML4_TAGS if self._genMode == self.M_PREVIEW else HTML5_TAGS
if self._isNovel and self._genMode != self.M_PREVIEW:
if self._isNovel:
# For story files, we bump the titles one level up
h1Cl = " class='title'"
h1 = "h1"
@@ -240,7 +211,7 @@ class ToHtml(Tokenizer):
# Process Text Type
if tType == self.T_TEXT:
lines.append(f"<p{hStyle}>{self._formatText(tText, tFormat, hTags)}</p>\n")
lines.append(f"<p{hStyle}>{self._formatText(tText, tFormat)}</p>\n")
elif tType == self.T_TITLE:
tHead = tText.replace(nwHeadFmt.BR, "<br>")
@@ -269,13 +240,13 @@ class ToHtml(Tokenizer):
lines.append(f"<p class='skip'{hStyle}>&nbsp;</p>\n")
elif tType == self.T_SYNOPSIS and self._doSynopsis:
lines.append(self._formatSynopsis(self._formatText(tText, tFormat, hTags), True))
lines.append(self._formatSynopsis(self._formatText(tText, tFormat), True))
elif tType == self.T_SHORT and self._doSynopsis:
lines.append(self._formatSynopsis(self._formatText(tText, tFormat, hTags), False))
lines.append(self._formatSynopsis(self._formatText(tText, tFormat), False))
elif tType == self.T_COMMENT and self._doComments:
lines.append(self._formatComments(self._formatText(tText, tFormat, hTags)))
lines.append(self._formatComments(self._formatText(tText, tFormat)))
elif tType == self.T_KEYWORD and self._doKeywords:
tag, text = self._formatKeywords(tText)
@@ -291,7 +262,6 @@ class ToHtml(Tokenizer):
def appendFootnotes(self) -> None:
"""Append the footnotes in the buffer."""
if self._usedNotes:
tags = HTML4_TAGS if self._genMode == self.M_PREVIEW else HTML5_TAGS
footnotes = self._localLookup("Footnotes")
lines = []
@@ -299,7 +269,7 @@ class ToHtml(Tokenizer):
lines.append("<ol>\n")
for key, index in self._usedNotes.items():
if content := self._footnotes.get(key):
text = self._formatText(*content, tags)
text = self._formatText(*content)
lines.append(f"<li id='footnote_{index}'><p>{text}</p></li>\n")
lines.append("</ol>\n")
@@ -468,7 +438,7 @@ class ToHtml(Tokenizer):
# Internal Functions
##
def _formatText(self, text: str, tFmt: T_Formats, tags: dict[int, str]) -> str:
def _formatText(self, text: str, tFmt: T_Formats) -> str:
"""Apply formatting tags to text."""
temp = text
for pos, fmt, data in reversed(tFmt):
@@ -481,7 +451,7 @@ class ToHtml(Tokenizer):
else:
html = "<sup>ERR</sup>"
else:
html = tags.get(fmt, "ERR")
html = HTML5_TAGS.get(fmt, "ERR")
temp = f"{temp[:pos]}{html}{temp[pos:]}"
temp = temp.replace("\n", "<br>")
return stripEscape(temp)
@@ -492,18 +462,12 @@ class ToHtml(Tokenizer):
sSynop = self._localLookup("Synopsis")
else:
sSynop = self._localLookup("Short Description")
if self._genMode == self.M_PREVIEW:
return f"<p class='note'><span class='modifier'>{sSynop}:</span> {text}</p>\n"
else:
return f"<p class='synopsis'><strong>{sSynop}:</strong> {text}</p>\n"
return f"<p class='synopsis'><strong>{sSynop}:</strong> {text}</p>\n"
def _formatComments(self, text: str) -> str:
"""Apply HTML formatting to comments."""
if self._genMode == self.M_PREVIEW:
return f"<p class='comment'>{text}</p>\n"
else:
sComm = self._localLookup("Comment")
return f"<p class='comment'><strong>{sComm}:</strong> {text}</p>\n"
sComm = self._localLookup("Comment")
return f"<p class='comment'><strong>{sComm}:</strong> {text}</p>\n"
def _formatKeywords(self, text: str) -> tuple[str, str]:
"""Apply HTML formatting to keywords."""
@@ -519,13 +483,8 @@ class ToHtml(Tokenizer):
if two:
result += f" | <span class='optional'>{two}</a>"
else:
if self._genMode == self.M_PREVIEW:
result += ", ".join(
f"<a class='tag' href='#{bits[0][1:]}={t}'>{t}</a>" for t in bits[1:]
)
else:
result += ", ".join(
f"<a class='tag' href='#tag_{t}'>{t}</a>" for t in bits[1:]
)
result += ", ".join(
f"<a class='tag' href='#tag_{t}'>{t}</a>" for t in bits[1:]
)
return bits[0][1:], result
+22 -65
View File
@@ -23,10 +23,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
from __future__ import annotations
import json
import logging
from datetime import datetime
from time import time
from typing import TYPE_CHECKING
@@ -41,12 +39,11 @@ from PyQt5.QtWidgets import (
)
from novelwriter import CONFIG, SHARED
from novelwriter.common import checkInt, fuzzyTime
from novelwriter.common import fuzzyTime
from novelwriter.core.buildsettings import BuildCollection, BuildSettings
from novelwriter.core.docbuild import NWBuildDocument
from novelwriter.core.tokenizer import HeadingFormatter
from novelwriter.core.toqdoc import TextDocumentTheme, ToQTextDocument
from novelwriter.error import logException
from novelwriter.extensions.circularprogress import NProgressCircle
from novelwriter.extensions.modified import NIconToggleButton, NIconToolButton, NToolDialog
from novelwriter.gui.theme import STYLES_FLAT_TABS, STYLES_MIN_TOOLBUTTON
@@ -250,20 +247,6 @@ class GuiManuscript(NToolDialog):
if selected in self._buildMap:
self.buildList.setCurrentItem(self._buildMap[selected])
# logger.debug("Loading build cache")
# cache = CONFIG.dataPath("cache") / f"build_{SHARED.project.data.uuid}.json"
# if cache.is_file():
# try:
# with open(cache, mode="r", encoding="utf-8") as fObj:
# data = json.load(fObj)
# build = self._builds.getBuild(data.get("uuid", ""))
# if isinstance(build, BuildSettings):
# self._updatePreview(data, build)
# except Exception:
# logger.error("Failed to load build cache")
# logException()
# return
return
##
@@ -342,7 +325,6 @@ class GuiManuscript(NToolDialog):
SHARED.saveDocument()
docBuild = NWBuildDocument(SHARED.project, build)
docBuild.setPreviewMode(True)
docBuild.queueAll()
theme = TextDocumentTheme()
@@ -364,23 +346,17 @@ class GuiManuscript(NToolDialog):
buildObj = docBuild.lastBuild
assert isinstance(buildObj, ToQTextDocument)
data = {
"uuid": build.buildID,
"time": int(time()),
"stats": buildObj.textStats,
"outline": buildObj.textOutline,
}
self._updatePreview(data, build, buildObj.document)
logger.debug("Saving build cache")
cache = CONFIG.dataPath("cache") / f"build_{SHARED.project.data.uuid}.json"
try:
with open(cache, mode="w+", encoding="utf-8") as outFile:
outFile.write(json.dumps(data, indent=2))
except Exception:
logger.error("Failed to save build cache")
logException()
return
font = QFont()
font.fromString(build.getStr("format.textFont"))
self.docPreview.setTextFont(font)
self.docPreview.setContent(buildObj.document)
self.docPreview.setBuildName(build.name)
self.docPreview.setJustify(build.getBool("format.justifyText"))
self.docStats.updateStats(buildObj.textStats)
self.buildOutline.updateOutline(buildObj.textOutline)
return
@@ -409,18 +385,6 @@ class GuiManuscript(NToolDialog):
# Internal Functions
##
def _updatePreview(self, data: dict, build: BuildSettings, document: QTextDocument) -> None:
"""Update the preview widget and set relevant values."""
font = QFont()
font.fromString(build.getStr("format.textFont"))
self.docPreview.setTextFont(font)
self.docPreview.setContent(data, document)
self.docPreview.setBuildName(build.name)
self.docPreview.setJustify(build.getBool("format.justifyText"))
self.docStats.updateStats(data.get("stats", {}))
self.buildOutline.updateOutline(data.get("outline", {}))
return
def _getSelectedBuild(self) -> BuildSettings | None:
"""Get the currently selected build. If none are selected,
automatically select the first one.
@@ -854,23 +818,19 @@ class _PreviewWidget(QTextBrowser):
QApplication.processEvents()
return
def setContent(self, data: dict, doc: QTextDocument) -> None:
def setContent(self, document: QTextDocument) -> None:
"""Set the content of the preview widget."""
QApplication.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor))
self.buildProgress.setCentreText(self.tr("Processing ..."))
QApplication.processEvents()
doc.setDocumentMargin(CONFIG.getTextMargin())
self.setDocument(doc)
document.setDocumentMargin(CONFIG.getTextMargin())
self.setDocument(document)
self._docTime = checkInt(data.get("time"), 0)
self._docTime = int(time())
self._updateBuildAge()
# Since we change the content while it may still be rendering, we mark
# the document as dirty again to make sure it's re-rendered properly.
# self.document().markContentsDirty(0, self.document().characterCount())
self.buildProgress.setCentreText(self.tr("Done"))
QApplication.restoreOverrideCursor()
QApplication.processEvents()
@@ -915,17 +875,14 @@ class _PreviewWidget(QTextBrowser):
@pyqtSlot()
def _updateBuildAge(self) -> None:
"""Update the build time and the fuzzy age."""
if self._docTime > 0:
strBuildTime = "%s (%s)" % (
CONFIG.localDateTime(datetime.fromtimestamp(self._docTime)),
fuzzyTime(int(time()) - self._docTime)
)
if self._buildName and self._docTime > 0:
self.ageLabel.setText("<b>{0}</b><br>{1}: {2}".format(
self._buildName,
self.tr("Built"),
fuzzyTime(int(time()) - self._docTime),
))
else:
strBuildTime = self.tr("Unknown")
text = "{0}: {1}".format(self.tr("Built"), strBuildTime)
if self._buildName:
text = "<b>{0}</b><br>{1}".format(self._buildName, text)
self.ageLabel.setText(text)
self.ageLabel.setText("<b>{0}</b>".format(self.tr("No Preview")))
return
@pyqtSlot()
-41
View File
@@ -284,21 +284,6 @@ def testCoreToHtml_ConvertParagraphs(mockGUI):
"</ol>\n"
)
# Preview Mode
# ============
html.setPreview(True)
# Text (HTML4)
html._text = "Some **nested bold and _italic_ and ~~strikethrough~~ text** here\n"
html.tokenizeText()
html.doConvert()
assert html.result == (
"<p>Some <b>nested bold and <i>italic</i> and "
"<span style='text-decoration: line-through;'>strikethrough</span> "
"text</b> here</p>\n"
)
@pytest.mark.core
def testCoreToHtml_ConvertDirect(mockGUI):
@@ -682,29 +667,3 @@ def testCoreToHtml_Format(mockGUI):
"<a class='tag' href='#tag_Bod'>Bod</a>, "
"<a class='tag' href='#tag_Jane'>Jane</a>"
)
# Preview Mode
# ============
html.setPreview(True)
assert html._formatSynopsis("synopsis text", True) == (
"<p class='note'><span class='modifier'>Synopsis:</span> synopsis text</p>\n"
)
assert html._formatSynopsis("short text", False) == (
"<p class='note'><span class='modifier'>Short Description:</span> short text</p>\n"
)
assert html._formatComments("comment text") == (
"<p class='comment'>comment text</p>\n"
)
assert html._formatKeywords("") == ("", "")
assert html._formatKeywords("tag: Jane") == (
"tag", "<span class='keyword'>Tag:</span> <a class='tag' name='tag_Jane'>Jane</a>"
)
assert html._formatKeywords("char: Bod, Jane") == (
"char",
"<span class='keyword'>Characters:</span> "
"<a class='tag' href='#char=Bod'>Bod</a>, "
"<a class='tag' href='#char=Jane'>Jane</a>"
)