From bc2692028004132392b2bb871f931d73084aeb96 Mon Sep 17 00:00:00 2001 From: Mark Mancewicz Date: Mon, 27 Oct 2025 09:23:33 -0700 Subject: [PATCH 01/13] Refactor / simplify __init__ method Add new methods: - connectSignals - createActions - setIcons - startFileSystemMonitor --- preditor/gui/loggerwindow.py | 156 +++++++++++++++++++---------------- 1 file changed, 85 insertions(+), 71 deletions(-) diff --git a/preditor/gui/loggerwindow.py b/preditor/gui/loggerwindow.py index d3608a6c..7f6cb612 100644 --- a/preditor/gui/loggerwindow.py +++ b/preditor/gui/loggerwindow.py @@ -98,9 +98,6 @@ def __init__(self, parent, name=None, run_workbox=False, standalone=False): self.uiConsoleTXT.flash_window = self self.uiConsoleTXT.clearExecutionTime = self.clearExecutionTime self.uiConsoleTXT.reportExecutionTime = self.reportExecutionTime - self.uiClearToLastPromptACT.triggered.connect( - self.uiConsoleTXT.clearToLastPrompt - ) # If we don't disable this shortcut Qt won't respond to this classes or # the ConsolePrEdit's self.uiConsoleTXT.uiClearToLastPromptACT.setShortcut('') @@ -126,6 +123,7 @@ def __init__(self, parent, name=None, run_workbox=False, standalone=False): self.uiLoggingLevelBTN, ) self.uiConsoleTOOLBAR.insertSeparator(self.uiRunSelectedACT) + self.uiConsoleTOOLBAR.show() # Configure Find in Workboxes self.uiFindInWorkboxesWGT.hide() @@ -137,6 +135,47 @@ def __init__(self, parent, name=None, run_workbox=False, standalone=False): self._stds = None self.uiLogToFileClearACT.setVisible(False) + # Call other setup methods + self.connectSignals() + self.createActions() + self.setIcons() + self.startFileSystemMonitor() + + self.maxRecentClosedWorkboxes = 20 + self.max_num_backups = 50 + self.dont_ask_again = [] + + # Load any plugins, and set window title + self.loadPlugins() + self.setWindowTitle(self.defineWindowTitle()) + + self.restorePrefs() + + self.setWorkboxFontBasedOnConsole() + self.setEditorChooserFontBasedOnConsole() + + self.setup_run_workbox() + + if not standalone: + # This action only is valid when running in standalone mode + self.uiRestartACT.setVisible(False) + + # Run the current workbox after the LoggerWindow is shown. + if run_workbox: + # By using two singleShot timers, we can show and draw the LoggerWindow, + # then call execAll. This makes it easier to see what code you are running + # before it has finished running completely. + # QTimer.singleShot(0, lambda: QTimer.singleShot(0, self.execAll)) + QTimer.singleShot( + 0, lambda: QTimer.singleShot(0, lambda: self.run_workbox(run_workbox)) + ) + + def connectSignals(self): + """Connect various signals""" + self.uiClearToLastPromptACT.triggered.connect( + self.uiConsoleTXT.clearToLastPrompt + ) + self.uiRestartACT.triggered.connect(self.restartLogger) self.uiCloseLoggerACT.triggered.connect(self.closeLoggerByAction) @@ -189,28 +228,6 @@ def __init__(self, parent, name=None, run_workbox=False, standalone=False): partial(self.adjustFontSize, "Gui", 1) ) - # Setup ability to cycle completer mode, and create action for each mode - self.completerModeCycle = itertools.cycle(CompleterMode) - # create CompleterMode submenu - defaultMode = next(self.completerModeCycle) - for mode in CompleterMode: - modeName = mode.displayName() - action = self.uiCompleterModeMENU.addAction(modeName) - action.setObjectName('ui{}ModeACT'.format(modeName)) - action.setData(mode) - action.setCheckable(True) - action.setChecked(mode == defaultMode) - completerMode = CompleterMode(mode) - action.setToolTip(completerMode.toolTip()) - action.triggered.connect(partial(self.selectCompleterMode, action)) - - self.uiCompleterModeMENU.addSeparator() - action = self.uiCompleterModeMENU.addAction('Cycle mode') - action.setObjectName('uiCycleModeACT') - action.setShortcut(QKeySequence(Qt.Modifier.CTRL | Qt.Key.Key_M)) - action.triggered.connect(self.cycleCompleterMode) - self.uiCompleterModeMENU.hovered.connect(handleMenuHovered) - # Workbox add/remove self.uiNewWorkboxACT.triggered.connect( lambda: self.uiWorkboxTAB.add_new_tab(group=True) @@ -294,6 +311,20 @@ def __init__(self, parent, name=None, run_workbox=False, standalone=False): for menu in menus: menu.hovered.connect(handleMenuHovered) + # Scroll thru workbox versions + self.uiShowFirstWorkboxVersionACT.triggered.connect( + partial(self.change_to_workbox_version_text, prefs.VersionTypes.First) + ) + self.uiShowPreviousWorkboxVersionACT.triggered.connect( + partial(self.change_to_workbox_version_text, prefs.VersionTypes.Previous) + ) + self.uiShowNextWorkboxVersionACT.triggered.connect( + partial(self.change_to_workbox_version_text, prefs.VersionTypes.Next) + ) + self.uiShowLastWorkboxVersionACT.triggered.connect( + partial(self.change_to_workbox_version_text, prefs.VersionTypes.Last) + ) + # Preferences window self.uiClosePreferencesBTN.clicked.connect(self.update_workbox_stack) self.uiClosePreferencesBTN.clicked.connect(self.update_window_settings) @@ -301,6 +332,7 @@ def __init__(self, parent, name=None, run_workbox=False, standalone=False): # Preferences self.uiExtraTooltipInfoCHK.toggled.connect(self.updateTabColorsAndToolTips) + def setIcons(self): """Set various icons""" self.uiClearLogACT.setIcon(QIcon(resourcePath('img/close-thick.png'))) self.uiNewWorkboxACT.setIcon(QIcon(resourcePath('img/file-plus.png'))) @@ -312,21 +344,32 @@ def __init__(self, parent, name=None, run_workbox=False, standalone=False): self.uiRestartACT.setIcon(QIcon(resourcePath('img/restart.svg'))) self.uiCloseLoggerACT.setIcon(QIcon(resourcePath('img/close-thick.png'))) - # Make action shortcuts available anywhere in the Logger + def createActions(self): + """Create the necessary actions""" self.addAction(self.uiClearLogACT) - self.dont_ask_again = [] - - # Load any plugins, and set window title - self.loadPlugins() - self.setWindowTitle(self.defineWindowTitle()) - - # Start the filesystem monitor - self.openFileMonitor = QFileSystemWatcher(self) - self.openFileMonitor.fileChanged.connect(self.linkedFileChanged) - self.setFileMonitoringEnabled(self.prefsPath(), True) + # Setup ability to cycle completer mode, and create action for each mode + self.completerModeCycle = itertools.cycle(CompleterMode) + # create CompleterMode submenu + defaultMode = next(self.completerModeCycle) + for mode in CompleterMode: + modeName = mode.displayName() + action = self.uiCompleterModeMENU.addAction(modeName) + action.setObjectName('ui{}ModeACT'.format(modeName)) + action.setData(mode) + action.setCheckable(True) + action.setChecked(mode == defaultMode) + completerMode = CompleterMode(mode) + action.setToolTip(completerMode.toolTip()) + action.triggered.connect(partial(self.selectCompleterMode, action)) - self.restorePrefs() + # Completer mode actions + self.uiCompleterModeMENU.addSeparator() + action = self.uiCompleterModeMENU.addAction('Cycle mode') + action.setObjectName('uiCycleModeACT') + action.setShortcut(QKeySequence(Qt.Modifier.CTRL | Qt.Key.Key_M)) + action.triggered.connect(self.cycleCompleterMode) + self.uiCompleterModeMENU.hovered.connect(handleMenuHovered) # add stylesheet menu options. for style_name in stylesheets.stylesheets(): @@ -336,40 +379,11 @@ def __init__(self, parent, name=None, run_workbox=False, standalone=False): action.setChecked(self._stylesheet == style_name) action.triggered.connect(partial(self.setStyleSheet, style_name)) - self.uiConsoleTOOLBAR.show() - - self.setWorkboxFontBasedOnConsole() - self.setEditorChooserFontBasedOnConsole() - - # Scroll thru workbox versions - self.uiShowFirstWorkboxVersionACT.triggered.connect( - partial(self.change_to_workbox_version_text, prefs.VersionTypes.First) - ) - self.uiShowPreviousWorkboxVersionACT.triggered.connect( - partial(self.change_to_workbox_version_text, prefs.VersionTypes.Previous) - ) - self.uiShowNextWorkboxVersionACT.triggered.connect( - partial(self.change_to_workbox_version_text, prefs.VersionTypes.Next) - ) - self.uiShowLastWorkboxVersionACT.triggered.connect( - partial(self.change_to_workbox_version_text, prefs.VersionTypes.Last) - ) - - self.setup_run_workbox() - - if not standalone: - # This action only is valid when running in standalone mode - self.uiRestartACT.setVisible(False) - - # Run the current workbox after the LoggerWindow is shown. - if run_workbox: - # By using two singleShot timers, we can show and draw the LoggerWindow, - # then call execAll. This makes it easier to see what code you are running - # before it has finished running completely. - # QTimer.singleShot(0, lambda: QTimer.singleShot(0, self.execAll)) - QTimer.singleShot( - 0, lambda: QTimer.singleShot(0, lambda: self.run_workbox(run_workbox)) - ) + def startFileSystemMonitor(self): + """Start the file system monitor, and add this PrEditor's prefs path""" + self.openFileMonitor = QFileSystemWatcher(self) + self.openFileMonitor.fileChanged.connect(self.linkedFileChanged) + self.setFileMonitoringEnabled(self.prefsPath(), True) @Slot() def apply_options(self): From 8247dbcfa33a686726522785d496fd842a785f42 Mon Sep 17 00:00:00 2001 From: Mark Mancewicz Date: Fri, 7 Nov 2025 16:40:02 -0800 Subject: [PATCH 02/13] Update default SublimeText path --- preditor/gui/loggerwindow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/preditor/gui/loggerwindow.py b/preditor/gui/loggerwindow.py index 7f6cb612..217f1740 100644 --- a/preditor/gui/loggerwindow.py +++ b/preditor/gui/loggerwindow.py @@ -1619,7 +1619,7 @@ def restorePrefs(self, skip_geom=False): self.uiFindInWorkboxesWGT.uiFindTXT.setText(pref.get('find_files_text', '')) # External text editor filepath and command template - defaultExePath = r"C:\Program Files\Sublime Text 3\sublime_text.exe" + defaultExePath = r"C:\Program Files\Sublime Text\sublime_text.exe" defaultCmd = r'"{exePath}" "{modulePath}":{lineNum}' self.textEditorPath = pref.get('textEditorPath', defaultExePath) self.textEditorCmdTempl = pref.get('textEditorCmdTempl', defaultCmd) From 5ef11103db3f92d4493b2501d3237960848b8700 Mon Sep 17 00:00:00 2001 From: Mark Mancewicz Date: Wed, 12 Nov 2025 06:57:36 -0800 Subject: [PATCH 03/13] Make console code-highlighting optional Code highlighting is the slowest aspect of outputting text to the console. If long output is expected, considering disabling code highlighting. --- preditor/gui/codehighlighter.py | 13 ++++++++- preditor/gui/loggerwindow.py | 15 ++++++++++ preditor/gui/ui/loggerwindow.ui | 52 +++++++++++++++++++++++++++------ 3 files changed, 70 insertions(+), 10 deletions(-) diff --git a/preditor/gui/codehighlighter.py b/preditor/gui/codehighlighter.py index 2da069b3..3764fba4 100644 --- a/preditor/gui/codehighlighter.py +++ b/preditor/gui/codehighlighter.py @@ -28,6 +28,8 @@ def initHighlightVariables(self): # comment, do not highlight it). self.spans = [] + self._enabled = True + # Language specific lists self._comments = [] self._keywords = [] @@ -52,6 +54,12 @@ def initHighlightVariables(self): self._resultColor = QColor(125, 128, 128) self._stringColor = QColor(255, 128, 0) + def enabled(self): + return self._enabled + + def setEnabled(self, state): + self._enabled = state + def setLanguage(self, lang): """Sets the language of the highlighter by loading the json definition""" filename = resourcePath('lang/%s.json' % lang.lower()) @@ -91,6 +99,9 @@ def highlightBlock(self, text): """Highlights the inputed text block based on the rules of this code highlighter""" + if not self.enabled(): + return + # Reset the highlight spans for this text block self.spans = [] @@ -131,7 +142,7 @@ def highlightText(self, text, expr, format): Args: text (str): text to highlight - expr (QRegularExpression): search parameter + expr (re.compile): search parameter format (QTextCharFormat): formatting rule """ if expr is None or not text: diff --git a/preditor/gui/loggerwindow.py b/preditor/gui/loggerwindow.py index 217f1740..89ddb0d1 100644 --- a/preditor/gui/loggerwindow.py +++ b/preditor/gui/loggerwindow.py @@ -332,6 +332,11 @@ def connectSignals(self): # Preferences self.uiExtraTooltipInfoCHK.toggled.connect(self.updateTabColorsAndToolTips) + # Code Highlighting + self.uiConsoleHighlightEnabledCHK.toggled.connect( + self.setConsoleHighlightEnabled + ) + def setIcons(self): """Set various icons""" self.uiClearLogACT.setIcon(QIcon(resourcePath('img/close-thick.png'))) @@ -971,6 +976,9 @@ def browsePreferences(self): def console(self): return self.uiConsoleTXT + def setConsoleHighlightEnabled(self, state): + self.console().codeHighlighter().setEnabled(state) + def clearLog(self): self.uiConsoleTXT.clear() @@ -1370,6 +1378,9 @@ def recordPrefs(self, manual=False, disableFileMonitoring=False): 'closedWorkboxData': self.getClosedWorkboxData(), 'confirmBeforeClose': self.uiConfirmBeforeCloseCHK.isChecked(), 'displayExtraTooltipInfo': self.uiExtraTooltipInfoCHK.isChecked(), + 'consoleHighlightEnabled': ( + self.uiConsoleHighlightEnabledCHK.isChecked() + ), } ) @@ -1645,6 +1656,10 @@ def restorePrefs(self, skip_geom=False): self.uiWorkboxAutoCompleteEnabledCHK.setChecked(workboxHintingEnabled) self.setAutoCompleteEnabled(workboxHintingEnabled, console=False) + self.uiConsoleHighlightEnabledCHK.setChecked( + pref.get('consoleHighlightEnabled', True) + ) + # Max backups and recently closed workboxes max_recent_workboxes = pref.get('max_recent_workboxes', 25) self.uiMaxNumRecentWorkboxesSPIN.setValue(max_recent_workboxes) diff --git a/preditor/gui/ui/loggerwindow.ui b/preditor/gui/ui/loggerwindow.ui index 5b8fb53e..e4d1ba59 100644 --- a/preditor/gui/ui/loggerwindow.ui +++ b/preditor/gui/ui/loggerwindow.ui @@ -7,7 +7,7 @@ 0 0 899 - 684 + 646 @@ -39,7 +39,7 @@ QFrame::NoFrame - 0 + 2 @@ -66,7 +66,7 @@ 0 0 879 - 379 + 369 @@ -155,7 +155,7 @@ 0 0 879 - 379 + 345 @@ -345,6 +345,37 @@ + + + + Clear + + + + 0 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + Clear console before running workbox code + + + + + + @@ -428,11 +459,11 @@ - + - Clear + Code Highlighting - + 0 @@ -449,9 +480,12 @@ 3 - + - Clear console before running workbox code + Code highlighting in console + + + true From 89850567c011d8a964195336ee537cd14bc13217 Mon Sep 17 00:00:00 2001 From: Mark Mancewicz Date: Tue, 18 Nov 2025 18:27:49 -0800 Subject: [PATCH 04/13] Add spacers to Preferences page --- preditor/gui/ui/loggerwindow.ui | 1155 ++++++++++++++++--------------- 1 file changed, 607 insertions(+), 548 deletions(-) diff --git a/preditor/gui/ui/loggerwindow.ui b/preditor/gui/ui/loggerwindow.ui index e4d1ba59..00f3ac49 100644 --- a/preditor/gui/ui/loggerwindow.ui +++ b/preditor/gui/ui/loggerwindow.ui @@ -7,7 +7,7 @@ 0 0 899 - 646 + 766 @@ -65,8 +65,8 @@ 0 0 - 879 - 369 + 156 + 29 @@ -146,6 +146,9 @@ + + + true @@ -155,40 +158,37 @@ 0 0 879 - 345 + 420 - + + + + 0 + 0 + + - - Preferences - - - - 3 - - - 3 - - - 3 - - - 3 - - - 3 - + - + + + + 0 + 0 + + - + + Preferences + + 3 @@ -199,274 +199,26 @@ 3 - 3 + 30 - 3 + 30 - - - - - - - - 3 - - - 3 - - - 3 - - - 3 - - - 3 - - - - - General - - - - 0 - - - 3 - - - 3 - - - 3 - - - 3 - - - - - Auto-prompt - - - - - - - Confirm before closing with Ctrl+Q action - - - true - - - - - - - Console Word Wrap - - - - - - - Convert tabs to spaces on copy - - - - - - - Indent using tabs - - - - - - - Spell check - - - - - - - Vertical editor - - - - - - - - - - Files - - - - 0 - - - 3 - - - 3 - - - 3 - - - 3 - - - - - Auto save on close - - - - - - - If a linked file has been deleted or modified, ask how to handle. - - - Prompt for linked file modification / deletion - - - true - - - - - - - - - - Clear - - - - 0 - - - 3 - - - 3 - - - 3 - - - 3 - - - - - Clear console before running workbox code - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - 3 - - - 3 - - - 3 - - - 3 - - - 3 - + - - - Auto-Completion + + + - + - 0 - - 3 - - 3 - - - 3 - - - 3 - - - - - Auto-Complete in console - - - - - - - Auto-Complete in workbox - - - - - - - Highligh exact completion - - - - - - - - - - Code Highlighting - - - - 0 - 3 @@ -480,155 +232,11 @@ 3 - - - Code highlighting in console - - - true - - - - - - - - - - Tracebacks - - - - 0 - - - 3 - - - 3 - - - 3 - - - 3 - - - - - Error hyperlinks - - - - - - - Visually separate internal PrEditor traceback - - - - - - - - - - Internal Debug - - - - 0 - - - 3 - - - 3 - - - 3 - - - 3 - - - - - Display extra workbox info in tooltips - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - - - - 3 - - - 3 - - - 3 - - - 3 - - - 3 - - - - - Numeric Settings - - - - 3 - - - 3 - - - 3 - - - 3 - - - 3 - - - - - Set the maximun number of backup files on disk per workbox. -Must be at least 1 - + - + 3 @@ -636,74 +244,187 @@ Must be at least 1 3 - 0 + 3 3 - 0 + 3 - - - Qt::Horizontal + + + General - - - 40 - 20 - - - + + + 0 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + Auto-prompt + + + + + + + Confirm before closing with Ctrl+Q action + + + true + + + + + + + Console Word Wrap + + + + + + + Convert tabs to spaces on copy + + + + + + + Indent using tabs + + + + + + + Spell check + + + + + + + Vertical editor + + + + + - - - Set the maximun number of backup files on disk per workbox. -Must be at least 1 - - - Max recently closed workboxes + + + Files + + + 0 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + Auto save on close + + + + + + + If a linked file has been deleted or modified, ask how to handle. + + + Prompt for linked file modification / deletion + + + true + + + + - - - - 0 - 0 - - - - Set the maximun number of backup files on disk per workbox. -Must be at least 1 + + + Clear - - 1 - - - 999 + + + 0 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + Clear console before running workbox code + + + + + + + + + + Qt::Vertical - - 25 + + + 20 + 0 + - + - - - Set the maximun number of backup files on disk per workbox. -Must be at least 1 - + - + 3 @@ -711,66 +432,184 @@ Must be at least 1 3 - 0 + 3 3 - 0 + 3 - - - Qt::Horizontal - - - - 40 - 20 - + + + Auto-Completion - + + + 0 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + Auto-Complete in console + + + + + + + Auto-Complete in workbox + + + + + + + Highligh exact completion + + + + + - - - Set the maximun number of backup files on disk per workbox. -Must be at least 1 + + + Code Highlighting - - Max number of Backups + + + 0 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + Code highlighting in console + + + true + + + + + + + + + + Tracebacks + + + 0 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + Error hyperlinks + + + + + + + Visually separate internal PrEditor traceback + + + + - - - Set the maximun number of backup files on disk per workbox. -Must be at least 1 + + + Internal Debug - - 1 + + + 0 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + Display extra workbox info in tooltips + + + + + + + + + + Qt::Vertical - - 999 + + + 20 + 0 + - + - - - 'If running code in the logger takes X seconds or longer, - the window will flash if it is not in focus. - Setting the value to zero will disable flashing.' - + - + 3 @@ -778,67 +617,268 @@ Must be at least 1 3 - 0 + 3 3 - 0 + 3 - - - Qt::Horizontal + + + Numeric Settings - - - 40 - 20 - - - - - - - - 'If running code in the logger takes X seconds or longer, + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + Set the maximun number of backup files on disk per workbox. +Must be at least 1 + + + + + + + 3 + + + 3 + + + 0 + + + 3 + + + 0 + + + + + Qt::Horizontal + + + + 0 + 20 + + + + + + + + Set the maximun number of backup files on disk per workbox. +Must be at least 1 + + + Max recently closed workboxes + + + + + + + + 0 + 0 + + + + Set the maximun number of backup files on disk per workbox. +Must be at least 1 + + + 1 + + + 999 + + + 25 + + + + + + + + + + Set the maximun number of backup files on disk per workbox. +Must be at least 1 + + + + + + + 3 + + + 3 + + + 0 + + + 3 + + + 0 + + + + + Qt::Horizontal + + + + 0 + 20 + + + + + + + + Set the maximun number of backup files on disk per workbox. +Must be at least 1 + + + Max number of Backups + + + + + + + Set the maximun number of backup files on disk per workbox. +Must be at least 1 + + + 1 + + + 999 + + + + + + + + + + 'If running code in the logger takes X seconds or longer, the window will flash if it is not in focus. Setting the value to zero will disable flashing.' - - - Flash Interval - + + + + + + + 3 + + + 3 + + + 0 + + + 3 + + + 0 + + + + + Qt::Horizontal + + + + 0 + 20 + + + + + + + + 'If running code in the logger takes X seconds or longer, + the window will flash if it is not in focus. + Setting the value to zero will disable flashing.' + + + Flash Interval + + + + + + + 'If running code in the logger takes X seconds or longer, + the window will flash if it is not in focus. + Setting the value to zero will disable flashing.' + + + + + + + - - - 'If running code in the logger takes X seconds or longer, - the window will flash if it is not in focus. - Setting the value to zero will disable flashing.' + + + Qt::Vertical - + + + 20 + 0 + + + - - - - Qt::Vertical - - - - 20 - 40 - - - - + + + + QDialogButtonBox::Close + + + @@ -846,15 +886,34 @@ Must be at least 1 - - - QDialogButtonBox::Close + + + Qt::Horizontal - + + + 57 + 20 + + + + + + + Qt::Vertical + + + + 20 + 0 + + + + From f05132d9aa61abd34cd9329b83e350889566b4cc Mon Sep 17 00:00:00 2001 From: Mark Mancewicz Date: Fri, 5 Sep 2025 15:39:37 -0700 Subject: [PATCH 05/13] When clearing or reporting execution time, stop the timer --- preditor/gui/loggerwindow.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/preditor/gui/loggerwindow.py b/preditor/gui/loggerwindow.py index 89ddb0d1..b00e943d 100644 --- a/preditor/gui/loggerwindow.py +++ b/preditor/gui/loggerwindow.py @@ -1312,11 +1312,13 @@ def clearExecutionTime(self): """Update status text with hyphens to indicate execution has begun.""" self.setStatusText('Exec: -.- Seconds') QApplication.instance().processEvents() + self.statusTimer.stop() def reportExecutionTime(self, seconds): """Update status text with seconds passed in.""" self.uiStatusLBL.showSeconds(seconds) self.uiMenuBar.adjustSize() + self.statusTimer.stop() def recordPrefs(self, manual=False, disableFileMonitoring=False): if not manual and not self.autoSaveEnabled(): From edbd0b3cb8d9ee8fd6d46932925af117bac6b6c2 Mon Sep 17 00:00:00 2001 From: Mark Mancewicz Date: Wed, 10 Sep 2025 10:02:19 -0700 Subject: [PATCH 06/13] Dedent after calling unix_end_lines so linked files (possibly windows eol) dedent --- preditor/gui/workbox_mixin.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/preditor/gui/workbox_mixin.py b/preditor/gui/workbox_mixin.py index ff6e1a8d..b239afae 100644 --- a/preditor/gui/workbox_mixin.py +++ b/preditor/gui/workbox_mixin.py @@ -245,12 +245,12 @@ def __exec_all__(self): def __exec_selected__(self, truncate=True): txt, lineNum = self.__selected_text__() - # Remove any leading white space shared across all lines - txt = textwrap.dedent(txt) - # Get rid of pesky \r's txt = self.__unix_end_lines__(txt) + # Remove any leading white space shared across all lines + txt = textwrap.dedent(txt) + # Make workbox line numbers match the workbox line numbers, by adding # the appropriate number of newlines to mimic it's original position in # the workbox. From ef1b3025850b2964be4c89ef01b33d1afb69624d Mon Sep 17 00:00:00 2001 From: Mike Hendricks Date: Tue, 21 Oct 2025 17:05:32 -0700 Subject: [PATCH 07/13] Include the filename when parsing json files Ask the user if they want to reset prefs if unable to parse preditor_pref.json. --- preditor/gui/codehighlighter.py | 5 +- preditor/gui/loggerwindow.py | 34 +++++++++-- preditor/logging_config.py | 6 +- preditor/prefs.py | 7 +-- preditor/utils/__init__.py | 99 +++++++++++++++++++++++++++++++++ 5 files changed, 136 insertions(+), 15 deletions(-) diff --git a/preditor/gui/codehighlighter.py b/preditor/gui/codehighlighter.py index 3764fba4..6c99fdaa 100644 --- a/preditor/gui/codehighlighter.py +++ b/preditor/gui/codehighlighter.py @@ -1,13 +1,12 @@ from __future__ import absolute_import -import json import keyword import os import re from Qt.QtGui import QColor, QSyntaxHighlighter, QTextCharFormat -from .. import resourcePath +from .. import resourcePath, utils class CodeHighlighter(QSyntaxHighlighter): @@ -64,7 +63,7 @@ def setLanguage(self, lang): """Sets the language of the highlighter by loading the json definition""" filename = resourcePath('lang/%s.json' % lang.lower()) if os.path.exists(filename): - data = json.load(open(filename)) + data = utils.Json(filename).load() self.setObjectName(data.get('name', '')) self._comments = data.get('comments', []) diff --git a/preditor/gui/loggerwindow.py b/preditor/gui/loggerwindow.py index b00e943d..c65bd4f7 100644 --- a/preditor/gui/loggerwindow.py +++ b/preditor/gui/loggerwindow.py @@ -48,7 +48,7 @@ from ..gui.fuzzy_search.fuzzy_search import FuzzySearch from ..gui.group_tab_widget.grouped_tab_models import GroupTabListItemModel from ..logging_config import LoggingConfig -from ..utils import stylesheets +from ..utils import Json, stylesheets from .completer import CompleterMode from .level_buttons import LoggingLevelButton from .set_text_editor_path_dialog import SetTextEditorPathDialog @@ -1450,9 +1450,35 @@ def load_prefs(self): prefs_dict = {} self.auto_backup_prefs(filename, onlyFirst=True) - if os.path.exists(filename): - with open(filename) as fp: - prefs_dict = json.load(fp) + filename = Path(filename) + if filename.exists(): + try: + prefs_dict = Json(filename).load() + except ValueError as error: + # If there is a problem with the preferences ask the user if they + # want to reset them. Depending on the problem the loaded workbox's + # have likely already losing the tab information, but this does + # allow the user to try to debug the file instead of just resetting + # preferences. The .py files likely still exist but won't have names. + msg = ( # noqa: E702, E231 + "The following error happened while restoring PrEditor prefs:", + f'

{error}

', + "This can be resolved by resetting the prefs. Do you want " + "to do it?", + ) + box = QMessageBox() + box.setIcon(QMessageBox.Icon.Question) + box.setWindowTitle("Reset Corrupted Preferences?") + box.setTextFormat(Qt.TextFormat.RichText) + box.setText("
".join(msg)) + box.addButton(QMessageBox.StandardButton.Yes) + box.addButton(QMessageBox.StandardButton.No) + if box.exec() == QMessageBox.StandardButton.Yes: + prefs_dict = {} + with filename.open("w") as fp: + json.dump(prefs_dict, fp, indent=4, sort_keys=True) + else: + raise return prefs_dict diff --git a/preditor/logging_config.py b/preditor/logging_config.py index d6239b4f..76e3cbb2 100644 --- a/preditor/logging_config.py +++ b/preditor/logging_config.py @@ -5,6 +5,7 @@ import logging.config import os +from . import utils from .prefs import prefs_path @@ -45,9 +46,8 @@ def load(self): if not os.path.exists(self.filename): return False - with open(self.filename) as fle: - self.cfg = json.load(fle) - logging.config.dictConfig(self.cfg) + self.cfg = utils.Json(self.filename).load() + logging.config.dictConfig(self.cfg) return True def save(self): diff --git a/preditor/prefs.py b/preditor/prefs.py index c4843932..16f4ff68 100644 --- a/preditor/prefs.py +++ b/preditor/prefs.py @@ -14,7 +14,7 @@ import six -from . import resourcePath +from . import resourcePath, utils # cache of all the preferences _cache = {} @@ -297,11 +297,8 @@ def get_prefs_updates(): """ updates = {} path = resourcePath(r"pref_updates\pref_updates.json") - with open(path, 'r') as f: - updates = json.load(f) try: - with open(path, 'r') as f: - updates = json.load(f) + updates = utils.Json(path).load() except (FileNotFoundError, json.decoder.JSONDecodeError): pass return updates diff --git a/preditor/utils/__init__.py b/preditor/utils/__init__.py index e69de29b..545dcfc5 100644 --- a/preditor/utils/__init__.py +++ b/preditor/utils/__init__.py @@ -0,0 +1,99 @@ +import errno +import json +import os +import sys +from pathlib import Path + + +class Json: + """Load a json file with a better tracebacks if something goes wrong. + + Args: + filename (pathlib.Path): The path to the file being loaded/parsed. Unless + `json_str` is also provided load will use `json.load` to parse the + contents of this json file. + json_str (str, optional): If provided then uses `json.loads` to parse + this value. `filename` must be provided and will be included in any + exceptions that are raised parsing this text. + """ + + def __init__(self, filename, json_str=None): + if isinstance(filename, str): + filename = Path(filename) + self.filename = filename + self.json_str = json_str + + @classmethod + def _load_json(cls, source, load_funct, *args, **kwargs): + """Work function that parses json and ensures any errors report the source. + + Args: + source (os.PathLike or str): The source of the json data. This is + reported in any raised exceptions. + load_funct (callable): A function called to parse the json data. + Normally this is `json.load` or `json.loads`. + *args: Arguments passed to `load_funct`. + *kwargs: Keyword arguments passed to `load_funct`. + + Raises: + FileNotFoundError: If filename is not pointing to a file that + actually exists. + ValueError: The error raised due to invalid json. + """ + try: + return load_funct(*args, **kwargs) + except ValueError as e: + # Using python's native json parser + msg = f'{e} Source("{source}")' + raise type(e)(msg, e.doc, e.pos).with_traceback(sys.exc_info()[2]) from None + + def load(self): + """Parse and return self.json_str if defined otherwise self.filename.""" + if self.json_str: + return self.loads_json(self.json_str, self.filename) + return self.load_json_file(self.filename) + + @classmethod + def load_json_file(cls, filename): + """Open and parse a json file. If a parsing error happens the file path + is added to the exception to allow for easier debugging. + + Args: + filename (pathlib.Path): A existing file path. + + Returns: + The data stored in the json file. + + Raises: + FileNotFoundError: If filename is not pointing to a file that + actually exists. + ValueError: The error raised due to invalid json. + """ + if not filename.is_file(): + raise FileNotFoundError( + errno.ENOENT, os.strerror(errno.ENOENT), str(filename) + ) + + with filename.open() as fle: + data = cls._load_json(filename, json.load, fle) + return data + + @classmethod + def loads_json(cls, json_str, source): + """Open and parse a json string. If a parsing error happens the source + file path is added to the exception to allow for easier debugging. + + Args: + json_str (str): The json data to parse. + source (pathlib.Path): The location json_str was pulled from. + This is reported if any parsing errors happen. + + Returns: + The data stored in the json file. + + Raises: + FileNotFoundError: If filename is not pointing to a file that + actually exists. + ValueError: The error raised due to invalid json. + """ + return cls._load_json(source, json.loads, json_str) From 32649d547d32a31a24f1fb24306a08316cf51a67 Mon Sep 17 00:00:00 2001 From: Mark Mancewicz Date: Tue, 11 Nov 2025 19:30:55 -0800 Subject: [PATCH 08/13] Move About/Preferences to Preferences page --- preditor/gui/loggerwindow.py | 20 +++++- preditor/gui/ui/loggerwindow.ui | 123 ++++++++++++++++++++++++++++---- 2 files changed, 126 insertions(+), 17 deletions(-) diff --git a/preditor/gui/loggerwindow.py b/preditor/gui/loggerwindow.py index c65bd4f7..6d97020e 100644 --- a/preditor/gui/loggerwindow.py +++ b/preditor/gui/loggerwindow.py @@ -149,6 +149,8 @@ def __init__(self, parent, name=None, run_workbox=False, standalone=False): self.loadPlugins() self.setWindowTitle(self.defineWindowTitle()) + self.handleChangedUiElements() + self.restorePrefs() self.setWorkboxFontBasedOnConsole() @@ -297,10 +299,12 @@ def connectSignals(self): self.uiClearBeforeRunningCHK.toggled.connect(self.setClearBeforeRunning) self.uiEditorVerticalCHK.toggled.connect(self.adjustWorkboxOrientation) self.uiEnvironmentVarsACT.triggered.connect(self.showEnvironmentVars) - self.uiBackupPreferencesACT.triggered.connect(self.backupPreferences) - self.uiBrowsePreferencesACT.triggered.connect(self.browsePreferences) self.uiAboutPreditorACT.triggered.connect(self.show_about) + # Prefs on disk + self.uiPrefsBrowseBTN.clicked.connect(self.browsePreferences) + self.uiPrefsBackupBTN.clicked.connect(self.backupPreferences) + self.uiSetPreferredTextEditorPathACT.triggered.connect( self.openSetPreferredTextEditorDialog ) @@ -450,6 +454,18 @@ def loadPlugins(self): if name not in self.plugins: self.plugins[name] = plugin(self) + def handleChangedUiElements(self): + """To prevent errors if user has newer PrEditor, but older plugins, + we keep the ui elements until the ui and plugins have been loaded. Now + we can check if now deprecated can safely be deleted. + """ + + # Preferences are moved to a tab page, so this menu should be removed. + # But it may be used by some plugins, so only remove it if the plugins + # have also been updated. + if self.uiPreferencesMENU.isEmpty(): + self.uiPreferencesMENU.deleteLater() + def defineWindowTitle(self): """Define the window title, including and info plugins may add.""" diff --git a/preditor/gui/ui/loggerwindow.ui b/preditor/gui/ui/loggerwindow.ui index 00f3ac49..cbef5a11 100644 --- a/preditor/gui/ui/loggerwindow.ui +++ b/preditor/gui/ui/loggerwindow.ui @@ -853,6 +853,114 @@ Must be at least 1 + + + + Prefs files on disk + + + + 3 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + Qt::Horizontal + + + + 0 + 20 + + + + + + + + + 6 + + + 6 + + + 0 + + + 0 + + + 3 + + + + + + 1 + 0 + + + + Browse + + + + + + + + 1 + 0 + + + + This may take a long time. + + + Backup + + + + + + + + + + + + @@ -975,8 +1083,6 @@ Must be at least 1 Preferences - - @@ -1439,14 +1545,6 @@ Must be at least 1 Clear Output File - - - Browse... - - - Browse Preferences - - true @@ -1759,11 +1857,6 @@ at the indicated line in the specified text editor. Ctrl+Alt+9 - - - Backup - - Focus To Name From 1d5cc6c3431362fb237f2e506b18f417a9209372 Mon Sep 17 00:00:00 2001 From: Mark Mancewicz Date: Mon, 20 Oct 2025 18:46:46 -0700 Subject: [PATCH 09/13] Add Open Most Recent Workbox action / shortcut --- preditor/gui/loggerwindow.py | 39 ++++++++++++++++++++++++++------- preditor/gui/ui/loggerwindow.ui | 15 +++++++++++++ preditor/gui/workbox_mixin.py | 6 +++++ 3 files changed, 52 insertions(+), 8 deletions(-) diff --git a/preditor/gui/loggerwindow.py b/preditor/gui/loggerwindow.py index 6d97020e..28d32c29 100644 --- a/preditor/gui/loggerwindow.py +++ b/preditor/gui/loggerwindow.py @@ -182,18 +182,22 @@ def connectSignals(self): self.uiCloseLoggerACT.triggered.connect(self.closeLoggerByAction) self.uiRunAllACT.triggered.connect(self.execAll) - # Even though the RunSelected actions (with shortcuts) are connected - # here, this only affects if the action is chosen from the menu. The - # shortcuts are always intercepted by the workbox document editor. To - # handle this, the workbox.keyPressEvent method will perceive the - # shortcut press, and call .execSelected, which will then ultimately call - # workbox.__exec_selected__ + # Even though the RunSelected and Open Most Recently Closed Workbox + # actions (with shortcuts) are connected here, this only affects if the + # action is chosen from the menu. The shortcuts are always intercepted + # by the workbox document editor. To handle this, the + # workbox.keyPressEvent method will perceive the shortcut press, and + # call the correct method. self.uiRunSelectedACT.triggered.connect( partial(self.execSelected, truncate=True) ) self.uiRunSelectedDontTruncateACT.triggered.connect( partial(self.execSelected, truncate=False) ) + # Closed workboxes + self.uiOpenMostRecentWorkboxACT.triggered.connect( + self.openMostRecentlyClosedWorkbox + ) self.uiConsoleAutoCompleteEnabledCHK.toggled.connect( partial(self.setAutoCompleteEnabled, console=True) @@ -1888,13 +1892,22 @@ def getClosedWorkboxData(self): data.append(datum) return data - def recentWorkboxActionTriggered(self): + def recentWorkboxActionTriggered(self, checked=None, action=None): """Slot for when user selects a Recently Closed Workbox. First, try to just show the workbox if it's currently open. If not, recreate it. In both cases, set focus on that workbox. + Args: + checked (bool, optional): If this is method is called as slot, the + arg 'checked' is automatically passed + action (QAction, optional): If this method is called by + openMostRecentlyClosedWorkbox, this is the determined most recent + workbox action. + """ - action = self.sender() + if action is None: + action = self.sender() + workboxDatum = action.data() workbox_id = workboxDatum.get("workbox_id") workbox_filename = workboxDatum.get("filename") @@ -1934,6 +1947,16 @@ def recentWorkboxActionTriggered(self): workbox.__tab_widget__().tabBar().updateColorsAndToolTips() + if workbox is not None: + workbox.__tab_widget__().tabBar().updateColorsAndToolTips() + + def openMostRecentlyClosedWorkbox(self): + """Restore the most recently closed workbox""" + actions = self.uiClosedWorkboxesMENU.actions() + if actions: + action = actions[0] + self.recentWorkboxActionTriggered(action=action) + def setAutoCompleteEnabled(self, state, console=True): if console: self.uiConsoleTXT.completer().setEnabled(state) diff --git a/preditor/gui/ui/loggerwindow.ui b/preditor/gui/ui/loggerwindow.ui index cbef5a11..7f3787cc 100644 --- a/preditor/gui/ui/loggerwindow.ui +++ b/preditor/gui/ui/loggerwindow.ui @@ -1071,6 +1071,7 @@ Must be at least 1 + @@ -2041,6 +2042,20 @@ at the indicated line in the specified text editor. Empty Workbox Recycle Bin + + Once a workbox is pruned off the Recently Closed Workboxes list +(as determiend by Max Recently Closed Workboxes preference), it +goes to the Workbox Recycle Bin. +This button removes those (very old) workboxes. + + + + + Open most recently closed Workbox + + + Ctrl+Shift+T + diff --git a/preditor/gui/workbox_mixin.py b/preditor/gui/workbox_mixin.py index b239afae..dea1024e 100644 --- a/preditor/gui/workbox_mixin.py +++ b/preditor/gui/workbox_mixin.py @@ -1130,6 +1130,9 @@ def process_shortcut(self, event, run=True): evalTrunc = enter or (ret and shift) evalNoTrunc = ret and ctrlShift + # See if shortcut for Open Most Recent Workbox is pressed + openRecentWorkbox = ctrlShift and key == Qt.Key.Key_T + if evalTrunc: # Execute with truncation self.window().execSelected() @@ -1137,6 +1140,9 @@ def process_shortcut(self, event, run=True): # Execute without truncation self.window().execSelected(truncate=False) + elif openRecentWorkbox: + self.window().openMostRecentlyClosedWorkbox() + if evalTrunc or evalNoTrunc: if self.window().uiAutoPromptCHK.isChecked(): self.__console__().startInputLine() From 07f30cc0b96ffb8895d1abdbcd397f17b79ee2e8 Mon Sep 17 00:00:00 2001 From: Mark Mancewicz Date: Tue, 18 Nov 2025 18:29:27 -0800 Subject: [PATCH 10/13] Optionally autoprompt after displaying find results --- preditor/gui/find_files.py | 10 ++++++++++ preditor/gui/ui/loggerwindow.ui | 3 +++ 2 files changed, 13 insertions(+) diff --git a/preditor/gui/find_files.py b/preditor/gui/find_files.py index 85ff80de..8fe1cafa 100644 --- a/preditor/gui/find_files.py +++ b/preditor/gui/find_files.py @@ -71,6 +71,11 @@ def find(self): self.finder.callback_matching = self.insert_found_text self.finder.callback_non_matching = self.insert_text + # Start fresh output line. + window = self.parent().window() if self.parent() else None + if window: + window.console().startPrompt("") + self.insert_text(self.finder.title()) self.match_files_count = 0 @@ -91,6 +96,11 @@ def find(self): ) ) + # If user has Auto-prompt chosen, do so now. + if window: + if window.uiAutoPromptCHK.isChecked(): + window.console().startInputLine() + def find_in_editor(self, editor, path): # Ensure the editor text is loaded and get its raw text editor.__show__() diff --git a/preditor/gui/ui/loggerwindow.ui b/preditor/gui/ui/loggerwindow.ui index 7f3787cc..8764efb8 100644 --- a/preditor/gui/ui/loggerwindow.ui +++ b/preditor/gui/ui/loggerwindow.ui @@ -275,6 +275,9 @@ + + After running workbox code, start a new prompt (>>> ) + Auto-prompt From bcb7e439ba2f00d2cd0e561dd8f98c75dd23d8d0 Mon Sep 17 00:00:00 2001 From: Mark Mancewicz Date: Wed, 22 Oct 2025 07:49:40 -0700 Subject: [PATCH 11/13] Only set language if it's different (to prevent loading default font) --- preditor/scintilla/documenteditor.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/preditor/scintilla/documenteditor.py b/preditor/scintilla/documenteditor.py index a586af84..09c0351d 100644 --- a/preditor/scintilla/documenteditor.py +++ b/preditor/scintilla/documenteditor.py @@ -1565,9 +1565,12 @@ def updateFilename(self, filename): if self._filename and ( filename and extension != os.path.splitext(self._filename)[1] ): - self.setLanguage(lang.byExtension(extension)) + language = lang.byExtension(extension) else: - self.setLanguage(self._defaultLanguage) + language = self._defaultLanguage + + if language != self.language(): + self.setLanguage(language) # update the filename information filename = os.path.abspath(filename) if filename else "" From 26aa3574937af74950e17d263fa977adaa41300e Mon Sep 17 00:00:00 2001 From: Mark Mancewicz Date: Tue, 18 Nov 2025 14:34:48 -0800 Subject: [PATCH 12/13] Retain orig cursor pos if clicking hyperlink --- preditor/gui/console.py | 48 +++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/preditor/gui/console.py b/preditor/gui/console.py index 3e47c172..49322963 100644 --- a/preditor/gui/console.py +++ b/preditor/gui/console.py @@ -135,8 +135,7 @@ def __init__(self, parent): self.addAction(self.uiClearToLastPromptACT) self.x = 0 - self.clickPos = None - self.anchor = None + self.mousePressPos = None # Make sure console cursor is visible. It can get it's width set to 0 with # unusual(ie not 100%) os display scaling. @@ -220,30 +219,47 @@ def setConsoleFont(self, font): if origPercent is not None: self.doubleSingleShotSetScrollValue(origPercent) + def mouseMoveEvent(self, event): + """Overload of mousePressEvent to change mouse pointer to indicate it is + over a clickable error hyperlink. + """ + if self.anchorAt(event.pos()): + QApplication.setOverrideCursor(Qt.CursorShape.PointingHandCursor) + else: + QApplication.restoreOverrideCursor() + return super().mouseMoveEvent(event) + def mousePressEvent(self, event): """Overload of mousePressEvent to capture click position, so on release, we can check release position. If it's the same (ie user clicked vs click-drag to select text), we check if user clicked an error hyperlink. """ - self.clickPos = event.pos() - self.anchor = self.anchorAt(event.pos()) - if self.anchor: - QApplication.setOverrideCursor(Qt.CursorShape.PointingHandCursor) - return super(ConsolePrEdit, self).mousePressEvent(event) + left = event.button() == Qt.MouseButton.LeftButton + anchor = self.anchorAt(event.pos()) + self.mousePressPos = event.pos() + + if left and anchor: + event.ignore() + return + + return super().mousePressEvent(event) def mouseReleaseEvent(self, event): """Overload of mouseReleaseEvent to capture if user has left clicked... Check if click position is the same as release position, if so, call errorHyperlink. """ - samePos = event.pos() == self.clickPos + samePos = event.pos() == self.mousePressPos left = event.button() == Qt.MouseButton.LeftButton - if samePos and left and self.anchor: - self.errorHyperlink() + anchor = self.anchorAt(event.pos()) + + if samePos and left and anchor: + self.errorHyperlink(anchor) + self.mousePressPos = None - self.clickPos = None - self.anchor = None QApplication.restoreOverrideCursor() - return super(ConsolePrEdit, self).mouseReleaseEvent(event) + ret = super(ConsolePrEdit, self).mouseReleaseEvent(event) + + return ret def keyReleaseEvent(self, event): """Override of keyReleaseEvent to determine when to end navigation of @@ -254,7 +270,7 @@ def keyReleaseEvent(self, event): else: event.ignore() - def errorHyperlink(self): + def errorHyperlink(self, anchor): """Determine if chosen line is an error traceback file-info line, if so, parse the filepath and line number, and attempt to open the module file in the user's chosen text editor at the relevant line, using specified Command Prompt pattern. @@ -267,13 +283,13 @@ def errorHyperlink(self): doHyperlink = ( hasattr(window, 'uiErrorHyperlinksCHK') and window.uiErrorHyperlinksCHK.isChecked() - and self.anchor + and anchor ) if not doHyperlink: return # info is a comma separated string, in the form: "filename, workboxIdx, lineNum" - info = self.anchor.split(', ') + info = anchor.split(', ') modulePath = info[0] workboxName = info[1] lineNum = info[2] From 68787056af1a53c26faa77370aa84fc04259e291 Mon Sep 17 00:00:00 2001 From: Mark Mancewicz Date: Tue, 18 Nov 2025 17:58:05 -0800 Subject: [PATCH 13/13] Remove old actions --- preditor/gui/ui/loggerwindow.ui | 135 -------------------------------- 1 file changed, 135 deletions(-) diff --git a/preditor/gui/ui/loggerwindow.ui b/preditor/gui/ui/loggerwindow.ui index 8764efb8..e714b1bb 100644 --- a/preditor/gui/ui/loggerwindow.ui +++ b/preditor/gui/ui/loggerwindow.ui @@ -1348,23 +1348,6 @@ Must be at least 1 Ctrl+Alt+Shift+D - - - true - - - false - - - Use Auto-Complete in console - - - Use Auto-Complete in console - - - Use Auto-Complete in console - - Run Line... @@ -1400,25 +1383,6 @@ Must be at least 1 Shift+Return - - - true - - - Indentations use tabs - - - - - true - - - Enable Console Word Wrap - - - Enable word wrap in the python output console - - Save Console Settings @@ -1430,17 +1394,6 @@ Must be at least 1 Ctrl+S - - - true - - - Clear before running workbox code - - - Clear console log before running workbox code. - - Close @@ -1452,17 +1405,6 @@ Must be at least 1 Ctrl+Q - - - true - - - Editor Vertical - - - Editor Vertical - - Clear to Last Prompt @@ -1474,14 +1416,6 @@ Must be at least 1 Ctrl+Shift+Backspace - - - true - - - Convert Tabs to Spaces on Copy - - Reset Warning Filters @@ -1508,14 +1442,6 @@ Must be at least 1 If executing code takes longer than this many seconds, flash the main window of the application. - - - true - - - Use Spell-Check - - Log Output to File @@ -1595,22 +1521,6 @@ Must be at least 1 Ctrl+M - - - true - - - true - - - Auto-Save Console Settings - - - Auto-Save Console Settings and Workbox code. -Useful if often using multiple DCC instances simultaneously. -Must manually save instead. - - New Workbox @@ -1721,14 +1631,6 @@ Must manually save instead. Ctrl+Shift+Tab - - - true - - - Auto-prompt - - true @@ -1742,19 +1644,6 @@ Must manually save instead. Set Preferred Text Editor Path - - - true - - - Error Hyperlinks - - - Show Error Hyperlinks, which can be clicked to open the indicated module -at the indicated line in the specified text editor. - - - Select Current Line @@ -1888,14 +1777,6 @@ at the indicated line in the specified text editor. Ctrl+Shift+F - - - true - - - Use Auto-Complete in workbox - - Choose from monospace fonts @@ -1928,14 +1809,6 @@ at the indicated line in the specified text editor. Ctrl+Shift+Return - - - true - - - Highlight Exact Completion - - Show First Workbox Version @@ -2017,14 +1890,6 @@ at the indicated line in the specified text editor. Ctrl+Alt+- - - - true - - - Visually Separate PrEditor Traceback - - Run First Workbox