Skip to content

Commit

Permalink
PR: Define Switcher Plugin public API + fix switcher position bug (#2…
Browse files Browse the repository at this point in the history
…0837)

Co-authored-by: Carlos Cordoba <ccordoba12@gmail.com>
Co-authored-by: Daniel Althviz Moré <d.althviz10@uniandes.edu.co>
  • Loading branch information
3 people authored Apr 25, 2023
1 parent 11dee3c commit 215199d
Show file tree
Hide file tree
Showing 15 changed files with 264 additions and 142 deletions.
4 changes: 2 additions & 2 deletions spyder/app/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -477,8 +477,8 @@ def main_window(request, tmpdir, qtbot):
for editorwindow in window.editor.editorwindows:
editorwindow.close()
editorstack = window.editor.get_current_editorstack()
if editorstack.switcher_dlg:
editorstack.switcher_dlg.close()
if editorstack.switcher_plugin:
editorstack.switcher_plugin.on_close()

window.projects.close_project()

Expand Down
57 changes: 28 additions & 29 deletions spyder/app/tests/test_mainwindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -2392,7 +2392,8 @@ def test_tight_layout_option_for_inline_plot(main_window, qtbot, tmpdir):
@pytest.mark.order(after="test_debug_unsaved_function")
def test_switcher(main_window, qtbot, tmpdir):
"""Test the use of shorten paths when necessary in the switcher."""
switcher = main_window.switcher.get_container().switcher
switcher = main_window.switcher
switcher_widget = switcher._switcher

# Assert that the full path of a file is shown in the switcher
file_a = tmpdir.join('test_file_a.py')
Expand All @@ -2405,11 +2406,11 @@ def example_def_2():
''')
main_window.editor.load(str(file_a))

main_window.switcher.get_container().open_switcher()
switcher_paths = [switcher.model.item(item_idx).get_description()
for item_idx in range(switcher.model.rowCount())]
switcher.open_switcher()
switcher_paths = [switcher_widget.model.item(item_idx).get_description()
for item_idx in range(switcher_widget.model.rowCount())]
assert osp.dirname(str(file_a)) in switcher_paths or len(str(file_a)) > 75
switcher.close()
switcher.on_close()

# Assert that long paths are shortened in the switcher
dir_b = tmpdir
Expand All @@ -2419,21 +2420,21 @@ def example_def_2():
file_b.write('bar\n')
main_window.editor.load(str(file_b))

main_window.switcher.get_container().open_switcher()
file_b_text = switcher.model.item(
switcher.model.rowCount() - 1).get_description()
switcher.open_switcher()
file_b_text = switcher_widget.model.item(
switcher_widget.model.rowCount() - 1).get_description()
assert '...' in file_b_text
switcher.close()
switcher.on_close()

# Assert search works correctly
search_texts = ['test_file_a', 'file_b', 'foo_spam']
expected_paths = [file_a, file_b, None]
for search_text, expected_path in zip(search_texts, expected_paths):
main_window.switcher.get_container().open_switcher()
qtbot.keyClicks(switcher.edit, search_text)
switcher.open_switcher()
qtbot.keyClicks(switcher_widget.edit, search_text)
qtbot.wait(200)
assert switcher.count() == bool(expected_path)
switcher.close()
assert switcher_widget.count() == bool(expected_path)
switcher.on_close()

# Assert symbol switcher works
main_window.editor.set_current_filename(str(file_a))
Expand All @@ -2449,15 +2450,15 @@ def example_def_2():

qtbot.wait(9000)

main_window.switcher.get_container().open_switcher()
qtbot.keyClicks(switcher.edit, '@')
switcher.open_switcher()
qtbot.keyClicks(switcher_widget.edit, '@')
qtbot.wait(200)
assert switcher.count() == 2
switcher.close()
assert switcher_widget.count() == 2
switcher.on_close()


@flaky(max_runs=3)
def test_edidorstack_open_switcher_dlg(main_window, tmpdir, qtbot):
def test_editorstack_open_switcher_dlg(main_window, tmpdir, qtbot):
"""
Test that the file switcher is working as expected when called from the
editorstack.
Expand All @@ -2472,16 +2473,15 @@ def test_edidorstack_open_switcher_dlg(main_window, tmpdir, qtbot):

# Add a file to the editor.
file = tmpdir.join('test_file_open_switcher_dlg.py')
file.write("a test file for test_edidorstack_open_switcher_dlg")
file.write("a test file for test_editorstack_open_switcher_dlg")
main_window.editor.load(str(file))

# Test that the file switcher opens as expected from the editorstack.
editorstack = main_window.editor.get_current_editorstack()
assert editorstack.switcher_dlg is None
editorstack.open_switcher_dlg()
assert editorstack.switcher_dlg
assert editorstack.switcher_dlg.isVisible()
assert (editorstack.switcher_dlg.count() ==
editorstack.switcher_plugin.open_switcher()
assert editorstack.switcher_plugin
assert editorstack.switcher_plugin.is_visible()
assert (editorstack.switcher_plugin.count() ==
len(main_window.editor.get_filenames()))


Expand Down Expand Up @@ -2527,11 +2527,10 @@ def example_def_2():

# Test that the symbol finder opens as expected from the editorstack.
editorstack = main_window.editor.get_current_editorstack()
assert editorstack.switcher_dlg is None
editorstack.open_symbolfinder_dlg()
assert editorstack.switcher_dlg
assert editorstack.switcher_dlg.isVisible()
assert editorstack.switcher_dlg.count() == 2
editorstack.switcher_plugin.open_symbolfinder()
assert editorstack.switcher_plugin
assert editorstack.switcher_plugin.is_visible()
assert editorstack.switcher_plugin.count() == 2


@flaky(max_runs=3)
Expand Down
9 changes: 2 additions & 7 deletions spyder/plugins/editor/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
SelectionContextModificator, ExtraAction)
from spyder.plugins.editor.confpage import EditorConfigPage
from spyder.plugins.editor.utils.autosave import AutosaveForPlugin
from spyder.plugins.switcher.manager import EditorSwitcherManager
from spyder.plugins.editor.utils.switcher_manager import EditorSwitcherManager
from spyder.plugins.editor.widgets.codeeditor import CodeEditor
from spyder.plugins.editor.widgets.editor import (EditorMainWindow,
EditorSplitter,
Expand Down Expand Up @@ -1362,14 +1362,9 @@ def register_plugin(self):

self.add_dockwidget()

# Add modes to switcher
# TODO: 'Switcher' object has no attribute 'add_mode'
# it is needed to create a public API that contains the methods
# that handles the EditorSwitcherManager

self.switcher_manager = EditorSwitcherManager(
self,
self.main.switcher.get_container().switcher,
self.main.switcher,
self.get_current_editor,
self.get_current_editorstack,
section=self.get_plugin_title())
Expand Down
1 change: 1 addition & 0 deletions spyder/plugins/editor/tests/test_editor_config_dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class MainWindowMock(QMainWindow):
ipyconsole = Mock()
mainmenu = Mock()
sig_setup_finished = Mock()
switcher = Mock()


@pytest.mark.parametrize(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class EditorSwitcherManager(object):
LINE_MODE = ':'
FILES_MODE = ''

def __init__(self, plugin, switcher_instance, get_codeeditor,
def __init__(self, plugin, switcher_plugin, get_codeeditor,
get_editorstack, section=_("Editor")):
"""
'get_codeeditor' and 'get_editorstack' params should be callables
Expand All @@ -42,7 +42,7 @@ def __init__(self, plugin, switcher_instance, get_codeeditor,
current_editorstack = get_editorstack()
"""
self._plugin = plugin
self._switcher = switcher_instance
self._switcher = switcher_plugin
self._editor = get_codeeditor
self._editorstack = get_editorstack
self._section = section
Expand Down Expand Up @@ -231,7 +231,7 @@ def line_switcher_handler(self, data, search_text, visible=False):
try:
line_number = int(line_number)
editorstack.go_to_line(line_number)
self._switcher.setVisible(visible)
self._switcher.set_visible(visible)
# Closing the switcher
if not visible:
self._current_line = None
Expand Down
67 changes: 15 additions & 52 deletions spyder/plugins/editor/widgets/editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@
get_filter, is_kde_desktop, is_anaconda)
from spyder.plugins.editor.utils.autosave import AutosaveForStack
from spyder.plugins.editor.utils.editor import get_file_language
from spyder.plugins.switcher.manager import EditorSwitcherManager
from spyder.plugins.editor.widgets import codeeditor
from spyder.plugins.editor.widgets.editorstack_helpers import (
ThreadManager, FileInfo, StackHistory)
Expand Down Expand Up @@ -280,7 +279,7 @@ class EditorStack(QWidget, SpyderConfigurationAccessor):
:py:meth:spyder.plugins.editor.widgets.editor.EditorStack.send_to_help
"""

def __init__(self, parent, actions):
def __init__(self, parent, actions, use_switcher=True):
QWidget.__init__(self, parent)

self.setAttribute(Qt.WA_DeleteOnClose)
Expand All @@ -297,10 +296,17 @@ def __init__(self, parent, actions):
self.setLayout(layout)

self.menu = None
self.switcher_dlg = None
self.switcher_manager = None
self.tabs = None
self.tabs_switcher = None
self.switcher_plugin = None

switcher_action = None
symbolfinder_action = None
if use_switcher:
self.switcher_plugin = self.get_plugin().main.switcher
switcher_action = self.switcher_plugin.get_action("file switcher")
symbolfinder_action = self.switcher_plugin.get_action("symbol finder")

self.stack_history = StackHistory(self)

Expand All @@ -313,16 +319,6 @@ def __init__(self, parent, actions):

self.data = []

switcher_action = create_action(
self,
_("File switcher..."),
icon=ima.icon('filelist'),
triggered=self.open_switcher_dlg)
symbolfinder_action = create_action(
self,
_("Find symbols in file..."),
icon=ima.icon('symbol_find'),
triggered=self.open_symbolfinder_dlg)
copy_to_cb_action = create_action(self, _("Copy path to clipboard"),
icon=ima.icon('editcopy'),
triggered=lambda:
Expand Down Expand Up @@ -792,41 +788,6 @@ def clone_from(self, other):
self.clone_editor_from(other_finfo, set_current=True)
self.set_stack_index(other.get_stack_index())

@Slot()
@Slot(str)
def open_switcher_dlg(self, initial_text=''):
"""Open file list management dialog box"""
if not self.tabs.count():
return
if self.switcher_dlg is not None and self.switcher_dlg.isVisible():
self.switcher_dlg.hide()
self.switcher_dlg.clear()
return
if self.switcher_dlg is None:
from spyder.plugins.switcher.widgets.switcher import Switcher
self.switcher_dlg = Switcher(self)
self.switcher_manager = EditorSwitcherManager(
self.get_plugin(),
self.switcher_dlg,
self.get_current_editor,
lambda: self,
section=self.get_plugin_title())

if isinstance(initial_text, bool):
initial_text = ''

self.switcher_dlg.set_search_text(initial_text)
self.switcher_dlg.setup()
self.switcher_dlg.show()
# Note: the +1 pixel on the top makes it look better
delta_top = (self.tabs.tabBar().geometry().height() +
self.fname_label.geometry().height() + 1)
self.switcher_dlg.set_position(delta_top)

@Slot()
def open_symbolfinder_dlg(self):
self.open_switcher_dlg(initial_text='@')

def get_plugin(self):
"""Get the plugin of the parent widget."""
# Needed for the editor stack to use its own switcher instance.
Expand Down Expand Up @@ -3003,7 +2964,8 @@ class EditorSplitter(QSplitter):
"""QSplitter for editor windows."""

def __init__(self, parent, plugin, menu_actions, first=False,
register_editorstack_cb=None, unregister_editorstack_cb=None):
register_editorstack_cb=None, unregister_editorstack_cb=None,
use_switcher=True):
"""Create a splitter for dividing an editor window into panels.
Adds a new EditorStack instance to this splitter. If it's not
Expand Down Expand Up @@ -3039,7 +3001,7 @@ def __init__(self, parent, plugin, menu_actions, first=False,
self.unregister_editorstack_cb = unregister_editorstack_cb

self.menu_actions = menu_actions
self.editorstack = EditorStack(self, menu_actions)
self.editorstack = EditorStack(self, menu_actions, use_switcher)
self.register_editorstack_cb(self.editorstack)
if not first:
self.plugin.clone_editorstack(editorstack=self.editorstack)
Expand Down Expand Up @@ -3559,13 +3521,14 @@ def __init__(self):
self.editorstacks = []
self.editorwindows = []

self.last_focused_editorstack = {} # fake
self.last_focused_editorstack = {} # fake

self.find_widget = FindReplace(self, enable_replace=True)
self.outlineexplorer = OutlineExplorerWidget(None, self, self)
self.outlineexplorer.edit_goto.connect(self.go_to_file)
self.editor_splitter = EditorSplitter(self, self, menu_actions,
first=True)
first=True,
use_switcher=False)

editor_widgets = QWidget(self)
editor_layout = QVBoxLayout()
Expand Down
2 changes: 1 addition & 1 deletion spyder/plugins/editor/widgets/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def codeeditor_factory():


def editor_factory(new_file=True, text=None):
editorstack = EditorStack(None, [])
editorstack = EditorStack(None, [], False)
editorstack.set_find_widget(FindReplace(editorstack))
editorstack.set_io_actions(Mock(), Mock(), Mock(), Mock())
if new_file:
Expand Down
2 changes: 1 addition & 1 deletion spyder/plugins/editor/widgets/tests/test_editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
# =============================================================================
@pytest.fixture
def base_editor_bot(qtbot):
editor_stack = EditorStack(None, [])
editor_stack = EditorStack(None, [], False)
editor_stack.set_find_widget(Mock())
editor_stack.set_io_actions(Mock(), Mock(), Mock(), Mock())
return editor_stack
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def get_tree_elements(treewidget):
this_tree = {node.name: []}
parent_tree.append(this_tree)
this_stack = [(this_tree[node.name], child)
for child in node.children]
for child in node.children]
stack = this_stack + stack
return root_tree

Expand Down Expand Up @@ -119,7 +119,7 @@ def completions_codeeditor_outline(completions_codeeditor, outlineexplorer):
@pytest.fixture
def editorstack(qtbot, outlineexplorer):
def _create_editorstack(files):
editorstack = editor.EditorStack(None, [])
editorstack = editor.EditorStack(None, [], False)
editorstack.set_find_widget(Mock())
editorstack.set_io_actions(Mock(), Mock(), Mock(), Mock())
editorstack.analysis_timer = Mock()
Expand Down
2 changes: 1 addition & 1 deletion spyder/plugins/editor/widgets/tests/test_editorsplitter.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
# ---- Qt Test Fixtures

def editor_stack():
editor_stack = EditorStack(None, [])
editor_stack = EditorStack(None, [], False)
editor_stack.set_find_widget(Mock())
editor_stack.set_io_actions(Mock(), Mock(), Mock(), Mock())
return editor_stack
Expand Down
2 changes: 1 addition & 1 deletion spyder/plugins/editor/widgets/tests/test_save.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def add_files(editorstack):
# ---- Qt Test Fixtures
@pytest.fixture
def base_editor_bot(qtbot):
editor_stack = editor.EditorStack(None, [])
editor_stack = editor.EditorStack(None, [], False)
editor_stack.set_find_widget(Mock())
editor_stack.set_io_actions(Mock(), Mock(), Mock(), Mock())
return editor_stack, qtbot
Expand Down
2 changes: 1 addition & 1 deletion spyder/plugins/editor/widgets/tests/test_shortcuts.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def editor_bot(qtbot):
Set up EditorStack with CodeEditors containing some Python code.
The cursor is at the empty line below the code.
"""
editorstack = EditorStack(None, [])
editorstack = EditorStack(None, [], False)
editorstack.set_find_widget(Mock())
editorstack.set_io_actions(Mock(), Mock(), Mock(), Mock())
editorstack.close_action.setEnabled(False)
Expand Down
Loading

0 comments on commit 215199d

Please sign in to comment.