Skip to content

Commit 80520c0

Browse files
authored
Fix format toggle issue (#1808)
2 parents 7999251 + 17cf9f0 commit 80520c0

File tree

3 files changed

+54
-32
lines changed

3 files changed

+54
-32
lines changed

novelwriter/gui/doceditor.py

+16-15
Original file line numberDiff line numberDiff line change
@@ -1470,7 +1470,7 @@ def replaceNext(self) -> None:
14701470
# Internal Functions : Text Manipulation
14711471
##
14721472

1473-
def _toggleFormat(self, fLen: int, fChar: str) -> bool:
1473+
def _toggleFormat(self, fLen: int, fChar: str) -> None:
14741474
"""Toggle the formatting of a specific type for a piece of text.
14751475
If more than one block is selected, the formatting is applied to
14761476
the first block.
@@ -1488,12 +1488,12 @@ def _toggleFormat(self, fLen: int, fChar: str) -> bool:
14881488

14891489
posS = cursor.selectionStart()
14901490
posE = cursor.selectionEnd()
1491-
if self._qDocument.characterAt(posO - 1) == fChar:
1491+
if posS == posE and self._qDocument.characterAt(posO - 1) == fChar:
14921492
logger.warning("Format repetition, cancelling action")
14931493
cursor.clearSelection()
14941494
cursor.setPosition(posO)
14951495
self.setTextCursor(cursor)
1496-
return False
1496+
return
14971497

14981498
blockS = self._qDocument.findBlock(posS)
14991499
blockE = self._qDocument.findBlock(posE)
@@ -1519,7 +1519,6 @@ def _toggleFormat(self, fLen: int, fChar: str) -> bool:
15191519
break
15201520

15211521
if fLen == min(numA, numB):
1522-
cursor.clearSelection()
15231522
cursor.beginEditBlock()
15241523
cursor.setPosition(posS)
15251524
for i in range(fLen):
@@ -1528,17 +1527,19 @@ def _toggleFormat(self, fLen: int, fChar: str) -> bool:
15281527
for i in range(fLen):
15291528
cursor.deletePreviousChar()
15301529
cursor.endEditBlock()
1531-
cursor.clearSelection()
1532-
cursor.setPosition(posO - fLen)
1533-
self.setTextCursor(cursor)
1530+
1531+
if select != _SelectAction.KEEP_SELECTION:
1532+
cursor.clearSelection()
1533+
cursor.setPosition(posO - fLen)
1534+
self.setTextCursor(cursor)
15341535

15351536
else:
15361537
self._wrapSelection(fChar*fLen, pos=posO, select=select)
15371538

1538-
return True
1539+
return
15391540

15401541
def _wrapSelection(self, before: str, after: str | None = None, pos: int | None = None,
1541-
select: _SelectAction = _SelectAction.NO_DECISION) -> bool:
1542+
select: _SelectAction = _SelectAction.NO_DECISION) -> None:
15421543
"""Wrap the selected text in whatever is in tBefore and tAfter.
15431544
If there is no selection, the autoSelect setting decides the
15441545
action. AutoSelect will select the word under the cursor before
@@ -1578,21 +1579,21 @@ def _wrapSelection(self, before: str, after: str | None = None, pos: int | None
15781579
if select == _SelectAction.MOVE_AFTER:
15791580
cursor.setPosition(posE + len(before + after))
15801581
elif select == _SelectAction.KEEP_SELECTION:
1581-
cursor.setPosition(posE + len(before), QtMoveAnchor)
1582-
cursor.setPosition(posS + len(before), QtKeepAnchor)
1582+
cursor.setPosition(posS + len(before), QtMoveAnchor)
1583+
cursor.setPosition(posE + len(before), QtKeepAnchor)
15831584
elif select == _SelectAction.KEEP_POSITION:
15841585
cursor.setPosition(posO + len(before))
15851586

15861587
self.setTextCursor(cursor)
15871588

1588-
return True
1589+
return
15891590

1590-
def _replaceQuotes(self, sQuote: str, oQuote: str, cQuote: str) -> bool:
1591+
def _replaceQuotes(self, sQuote: str, oQuote: str, cQuote: str) -> None:
15911592
"""Replace all straight quotes in the selected text."""
15921593
cursor = self.textCursor()
15931594
if not cursor.hasSelection():
15941595
SHARED.error(self.tr("Please select some text before calling replace quotes."))
1595-
return False
1596+
return
15961597

15971598
posS = cursor.selectionStart()
15981599
posE = cursor.selectionEnd()
@@ -1632,7 +1633,7 @@ def _replaceQuotes(self, sQuote: str, oQuote: str, cQuote: str) -> bool:
16321633

16331634
self._allowAutoReplace(True)
16341635

1635-
return True
1636+
return
16361637

16371638
def _processBlockFormat(
16381639
self, action: nwDocAction, text: str, toggle: bool = True

tests/test_core/test_core_tokenizer.py

+9
Original file line numberDiff line numberDiff line change
@@ -949,6 +949,15 @@ def testCoreToken_ExtractFormats(mockGUI):
949949
(10, tokens.FMT_B_B), (31, tokens.FMT_I_B), (38, tokens.FMT_B_E), (38, tokens.FMT_I_E)
950950
]
951951

952+
# So does this
953+
text, fmt = tokens._extractFormats(
954+
"Text with [b]bold and overlapping [i]italics[/b] in[/i] it."
955+
)
956+
assert text == "Text with bold and overlapping italics in it."
957+
assert fmt == [
958+
(10, tokens.FMT_B_B), (31, tokens.FMT_I_B), (38, tokens.FMT_B_E), (41, tokens.FMT_I_E)
959+
]
960+
952961
# END Test testCoreToken_ExtractFormats
953962

954963

tests/test_gui/test_gui_doceditor.py

+29-17
Original file line numberDiff line numberDiff line change
@@ -880,13 +880,13 @@ def testGuiEditor_TextManipulation(qtbot, nwGUI, projPath, ipsumText, mockRnd):
880880
# Wrap Equal
881881
nwGUI.docEditor.replaceText(text)
882882
nwGUI.docEditor.setCursorPosition(45)
883-
assert nwGUI.docEditor._wrapSelection("=") is True
883+
nwGUI.docEditor._wrapSelection("=")
884884
assert nwGUI.docEditor.getText() == text.replace("consectetur", "=consectetur=")
885885

886886
# Wrap Unequal
887887
nwGUI.docEditor.replaceText(text)
888888
nwGUI.docEditor.setCursorPosition(45)
889-
assert nwGUI.docEditor._wrapSelection("=", "*") is True
889+
nwGUI.docEditor._wrapSelection("=", "*")
890890
assert nwGUI.docEditor.getText() == text.replace("consectetur", "=consectetur*")
891891

892892
# Past Paragraph
@@ -895,7 +895,7 @@ def testGuiEditor_TextManipulation(qtbot, nwGUI, projPath, ipsumText, mockRnd):
895895
cursor.setPosition(13, QTextCursor.MoveAnchor)
896896
cursor.setPosition(1000, QTextCursor.KeepAnchor)
897897
nwGUI.docEditor.setTextCursor(cursor)
898-
assert nwGUI.docEditor._wrapSelection("=") is True
898+
nwGUI.docEditor._wrapSelection("=")
899899

900900
newText = nwGUI.docEditor.getText()
901901
newPara = list(filter(str.strip, newText.split("\n")))
@@ -910,14 +910,15 @@ def testGuiEditor_TextManipulation(qtbot, nwGUI, projPath, ipsumText, mockRnd):
910910
# Block format repetition
911911
nwGUI.docEditor.replaceText(text)
912912
nwGUI.docEditor.setCursorPosition(39)
913-
assert nwGUI.docEditor._toggleFormat(1, "=") is True
913+
nwGUI.docEditor._toggleFormat(1, "=")
914+
assert nwGUI.docEditor.getText() == text.replace("amet", "=amet=", 1)
915+
nwGUI.docEditor._toggleFormat(1, "=")
914916
assert nwGUI.docEditor.getText() == text.replace("amet", "=amet=", 1)
915-
assert nwGUI.docEditor._toggleFormat(1, "=") is False
916917

917918
# Wrap Single Equal
918919
nwGUI.docEditor.replaceText(text)
919920
nwGUI.docEditor.setCursorPosition(45)
920-
assert nwGUI.docEditor._toggleFormat(1, "=") is True
921+
nwGUI.docEditor._toggleFormat(1, "=")
921922
assert nwGUI.docEditor.getText() == text.replace("consectetur", "=consectetur=")
922923

923924
# Past Paragraph
@@ -926,7 +927,7 @@ def testGuiEditor_TextManipulation(qtbot, nwGUI, projPath, ipsumText, mockRnd):
926927
cursor.setPosition(13, QTextCursor.MoveAnchor)
927928
cursor.setPosition(1000, QTextCursor.KeepAnchor)
928929
nwGUI.docEditor.setTextCursor(cursor)
929-
assert nwGUI.docEditor._toggleFormat(1, "=") is True
930+
nwGUI.docEditor._toggleFormat(1, "=")
930931

931932
newText = nwGUI.docEditor.getText()
932933
newPara = list(filter(str.strip, newText.split("\n")))
@@ -936,30 +937,40 @@ def testGuiEditor_TextManipulation(qtbot, nwGUI, projPath, ipsumText, mockRnd):
936937
# Wrap Double Equal
937938
nwGUI.docEditor.replaceText(text)
938939
nwGUI.docEditor.setCursorPosition(45)
939-
assert nwGUI.docEditor._toggleFormat(2, "=") is True
940+
nwGUI.docEditor._toggleFormat(2, "=")
941+
assert nwGUI.docEditor.getText() == text.replace("consectetur", "==consectetur==")
942+
943+
# Toggle Double Equal with Selection
944+
nwGUI.docEditor.replaceText(text)
945+
nwGUI.docEditor.setCursorSelection(41, 11)
946+
nwGUI.docEditor._toggleFormat(2, "=")
940947
assert nwGUI.docEditor.getText() == text.replace("consectetur", "==consectetur==")
948+
assert nwGUI.docEditor.getSelectedText() == "consectetur"
949+
nwGUI.docEditor._toggleFormat(2, "=")
950+
assert nwGUI.docEditor.getText() == text
951+
assert nwGUI.docEditor.getSelectedText() == "consectetur"
941952

942953
# Toggle Double Equal
943954
nwGUI.docEditor.replaceText(text)
944955
nwGUI.docEditor.setCursorPosition(45)
945-
assert nwGUI.docEditor._toggleFormat(2, "=") is True
946-
assert nwGUI.docEditor._toggleFormat(2, "=") is True
956+
nwGUI.docEditor._toggleFormat(2, "=")
957+
nwGUI.docEditor._toggleFormat(2, "=")
947958
assert nwGUI.docEditor.getText() == text
948959

949960
# Toggle Triple+Double Equal
950961
nwGUI.docEditor.replaceText(text)
951962
nwGUI.docEditor.setCursorPosition(45)
952-
assert nwGUI.docEditor._toggleFormat(3, "=") is True
953-
assert nwGUI.docEditor._toggleFormat(2, "=") is True
963+
nwGUI.docEditor._toggleFormat(3, "=")
964+
nwGUI.docEditor._toggleFormat(2, "=")
954965
assert nwGUI.docEditor.getText() == text.replace("consectetur", "=consectetur=")
955966

956967
# Toggle Unequal
957968
repText = text.replace("consectetur", "=consectetur==")
958969
nwGUI.docEditor.replaceText(repText)
959970
nwGUI.docEditor.setCursorPosition(45)
960-
assert nwGUI.docEditor._toggleFormat(1, "=") is True
971+
nwGUI.docEditor._toggleFormat(1, "=")
961972
assert nwGUI.docEditor.getText() == text.replace("consectetur", "consectetur=")
962-
assert nwGUI.docEditor._toggleFormat(1, "=") is True
973+
nwGUI.docEditor._toggleFormat(1, "=")
963974
assert nwGUI.docEditor.getText() == repText
964975

965976
# Replace Quotes
@@ -969,15 +980,16 @@ def testGuiEditor_TextManipulation(qtbot, nwGUI, projPath, ipsumText, mockRnd):
969980
text = "### A Scene\n\n%s" % ipsumText[0].replace("consectetur", "=consectetur=")
970981
nwGUI.docEditor.replaceText(text)
971982
nwGUI.docEditor.setCursorPosition(45)
972-
assert nwGUI.docEditor._replaceQuotes("=", "<", ">") is False
983+
nwGUI.docEditor._replaceQuotes("=", "<", ">")
984+
assert nwGUI.docEditor.getText() == text
973985

974986
# First Paragraph Selected
975987
# This should not replace anything in second paragraph
976988
text = "### A Scene\n\n%s" % "\n\n".join(ipsumText[0:2]).replace("ipsum", "=ipsum=")
977989
nwGUI.docEditor.replaceText(text)
978990
nwGUI.docEditor.setCursorPosition(45)
979991
assert nwGUI.docEditor.docAction(nwDocAction.SEL_PARA)
980-
assert nwGUI.docEditor._replaceQuotes("=", "<", ">") is True
992+
nwGUI.docEditor._replaceQuotes("=", "<", ">")
981993

982994
newText = nwGUI.docEditor.getText()
983995
newPara = list(filter(str.strip, newText.split("\n")))
@@ -989,7 +1001,7 @@ def testGuiEditor_TextManipulation(qtbot, nwGUI, projPath, ipsumText, mockRnd):
9891001
nwGUI.docEditor.replaceText(text)
9901002
nwGUI.docEditor.setCursorPosition(45)
9911003
assert nwGUI.docEditor.docAction(nwDocAction.SEL_ALL)
992-
assert nwGUI.docEditor._replaceQuotes("=", "<", ">") is True
1004+
nwGUI.docEditor._replaceQuotes("=", "<", ">")
9931005
assert nwGUI.docEditor.getText() == text.replace("=Lorem=", "<Lorem>")
9941006

9951007
# Remove Line Breaks

0 commit comments

Comments
 (0)