From b05028e3c9f196beb8485342ad122c49476b225d Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Fri, 11 Nov 2022 12:50:36 +0100 Subject: [PATCH] Split up the storage of quote symbols in config --- novelwriter/config.py | 38 +++++++++---- novelwriter/dialogs/preferences.py | 16 +++--- novelwriter/gui/doceditor.py | 54 +++++++++---------- novelwriter/gui/dochighlight.py | 12 +++-- tests/reference/baseConfig_novelwriter.conf | 8 +-- .../reference/guiPreferences_novelwriter.conf | 8 +-- tests/test_base/test_base_config.py | 6 ++- tests/test_gui/test_gui_mainmenu.py | 8 +-- 8 files changed, 85 insertions(+), 65 deletions(-) diff --git a/novelwriter/config.py b/novelwriter/config.py index 53fe20fe..8c6a72e9 100644 --- a/novelwriter/config.py +++ b/novelwriter/config.py @@ -161,8 +161,10 @@ class Config: # User-Selected Symbol Settings self.fmtApostrophe = nwUnicode.U_RSQUO - self.fmtSingleQuotes = [nwUnicode.U_LSQUO, nwUnicode.U_RSQUO] - self.fmtDoubleQuotes = [nwUnicode.U_LDQUO, nwUnicode.U_RDQUO] + self.fmtSQuoteOpen = nwUnicode.U_LSQUO + self.fmtSQuoteClose = nwUnicode.U_RSQUO + self.fmtDQuoteOpen = nwUnicode.U_LDQUO + self.fmtDQuoteClose = nwUnicode.U_RDQUO self.fmtPadBefore = "" self.fmtPadAfter = "" self.fmtPadThin = False @@ -570,8 +572,10 @@ class Config: self.scrollPastEnd = theConf.rdInt(cnfSec, "scrollpastend", self.scrollPastEnd) self.autoScroll = theConf.rdBool(cnfSec, "autoscroll", self.autoScroll) self.autoScrollPos = theConf.rdInt(cnfSec, "autoscrollpos", self.autoScrollPos) - self.fmtSingleQuotes = theConf.rdStrList(cnfSec, "fmtsinglequote", self.fmtSingleQuotes) - self.fmtDoubleQuotes = theConf.rdStrList(cnfSec, "fmtdoublequote", self.fmtDoubleQuotes) + self.fmtSQuoteOpen = theConf.rdStr(cnfSec, "fmtsquoteopen", self.fmtSQuoteOpen) + self.fmtSQuoteClose = theConf.rdStr(cnfSec, "fmtsquoteclose", self.fmtSQuoteClose) + self.fmtDQuoteOpen = theConf.rdStr(cnfSec, "fmtdquoteopen", self.fmtDQuoteOpen) + self.fmtDQuoteClose = theConf.rdStr(cnfSec, "fmtdquoteclose", self.fmtDQuoteClose) self.fmtPadBefore = theConf.rdStr(cnfSec, "fmtpadbefore", self.fmtPadBefore) self.fmtPadAfter = theConf.rdStr(cnfSec, "fmtpadafter", self.fmtPadAfter) self.fmtPadThin = theConf.rdBool(cnfSec, "fmtpadthin", self.fmtPadThin) @@ -604,23 +608,35 @@ class Config: self.searchMatchCap = theConf.rdBool(cnfSec, "searchmatchcap", self.searchMatchCap) # Deprecated Settings or Locations as of 2.0 - # These will be loaded for a few minor releases until the users have converted them + # ToDo: These will be loaded for a few minor releases until the users have converted them self.guiFont = theConf.rdStr("Main", "guifont", self.guiFont) self.guiFontSize = theConf.rdInt("Main", "guifontsize", self.guiFontSize) - self.guiLocale = theConf.rdStr("Main", "guilang", self.guiLocale) + self.guiLocale = theConf.rdStr("Main", "guilang", self.guiLocale) self._backupPath = theConf.rdPath("Backup", "backuppath", self._backupPath) self.backupOnClose = theConf.rdBool("Backup", "backuponclose", self.backupOnClose) self.askBeforeBackup = theConf.rdBool("Backup", "askbeforebackup", self.askBeforeBackup) + fmtSingleQuotes = theConf.rdStrList(cnfSec, "fmtsinglequote", []) + fmtDoubleQuotes = theConf.rdStrList(cnfSec, "fmtdoublequote", []) + + if isinstance(fmtSingleQuotes, list) and len(fmtSingleQuotes) == 2: + self.fmtSQuoteOpen = fmtSingleQuotes[0] + self.fmtSQuoteClose = fmtSingleQuotes[1] + if isinstance(fmtDoubleQuotes, list) and len(fmtDoubleQuotes) == 2: + self.fmtDQuoteOpen = fmtDoubleQuotes[0] + self.fmtDQuoteClose = fmtDoubleQuotes[1] + + # Check Values + # ============ # Check Certain Values for None self.spellLanguage = self._checkNone(self.spellLanguage) # If we're using straight quotes, disable auto-replace - if self.fmtSingleQuotes == ["'", "'"] and self.doReplaceSQuote: + if self.fmtSQuoteOpen == self.fmtSQuoteClose == "'" and self.doReplaceSQuote: logger.info("Using straight single quotes, so disabling auto-replace") self.doReplaceSQuote = False - if self.fmtDoubleQuotes == ['"', '"'] and self.doReplaceDQuote: + if self.fmtDQuoteOpen == self.fmtDQuoteClose == '"' and self.doReplaceDQuote: logger.info("Using straight double quotes, so disabling auto-replace") self.doReplaceDQuote = False @@ -685,8 +701,10 @@ class Config: "scrollpastend": str(self.scrollPastEnd), "autoscroll": str(self.autoScroll), "autoscrollpos": str(self.autoScrollPos), - "fmtsinglequote": self._packList(self.fmtSingleQuotes), - "fmtdoublequote": self._packList(self.fmtDoubleQuotes), + "fmtsquoteopen": str(self.fmtSQuoteOpen), + "fmtsquoteclose": str(self.fmtSQuoteClose), + "fmtdquoteopen": str(self.fmtDQuoteOpen), + "fmtdquoteclose": str(self.fmtDQuoteClose), "fmtpadbefore": str(self.fmtPadBefore), "fmtpadafter": str(self.fmtPadAfter), "fmtpadthin": str(self.fmtPadThin), diff --git a/novelwriter/dialogs/preferences.py b/novelwriter/dialogs/preferences.py index 568ee265..7804c0a6 100644 --- a/novelwriter/dialogs/preferences.py +++ b/novelwriter/dialogs/preferences.py @@ -1104,7 +1104,7 @@ class GuiPreferencesQuotes(QWidget): self.quoteSym["SO"].setReadOnly(True) self.quoteSym["SO"].setFixedWidth(qWidth) self.quoteSym["SO"].setAlignment(Qt.AlignCenter) - self.quoteSym["SO"].setText(self.mainConf.fmtSingleQuotes[0]) + self.quoteSym["SO"].setText(self.mainConf.fmtSQuoteOpen) self.btnSingleStyleO = QPushButton("...") self.btnSingleStyleO.setMaximumWidth(bWidth) self.btnSingleStyleO.clicked.connect(lambda: self._getQuote("SO")) @@ -1120,7 +1120,7 @@ class GuiPreferencesQuotes(QWidget): self.quoteSym["SC"].setReadOnly(True) self.quoteSym["SC"].setFixedWidth(qWidth) self.quoteSym["SC"].setAlignment(Qt.AlignCenter) - self.quoteSym["SC"].setText(self.mainConf.fmtSingleQuotes[1]) + self.quoteSym["SC"].setText(self.mainConf.fmtSQuoteClose) self.btnSingleStyleC = QPushButton("...") self.btnSingleStyleC.setMaximumWidth(bWidth) self.btnSingleStyleC.clicked.connect(lambda: self._getQuote("SC")) @@ -1137,7 +1137,7 @@ class GuiPreferencesQuotes(QWidget): self.quoteSym["DO"].setReadOnly(True) self.quoteSym["DO"].setFixedWidth(qWidth) self.quoteSym["DO"].setAlignment(Qt.AlignCenter) - self.quoteSym["DO"].setText(self.mainConf.fmtDoubleQuotes[0]) + self.quoteSym["DO"].setText(self.mainConf.fmtDQuoteOpen) self.btnDoubleStyleO = QPushButton("...") self.btnDoubleStyleO.setMaximumWidth(bWidth) self.btnDoubleStyleO.clicked.connect(lambda: self._getQuote("DO")) @@ -1153,7 +1153,7 @@ class GuiPreferencesQuotes(QWidget): self.quoteSym["DC"].setReadOnly(True) self.quoteSym["DC"].setFixedWidth(qWidth) self.quoteSym["DC"].setAlignment(Qt.AlignCenter) - self.quoteSym["DC"].setText(self.mainConf.fmtDoubleQuotes[1]) + self.quoteSym["DC"].setText(self.mainConf.fmtDQuoteClose) self.btnDoubleStyleC = QPushButton("...") self.btnDoubleStyleC.setMaximumWidth(bWidth) self.btnDoubleStyleC.clicked.connect(lambda: self._getQuote("DC")) @@ -1170,10 +1170,10 @@ class GuiPreferencesQuotes(QWidget): """Save the values set for this tab. """ # Quotation Style - self.mainConf.fmtSingleQuotes[0] = self.quoteSym["SO"].text() - self.mainConf.fmtSingleQuotes[1] = self.quoteSym["SC"].text() - self.mainConf.fmtDoubleQuotes[0] = self.quoteSym["DO"].text() - self.mainConf.fmtDoubleQuotes[1] = self.quoteSym["DC"].text() + self.mainConf.fmtSQuoteOpen = self.quoteSym["SO"].text() + self.mainConf.fmtSQuoteClose = self.quoteSym["SC"].text() + self.mainConf.fmtDQuoteOpen = self.quoteSym["DO"].text() + self.mainConf.fmtDQuoteClose = self.quoteSym["DC"].text() return ## diff --git a/novelwriter/gui/doceditor.py b/novelwriter/gui/doceditor.py index 39c5edb3..4c79ff55 100644 --- a/novelwriter/gui/doceditor.py +++ b/novelwriter/gui/doceditor.py @@ -106,10 +106,6 @@ class GuiDocEditor(QTextEdit): self._queuePos = None # Used for delayed change of cursor position # Typography - self._typDQOpen = '"' - self._typDQClose = '"' - self._typSQOpen = "'" - self._typSQClose = "'" self._typPadChar = " " # Core Elements and Signals @@ -242,9 +238,12 @@ class GuiDocEditor(QTextEdit): created, and when the user changes the main editor preferences. """ # Some Constants - self._nonWord = "\"'" - self._nonWord += "".join(self.mainConf.fmtDoubleQuotes) - self._nonWord += "".join(self.mainConf.fmtSingleQuotes) + self._nonWord = ( + "\"'" + f"{self.mainConf.fmtSQuoteOpen}{self.mainConf.fmtSQuoteClose}" + f"{self.mainConf.fmtDQuoteOpen}{self.mainConf.fmtDQuoteClose}" + ) + print(self._nonWord) # Typography if self.mainConf.fmtPadThin: @@ -252,11 +251,6 @@ class GuiDocEditor(QTextEdit): else: self._typPadChar = nwUnicode.U_NBSP - self._typDQOpen = self.mainConf.fmtDoubleQuotes[0] - self._typDQClose = self.mainConf.fmtDoubleQuotes[1] - self._typSQOpen = self.mainConf.fmtSingleQuotes[0] - self._typSQClose = self.mainConf.fmtSingleQuotes[1] - # Reload spell check and dictionaries self.setDictionaries() @@ -792,9 +786,9 @@ class GuiDocEditor(QTextEdit): elif theAction == nwDocAction.STRIKE: self._toggleFormat(2, "~") elif theAction == nwDocAction.S_QUOTE: - self._wrapSelection(self._typSQOpen, self._typSQClose) + self._wrapSelection(self.mainConf.fmtSQuoteOpen, self.mainConf.fmtSQuoteClose) elif theAction == nwDocAction.D_QUOTE: - self._wrapSelection(self._typDQOpen, self._typDQClose) + self._wrapSelection(self.mainConf.fmtDQuoteOpen, self.mainConf.fmtDQuoteClose) elif theAction == nwDocAction.SEL_ALL: self._makeSelection(QTextCursor.Document) elif theAction == nwDocAction.SEL_PARA: @@ -816,9 +810,9 @@ class GuiDocEditor(QTextEdit): elif theAction == nwDocAction.BLOCK_UNN: self._formatBlock(nwDocAction.BLOCK_UNN) elif theAction == nwDocAction.REPL_SNG: - self._replaceQuotes("'", self._typSQOpen, self._typSQClose) + self._replaceQuotes("'", self.mainConf.fmtSQuoteOpen, self.mainConf.fmtSQuoteClose) elif theAction == nwDocAction.REPL_DBL: - self._replaceQuotes("\"", self._typDQOpen, self._typDQClose) + self._replaceQuotes("\"", self.mainConf.fmtDQuoteOpen, self.mainConf.fmtDQuoteClose) elif theAction == nwDocAction.RM_BREAKS: self._removeInParLineBreaks() elif theAction == nwDocAction.ALIGN_L: @@ -884,13 +878,13 @@ class GuiDocEditor(QTextEdit): theText = theInsert elif isinstance(theInsert, nwDocInsert): if theInsert == nwDocInsert.QUOTE_LS: - theText = self._typSQOpen + theText = self.mainConf.fmtSQuoteOpen elif theInsert == nwDocInsert.QUOTE_RS: - theText = self._typSQClose + theText = self.mainConf.fmtSQuoteClose elif theInsert == nwDocInsert.QUOTE_LD: - theText = self._typDQOpen + theText = self.mainConf.fmtDQuoteOpen elif theInsert == nwDocInsert.QUOTE_RD: - theText = self._typDQClose + theText = self.mainConf.fmtDQuoteClose elif theInsert == nwDocInsert.SYNOPSIS: theText = "% Synopsis: " newBlock = True @@ -1967,33 +1961,33 @@ class GuiDocEditor(QTextEdit): if self.mainConf.doReplaceDQuote and theTwo[:1].isspace() and theTwo.endswith('"'): nDelete = 1 - tInsert = self._typDQOpen + tInsert = self.mainConf.fmtDQuoteOpen elif self.mainConf.doReplaceDQuote and theOne == '"': nDelete = 1 if thePos == 1: - tInsert = self._typDQOpen + tInsert = self.mainConf.fmtDQuoteOpen elif thePos == 2 and theTwo == '>"': - tInsert = self._typDQOpen + tInsert = self.mainConf.fmtDQuoteOpen elif thePos == 3 and theThree == '>>"': - tInsert = self._typDQOpen + tInsert = self.mainConf.fmtDQuoteOpen else: - tInsert = self._typDQClose + tInsert = self.mainConf.fmtDQuoteClose elif self.mainConf.doReplaceSQuote and theTwo[:1].isspace() and theTwo.endswith("'"): nDelete = 1 - tInsert = self._typSQOpen + tInsert = self.mainConf.fmtSQuoteOpen elif self.mainConf.doReplaceSQuote and theOne == "'": nDelete = 1 if thePos == 1: - tInsert = self._typSQOpen + tInsert = self.mainConf.fmtSQuoteOpen elif thePos == 2 and theTwo == ">'": - tInsert = self._typSQOpen + tInsert = self.mainConf.fmtSQuoteOpen elif thePos == 3 and theThree == ">>'": - tInsert = self._typSQOpen + tInsert = self.mainConf.fmtSQuoteOpen else: - tInsert = self._typSQClose + tInsert = self.mainConf.fmtSQuoteClose elif self.mainConf.doReplaceDash and theThree == "---": nDelete = 3 diff --git a/novelwriter/gui/dochighlight.py b/novelwriter/gui/dochighlight.py index 91aa0416..baea34bb 100644 --- a/novelwriter/gui/dochighlight.py +++ b/novelwriter/gui/dochighlight.py @@ -151,11 +151,13 @@ class GuiDocHighlighter(QSyntaxHighlighter): # Quoted Strings if self.mainConf.highlightQuotes: - fmtDbl = self.mainConf.fmtDoubleQuotes - fmtSng = self.mainConf.fmtSingleQuotes + fmtDblO = self.mainConf.fmtDQuoteOpen + fmtDblC = self.mainConf.fmtDQuoteClose + fmtSngO = self.mainConf.fmtSQuoteOpen + fmtSngC = self.mainConf.fmtSQuoteClose # Straight Quotes - if fmtDbl != ["\"", "\""]: + if not (fmtDblO == fmtDblC == "\""): self.hRules.append(( "(\\B\")(.*?)(\"\\B)", { 0: self.hStyles["dialogue1"], @@ -165,7 +167,7 @@ class GuiDocHighlighter(QSyntaxHighlighter): # Double Quotes dblEnd = "|$" if self.mainConf.allowOpenDQuote else "" self.hRules.append(( - f"(\\B{fmtDbl[0]})(.*?)({fmtDbl[1]}\\B{dblEnd})", { + f"(\\B{fmtDblO})(.*?)({fmtDblC}\\B{dblEnd})", { 0: self.hStyles["dialogue2"], } )) @@ -173,7 +175,7 @@ class GuiDocHighlighter(QSyntaxHighlighter): # Single Quotes sngEnd = "|$" if self.mainConf.allowOpenSQuote else "" self.hRules.append(( - f"(\\B{fmtSng[0]})(.*?)({fmtSng[1]}\\B{sngEnd})", { + f"(\\B{fmtSngO})(.*?)({fmtSngC}\\B{sngEnd})", { 0: self.hStyles["dialogue3"], } )) diff --git a/tests/reference/baseConfig_novelwriter.conf b/tests/reference/baseConfig_novelwriter.conf index ed621ba2..185fbd50 100644 --- a/tests/reference/baseConfig_novelwriter.conf +++ b/tests/reference/baseConfig_novelwriter.conf @@ -1,5 +1,5 @@ [Meta] -timestamp = 2022-11-10 11:10:10 +timestamp = 2022-11-11 12:48:18 [Main] theme = default @@ -46,8 +46,10 @@ repdots = True scrollpastend = 25 autoscroll = False autoscrollpos = 30 -fmtsinglequote = ‘, ’ -fmtdoublequote = “, ” +fmtsquoteopen = ‘ +fmtsquoteclose = ’ +fmtdquoteopen = “ +fmtdquoteclose = ” fmtpadbefore = fmtpadafter = fmtpadthin = False diff --git a/tests/reference/guiPreferences_novelwriter.conf b/tests/reference/guiPreferences_novelwriter.conf index 47c5579d..672f6f7b 100644 --- a/tests/reference/guiPreferences_novelwriter.conf +++ b/tests/reference/guiPreferences_novelwriter.conf @@ -1,5 +1,5 @@ [Meta] -timestamp = 2022-11-10 11:10:13 +timestamp = 2022-11-11 12:48:20 [Main] theme = default @@ -46,8 +46,10 @@ repdots = True scrollpastend = 0 autoscroll = True autoscrollpos = 30 -fmtsinglequote = ‘, ’ -fmtdoublequote = “, ” +fmtsquoteopen = ‘ +fmtsquoteclose = ’ +fmtdquoteopen = “ +fmtdquoteclose = ” fmtpadbefore = fmtpadafter = fmtpadthin = False diff --git a/tests/test_base/test_base_config.py b/tests/test_base/test_base_config.py index 0159952b..8282e558 100644 --- a/tests/test_base/test_base_config.py +++ b/tests/test_base/test_base_config.py @@ -141,8 +141,10 @@ def testBaseConfig_InitLoadSave(monkeypatch, fncPath, tstPaths): assert newConf.guiSyntax == "bar" # Test Correcting Quote Settings - tstConf.fmtDoubleQuotes = ["\"", "\""] - tstConf.fmtSingleQuotes = ["'", "'"] + tstConf.fmtDQuoteOpen = "\"" + tstConf.fmtDQuoteClose = "\"" + tstConf.fmtSQuoteOpen = "'" + tstConf.fmtSQuoteClose = "'" tstConf.doReplaceDQuote = True tstConf.doReplaceSQuote = True assert tstConf.saveConfig() is True diff --git a/tests/test_gui/test_gui_mainmenu.py b/tests/test_gui/test_gui_mainmenu.py index 57696584..157b9d46 100644 --- a/tests/test_gui/test_gui_mainmenu.py +++ b/tests/test_gui/test_gui_mainmenu.py @@ -461,19 +461,19 @@ def testGuiMenu_Insert(qtbot, monkeypatch, nwGUI, fncPath, projPath, mockRnd): nwGUI.docEditor.clear() nwGUI.mainMenu.aInsQuoteLS.activate(QAction.Trigger) - assert nwGUI.docEditor.getText() == nwGUI.mainConf.fmtSingleQuotes[0] + assert nwGUI.docEditor.getText() == nwGUI.mainConf.fmtSQuoteOpen nwGUI.docEditor.clear() nwGUI.mainMenu.aInsQuoteRS.activate(QAction.Trigger) - assert nwGUI.docEditor.getText() == nwGUI.mainConf.fmtSingleQuotes[1] + assert nwGUI.docEditor.getText() == nwGUI.mainConf.fmtSQuoteClose nwGUI.docEditor.clear() nwGUI.mainMenu.aInsQuoteLD.activate(QAction.Trigger) - assert nwGUI.docEditor.getText() == nwGUI.mainConf.fmtDoubleQuotes[0] + assert nwGUI.docEditor.getText() == nwGUI.mainConf.fmtDQuoteOpen nwGUI.docEditor.clear() nwGUI.mainMenu.aInsQuoteRD.activate(QAction.Trigger) - assert nwGUI.docEditor.getText() == nwGUI.mainConf.fmtDoubleQuotes[1] + assert nwGUI.docEditor.getText() == nwGUI.mainConf.fmtDQuoteClose nwGUI.docEditor.clear() nwGUI.mainMenu.aInsMSApos.activate(QAction.Trigger)