From 5032ffdfd446187f69b89b6d794aead0c0721da9 Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Sat, 14 Jun 2025 16:44:51 +0200 Subject: [PATCH 1/8] Add current line highlight --- novelwriter/config.py | 22 +++++++++++++--------- novelwriter/gui/doceditor.py | 28 +++++++++++++++++++++++++--- 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/novelwriter/config.py b/novelwriter/config.py index 9258bcca..9f422b4d 100644 --- a/novelwriter/config.py +++ b/novelwriter/config.py @@ -77,15 +77,16 @@ class Config: "fmtSQuoteOpen", "focusWidth", "guiFont", "guiLocale", "hasEnchant", "hideFocusFooter", "hideHScroll", "hideVScroll", "highlightEmph", "hostName", "iconColDocs", "iconColTree", "iconTheme", "incNotesWCount", "isDebug", "kernelVer", "lastNotes", "lightTheme", - "mainPanePos", "mainWinSize", "memInfo", "narratorBreak", "narratorDialog", "nativeFont", - "osDarwin", "osLinux", "osType", "osUnknown", "osWindows", "outlinePanePos", - "prefsWinSize", "scrollPastEnd", "searchCase", "searchLoop", "searchMatchCap", - "searchNextFile", "searchProjCase", "searchProjRegEx", "searchProjWord", "searchRegEx", - "searchWord", "showEditToolBar", "showFullPath", "showLineEndings", "showMultiSpaces", - "showSessionTime", "showTabsNSpaces", "showViewerPanel", "spellLanguage", "stopWhenIdle", - "tabWidth", "textFont", "textMargin", "textWidth", "themeMode", "useCharCount", - "userIdleTime", "verPyQtString", "verPyQtValue", "verPyString", "verQtString", - "verQtValue", "viewComments", "viewPanePos", "viewSynopsis", "welcomeWinSize", + "lineHighlight", "mainPanePos", "mainWinSize", "memInfo", "narratorBreak", + "narratorDialog", "nativeFont", "osDarwin", "osLinux", "osType", "osUnknown", "osWindows", + "outlinePanePos", "prefsWinSize", "scrollPastEnd", "searchCase", "searchLoop", + "searchMatchCap", "searchNextFile", "searchProjCase", "searchProjRegEx", "searchProjWord", + "searchRegEx", "searchWord", "showEditToolBar", "showFullPath", "showLineEndings", + "showMultiSpaces", "showSessionTime", "showTabsNSpaces", "showViewerPanel", + "spellLanguage", "stopWhenIdle", "tabWidth", "textFont", "textMargin", "textWidth", + "themeMode", "useCharCount", "userIdleTime", "verPyQtString", "verPyQtValue", + "verPyString", "verQtString", "verQtValue", "viewComments", "viewPanePos", "viewSynopsis", + "welcomeWinSize", ) LANG_NW = 1 @@ -191,6 +192,7 @@ class Config: self.textMargin = 40 # Editor/viewer text margin self.tabWidth = 40 # Editor tabulator width self.cursorWidth = 1 # Editor cursor width + self.lineHighlight = False # Highlight current line in editor self.focusWidth = 800 # Focus Mode text width self.hideFocusFooter = False # Hide document footer in Focus Mode @@ -667,6 +669,7 @@ class Config: self.textMargin = conf.rdInt(sec, "margin", self.textMargin) self.tabWidth = conf.rdInt(sec, "tabwidth", self.tabWidth) self.cursorWidth = conf.rdInt(sec, "cursorwidth", self.cursorWidth) + self.lineHighlight = conf.rdBool(sec, "linehighlight", self.lineHighlight) self.focusWidth = conf.rdInt(sec, "focuswidth", self.focusWidth) self.hideFocusFooter = conf.rdBool(sec, "hidefocusfooter", self.hideFocusFooter) self.doJustify = conf.rdBool(sec, "justify", self.doJustify) @@ -793,6 +796,7 @@ class Config: "margin": str(self.textMargin), "tabwidth": str(self.tabWidth), "cursorwidth": str(self.cursorWidth), + "lineHighlight": str(self.lineHighlight), "focuswidth": str(self.focusWidth), "hidefocusfooter": str(self.hideFocusFooter), "justify": str(self.doJustify), diff --git a/novelwriter/gui/doceditor.py b/novelwriter/gui/doceditor.py index 846b6317..4def208e 100644 --- a/novelwriter/gui/doceditor.py +++ b/novelwriter/gui/doceditor.py @@ -45,11 +45,11 @@ from PyQt6.QtCore import ( from PyQt6.QtGui import ( QAction, QCursor, QDragEnterEvent, QDragMoveEvent, QDropEvent, QKeyEvent, QKeySequence, QMouseEvent, QPalette, QPixmap, QResizeEvent, QShortcut, - QTextBlock, QTextCursor, QTextDocument, QTextOption + QTextBlock, QTextCursor, QTextDocument, QTextFormat, QTextOption ) from PyQt6.QtWidgets import ( QApplication, QFrame, QGridLayout, QHBoxLayout, QLabel, QLineEdit, QMenu, - QPlainTextEdit, QToolBar, QVBoxLayout, QWidget + QPlainTextEdit, QTextEdit, QToolBar, QVBoxLayout, QWidget ) from novelwriter import CONFIG, SHARED @@ -75,7 +75,8 @@ from novelwriter.tools.lipsum import GuiLipsum from novelwriter.types import ( QtAlignCenterTop, QtAlignJustify, QtAlignLeft, QtAlignLeftTop, QtAlignRight, QtKeepAnchor, QtModCtrl, QtModNone, QtModShift, QtMouseLeft, - QtMoveAnchor, QtMoveLeft, QtMoveRight, QtScrollAlwaysOff, QtScrollAsNeeded + QtMoveAnchor, QtMoveLeft, QtMoveRight, QtScrollAlwaysOff, QtScrollAsNeeded, + QtTransparent ) logger = logging.getLogger(__name__) @@ -145,6 +146,7 @@ class GuiDocEditor(QPlainTextEdit): self._lastActive = 0.0 # Timestamp of last activity self._lastFind = None # Position of the last found search word self._doReplace = False # Switch to temporarily disable auto-replace + self._lineColor = QtTransparent # Auto-Replace self._autoReplace = TextAutoReplace() @@ -231,6 +233,9 @@ class GuiDocEditor(QPlainTextEdit): self.updateSyntaxColors() self.initEditor() + # Connect Additional Signal + self.cursorPositionChanged.connect(self._highlightCurrentLine) + logger.debug("Ready: GuiDocEditor") return @@ -315,6 +320,9 @@ class GuiDocEditor(QPlainTextEdit): self.docHeader.matchColors() self.docFooter.matchColors() + self._lineColor = self.palette().alternateBase().color() + self._lineColor.setAlpha(160) + return def initEditor(self) -> None: @@ -372,6 +380,8 @@ class GuiDocEditor(QPlainTextEdit): # Refresh sizes self.setTabStopDistance(CONFIG.tabWidth) self.setCursorWidth(CONFIG.cursorWidth) + self.setExtraSelections([]) + self._highlightCurrentLine() # If we have a document open, we should refresh it in case the # font changed, otherwise we just clear the editor entirely, @@ -1301,6 +1311,18 @@ class GuiDocEditor(QPlainTextEdit): CONFIG.showEditToolBar = state return + @pyqtSlot() + def _highlightCurrentLine(self) -> None: + """Highlight the cursor line if setting is enabled.""" + if CONFIG.lineHighlight: + selection = QTextEdit.ExtraSelection() + selection.format.setBackground(self._lineColor) + selection.format.setProperty(QTextFormat.Property.FullWidthSelection, True) + selection.cursor = self.textCursor() + selection.cursor.clearSelection() + self.setExtraSelections([selection]) + return + ## # Search & Replace ## From 2589c43214e4e6280933f6abb360e8df5e0e22c0 Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Sat, 14 Jun 2025 16:45:06 +0200 Subject: [PATCH 2/8] Expose line highlight setting in Preferences --- novelwriter/dialogs/preferences.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/novelwriter/dialogs/preferences.py b/novelwriter/dialogs/preferences.py index 1a8645b3..23620cef 100644 --- a/novelwriter/dialogs/preferences.py +++ b/novelwriter/dialogs/preferences.py @@ -544,6 +544,13 @@ class GuiPreferences(NDialog): unit=self.tr("px") ) + # Highlight Current Line + self.lineHighlight = NSwitch(self) + self.lineHighlight.setChecked(CONFIG.lineHighlight) + self.mainForm.addRow( + self.tr("Highlight current line"), self.lineHighlight + ) + # Show Tabs and Spaces self.showTabsNSpaces = NSwitch(self) self.showTabsNSpaces.setChecked(CONFIG.showTabsNSpaces) @@ -1032,9 +1039,14 @@ class GuiPreferences(NDialog): CONFIG.tabWidth = self.tabWidth.value() # Text Editing + lineHighlight = self.lineHighlight.isChecked() + + updateSyntax |= CONFIG.lineHighlight != lineHighlight + CONFIG.spellLanguage = self.spellLanguage.currentData() CONFIG.autoSelect = self.autoSelect.isChecked() CONFIG.cursorWidth = self.cursorWidth.value() + CONFIG.lineHighlight = lineHighlight CONFIG.showTabsNSpaces = self.showTabsNSpaces.isChecked() CONFIG.showLineEndings = self.showLineEndings.isChecked() From 7a95980d2fe1acb75d87bb7b7744d8427c8935f9 Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Sat, 14 Jun 2025 17:04:53 +0200 Subject: [PATCH 3/8] Add theme setting for current line --- novelwriter/gui/doceditor.py | 3 +-- novelwriter/gui/theme.py | 2 ++ tests/reference/baseConfig_novelwriter.conf | 3 ++- tests/test_gui/test_gui_theme.py | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/novelwriter/gui/doceditor.py b/novelwriter/gui/doceditor.py index 4def208e..b3c930ae 100644 --- a/novelwriter/gui/doceditor.py +++ b/novelwriter/gui/doceditor.py @@ -320,8 +320,7 @@ class GuiDocEditor(QPlainTextEdit): self.docHeader.matchColors() self.docFooter.matchColors() - self._lineColor = self.palette().alternateBase().color() - self._lineColor.setAlpha(160) + self._lineColor = syntax.line return diff --git a/novelwriter/gui/theme.py b/novelwriter/gui/theme.py index fbde3028..a92c6add 100644 --- a/novelwriter/gui/theme.py +++ b/novelwriter/gui/theme.py @@ -80,6 +80,7 @@ class SyntaxColors: back: QColor = QColor(255, 255, 255) text: QColor = QColor(0, 0, 0) + line: QColor = QColor(0, 0, 0) link: QColor = QColor(0, 0, 0) head: QColor = QColor(0, 0, 0) headH: QColor = QColor(0, 0, 0) @@ -364,6 +365,7 @@ class GuiTheme: if parser.has_section(sec): self.syntaxTheme.back = self._readColor(parser, sec, "background") self.syntaxTheme.text = self._readColor(parser, sec, "text") + self.syntaxTheme.line = self._readColor(parser, sec, "line") self.syntaxTheme.link = self._readColor(parser, sec, "link") self.syntaxTheme.head = self._readColor(parser, sec, "headertext") self.syntaxTheme.headH = self._readColor(parser, sec, "headertag") diff --git a/tests/reference/baseConfig_novelwriter.conf b/tests/reference/baseConfig_novelwriter.conf index fa16b190..859cca52 100644 --- a/tests/reference/baseConfig_novelwriter.conf +++ b/tests/reference/baseConfig_novelwriter.conf @@ -1,5 +1,5 @@ [Meta] -timestamp = 2025-06-10 23:18:12 +timestamp = 2025-06-14 17:03:01 [Main] font = @@ -40,6 +40,7 @@ width = 700 margin = 40 tabwidth = 40 cursorwidth = 1 +linehighlight = False focuswidth = 800 hidefocusfooter = False justify = False diff --git a/tests/test_gui/test_gui_theme.py b/tests/test_gui/test_gui_theme.py index 04e4c62b..805f5009 100644 --- a/tests/test_gui/test_gui_theme.py +++ b/tests/test_gui/test_gui_theme.py @@ -632,7 +632,7 @@ def testGuiTheme_CheckTheme(theme): "helptext", "fadedtext", "errortext", ], "Syntax": [ - "background", "text", "link", "headertext", "headertag", + "background", "text", "line", "link", "headertext", "headertag", "emphasis", "dialog", "altdialog", "hidden", "note", "shortcode", "keyword", "tag", "value", "optional", "spellcheckline", "errorline", "replacetag", "modifier", "texthighlight", From f6408e74d205f2c5571f25a167966e0771efef6b Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Sat, 14 Jun 2025 17:06:02 +0200 Subject: [PATCH 4/8] Update themes and docs --- docs/source/more/customise.rst | 3 ++- novelwriter/assets/themes/blue_streak_dark.conf | 1 + novelwriter/assets/themes/blue_streak_light.conf | 1 + novelwriter/assets/themes/cyberpunk_night.conf | 1 + novelwriter/assets/themes/default_dark.conf | 1 + novelwriter/assets/themes/default_light.conf | 1 + novelwriter/assets/themes/dracula.conf | 1 + novelwriter/assets/themes/grey_dark.conf | 1 + novelwriter/assets/themes/grey_light.conf | 1 + novelwriter/assets/themes/lcars.conf | 1 + novelwriter/assets/themes/light_owl.conf | 1 + novelwriter/assets/themes/night_owl.conf | 1 + novelwriter/assets/themes/primer_dark.conf | 1 + novelwriter/assets/themes/primer_light.conf | 1 + novelwriter/assets/themes/snazzy.conf | 1 + novelwriter/assets/themes/solarized_dark.conf | 1 + novelwriter/assets/themes/solarized_light.conf | 1 + novelwriter/assets/themes/tango_dark.conf | 1 + novelwriter/assets/themes/tango_light.conf | 1 + novelwriter/assets/themes/tomorrow.conf | 1 + novelwriter/assets/themes/tomorrow_night.conf | 1 + novelwriter/assets/themes/tomorrow_night_blue.conf | 1 + novelwriter/assets/themes/tomorrow_night_bright.conf | 1 + novelwriter/assets/themes/tomorrow_night_eighties.conf | 1 + 24 files changed, 25 insertions(+), 1 deletion(-) diff --git a/docs/source/more/customise.rst b/docs/source/more/customise.rst index ef06f156..70905def 100644 --- a/docs/source/more/customise.rst +++ b/docs/source/more/customise.rst @@ -107,6 +107,7 @@ A colour theme ``.conf`` file consists of the following settings: [Syntax] background = base text = default + line = default:32 link = blue headertext = green headertag = green:L135 @@ -175,7 +176,7 @@ There are several ways to enter colour values: .. versionadded:: 2.8 The ``[Syntax]`` section was moved into the main theme file. Previously, these settings were in - their own file. The ``[Icons]`` section was renamed to ``[Base]``. + their own file. The ``[Icons]`` section was renamed to ``[Base]``. Added the ``line`` setting. Icon Themes diff --git a/novelwriter/assets/themes/blue_streak_dark.conf b/novelwriter/assets/themes/blue_streak_dark.conf index ed0f912d..7b4133a5 100644 --- a/novelwriter/assets/themes/blue_streak_dark.conf +++ b/novelwriter/assets/themes/blue_streak_dark.conf @@ -56,6 +56,7 @@ errortext = red [Syntax] background = base text = default +line = blue:48 link = blue headertext = blue headertag = blue:D150 diff --git a/novelwriter/assets/themes/blue_streak_light.conf b/novelwriter/assets/themes/blue_streak_light.conf index 0a3673b1..215cc8e1 100644 --- a/novelwriter/assets/themes/blue_streak_light.conf +++ b/novelwriter/assets/themes/blue_streak_light.conf @@ -56,6 +56,7 @@ errortext = red [Syntax] background = base text = default +line = blue:32 link = blue headertext = blue headertag = blue:D150 diff --git a/novelwriter/assets/themes/cyberpunk_night.conf b/novelwriter/assets/themes/cyberpunk_night.conf index 70996a22..4ba750f2 100644 --- a/novelwriter/assets/themes/cyberpunk_night.conf +++ b/novelwriter/assets/themes/cyberpunk_night.conf @@ -56,6 +56,7 @@ errortext = red [Syntax] background = base text = #969696 +line = #282828 link = blue headertext = #ffffff headertag = purple diff --git a/novelwriter/assets/themes/default_dark.conf b/novelwriter/assets/themes/default_dark.conf index 3d5436d7..0c7bd643 100644 --- a/novelwriter/assets/themes/default_dark.conf +++ b/novelwriter/assets/themes/default_dark.conf @@ -57,6 +57,7 @@ errortext = red [Syntax] background = base text = default +line = default:32 link = blue headertext = green headertag = green:D150 diff --git a/novelwriter/assets/themes/default_light.conf b/novelwriter/assets/themes/default_light.conf index 1fb2533d..fb4e707a 100644 --- a/novelwriter/assets/themes/default_light.conf +++ b/novelwriter/assets/themes/default_light.conf @@ -57,6 +57,7 @@ errortext = red [Syntax] background = base text = default +line = default:32 link = blue headertext = green headertag = green:L135 diff --git a/novelwriter/assets/themes/dracula.conf b/novelwriter/assets/themes/dracula.conf index 8e0d0133..3330f04c 100644 --- a/novelwriter/assets/themes/dracula.conf +++ b/novelwriter/assets/themes/dracula.conf @@ -73,6 +73,7 @@ errortext = red [Syntax] background = base text = #f8f8f2 +line = base:L150 link = #ff79c6 headertext = purple headertag = purple:D150 diff --git a/novelwriter/assets/themes/grey_dark.conf b/novelwriter/assets/themes/grey_dark.conf index 862caaf3..570a84b9 100644 --- a/novelwriter/assets/themes/grey_dark.conf +++ b/novelwriter/assets/themes/grey_dark.conf @@ -56,6 +56,7 @@ errortext = red [Syntax] background = #363636 text = default +line = default:32 link = default headertext = default:L115 headertag = default:D125 diff --git a/novelwriter/assets/themes/grey_light.conf b/novelwriter/assets/themes/grey_light.conf index 2da58171..feccddaa 100644 --- a/novelwriter/assets/themes/grey_light.conf +++ b/novelwriter/assets/themes/grey_light.conf @@ -56,6 +56,7 @@ errortext = red [Syntax] background = base text = default +line = default:32 link = default headertext = default:D200 headertag = default:L400 diff --git a/novelwriter/assets/themes/lcars.conf b/novelwriter/assets/themes/lcars.conf index e0130c59..0d5467db 100644 --- a/novelwriter/assets/themes/lcars.conf +++ b/novelwriter/assets/themes/lcars.conf @@ -57,6 +57,7 @@ errortext = red [Syntax] background = base text = default +line = yellow:48 link = purple headertext = orange headertag = red diff --git a/novelwriter/assets/themes/light_owl.conf b/novelwriter/assets/themes/light_owl.conf index 208cb459..a50c48b2 100644 --- a/novelwriter/assets/themes/light_owl.conf +++ b/novelwriter/assets/themes/light_owl.conf @@ -76,6 +76,7 @@ errortext = red [Syntax] background = base text = default +line = default:32 link = blue headertext = blue headertag = blue:160 diff --git a/novelwriter/assets/themes/night_owl.conf b/novelwriter/assets/themes/night_owl.conf index 79f9a5a5..c5ee6dd0 100644 --- a/novelwriter/assets/themes/night_owl.conf +++ b/novelwriter/assets/themes/night_owl.conf @@ -76,6 +76,7 @@ errortext = red [Syntax] background = base text = default +line = default:48 link = blue headertext = blue headertag = blue:160 diff --git a/novelwriter/assets/themes/primer_dark.conf b/novelwriter/assets/themes/primer_dark.conf index 8c26ce67..20be9548 100644 --- a/novelwriter/assets/themes/primer_dark.conf +++ b/novelwriter/assets/themes/primer_dark.conf @@ -56,6 +56,7 @@ errortext = #f85149 [Syntax] background = base text = faded +line = default:32 link = blue headertext = default headertag = faded diff --git a/novelwriter/assets/themes/primer_light.conf b/novelwriter/assets/themes/primer_light.conf index 93e7a87b..6d1263c5 100644 --- a/novelwriter/assets/themes/primer_light.conf +++ b/novelwriter/assets/themes/primer_light.conf @@ -56,6 +56,7 @@ errortext = #cf222e [Syntax] background = base text = faded +line = default:32 link = blue headertext = default headertag = faded:128 diff --git a/novelwriter/assets/themes/snazzy.conf b/novelwriter/assets/themes/snazzy.conf index 0cec0326..09b18a77 100644 --- a/novelwriter/assets/themes/snazzy.conf +++ b/novelwriter/assets/themes/snazzy.conf @@ -69,6 +69,7 @@ errortext = red [Syntax] background = base text = default +line = default:32 link = blue headertext = green headertag = green:D125 diff --git a/novelwriter/assets/themes/solarized_dark.conf b/novelwriter/assets/themes/solarized_dark.conf index e3f146ba..8bf4e983 100644 --- a/novelwriter/assets/themes/solarized_dark.conf +++ b/novelwriter/assets/themes/solarized_dark.conf @@ -75,6 +75,7 @@ errortext = red [Syntax] background = base text = default +line = default:32 link = blue headertext = default:D125 headertag = cyan diff --git a/novelwriter/assets/themes/solarized_light.conf b/novelwriter/assets/themes/solarized_light.conf index 76c2eec2..5f01abe7 100644 --- a/novelwriter/assets/themes/solarized_light.conf +++ b/novelwriter/assets/themes/solarized_light.conf @@ -75,6 +75,7 @@ errortext = red [Syntax] background = base text = default +line = default:32 link = blue headertext = default:L125 headertag = cyan diff --git a/novelwriter/assets/themes/tango_dark.conf b/novelwriter/assets/themes/tango_dark.conf index 8bd7d23c..aacb5e5f 100644 --- a/novelwriter/assets/themes/tango_dark.conf +++ b/novelwriter/assets/themes/tango_dark.conf @@ -66,6 +66,7 @@ errortext = red [Syntax] background = base text = default +line = default:32 link = blue headertext = blue headertag = blue:160 diff --git a/novelwriter/assets/themes/tango_light.conf b/novelwriter/assets/themes/tango_light.conf index df4b0a1b..70d6f741 100644 --- a/novelwriter/assets/themes/tango_light.conf +++ b/novelwriter/assets/themes/tango_light.conf @@ -66,6 +66,7 @@ errortext = red [Syntax] background = base text = default +line = default:32 link = blue headertext = blue headertag = blue:160 diff --git a/novelwriter/assets/themes/tomorrow.conf b/novelwriter/assets/themes/tomorrow.conf index 3175e68b..e355356a 100644 --- a/novelwriter/assets/themes/tomorrow.conf +++ b/novelwriter/assets/themes/tomorrow.conf @@ -76,6 +76,7 @@ errortext = red [Syntax] background = base text = #4d4d4c +line = default:32 link = blue headertext = blue headertag = blue:L135 diff --git a/novelwriter/assets/themes/tomorrow_night.conf b/novelwriter/assets/themes/tomorrow_night.conf index 671d1a9c..41298008 100644 --- a/novelwriter/assets/themes/tomorrow_night.conf +++ b/novelwriter/assets/themes/tomorrow_night.conf @@ -76,6 +76,7 @@ errortext = red [Syntax] background = base text = default +line = default:48 link = blue headertext = blue headertag = blue:D150 diff --git a/novelwriter/assets/themes/tomorrow_night_blue.conf b/novelwriter/assets/themes/tomorrow_night_blue.conf index a9b48dcc..5f951353 100644 --- a/novelwriter/assets/themes/tomorrow_night_blue.conf +++ b/novelwriter/assets/themes/tomorrow_night_blue.conf @@ -76,6 +76,7 @@ errortext = red [Syntax] background = base text = default +line = default:32 link = blue headertext = blue headertag = blue:D150 diff --git a/novelwriter/assets/themes/tomorrow_night_bright.conf b/novelwriter/assets/themes/tomorrow_night_bright.conf index e2df7d59..9207162f 100644 --- a/novelwriter/assets/themes/tomorrow_night_bright.conf +++ b/novelwriter/assets/themes/tomorrow_night_bright.conf @@ -76,6 +76,7 @@ errortext = red [Syntax] background = base text = default +line = default:48 link = blue headertext = blue headertag = blue:D150 diff --git a/novelwriter/assets/themes/tomorrow_night_eighties.conf b/novelwriter/assets/themes/tomorrow_night_eighties.conf index 367e1968..dcd093fb 100644 --- a/novelwriter/assets/themes/tomorrow_night_eighties.conf +++ b/novelwriter/assets/themes/tomorrow_night_eighties.conf @@ -76,6 +76,7 @@ errortext = red [Syntax] background = base text = default +line = default:32 link = blue headertext = blue headertag = blue:D150 From 294772172795556affcc5e122a2c21b344b9a95f Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Sat, 14 Jun 2025 17:08:06 +0200 Subject: [PATCH 5/8] Improve test coverage --- tests/conftest.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/conftest.py b/tests/conftest.py index 4017bb9f..d8407d28 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -65,7 +65,11 @@ def resetConfigVars(): CONFIG.darkTheme = DEF_GUI_DARK CONFIG.lightTheme = DEF_GUI_LIGHT CONFIG.themeMode = nwTheme.LIGHT - CONFIG.emphLabels = True # Ensures better coverage, off by default + + # Enable a few settings to ensure better coverage + CONFIG.emphLabels = True + CONFIG.lineHighlight = True + return From d5dc66a33c6333a94fe5f2a25e36bc826b870bad Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Sat, 14 Jun 2025 17:13:35 +0200 Subject: [PATCH 6/8] Add to preferences test --- tests/test_dialogs/test_dlg_preferences.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/test_dialogs/test_dlg_preferences.py b/tests/test_dialogs/test_dlg_preferences.py index 66d6183e..da87a629 100644 --- a/tests/test_dialogs/test_dlg_preferences.py +++ b/tests/test_dialogs/test_dlg_preferences.py @@ -250,12 +250,14 @@ def testDlgPreferences_Settings(qtbot, monkeypatch, nwGUI, fncPath, tstPaths): prefs.spellLanguage.setCurrentIndex(prefs.spellLanguage.findData("de")) prefs.autoSelect.setChecked(False) prefs.cursorWidth.setValue(5) + prefs.lineHighlight.setChecked(False) prefs.showTabsNSpaces.setChecked(True) prefs.showLineEndings.setChecked(True) assert CONFIG.spellLanguage != "de" assert CONFIG.autoSelect is True assert CONFIG.cursorWidth == 1 + assert CONFIG.lineHighlight is True assert CONFIG.showTabsNSpaces is False assert CONFIG.showLineEndings is False @@ -390,6 +392,7 @@ def testDlgPreferences_Settings(qtbot, monkeypatch, nwGUI, fncPath, tstPaths): assert CONFIG.spellLanguage == "de" assert CONFIG.autoSelect is False assert CONFIG.cursorWidth == 5 + assert CONFIG.lineHighlight is False assert CONFIG.showTabsNSpaces is True assert CONFIG.showLineEndings is True From 6d04c88d83e3e640928faac489ec75cad7ac4982 Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Sat, 14 Jun 2025 17:20:34 +0200 Subject: [PATCH 7/8] Keep the ExtraSelection object around to prevent garbage collector race and segfault --- novelwriter/gui/doceditor.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/novelwriter/gui/doceditor.py b/novelwriter/gui/doceditor.py index b3c930ae..c7b1e6a2 100644 --- a/novelwriter/gui/doceditor.py +++ b/novelwriter/gui/doceditor.py @@ -147,6 +147,7 @@ class GuiDocEditor(QPlainTextEdit): self._lastFind = None # Position of the last found search word self._doReplace = False # Switch to temporarily disable auto-replace self._lineColor = QtTransparent + self._selection = QTextEdit.ExtraSelection() # Auto-Replace self._autoReplace = TextAutoReplace() @@ -321,6 +322,8 @@ class GuiDocEditor(QPlainTextEdit): self.docFooter.matchColors() self._lineColor = syntax.line + self._selection.format.setBackground(self._lineColor) + self._selection.format.setProperty(QTextFormat.Property.FullWidthSelection, True) return @@ -1314,12 +1317,9 @@ class GuiDocEditor(QPlainTextEdit): def _highlightCurrentLine(self) -> None: """Highlight the cursor line if setting is enabled.""" if CONFIG.lineHighlight: - selection = QTextEdit.ExtraSelection() - selection.format.setBackground(self._lineColor) - selection.format.setProperty(QTextFormat.Property.FullWidthSelection, True) - selection.cursor = self.textCursor() - selection.cursor.clearSelection() - self.setExtraSelections([selection]) + self._selection.cursor = self.textCursor() + self._selection.cursor.clearSelection() + self.setExtraSelections([self._selection]) return ## From cbc79d70820d4874ab5de04a57275364d8f18446 Mon Sep 17 00:00:00 2001 From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com> Date: Sat, 14 Jun 2025 17:30:30 +0200 Subject: [PATCH 8/8] Merge line highlight with existing signal handler for cursor move --- novelwriter/gui/doceditor.py | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/novelwriter/gui/doceditor.py b/novelwriter/gui/doceditor.py index c7b1e6a2..5e49d67e 100644 --- a/novelwriter/gui/doceditor.py +++ b/novelwriter/gui/doceditor.py @@ -234,9 +234,6 @@ class GuiDocEditor(QPlainTextEdit): self.updateSyntaxColors() self.initEditor() - # Connect Additional Signal - self.cursorPositionChanged.connect(self._highlightCurrentLine) - logger.debug("Ready: GuiDocEditor") return @@ -383,7 +380,7 @@ class GuiDocEditor(QPlainTextEdit): self.setTabStopDistance(CONFIG.tabWidth) self.setCursorWidth(CONFIG.cursorWidth) self.setExtraSelections([]) - self._highlightCurrentLine() + self._cursorMoved() # If we have a document open, we should refresh it in case the # font changed, otherwise we just clear the editor entirely, @@ -1122,6 +1119,10 @@ class GuiDocEditor(QPlainTextEdit): def _cursorMoved(self) -> None: """Triggered when the cursor moved in the editor.""" self.docFooter.updateLineCount(self.textCursor()) + if CONFIG.lineHighlight: + self._selection.cursor = self.textCursor() + self._selection.cursor.clearSelection() + self.setExtraSelections([self._selection]) return @pyqtSlot(int, int, str) @@ -1313,15 +1314,6 @@ class GuiDocEditor(QPlainTextEdit): CONFIG.showEditToolBar = state return - @pyqtSlot() - def _highlightCurrentLine(self) -> None: - """Highlight the cursor line if setting is enabled.""" - if CONFIG.lineHighlight: - self._selection.cursor = self.textCursor() - self._selection.cursor.clearSelection() - self.setExtraSelections([self._selection]) - return - ## # Search & Replace ##