Add insert footnote feature in editor

This commit is contained in:
Veronica Berglyd Olsen
2024-04-14 23:33:35 +02:00
parent da102d3d5a
commit 70033cb0f3
6 changed files with 82 additions and 16 deletions
+9 -2
View File
@@ -25,7 +25,9 @@ from __future__ import annotations
from PyQt5.QtCore import QCoreApplication, QT_TRANSLATE_NOOP
from novelwriter.enum import nwBuildFmt, nwItemClass, nwItemLayout, nwOutline, nwStatusShape
from novelwriter.enum import (
nwBuildFmt, nwComment, nwItemClass, nwItemLayout, nwOutline, nwStatusShape
)
def trConst(text: str) -> str:
@@ -67,7 +69,7 @@ class nwRegEx:
FMT_EB = r"(?<![\w\\])([\*]{2})(?![\s\*])(.+?)(?<![\s\\])(\1)(?!\w)"
FMT_ST = r"(?<![\w\\])([~]{2})(?![\s~])(.+?)(?<![\s\\])(\1)(?!\w)"
FMT_SC = r"(?i)(?<!\\)(\[[\/\!]?(?:i|b|s|u|m|sup|sub)\])"
FMT_SV = r"(?<!\\)(\[(?i)(?:fn|footnote):)(.+?)(?<!\\)(\])"
FMT_SV = r"(?<!\\)(\[(?i)(?:footnote):)(.+?)(?<!\\)(\])"
# END Class nwRegEx
@@ -89,6 +91,11 @@ class nwShortcode:
SUB_O = "[sub]"
SUB_C = "[/sub]"
COMMENT_STYLES = {
nwComment.FOOTNOTE: "[footnote:{0}]",
nwComment.COMMENT: "[comment:{0}]",
}
# END Class nwShortcode
+10 -2
View File
@@ -514,6 +514,14 @@ class NWIndex:
name, _, display = text.partition("|")
return name.rstrip(), display.lstrip()
def newCommentKey(self, style: nwComment) -> str | None:
"""Generate a new key for a comment style."""
if style == nwComment.FOOTNOTE:
return self._textIndex.footnotes.newKey()
elif style == nwComment.COMMENT:
return self._textIndex.comments.newKey()
return None
##
# Extract Data
##
@@ -1322,8 +1330,8 @@ class TextIndex:
__slots__ = ("_comments", "_footnotes")
def __init__(self) -> None:
self._comments = TextRegistry("c_")
self._footnotes = TextRegistry("f_")
self._comments = TextRegistry("c")
self._footnotes = TextRegistry("f")
return
@property
+31 -1
View File
@@ -55,7 +55,7 @@ from novelwriter import CONFIG, SHARED
from novelwriter.common import minmax, transferCase
from novelwriter.constants import nwConst, nwKeyWords, nwShortcode, nwUnicode
from novelwriter.core.document import NWDocument
from novelwriter.enum import nwDocAction, nwDocInsert, nwDocMode, nwItemClass, nwTrinary
from novelwriter.enum import nwComment, nwDocAction, nwDocInsert, nwDocMode, nwItemClass, nwTrinary
from novelwriter.extensions.eventfilters import WheelEventFilter
from novelwriter.extensions.modified import NIconToggleButton, NIconToolButton
from novelwriter.gui.dochighlight import BLOCK_META, BLOCK_TITLE
@@ -884,6 +884,9 @@ class GuiDocEditor(QPlainTextEdit):
text = GuiLipsum.getLipsum(self)
newBlock = True
goAfter = False
elif insert == nwDocInsert.FOOTNOTE:
text = ""
self._insertCommentStructure(nwComment.FOOTNOTE)
else:
return False
else:
@@ -1850,6 +1853,33 @@ class GuiDocEditor(QPlainTextEdit):
return
def _insertCommentStructure(self, style: nwComment) -> None:
"""Insert a shortcut/comment combo."""
if style == nwComment.FOOTNOTE:
key = SHARED.project.index.newCommentKey(style)
code = nwShortcode.COMMENT_STYLES[nwComment.FOOTNOTE]
cursor = self.textCursor()
block = cursor.block()
text = block.text().rstrip()
if not text or text.startswith(("@", "#", "%")):
SHARED.error(self.tr("Footnotes can only be inserted in text."))
return
cursor.beginEditBlock()
cursor.insertText(code.format(key))
cursor.setPosition(block.position() + block.length())
cursor.insertBlock()
cursor.insertText(f"%Footnote.{key}: ")
cursor.insertBlock()
cursor.endEditBlock()
cursor.setPosition(cursor.position() - 1)
self.setTextCursor(cursor)
return
##
# Internal Functions
##
+24 -5
View File
@@ -44,6 +44,10 @@ logger = logging.getLogger(__name__)
SPELLRX = QRegularExpression(r"\b[^\s\-\+\/–—\[\]:]+\b")
SPELLRX.setPatternOptions(QRegularExpression.UseUnicodePropertiesOption)
SPELLSC = QRegularExpression(nwRegEx.FMT_SC)
SPELLSC.setPatternOptions(QRegularExpression.UseUnicodePropertiesOption)
SPELLSV = QRegularExpression(nwRegEx.FMT_SV)
SPELLSV.setPatternOptions(QRegularExpression.UseUnicodePropertiesOption)
BLOCK_NONE = 0
BLOCK_TEXT = 1
@@ -53,7 +57,10 @@ BLOCK_TITLE = 4
class GuiDocHighlighter(QSyntaxHighlighter):
__slots__ = ("_tItem", "_tHandle", "_spellCheck", "_spellErr", "_hRules", "_hStyles")
__slots__ = (
"_tHandle", "_isInactive", "_spellCheck", "_spellErr", "_hRules",
"_hStyles", "_rxRules"
)
def __init__(self, document: QTextDocument) -> None:
super().__init__(document)
@@ -67,6 +74,7 @@ class GuiDocHighlighter(QSyntaxHighlighter):
self._hRules: list[tuple[str, dict]] = []
self._hStyles: dict[str, QTextCharFormat] = {}
self._rxRules: list[tuple[QRegularExpression, dict[int, QTextCharFormat]]] = []
self.initHighlighter()
@@ -217,12 +225,12 @@ class GuiDocHighlighter(QSyntaxHighlighter):
}
))
# Build a QRegExp for each highlight pattern
self.rxRules = []
# Build a QRegularExpression for each highlight pattern
self._rxRules = []
for regEx, regRules in self._hRules:
hReg = QRegularExpression(regEx)
hReg.setPatternOptions(QRegularExpression.UseUnicodePropertiesOption)
self.rxRules.append((hReg, regRules))
self._rxRules.append((hReg, regRules))
return
@@ -367,7 +375,7 @@ class GuiDocHighlighter(QSyntaxHighlighter):
# Regular Text
self.setCurrentBlockState(BLOCK_TEXT)
for rX, xFmt in self.rxRules:
for rX, xFmt in self._rxRules:
rxItt = rX.globalMatch(text, 0)
while rxItt.hasNext():
rxMatch = rxItt.next()
@@ -448,6 +456,17 @@ class TextBlockData(QTextBlockUserData):
"""Run the spell checker and cache the result, and return the
list of spell check errors.
"""
if "[" in text:
# Strip shortcodes
for rX in [SPELLSC, SPELLSV]:
rxItt = rX.globalMatch(text, 0)
while rxItt.hasNext():
rxMatch = rxItt.next()
xPos = rxMatch.capturedStart(0)
xLen = rxMatch.capturedLength(0)
xEnd = rxMatch.capturedEnd(0)
text = text[:xPos] + " "*xLen + text[xEnd:]
self._spellErrors = []
rxSpell = SPELLRX.globalMatch(text[offset:].replace("_", " "), 0)
while rxSpell.hasNext():
+5 -3
View File
@@ -1,8 +1,8 @@
%%~name: Making a Scene
%%~path: 6a2d6d5f4f401/636b6aa9b697b
%%~kind: NOVEL/DOCUMENT
%%~hash: e1c58699b05b512306a534da70c2952aafc60e8b
%%~date: Unknown/2024-02-25 16:33:40
%%~hash: 06b80d830f3f4d5c703eff82067d4335b8b98151
%%~date: Unknown/2024-04-14 23:28:43
### Making a Scene
@pov: Jane
@@ -21,7 +21,9 @@ If you have the need for it, you can also add text that can be automatically rep
The editor also supports non breaking spaces, and the spell checker accepts long dashes—like this—as valid word separators. Regular dashes are also supported and can be automatically inserted when typing two hyphens.
Thin spaces and thin non-breaking spaces are also supported from the Insert menu, and can be used to separate numbers from their units, like: 25kg.
Thin spaces and thin non-breaking spaces are also supported from the Insert menu, and can be used to separate numbers from their units, like: 25kg.[footnote:fq2ms]
%Footnote.fq2ms: This is a footnote about non-breaking spaces.
#### Some Section Here
+3 -3
View File
@@ -1,6 +1,6 @@
<?xml version='1.0' encoding='utf-8'?>
<novelWriterXML appVersion="2.4rc1" hexVersion="0x020400c1" fileVersion="1.5" fileRevision="4" timeStamp="2024-04-11 14:19:47">
<project id="e2be99af-f9bf-4403-857a-c3d1ac25abea" saveCount="1850" autoCount="272" editTime="86438">
<novelWriterXML appVersion="2.5a1" hexVersion="0x020500a1" fileVersion="1.5" fileRevision="4" timeStamp="2024-04-14 23:31:44">
<project id="e2be99af-f9bf-4403-857a-c3d1ac25abea" saveCount="1879" autoCount="272" editTime="86979">
<name>Sample Project</name>
<author>Jane Smith</author>
</project>
@@ -58,7 +58,7 @@
<name status="sf24ce6" import="ia857f0" active="yes">Chapter One</name>
</item>
<item handle="636b6aa9b697b" parent="6a2d6d5f4f401" root="7031beac91f75" order="0" type="FILE" class="NOVEL" layout="DOCUMENT">
<meta expanded="no" heading="H3" charCount="2937" wordCount="520" paraCount="15" cursorPos="0" />
<meta expanded="no" heading="H3" charCount="2953" wordCount="520" paraCount="15" cursorPos="2049" />
<name status="s90e6c9" import="ia857f0" active="yes">Making a Scene</name>
</item>
<item handle="bc0cbd2a407f3" parent="6a2d6d5f4f401" root="7031beac91f75" order="1" type="FILE" class="NOVEL" layout="DOCUMENT">