Add line break shortcode support

This commit is contained in:
Veronica Berglyd Olsen
2024-10-24 01:07:03 +02:00
parent 560540618c
commit ff7404d01d
9 changed files with 45 additions and 15 deletions
+3 -1
View File
@@ -61,10 +61,11 @@ class nwConst:
class nwRegEx:
WORDS = r"\b[^\s\-\+\/–—\[\]:]+\b"
BREAK = r"(?i)(?<!\\)(\[br\]\n?)"
FMT_EI = r"(?<![\w\\])(_)(?![\s_])(.+?)(?<![\s\\])(\1)(?!\w)"
FMT_EB = r"(?<![\w\\])(\*{2})(?![\s\*])(.+?)(?<![\s\\])(\1)(?!\w)"
FMT_ST = r"(?<![\w\\])(~{2})(?![\s~])(.+?)(?<![\s\\])(\1)(?!\w)"
FMT_SC = r"(?i)(?<!\\)(\[[\/\!]?(?:b|i|s|u|m|sup|sub)\])"
FMT_SC = r"(?i)(?<!\\)(\[(?:b|/b|i|/i|s|/s|u|/u|m|/m|sup|/sup|sub|/sub|br)\])"
FMT_SV = r"(?i)(?<!\\)(\[(?:footnote):)(.+?)(?<!\\)(\])"
@@ -84,6 +85,7 @@ class nwShortcode:
SUP_C = "[/sup]"
SUB_O = "[sub]"
SUB_C = "[/sub]"
BREAK = "[br]"
FOOTNOTE_B = "[footnote:"
+1
View File
@@ -137,6 +137,7 @@ class nwDocInsert(Enum):
VSPACE_M = 9
LIPSUM = 10
FOOTNOTE = 11
LINE_BRK = 12
class nwView(Enum):
+4 -8
View File
@@ -56,7 +56,6 @@ class ComStyle(NamedTuple):
textClass: str = ""
B_EMPTY: T_Block = (BlockTyp.EMPTY, "", "", [], BlockFmt.NONE)
COMMENT_STYLE = {
nwComment.PLAIN: ComStyle("Comment", "comment", "comment"),
nwComment.IGNORE: ComStyle(),
@@ -67,13 +66,12 @@ COMMENT_STYLE = {
nwComment.COMMENT: ComStyle(),
nwComment.STORY: ComStyle("", "modifier", "note"),
}
# Lookups
HEADINGS = [BlockTyp.TITLE, BlockTyp.HEAD1, BlockTyp.HEAD2, BlockTyp.HEAD3, BlockTyp.HEAD4]
SKIP_INDENT = [
BlockTyp.TITLE, BlockTyp.HEAD1, BlockTyp.HEAD2, BlockTyp.HEAD2, BlockTyp.HEAD3,
BlockTyp.HEAD4, BlockTyp.SEP, BlockTyp.SKIP,
]
B_EMPTY: T_Block = (BlockTyp.EMPTY, "", "", [], BlockFmt.NONE)
class Tokenizer(ABC):
@@ -182,8 +180,6 @@ class Tokenizer(ABC):
(REGEX_PATTERNS.markdownBold, [0, TextFmt.B_B, 0, TextFmt.B_E]),
(REGEX_PATTERNS.markdownStrike, [0, TextFmt.D_B, 0, TextFmt.D_E]),
]
self._rxShortCodes = REGEX_PATTERNS.shortcodePlain
self._rxShortCodeVals = REGEX_PATTERNS.shortcodeValue
self._shortCodeFmt = {
nwShortcode.ITALIC_O: TextFmt.I_B, nwShortcode.ITALIC_C: TextFmt.I_E,
@@ -1136,12 +1132,12 @@ class Tokenizer(ABC):
# Post-process text and format
result = text
formats = []
for pos, end, fmt, key in reversed(sorted(temp, key=lambda x: x[0])):
for pos, end, fmt, meta in reversed(sorted(temp, key=lambda x: x[0])):
if fmt > 0:
if end > pos:
result = result[:pos] + result[end:]
formats = [(p+pos-end if p > pos else p, f, k) for p, f, k in formats]
formats.insert(0, (pos, fmt, key))
formats = [(p+pos-end if p > pos else p, f, m) for p, f, m in formats]
formats.insert(0, (pos, fmt, meta))
return result, formats
+2
View File
@@ -877,6 +877,8 @@ class GuiDocEditor(QPlainTextEdit):
after = False
elif insert == nwDocInsert.FOOTNOTE:
self._insertCommentStructure(nwComment.FOOTNOTE)
elif insert == nwDocInsert.LINE_BRK:
text = nwShortcode.BREAK
if text:
if block:
+8 -2
View File
@@ -570,8 +570,8 @@ class GuiMainMenu(QMenuBar):
lambda: self.requestDocInsert.emit(nwDocInsert.SHORT)
)
# Insert > Symbols
self.mInsBreaks = self.insMenu.addMenu(self.tr("Page Break and Space"))
# Insert > Breaks and Vertical Space
self.mInsBreaks = self.insMenu.addMenu(self.tr("Breaks and Vertical Space"))
# Insert > New Page
self.aInsNewPage = self.mInsBreaks.addAction(self.tr("Page Break"))
@@ -579,6 +579,12 @@ class GuiMainMenu(QMenuBar):
lambda: self.requestDocInsert.emit(nwDocInsert.NEW_PAGE)
)
# Insert > Forced Line Break
self.aInsLineBreak = self.mInsBreaks.addAction(self.tr("Forced Line Break"))
self.aInsLineBreak.triggered.connect(
lambda: self.requestDocInsert.emit(nwDocInsert.LINE_BRK)
)
# Insert > Vertical Space (Single)
self.aInsVSpaceS = self.mInsBreaks.addAction(self.tr("Vertical Space (Single)"))
self.aInsVSpaceS.triggered.connect(
+6
View File
@@ -33,6 +33,7 @@ class RegExPatterns:
# Static RegExes
_rxWords = re.compile(nwRegEx.WORDS, re.UNICODE)
_rxBreak = re.compile(nwRegEx.BREAK, re.UNICODE)
_rxItalic = re.compile(nwRegEx.FMT_EI, re.UNICODE)
_rxBold = re.compile(nwRegEx.FMT_EB, re.UNICODE)
_rxStrike = re.compile(nwRegEx.FMT_ST, re.UNICODE)
@@ -44,6 +45,11 @@ class RegExPatterns:
"""Split text into words."""
return self._rxWords
@property
def lineBreak(self) -> re.Pattern:
"""Find forced line break."""
return self._rxBreak
@property
def markdownItalic(self) -> re.Pattern:
"""Markdown italic style."""
+7 -2
View File
@@ -522,13 +522,18 @@ def testGuiMainMenu_Insert(qtbot, monkeypatch, nwGUI, fncPath, projPath, mockRnd
nwGUI.mainMenu.aInsShort.activate(QAction.ActionEvent.Trigger)
assert nwGUI.docEditor.getText() == "Stuff\n%Short: \n"
# Insert Break or Space
# =====================
# Breaks and Vertical Space
# =========================
nwGUI.docEditor.setPlainText("### Stuff\n")
nwGUI.mainMenu.aInsNewPage.activate(QAction.ActionEvent.Trigger)
assert nwGUI.docEditor.getText() == "[newpage]\n### Stuff\n"
nwGUI.docEditor.setPlainText("Line OneLine Two\n")
nwGUI.docEditor.setCursorPosition(8)
nwGUI.mainMenu.aInsLineBreak.activate(QAction.ActionEvent.Trigger)
assert nwGUI.docEditor.getText() == "Line One[br]Line Two\n"
nwGUI.docEditor.setPlainText("### Stuff\n")
nwGUI.mainMenu.aInsVSpaceS.activate(QAction.ActionEvent.Trigger)
assert nwGUI.docEditor.getText() == "[vspace]\n### Stuff\n"
+3 -2
View File
@@ -47,6 +47,7 @@ def testTextCounting_preProcessText():
"[vspace:3]\n\n"
"[New Page]\n\n"
"[footnote:abcd]\n\n"
"[br]\n\n"
"Dashes\u2013and even longer\u2014dashes.\n\n"
)
@@ -60,7 +61,7 @@ def testTextCounting_preProcessText():
"#### Heading Four",
"", "", "",
"A paragraph.", "",
"", "", "", "", "", "",
"", "", "", "", "", "", "", "",
"Dashes and even longer dashes.", ""
]
@@ -68,7 +69,7 @@ def testTextCounting_preProcessText():
assert preProcessText(text, keepHeaders=False) == [
"", "", "",
"A paragraph.", "",
"", "", "", "", "", "",
"", "", "", "", "", "", "", "",
"Dashes and even longer dashes.", ""
]
+11
View File
@@ -198,6 +198,17 @@ def testTextPatterns_ShortcodesPlain():
assert allMatches(regEx, "one [x]two[/x] three") == []
# Line Break Substitution
# =======================
regEx = REGEX_PATTERNS.lineBreak
assert regEx.sub("\n", "one[br]two") == "one\ntwo"
assert regEx.sub("\n", "one[br]\ntwo") == "one\ntwo"
assert regEx.sub("\n", "one[br]\n\ntwo") == "one\n\ntwo"
assert regEx.sub("\n", "one[BR]two") == "one\ntwo"
assert regEx.sub("\n", "one[BR]\ntwo") == "one\ntwo"
assert regEx.sub("\n", "one[BR]\n\ntwo") == "one\n\ntwo"
@pytest.mark.core
def testTextPatterns_ShortcodesValue():