From ca188fee082e69a957062bbe98bceab2d28a1848 Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Tue, 30 Jan 2024 21:34:36 +0100 Subject: [PATCH] Implement alternative tag display name format --- novelwriter/core/index.py | 32 +++++++++++++----------- novelwriter/core/tohtml.py | 5 +++- novelwriter/gui/doceditor.py | 7 +++--- novelwriter/gui/dochighlight.py | 34 ++++++++++++------------- novelwriter/gui/docviewer.py | 43 +++++++++++++------------------- sample/content/14298de4d9524.nwd | 6 ++--- sample/content/bb2c23b3c42cc.nwd | 6 ++--- 7 files changed, 65 insertions(+), 68 deletions(-) diff --git a/novelwriter/core/index.py b/novelwriter/core/index.py index edea8f71..67d790b1 100644 --- a/novelwriter/core/index.py +++ b/novelwriter/core/index.py @@ -420,8 +420,7 @@ class NWIndex: return if tBits[0] == nwKeyWords.TAG_KEY: - tagKey = tBits[1] - displayName = tBits[2] if len(tBits) > 2 else tagKey + tagKey, displayName = self.parseValue(tBits[1]) self._tagsIndex.add(tagKey, displayName, tHandle, sTitle, itemClass.name) self._itemIndex.setHeadingTag(tHandle, sTitle, tagKey) tags[tagKey.lower()] = True @@ -472,10 +471,8 @@ class NWIndex: return True, tBits, tPos - def checkThese(self, tBits: list[str], nwItem: NWItem) -> list[bool]: - """Check the tags against the index to see if they are valid - tags. This is needed for syntax highlighting. - """ + def checkThese(self, tBits: list[str], tHandle: str) -> list[bool]: + """Check tags against the index to see if they are valid.""" nBits = len(tBits) isGood = [False]*nBits if nBits == 0: @@ -489,19 +486,25 @@ class NWIndex: # For a tag, only the first value is accepted, the rest are ignored if tBits[0] == nwKeyWords.TAG_KEY and nBits > 1: if tBits[1] in self._tagsIndex: - isGood[1] = self._tagsIndex.tagHandle(tBits[1]) == nwItem.itemHandle + isGood[1] = self._tagsIndex.tagHandle(tBits[1]) == tHandle else: isGood[1] = True return isGood # If we're still here, we check that the references exist + # Class references cannot have the | symbol in them refKey = nwKeyWords.KEY_CLASS[tBits[0]].name for n in range(1, nBits): - if tBits[n] in self._tagsIndex: - isGood[n] = self._tagsIndex.tagClass(tBits[n]) == refKey + if (aBit := tBits[n]) in self._tagsIndex: + isGood[n] = self._tagsIndex.tagClass(aBit) == refKey and "|" not in aBit return isGood + def parseValue(self, text: str) -> tuple[str, str]: + """Parse a single value into a name and display part.""" + name, _, display = text.partition("|") + return name.rstrip(), display.lstrip() + ## # Extract Data ## @@ -725,11 +728,12 @@ class TagsIndex: """Return a dictionary view of all tags.""" return self._tags.items() - def add(self, tagKey: str, display: str, tHandle: str, sTitle: str, className: str) -> None: + def add(self, tagKey: str, displayName: str, tHandle: str, + sTitle: str, className: str) -> None: """Add a key to the index and set all values.""" self._tags[tagKey.lower()] = { "name": tagKey, - "display": display, + "display": displayName or tagKey, "handle": tHandle, "heading": sTitle, "class": className, @@ -786,9 +790,9 @@ class TagsIndex: name = entry.get("name") display = entry.get("display") - handle = entry.get("handle", "") - heading = entry.get("heading", "") - className = entry.get("class", "") + handle = entry.get("handle") + heading = entry.get("heading") + className = entry.get("class") if not isinstance(name, str): raise ValueError("tagsIndex name is not a string") diff --git a/novelwriter/core/tohtml.py b/novelwriter/core/tohtml.py index 5598ece7..51e0d04a 100644 --- a/novelwriter/core/tohtml.py +++ b/novelwriter/core/tohtml.py @@ -484,7 +484,10 @@ class ToHtml(Tokenizer): result = f"{self._localLookup(nwLabels.KEY_NAME[bits[0]])}: " if len(bits) > 1: if bits[0] == nwKeyWords.TAG_KEY: - result += f"{bits[1]}" + one, two = self._project.index.parseValue(bits[1]) + result += f"{one}" + if two: + result += f" | {two}" else: if self._genMode == self.M_PREVIEW: result += ", ".join(f"{t}" for t in bits[1:]) diff --git a/novelwriter/gui/doceditor.py b/novelwriter/gui/doceditor.py index 6baddf67..b3223aab 100644 --- a/novelwriter/gui/doceditor.py +++ b/novelwriter/gui/doceditor.py @@ -56,7 +56,6 @@ from novelwriter import CONFIG, SHARED from novelwriter.enum import nwDocAction, nwDocInsert, nwDocMode, nwItemClass, nwTrinary from novelwriter.common import minmax, transferCase from novelwriter.constants import nwKeyWords, nwLabels, nwShortcode, nwUnicode, trConst -from novelwriter.core.item import NWItem from novelwriter.core.index import countWords from novelwriter.tools.lipsum import GuiLipsum from novelwriter.core.document import NWDocument @@ -1835,16 +1834,16 @@ class GuiDocEditor(QPlainTextEdit): if len(text) == 0: return nwTrinary.NEUTRAL - if text.startswith("@") and isinstance(self._nwItem, NWItem): + if text.startswith("@") and self._docHandle: isGood, tBits, tPos = SHARED.project.index.scanThis(text) - if not isGood: + if not isGood or not tBits or tBits[0] == nwKeyWords.TAG_KEY: return nwTrinary.NEUTRAL tag = "" exist = False cPos = cursor.selectionStart() - block.position() - tExist = SHARED.project.index.checkThese(tBits, self._nwItem) + tExist = SHARED.project.index.checkThese(tBits, self._docHandle) for sTag, sPos, sExist in zip(reversed(tBits), reversed(tPos), reversed(tExist)): if cPos >= sPos: # The cursor is between the start of two tags diff --git a/novelwriter/gui/dochighlight.py b/novelwriter/gui/dochighlight.py index 01accfda..f292e2f9 100644 --- a/novelwriter/gui/dochighlight.py +++ b/novelwriter/gui/dochighlight.py @@ -279,23 +279,23 @@ class GuiDocHighlighter(QSyntaxHighlighter): if text.startswith("@"): # Keywords and commands self.setCurrentBlockState(self.BLOCK_META) - if self._tItem: - pIndex = SHARED.project.index - isValid, bits, pos = pIndex.scanThis(text) - isGood = pIndex.checkThese(bits, self._tItem) - if isValid: - for n, bit in enumerate(bits): - xPos = pos[n] - xLen = len(bit) - if isGood[n]: - if n == 0: - self.setFormat(xPos, xLen, self._hStyles["keyword"]) - else: - self.setFormat(xPos, xLen, self._hStyles["value"]) - else: - kwFmt = self.format(xPos) - kwFmt.merge(self._hStyles["codeinval"]) - self.setFormat(xPos, xLen, kwFmt) + index = SHARED.project.index + isValid, bits, pos = index.scanThis(text) + isGood = index.checkThese(bits, self._tHandle) + if isValid: + for n, bit in enumerate(bits): + xPos = pos[n] + xLen = len(bit) + if not isGood[n]: + self.setFormat(xPos, xLen, self._hStyles["codeinval"]) + elif n == 0: + self.setFormat(xPos, xLen, self._hStyles["keyword"]) + else: + one, two = index.parseValue(bit) + self.setFormat(xPos, len(one), self._hStyles["value"]) + if two: + yPos = xPos + len(bit) - len(two) + self.setFormat(yPos, len(two), self._hStyles["optional"]) # We never want to run the spell checker on keyword/values, # so we force a return here diff --git a/novelwriter/gui/docviewer.py b/novelwriter/gui/docviewer.py index 20b78ce7..b6ca8480 100644 --- a/novelwriter/gui/docviewer.py +++ b/novelwriter/gui/docviewer.py @@ -461,15 +461,16 @@ class GuiDocViewer(QTextBrowser): def _makeStyleSheet(self) -> None: """Generate an appropriate style sheet for the document viewer, - based on the current syntax highlighter theme, + based on the current syntax highlighter theme. """ colText = SHARED.theme.colText colHead = SHARED.theme.colHead - colVal = SHARED.theme.colVal + colVals = SHARED.theme.colVal colEmph = SHARED.theme.colEmph - colKey = SHARED.theme.colKey - colHidden = SHARED.theme.colHidden - colMod = SHARED.theme.colMod + colKeys = SHARED.theme.colKey + colHide = SHARED.theme.colHidden + colMods = SHARED.theme.colMod + colOpts = SHARED.theme.colOpt styleSheet = ( "body {{" " color: rgb({tColR}, {tColG}, {tColB});" @@ -486,6 +487,9 @@ class GuiDocViewer(QTextBrowser): ".tags {{" " color: rgb({kColR}, {kColG}, {kColB});" "}}\n" + ".optional {{" + " color: rgb({oColR}, {oColG}, {oColB});" + "}}\n" ".comment {{" " color: rgb({cColR}, {cColG}, {cColB});" "}}\n" @@ -496,27 +500,14 @@ class GuiDocViewer(QTextBrowser): " text-align: center;" "}}\n" ).format( - tColR=colText.red(), - tColG=colText.green(), - tColB=colText.blue(), - hColR=colHead.red(), - hColG=colHead.green(), - hColB=colHead.blue(), - aColR=colVal.red(), - aColG=colVal.green(), - aColB=colVal.blue(), - eColR=colEmph.red(), - eColG=colEmph.green(), - eColB=colEmph.blue(), - kColR=colKey.red(), - kColG=colKey.green(), - kColB=colKey.blue(), - cColR=colHidden.red(), - cColG=colHidden.green(), - cColB=colHidden.blue(), - mColR=colMod.red(), - mColG=colMod.green(), - mColB=colMod.blue(), + tColR=colText.red(), tColG=colText.green(), tColB=colText.blue(), + hColR=colHead.red(), hColG=colHead.green(), hColB=colHead.blue(), + aColR=colVals.red(), aColG=colVals.green(), aColB=colVals.blue(), + eColR=colEmph.red(), eColG=colEmph.green(), eColB=colEmph.blue(), + kColR=colKeys.red(), kColG=colKeys.green(), kColB=colKeys.blue(), + cColR=colHide.red(), cColG=colHide.green(), cColB=colHide.blue(), + mColR=colMods.red(), mColG=colMods.green(), mColB=colMods.blue(), + oColR=colOpts.red(), oColG=colOpts.green(), oColB=colOpts.blue(), ) self.document().setDefaultStyleSheet(styleSheet) diff --git a/sample/content/14298de4d9524.nwd b/sample/content/14298de4d9524.nwd index a0f7992b..b37ae5a8 100644 --- a/sample/content/14298de4d9524.nwd +++ b/sample/content/14298de4d9524.nwd @@ -1,11 +1,11 @@ %%~name: John Smith %%~path: f7e2d9f330615/14298de4d9524 %%~kind: CHARACTER/NOTE -%%~hash: 0f40182de0bb7935bb40fc4c7fd0d75d55421299 -%%~date: Unknown/2024-01-29 12:19:42 +%%~hash: f85b4da6ba4a557db0c4d5f1b59f33ba01542606 +%%~date: Unknown/2024-01-30 10:58:18 # John Smith -@tag: John, John Smith +@tag: John | John Smith % Short: The sidekick diff --git a/sample/content/bb2c23b3c42cc.nwd b/sample/content/bb2c23b3c42cc.nwd index b4abf57b..9c18a616 100644 --- a/sample/content/bb2c23b3c42cc.nwd +++ b/sample/content/bb2c23b3c42cc.nwd @@ -1,11 +1,11 @@ %%~name: Jane Smith %%~path: f7e2d9f330615/bb2c23b3c42cc %%~kind: CHARACTER/NOTE -%%~hash: 0faba71c86841552090a9e82dd9b7acd5b0bf56f -%%~date: Unknown/2024-01-29 12:31:34 +%%~hash: 10f072a4bf7389b0c178a4181e50833d39b945af +%%~date: Unknown/2024-01-30 11:05:37 # Jane Smith -@tag: Jane, Jane Smith +@tag: Jane | Jane Smith % Short: The heroine