Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PR: Define Switcher Plugin public API + fix switcher position bug #20837

Merged
merged 19 commits into from
Apr 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
ccordoba12 marked this conversation as resolved.
Show resolved Hide resolved

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