diff --git a/spyder/api/shortcuts.py b/spyder/api/shortcuts.py index fa0005aa80a..e00fc041b08 100644 --- a/spyder/api/shortcuts.py +++ b/spyder/api/shortcuts.py @@ -142,8 +142,14 @@ def register_shortcut_for_widget( name = name.lower() context = context.lower() - # Add observer to register shortcut when its associated option is - # broadcasted by CONF or updated in Preferences. + # Register shortcurt for widget + keystr = self.get_shortcut(name, context, plugin_name) + self._register_shortcut( + keystr, name, triggered, context, widget, plugin_name + ) + + # Add observer for shortcut so that it's updated when changed by users + # in Preferences config_observer = functools.partial( self._register_shortcut, name=name, @@ -200,6 +206,14 @@ def _register_shortcut( # Disable current shortcut, if available current_shortcut = self._shortcuts.get((context, name, plugin_name)) if current_shortcut: + # Don't do the rest if we're trying to register the same shortcut + # again. This happens at startup because shortcuts are registered + # on widget creation and then the observer attached to the shortcut + # tries to do it again after CONF.notify_all_observers() is called. + if current_shortcut.key().toString() == keystr: + return + + # Disable current shortcut to create a new one below current_shortcut.setEnabled(False) current_shortcut.deleteLater() self._shortcuts.pop((context, name, plugin_name)) diff --git a/spyder/app/tests/test_mainwindow.py b/spyder/app/tests/test_mainwindow.py index 075fa33c126..f977b90c2a0 100644 --- a/spyder/app/tests/test_mainwindow.py +++ b/spyder/app/tests/test_mainwindow.py @@ -5375,10 +5375,6 @@ def test_copy_paste(main_window, qtbot, tmpdir): code_editor = main_window.editor.get_focus_widget() code_editor.set_text(code) - # Register codeeditor shortcuts - CONF.notify_section_all_observers("shortcuts") - qtbot.wait(300) - # Test copy cursor = code_editor.textCursor() cursor.setPosition(69) diff --git a/spyder/plugins/editor/widgets/codeeditor/tests/conftest.py b/spyder/plugins/editor/widgets/codeeditor/tests/conftest.py index 4879310d406..edb89b9cd0e 100644 --- a/spyder/plugins/editor/widgets/codeeditor/tests/conftest.py +++ b/spyder/plugins/editor/widgets/codeeditor/tests/conftest.py @@ -149,10 +149,6 @@ def mock_completions_codeeditor(qtbot_module, request): qtbot_module.addWidget(editor) editor.show() - # Register shortcuts for CodeEditor - CONF.notify_section_all_observers("shortcuts") - qtbot_module.wait(300) - mock_response = Mock() def perform_request(lang, method, params): @@ -186,10 +182,6 @@ def completions_codeeditor(completion_plugin_all_started, qtbot_module, completion_plugin, capabilities = completion_plugin_all_started completion_plugin.wait_for_ms = 2000 - # Register shortcuts for CodeEditor - CONF.notify_section_all_observers("shortcuts") - qtbot_module.wait(300) - CONF.set('completions', 'enable_code_snippets', False) completion_plugin.after_configuration_update([]) CONF.notify_section_all_observers('completions') @@ -257,10 +249,6 @@ def codeeditor(qtbot): widget.resize(640, 480) widget.show() - # Register shortcuts for CodeEditor - CONF.notify_section_all_observers("shortcuts") - qtbot.wait(300) - yield widget widget.close() diff --git a/spyder/plugins/editor/widgets/codeeditor/tests/test_codeeditor.py b/spyder/plugins/editor/widgets/codeeditor/tests/test_codeeditor.py index 405abce2e05..0d6ca09635f 100644 --- a/spyder/plugins/editor/widgets/codeeditor/tests/test_codeeditor.py +++ b/spyder/plugins/editor/widgets/codeeditor/tests/test_codeeditor.py @@ -721,6 +721,9 @@ def test_shortcut_for_widget_is_updated(config_dialog, codeeditor, qtbot): text = ('aa\nbb\ncc\ndd\n') editor.set_text(text) + # We need to wait for a bit so shortcuts are registered correctly + qtbot.wait(300) + # Check shortcuts were registered assert editor._shortcuts != {} diff --git a/spyder/plugins/editor/widgets/editorstack/tests/test_shortcuts.py b/spyder/plugins/editor/widgets/editorstack/tests/test_shortcuts.py index 7a704ccf15e..8a5df73b4bc 100644 --- a/spyder/plugins/editor/widgets/editorstack/tests/test_shortcuts.py +++ b/spyder/plugins/editor/widgets/editorstack/tests/test_shortcuts.py @@ -42,8 +42,7 @@ def editorstack(qtbot): editorstack.show() editorstack.go_to_line(1) - # Register shortcuts - CONF.notify_section_all_observers("shortcuts") + # We need to wait for a bit so shortcuts are registered correctly qtbot.wait(300) return editorstack @@ -344,6 +343,27 @@ def test_builtin_undo_redo(editorstack, qtbot): assert editor.toPlainText() == 'Something\nLine1\nLine2\nLine3\nLine4\n' +@pytest.mark.skipif( + sys.platform.startswith("linux") and running_in_ci(), + reason='Fails on Linux and CI' +) +def test_shortcuts_for_new_editors(editorstack, qtbot): + """ + Test that widget shortcuts are working for new editors. + + This is a regression test for spyder-ide/spyder#23151. + """ + # Create new file and give it focus + editorstack.new('bar.py', 'utf-8', 'Line5\nLine6\nLine7\nLine8') + editorstack.tabs.setCurrentIndex(1) + + # Go to its first line, click the shortcut to comment it and check it was + editorstack.go_to_line(1) + editor = editorstack.get_current_editor() + qtbot.keyClick(editor, Qt.Key_1, modifier=Qt.ControlModifier) + assert editor.toPlainText() == '# Line5\nLine6\nLine7\nLine8\n' + + if __name__ == "__main__": import os pytest.main(['-x', os.path.basename(__file__), '-vv', '-rw'])