Skip to content

Commit

Permalink
Merge pull request #21667 from ccordoba12/fix-symbol-switcher
Browse files Browse the repository at this point in the history
PR: Fix errors when displaying the Symbols switcher
  • Loading branch information
ccordoba12 authored Jan 1, 2024
2 parents 37ddbc7 + 29816cd commit fada1c4
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 104 deletions.
25 changes: 20 additions & 5 deletions spyder/app/tests/test_mainwindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -2490,20 +2490,35 @@ 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)

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()


Expand Down
62 changes: 40 additions & 22 deletions spyder/plugins/editor/utils/switcher_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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()
)
Expand Down Expand Up @@ -136,50 +137,66 @@ 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']
if language.lower() == 'python':
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

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}
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):
Expand Down Expand Up @@ -217,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)

Expand All @@ -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
Expand Down
4 changes: 4 additions & 0 deletions spyder/plugins/switcher/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,7 @@
"""
Spyder Switcher API.
"""

class SwitcherActions:
FileSwitcherAction = 'file switcher'
SymbolFinderAction = 'symbol finder'
44 changes: 31 additions & 13 deletions spyder/plugins/switcher/container.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,26 @@
# 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 _
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):

# --- PluginMainContainer API
# ------------------------------------------------------------------------
# ---- PluginMainContainer API
# -------------------------------------------------------------------------
def setup(self):
self.switcher = Switcher(self._plugin.get_main())

# Switcher shortcuts
self.create_action(
'file switcher',
SwitcherActions.FileSwitcherAction,
_('File switcher...'),
icon=self._plugin.get_icon(),
tip=_('Fast switch between files'),
Expand All @@ -36,7 +39,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'),
Expand All @@ -48,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
Expand All @@ -60,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('')

Expand All @@ -70,18 +80,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()
Expand Down
Loading

0 comments on commit fada1c4

Please sign in to comment.