From ec245a94252571f700590b9a5719156365a3cca3 Mon Sep 17 00:00:00 2001 From: Carlos Cordoba Date: Sat, 30 Dec 2023 16:37:27 -0500 Subject: [PATCH 1/9] Switcher: Remove old usage of super and other small fixes --- spyder/plugins/switcher/widgets/proxymodel.py | 4 ++-- spyder/plugins/switcher/widgets/switcher.py | 11 ++++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/spyder/plugins/switcher/widgets/proxymodel.py b/spyder/plugins/switcher/widgets/proxymodel.py index 665bff8e621..10bcb56e94c 100644 --- a/spyder/plugins/switcher/widgets/proxymodel.py +++ b/spyder/plugins/switcher/widgets/proxymodel.py @@ -7,7 +7,7 @@ """Switcher Proxy Model.""" # Third party imports -from qtpy.QtCore import (QSortFilterProxyModel, Qt) +from qtpy.QtCore import QSortFilterProxyModel, Qt class SwitcherProxyModel(QSortFilterProxyModel): @@ -15,7 +15,7 @@ class SwitcherProxyModel(QSortFilterProxyModel): def __init__(self, parent=None): """Proxy model to perform sorting on the scored items.""" - super(SwitcherProxyModel, self).__init__(parent) + super().__init__(parent) self.setFilterCaseSensitivity(Qt.CaseInsensitive) self.setSortCaseSensitivity(Qt.CaseInsensitive) self.setDynamicSortFilter(True) diff --git a/spyder/plugins/switcher/widgets/switcher.py b/spyder/plugins/switcher/widgets/switcher.py index c949d2e1044..35cdd97c94c 100644 --- a/spyder/plugins/switcher/widgets/switcher.py +++ b/spyder/plugins/switcher/widgets/switcher.py @@ -63,7 +63,7 @@ def eventFilter(self, src, e): elif (e.key() == Qt.Key_Return): self.sig_enter_key_pressed.emit() return True - return super(KeyPressFilter, self).eventFilter(src, e) + return super().eventFilter(src, e) class SwitcherDelegate(HTMLDelegate): @@ -77,7 +77,7 @@ def paint(self, painter, option, index): Override Qt method to force this delegate to look active at all times. """ option.state |= QStyle.State_Active - super(SwitcherDelegate, self).paint(painter, option, index) + super().paint(painter, option, index) class Switcher(QDialog): @@ -457,7 +457,7 @@ def enter(self, itemClicked=None): def accept(self): """Override Qt method.""" - super(Switcher, self).accept() + super().accept() def reject(self): """Override Qt method.""" @@ -468,7 +468,7 @@ def reject(self): self.edit.blockSignals(False) self.sig_rejected.emit() - super(Switcher, self).reject() + super().reject() # ---- Helper methods: Lineedit widget def search_text(self): @@ -546,7 +546,8 @@ def set_current_row(self, row): # https://doc.qt.io/qt-5/qitemselectionmodel.html#SelectionFlag-enum selection_model.setCurrentIndex( - proxy_index, selection_model.ClearAndSelect) + proxy_index, selection_model.ClearAndSelect + ) # Ensure that the selected item is visible self.list.scrollTo(proxy_index, QAbstractItemView.EnsureVisible) From 704224d835a4f313bd5ce33ec1f6bed318a02321 Mon Sep 17 00:00:00 2001 From: Carlos Cordoba Date: Sat, 30 Dec 2023 16:55:05 -0500 Subject: [PATCH 2/9] Editor: Remove direct usage of CONF in EditorSwitcherManager Also, make some small code formatting changes. --- .../plugins/editor/utils/switcher_manager.py | 46 +++++++++++++------ 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/spyder/plugins/editor/utils/switcher_manager.py b/spyder/plugins/editor/utils/switcher_manager.py index 6f8e1d40ffd..dcea583a1fe 100644 --- a/spyder/plugins/editor/utils/switcher_manager.py +++ b/spyder/plugins/editor/utils/switcher_manager.py @@ -12,14 +12,14 @@ import os.path as osp # Local imports +from spyder.api.config.mixins import SpyderConfigurationAccessor from spyder.config.base import _ -from spyder.config.manager import CONF from spyder.utils.icon_manager import ima from spyder.plugins.switcher.utils import shorten_paths, get_file_icon from spyder.plugins.completion.api import SymbolKind, SYMBOL_KIND_ICON -class EditorSwitcherManager(object): +class EditorSwitcherManager(SpyderConfigurationAccessor): """ Switcher instance manager to handle base modes for an Editor. @@ -136,16 +136,23 @@ def create_symbol_switcher(self): editor = self._editor() language = editor.language editor.update_whitespace_count(0, 0) + self._current_line = editor.get_cursor_line_number() self._switcher.clear() self._switcher.set_placeholder_text(_('Select symbol')) + oe_symbols = editor.oe_proxy.info or [] - display_variables = CONF.get('outline_explorer', 'display_variables') + display_variables = self.get_conf( + 'display_variables', + section='outline_explorer' + ) idx = 0 total_symbols = len(oe_symbols) oe_symbols = sorted( - oe_symbols, key=lambda x: x['location']['range']['start']['line']) + oe_symbols, key=lambda x: x['location']['range']['start']['line'] + ) + for symbol in oe_symbols: symbol_name = symbol['name'] symbol_kind = symbol['kind'] @@ -153,10 +160,14 @@ def create_symbol_switcher(self): if symbol_kind == SymbolKind.MODULE: total_symbols -= 1 continue - if (symbol_kind == SymbolKind.VARIABLE and - not display_variables): + + if ( + symbol_kind == SymbolKind.VARIABLE and + not display_variables + ): total_symbols -= 1 continue + if symbol_kind == SymbolKind.FIELD and not display_variables: total_symbols -= 1 continue @@ -170,16 +181,22 @@ def create_symbol_switcher(self): formated_title = '{space}{title}'.format(title=symbol_name, space=space) icon = ima.icon(SYMBOL_KIND_ICON.get(symbol_kind, 'no_match')) - data = {'title': symbol_name, - 'line_number': symbol_start + 1} + data = { + 'title': symbol_name, + 'line_number': symbol_start + 1 + } last_item = idx + 1 == total_symbols - self._switcher.add_item(title=formated_title, - icon=icon, - section=self._section, - data=data, - last_item=last_item) + self._switcher.add_item( + title=formated_title, + icon=icon, + section=self._section, + data=data, + last_item=last_item + ) + idx += 1 - # Needed to update fold spaces for items titles + + # Needed to update fold spaces for item titles self._switcher.setup() def handle_switcher_selection(self, item, mode, search_text): @@ -238,6 +255,7 @@ def line_switcher_handler(self, data, search_text, visible=False): line_number = int(line_number) editorstack.go_to_line(line_number) self._switcher.set_visible(visible) + # Closing the switcher if not visible: self._current_line = None From 961d79fbdba3d97d06f8e784357c0d1799f8dff9 Mon Sep 17 00:00:00 2001 From: Carlos Cordoba Date: Sat, 30 Dec 2023 17:15:28 -0500 Subject: [PATCH 3/9] Switcher: Move actions enum to its api module --- spyder/plugins/switcher/api.py | 4 ++++ spyder/plugins/switcher/container.py | 5 +++-- spyder/plugins/switcher/plugin.py | 7 +------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/spyder/plugins/switcher/api.py b/spyder/plugins/switcher/api.py index 94075582b49..42fab3bfca8 100644 --- a/spyder/plugins/switcher/api.py +++ b/spyder/plugins/switcher/api.py @@ -7,3 +7,7 @@ """ Spyder Switcher API. """ + +class SwitcherActions: + FileSwitcherAction = 'file switcher' + SymbolFinderAction = 'symbol finder' diff --git a/spyder/plugins/switcher/container.py b/spyder/plugins/switcher/container.py index 9becff78d96..a7130243578 100644 --- a/spyder/plugins/switcher/container.py +++ b/spyder/plugins/switcher/container.py @@ -14,6 +14,7 @@ # Spyder imports from spyder.api.translations import _ from spyder.api.widgets.main_container import PluginMainContainer +from spyder.plugins.switcher.api import SwitcherActions from spyder.plugins.switcher.widgets.switcher import Switcher @@ -26,7 +27,7 @@ def setup(self): # Switcher shortcuts self.create_action( - 'file switcher', + SwitcherActions.FileSwitcherAction, _('File switcher...'), icon=self._plugin.get_icon(), tip=_('Fast switch between files'), @@ -36,7 +37,7 @@ def setup(self): ) self.create_action( - 'symbol finder', + SwitcherActions.SymbolFinderAction, _('Symbol finder...'), icon=self.create_icon('symbol_find'), tip=_('Fast symbol search in file'), diff --git a/spyder/plugins/switcher/plugin.py b/spyder/plugins/switcher/plugin.py index 14164a5de40..78391af915c 100644 --- a/spyder/plugins/switcher/plugin.py +++ b/spyder/plugins/switcher/plugin.py @@ -20,16 +20,11 @@ from spyder.api.plugins import Plugins, SpyderPluginV2 from spyder.api.plugin_registration.decorators import (on_plugin_available, on_plugin_teardown) +from spyder.plugins.switcher.api import SwitcherActions from spyder.plugins.switcher.container import SwitcherContainer from spyder.plugins.mainmenu.api import ApplicationMenus, FileMenuSections -# --- Constants -# ---------------------------------------------------------------------------- -class SwitcherActions: - FileSwitcherAction = 'file switcher' - SymbolFinderAction = 'symbol finder' - # --- Plugin # ---------------------------------------------------------------------------- From b6eb44e514c35abb39f5efdc0efb3c576281aa17 Mon Sep 17 00:00:00 2001 From: Carlos Cordoba Date: Sat, 30 Dec 2023 17:32:59 -0500 Subject: [PATCH 4/9] Switcher: Correctly align it vertically with the main menu and toolbar --- spyder/plugins/switcher/container.py | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/spyder/plugins/switcher/container.py b/spyder/plugins/switcher/container.py index a7130243578..49559bab827 100644 --- a/spyder/plugins/switcher/container.py +++ b/spyder/plugins/switcher/container.py @@ -16,6 +16,7 @@ from spyder.api.widgets.main_container import PluginMainContainer from spyder.plugins.switcher.api import SwitcherActions from spyder.plugins.switcher.widgets.switcher import Switcher +from spyder.utils.stylesheet import APP_TOOLBAR_STYLESHEET class SwitcherContainer(PluginMainContainer): @@ -71,18 +72,26 @@ def open_switcher(self, symbol=False): # Set position mainwindow = self._plugin.get_main() - # Note: The +8 pixel on the top makes it look better - default_top = (mainwindow.toolbar.toolbars_menu.geometry().height() + - mainwindow.menuBar().geometry().height() + 8) + # Note: The +3 pixels makes it vertically align with the main menu or + # main menu + toolbar + default_top_without_toolbar = ( + mainwindow.menuBar().geometry().height() + + 3 + ) + + default_top_with_toolbar = ( + int(APP_TOOLBAR_STYLESHEET.BUTTON_HEIGHT.split("px")[0]) + + default_top_without_toolbar + ) current_window = QApplication.activeWindow() if current_window == mainwindow: if self.get_conf('toolbars_visible', section='toolbar'): - delta_top = default_top + delta_top = default_top_with_toolbar else: - delta_top = mainwindow.menuBar().geometry().height() + 8 + delta_top = default_top_without_toolbar else: - delta_top = default_top + delta_top = default_top_with_toolbar switcher.set_position(delta_top, current_window) switcher.show() From cbea6df4cdff245bb73ca2984113e18382dd7aa9 Mon Sep 17 00:00:00 2001 From: Carlos Cordoba Date: Sun, 31 Dec 2023 09:46:34 -0500 Subject: [PATCH 5/9] Switcher: Remove sig_text_changed signal That signal is not really necessary because we have sig_search_text_available, which is debounced and does pretty much the same. --- spyder/plugins/editor/utils/switcher_manager.py | 7 ++++--- spyder/plugins/switcher/plugin.py | 16 +++------------- spyder/plugins/switcher/widgets/switcher.py | 11 ----------- 3 files changed, 7 insertions(+), 27 deletions(-) diff --git a/spyder/plugins/editor/utils/switcher_manager.py b/spyder/plugins/editor/utils/switcher_manager.py index dcea583a1fe..72e138bf630 100644 --- a/spyder/plugins/editor/utils/switcher_manager.py +++ b/spyder/plugins/editor/utils/switcher_manager.py @@ -56,11 +56,12 @@ def setup_switcher(self): self._switcher.add_mode(self.SYMBOL_MODE, _('Go to Symbol in File')) self._switcher.sig_mode_selected.connect(self.handle_switcher_modes) self._switcher.sig_item_selected.connect( - self.handle_switcher_selection) - self._switcher.sig_text_changed.connect(self.handle_switcher_text) + self.handle_switcher_selection + ) self._switcher.sig_rejected.connect(self.handle_switcher_rejection) self._switcher.sig_item_changed.connect( - self.handle_switcher_item_change) + self.handle_switcher_item_change + ) self._switcher.sig_search_text_available.connect( lambda text: self._switcher.setup() ) diff --git a/spyder/plugins/switcher/plugin.py b/spyder/plugins/switcher/plugin.py index 78391af915c..85b1ee7f554 100644 --- a/spyder/plugins/switcher/plugin.py +++ b/spyder/plugins/switcher/plugin.py @@ -45,19 +45,9 @@ class Switcher(SpyderPluginV2): This signal is emitted when the plugin is dismissed. """ - sig_text_changed = Signal(str) - """ - This signal is emitted when the plugin search/filter text changes. - - Parameters - ---------- - search_text: str - The current search/filter text. - """ - sig_item_changed = Signal(object) """ - This signal is emitted when the plugin current item changes. + This signal is emitted when the current item changes. """ sig_item_selected = Signal(object, str, str) @@ -114,12 +104,12 @@ def on_initialize(self): self._switcher = container.switcher self._switcher.sig_rejected.connect(self.sig_rejected) - self._switcher.sig_text_changed.connect(self.sig_text_changed) self._switcher.sig_item_changed.connect(self.sig_item_changed) self._switcher.sig_item_selected.connect(self.sig_item_selected) self._switcher.sig_mode_selected.connect(self.sig_mode_selected) self._switcher.sig_search_text_available.connect( - self.sig_search_text_available) + self.sig_search_text_available + ) def on_close(self, cancellable=True): """Close switcher widget.""" diff --git a/spyder/plugins/switcher/widgets/switcher.py b/spyder/plugins/switcher/widgets/switcher.py index 35cdd97c94c..4b424fb8c1d 100644 --- a/spyder/plugins/switcher/widgets/switcher.py +++ b/spyder/plugins/switcher/widgets/switcher.py @@ -99,16 +99,6 @@ class Switcher(QDialog): This signal is emitted when the plugin is dismissed. """ - sig_text_changed = Signal(str) - """ - This signal is emitted when the plugin search/filter text changes. - - Parameters - ---------- - search_text: str - The current search/filter text. - """ - sig_item_changed = Signal(object) """ This signal is emitted when the plugin current item changes. @@ -208,7 +198,6 @@ def __init__(self, parent, help_text=None, item_styles=ITEM_STYLES, self.filter.sig_down_key_pressed.connect(self.next_row) self.filter.sig_enter_key_pressed.connect(self.enter) - self.edit.textChanged.connect(self.sig_text_changed) self.edit.textChanged.connect(lambda: self._search_timer.start()) self.edit.returnPressed.connect(self.enter) From 9645f2c5923dab99d0346bcebffcf36451c6bcb4 Mon Sep 17 00:00:00 2001 From: Carlos Cordoba Date: Sun, 31 Dec 2023 09:57:47 -0500 Subject: [PATCH 6/9] Switcher: Use superqt utility functions in several places --- spyder/plugins/switcher/widgets/switcher.py | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/spyder/plugins/switcher/widgets/switcher.py b/spyder/plugins/switcher/widgets/switcher.py index 4b424fb8c1d..ae418346339 100644 --- a/spyder/plugins/switcher/widgets/switcher.py +++ b/spyder/plugins/switcher/widgets/switcher.py @@ -8,11 +8,12 @@ # Third party imports -from qtpy.QtCore import QEvent, QObject, Qt, Signal, Slot, QModelIndex, QTimer +from qtpy.QtCore import QEvent, QObject, Qt, Signal, Slot, QModelIndex from qtpy.QtGui import QStandardItemModel from qtpy.QtWidgets import (QAbstractItemView, QDialog, QLineEdit, QListView, QListWidgetItem, QStyle, QVBoxLayout) +from superqt.utils import qdebounced, signals_blocked # Local imports from spyder.plugins.switcher.widgets.proxymodel import SwitcherProxyModel @@ -163,12 +164,6 @@ def __init__(self, parent, help_text=None, item_styles=ITEM_STYLES, self.proxy = SwitcherProxyModel(self.list) self.filter = KeyPressFilter() - # Search timer - self._search_timer = QTimer(self) - self._search_timer.setInterval(300) - self._search_timer.setSingleShot(True) - self._search_timer.timeout.connect(self._on_search_text_changed) - # Widgets setup self.setWindowFlags(Qt.Popup | Qt.FramelessWindowHint) self.setWindowOpacity(0.95) @@ -198,7 +193,7 @@ def __init__(self, parent, help_text=None, item_styles=ITEM_STYLES, self.filter.sig_down_key_pressed.connect(self.next_row) self.filter.sig_enter_key_pressed.connect(self.enter) - self.edit.textChanged.connect(lambda: self._search_timer.start()) + self.edit.textChanged.connect(self._on_search_text_changed) self.edit.returnPressed.connect(self.enter) self.list.clicked.connect(self.enter) @@ -452,9 +447,8 @@ def reject(self): """Override Qt method.""" # This prevents calling _on_search_text_changed, which unnecessarily # tries to populate the switcher when we're closing it. - self.edit.blockSignals(True) - self.set_search_text('') - self.edit.blockSignals(False) + with signals_blocked(self.edit): + self.set_search_text('') self.sig_rejected.emit() super().reject() @@ -478,6 +472,7 @@ def set_search_text(self, string): """Set the content of the search text.""" self.edit.setText(string) + @qdebounced(timeout=250) def _on_search_text_changed(self): """Actions to take when the search text has changed.""" if self.search_text() != "": From f2fb98920ba74d4274d2dc2759b32a94b3a8d46d Mon Sep 17 00:00:00 2001 From: Carlos Cordoba Date: Sun, 31 Dec 2023 12:42:03 -0500 Subject: [PATCH 7/9] Switcher: Fix symbols mode - Emit sig_mode_selected manually when calling the action to show symbols. This makes symbols to be shown instantly. - Fix default "score" kwarg value in the plugin API. This was giving an error when comparing symbol scores. - Reset switcher mode when rejecting it. This was preventing to show symbols when calling the action to do it several times in a row. --- spyder/plugins/switcher/container.py | 18 +++++++++++++----- spyder/plugins/switcher/plugin.py | 19 ++++++++----------- spyder/plugins/switcher/widgets/switcher.py | 13 ++++++++----- 3 files changed, 29 insertions(+), 21 deletions(-) diff --git a/spyder/plugins/switcher/container.py b/spyder/plugins/switcher/container.py index 49559bab827..6c323db0a5e 100644 --- a/spyder/plugins/switcher/container.py +++ b/spyder/plugins/switcher/container.py @@ -10,6 +10,7 @@ # Third-party imports from qtpy.QtCore import Qt from qtpy.QtWidgets import QApplication +from superqt.utils import signals_blocked # Spyder imports from spyder.api.translations import _ @@ -21,8 +22,8 @@ class SwitcherContainer(PluginMainContainer): - # --- PluginMainContainer API - # ------------------------------------------------------------------------ + # ---- PluginMainContainer API + # ------------------------------------------------------------------------- def setup(self): self.switcher = Switcher(self._plugin.get_main()) @@ -50,8 +51,8 @@ def setup(self): def update_actions(self): pass - # --- Public API - # ------------------------------------------------------------------------ + # ---- Public API + # ------------------------------------------------------------------------- def open_switcher(self, symbol=False): """Open switcher dialog.""" switcher = self.switcher @@ -62,7 +63,14 @@ def open_switcher(self, symbol=False): # Set mode and setup if symbol: - switcher.set_search_text('@') + # Avoid emitting sig_search_text_available + with signals_blocked(switcher.edit): + switcher.set_search_text('@') + + # Manually set mode and emit sig_mode_selected so that symbols are + # shown instantly. + switcher._mode_on = "@" + switcher.sig_mode_selected.emit("@") else: switcher.set_search_text('') diff --git a/spyder/plugins/switcher/plugin.py b/spyder/plugins/switcher/plugin.py index 85b1ee7f554..13481ff64a0 100644 --- a/spyder/plugins/switcher/plugin.py +++ b/spyder/plugins/switcher/plugin.py @@ -25,9 +25,6 @@ from spyder.plugins.mainmenu.api import ApplicationMenus, FileMenuSections - -# --- Plugin -# ---------------------------------------------------------------------------- class Switcher(SpyderPluginV2): """ Switcher plugin. @@ -85,8 +82,8 @@ class Switcher(SpyderPluginV2): The current search/filter text. """ - # --- SpyderPluginV2 API - # ------------------------------------------------------------------------ + # ---- SpyderPluginV2 API + # ------------------------------------------------------------------------- @staticmethod def get_name(): return _("Switcher") @@ -147,7 +144,7 @@ def on_main_menu_teardown(self): # ---- Public API # ------------------------------------------------------------------------- - # Switcher methods + # --- Switcher methods def set_placeholder_text(self, text): """Set the text appearing on the empty line edit.""" self._switcher.set_placeholder_text(text) @@ -164,7 +161,7 @@ def open_symbolfinder(self): """Open symbol list management dialog.""" self.get_container().open_symbolfinder() - # QDialog methods + # --- QDialog methods def show(self): """Show switcher.""" self._switcher.show() @@ -181,14 +178,14 @@ def is_visible(self): """Return if the switcher is visible.""" return self._switcher.isVisible() - # Item methods + # --- Item methods def current_item(self): """Return the current selected item in the list widget.""" return self._switcher.current_item() def add_item(self, icon=None, title=None, description=None, shortcut=None, section=None, data=None, tool_tip=None, action_item=False, - last_item=True, score=None, use_score=True): + last_item=True, score=-1, use_score=True): """Add a switcher list item.""" self._switcher.add_item(icon, title, description, shortcut, section, data, tool_tip, action_item, @@ -214,7 +211,7 @@ def remove_section(self, section): """Remove all items in a section of the switcher.""" self._switcher.remove_section(section) - # Mode methods + # --- Mode methods def add_mode(self, token, description): """Add mode by token key and description.""" self._switcher.add_mode(token, description) @@ -231,7 +228,7 @@ def clear_modes(self): """Delete all modes spreviously defined.""" self._switcher.clear_modes() - # Lineedit methods + # --- Lineedit methods def set_search_text(self, string): """Set the content of the search text.""" self._switcher.set_search_text(string) diff --git a/spyder/plugins/switcher/widgets/switcher.py b/spyder/plugins/switcher/widgets/switcher.py index ae418346339..d4f9d012d99 100644 --- a/spyder/plugins/switcher/widgets/switcher.py +++ b/spyder/plugins/switcher/widgets/switcher.py @@ -205,6 +205,7 @@ def __init__(self, parent, help_text=None, item_styles=ITEM_STYLES, self.edit.setFocus() # ---- Helper methods + # ------------------------------------------------------------------------- def _add_item(self, item, last_item=True): """Perform common actions when adding items.""" item.set_width(self._ITEM_WIDTH) @@ -218,6 +219,7 @@ def _add_item(self, item, last_item=True): self.set_height() # ---- API + # ------------------------------------------------------------------------- def clear(self): """Remove all items from the list and clear the search text.""" self.set_placeholder_text('') @@ -425,7 +427,7 @@ def current_item_changed(self, current, previous): self.sig_item_changed.emit(self.current_item()) # ---- Qt overrides - # ------------------------------------------------------------------------ + # ------------------------------------------------------------------------- @Slot() @Slot(QListWidgetItem) def enter(self, itemClicked=None): @@ -439,10 +441,6 @@ def enter(self, itemClicked=None): item, mode, self.search_text_without_mode() ) - def accept(self): - """Override Qt method.""" - super().accept() - def reject(self): """Override Qt method.""" # This prevents calling _on_search_text_changed, which unnecessarily @@ -450,10 +448,14 @@ def reject(self): with signals_blocked(self.edit): self.set_search_text('') + # Reset mode + self._mode_on = "" + self.sig_rejected.emit() super().reject() # ---- Helper methods: Lineedit widget + # ------------------------------------------------------------------------- def search_text(self): """Get the normalized (lowecase) content of the search text.""" return to_text_string(self.edit.text()).lower() @@ -495,6 +497,7 @@ def _on_search_text_changed(self): self.setup() # ---- Helper methods: List widget + # ------------------------------------------------------------------------- def _is_separator(self, item): """Check if item is an separator item (SwitcherSeparatorItem).""" return isinstance(item, SwitcherSeparatorItem) From 95f74d48ecbd4f69353ee6220d5e16f3bcc606c4 Mon Sep 17 00:00:00 2001 From: Carlos Cordoba Date: Sun, 31 Dec 2023 13:40:28 -0500 Subject: [PATCH 8/9] Switcher: Fix jumping to different symbols in the editor from it Also, make some small performance improvements for the symbols switcher. --- spyder/plugins/editor/utils/switcher_manager.py | 9 ++++----- spyder/plugins/switcher/plugin.py | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/spyder/plugins/editor/utils/switcher_manager.py b/spyder/plugins/editor/utils/switcher_manager.py index 72e138bf630..ca5542214aa 100644 --- a/spyder/plugins/editor/utils/switcher_manager.py +++ b/spyder/plugins/editor/utils/switcher_manager.py @@ -175,18 +175,17 @@ def create_symbol_switcher(self): symbol_range = symbol['location']['range'] symbol_start = symbol_range['start']['line'] - fold_level = editor.leading_whitespaces[symbol_start] - space = ' ' * fold_level - formated_title = '{space}{title}'.format(title=symbol_name, - space=space) + formated_title = f'{space}{symbol_name}' + icon = ima.icon(SYMBOL_KIND_ICON.get(symbol_kind, 'no_match')) data = { 'title': symbol_name, 'line_number': symbol_start + 1 } last_item = idx + 1 == total_symbols + self._switcher.add_item( title=formated_title, icon=icon, @@ -235,9 +234,9 @@ def handle_switcher_rejection(self): def handle_switcher_item_change(self, current): """Handle item selection change.""" - editorstack = self._editorstack() mode = self._switcher.get_mode() if mode == '@' and current is not None: + editorstack = self._editorstack() line_number = int(current.get_data()['line_number']) editorstack.go_to_line(line_number) diff --git a/spyder/plugins/switcher/plugin.py b/spyder/plugins/switcher/plugin.py index 13481ff64a0..0ba1d81bbf4 100644 --- a/spyder/plugins/switcher/plugin.py +++ b/spyder/plugins/switcher/plugin.py @@ -218,7 +218,7 @@ def add_mode(self, token, description): def get_mode(self): """Get the current mode the switcher is in.""" - self._switcher.get_mode() + return self._switcher.get_mode() def remove_mode(self, token): """Remove mode by token key.""" From 29816cd9211058242cb27c31499932a742bdc468 Mon Sep 17 00:00:00 2001 From: Carlos Cordoba Date: Mon, 1 Jan 2024 13:23:49 -0500 Subject: [PATCH 9/9] Testing: Improve test for the symbol switcher --- spyder/app/tests/test_mainwindow.py | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/spyder/app/tests/test_mainwindow.py b/spyder/app/tests/test_mainwindow.py index 3ee074c8cfd..be0647b2b53 100644 --- a/spyder/app/tests/test_mainwindow.py +++ b/spyder/app/tests/test_mainwindow.py @@ -2440,7 +2440,7 @@ def test_plot_from_collectioneditor(main_window, qtbot): @flaky(max_runs=3) @pytest.mark.use_introspection @pytest.mark.order(after="test_debug_unsaved_function") -def test_switcher(main_window, qtbot, tmpdir): +def test_switcher(main_window, capsys, qtbot, tmpdir): """Test the use of shorten paths when necessary in the switcher.""" switcher = main_window.switcher switcher_widget = switcher._switcher @@ -2490,12 +2490,15 @@ def example_def_2(): main_window.editor.set_current_filename(str(file_a)) code_editor = main_window.editor.get_focus_widget() - qtbot.waitUntil(lambda: code_editor.completions_available, - timeout=COMPLETION_TIMEOUT) + qtbot.waitUntil( + lambda: code_editor.completions_available, + timeout=COMPLETION_TIMEOUT + ) with qtbot.waitSignal( - code_editor.completions_response_signal, - timeout=COMPLETION_TIMEOUT): + code_editor.completions_response_signal, + timeout=COMPLETION_TIMEOUT + ): code_editor.request_symbols() qtbot.wait(9000) @@ -2503,7 +2506,19 @@ def example_def_2(): switcher.open_switcher() qtbot.keyClicks(switcher_widget.edit, '@') qtbot.wait(500) + + # Capture stderr and assert there are no errors + sys_stream = capsys.readouterr() + assert sys_stream.err == '' + + # Check number of items assert switcher_widget.count() == 2 + + # Check that selecting different items in the switcher jumps to the + # corresponding line in the editor + switcher.set_current_row(1) + code_editor.textCursor().blockNumber() == 5 + switcher.on_close()