Skip to content

Commit

Permalink
Merge pull request #16977 from ccordoba12/fix-cell-focus
Browse files Browse the repository at this point in the history
PR: Fix option to maintain focus on editor after running cells or selections
  • Loading branch information
dalthviz committed Dec 8, 2021
2 parents ffffffa + 85da040 commit 1b63a12
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 31 deletions.
69 changes: 69 additions & 0 deletions spyder/app/tests/test_mainwindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -4311,5 +4311,74 @@ def crash_func():
assert 'in crash_func' in control.toPlainText()


@pytest.mark.slow
@flaky(max_runs=3)
@pytest.mark.parametrize("focus_to_editor", [True, False])
def test_focus_to_editor(main_window, qtbot, tmpdir, focus_to_editor):
"""Test that the focus_to_editor option works as expected."""
# Write code with cells to a file
code = """# %%
def foo(x):
return 2 * x
# %%
foo(1)
"""
p = tmpdir.join("test.py")
p.write(code)

# Load code in the editor
main_window.editor.load(to_text_string(p))

# Change focus_to_editor option
main_window.editor.set_option('focus_to_editor', focus_to_editor)
main_window.editor.apply_plugin_settings({(None, 'focus_to_editor')})
code_editor = main_window.editor.get_current_editor()

# Wait for the console to be up
shell = main_window.ipyconsole.get_current_shellwidget()
qtbot.waitUntil(lambda: shell._prompt_html is not None,
timeout=SHELL_TIMEOUT)
control = main_window.ipyconsole.get_widget().get_focus_widget()

# Be sure the focus is on the editor before proceeding
code_editor.setFocus()

# Click the run cell button
run_cell_action = main_window.run_toolbar_actions[1]
run_cell_button = main_window.run_toolbar.widgetForAction(run_cell_action)
qtbot.mouseClick(run_cell_button, Qt.LeftButton)
qtbot.wait(1000)

focus_widget = QApplication.focusWidget()
if focus_to_editor:
assert focus_widget is code_editor
else:
assert focus_widget is control

# Give focus back to the editor before running the next test
if not focus_to_editor:
code_editor.setFocus()

# Move cursor to last line to run it
cursor = code_editor.textCursor()
cursor.movePosition(QTextCursor.End, QTextCursor.MoveAnchor)
cursor.movePosition(QTextCursor.PreviousBlock, QTextCursor.KeepAnchor)
code_editor.setTextCursor(cursor)

# Click the run selection button
run_selection_action = main_window.run_toolbar_actions[3]
run_selection_button = main_window.run_toolbar.widgetForAction(
run_selection_action)
qtbot.mouseClick(run_selection_button, Qt.LeftButton)
qtbot.wait(1000)

focus_widget = QApplication.focusWidget()
if focus_to_editor:
assert focus_widget is code_editor
else:
assert focus_widget is control


if __name__ == "__main__":
pytest.main()
13 changes: 4 additions & 9 deletions spyder/plugins/editor/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,8 @@ class Editor(SpyderPluginWidget, SpyderConfigurationObserver):
# Signals
run_in_current_ipyclient = Signal(str, str, str,
bool, bool, bool, bool, bool)
run_cell_in_ipyclient = Signal(str, object, str, bool)
debug_cell_in_ipyclient = Signal(str, object, str, bool)
run_cell_in_ipyclient = Signal(str, object, str, bool, bool)
debug_cell_in_ipyclient = Signal(str, object, str, bool, bool)
exec_in_extconsole = Signal(str, bool)
redirect_stdio = Signal(bool)

Expand Down Expand Up @@ -1535,14 +1535,9 @@ def register_editorstack(self, editorstack):
editorstack.exec_in_extconsole.connect(
lambda text, option:
self.exec_in_extconsole.emit(text, option))
editorstack.run_cell_in_ipyclient.connect(
lambda code, cell_name, filename, run_cell_copy:
self.run_cell_in_ipyclient.emit(code, cell_name, filename,
run_cell_copy))
editorstack.run_cell_in_ipyclient.connect(self.run_cell_in_ipyclient)
editorstack.debug_cell_in_ipyclient.connect(
lambda code, cell_name, filename, run_cell_copy:
self.debug_cell_in_ipyclient.emit(code, cell_name, filename,
run_cell_copy))
self.debug_cell_in_ipyclient)
editorstack.update_plugin_title.connect(
lambda: self.sig_update_plugin_title.emit())
editorstack.editor_focus_changed.connect(self.save_focused_editorstack)
Expand Down
19 changes: 5 additions & 14 deletions spyder/plugins/editor/widgets/editor.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,8 +180,8 @@ class EditorStack(QWidget):
ending_long_process = Signal(str)
redirect_stdio = Signal(bool)
exec_in_extconsole = Signal(str, bool)
run_cell_in_ipyclient = Signal(str, object, str, bool)
debug_cell_in_ipyclient = Signal(str, object, str, bool)
run_cell_in_ipyclient = Signal(str, object, str, bool, bool)
debug_cell_in_ipyclient = Signal(str, object, str, bool, bool)
update_plugin_title = Signal()
editor_focus_changed = Signal()
zoom_in = Signal()
Expand Down Expand Up @@ -2752,15 +2752,7 @@ def advance_cell(self, reverse=False):
else:
move_func = self.get_current_editor().go_to_previous_cell

if self.focus_to_editor:
move_func()
else:
term = QApplication.focusWidget()
move_func()
term.setFocus()
term = QApplication.focusWidget()
move_func()
term.setFocus()
move_func()

def re_run_last_cell(self):
"""Run the previous cell again."""
Expand Down Expand Up @@ -2795,13 +2787,12 @@ def _run_cell_text(self, text, editor, cell_id, debug=False):
"""
(filename, cell_name) = cell_id
if editor.is_python_or_ipython():
args = (text, cell_name, filename, self.run_cell_copy)
args = (text, cell_name, filename, self.run_cell_copy,
self.focus_to_editor)
if debug:
self.debug_cell_in_ipyclient.emit(*args)
else:
self.run_cell_in_ipyclient.emit(*args)
if self.focus_to_editor and not editor.hasFocus():
editor.setFocus()

# ------ Drag and drop
def dragEnterEvent(self, event):
Expand Down
17 changes: 13 additions & 4 deletions spyder/plugins/ipythonconsole/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,7 @@ def run_script(self, filename, wdir, args, debug, post_mortem,
console_namespace)

def run_cell(self, code, cell_name, filename, run_cell_copy,
function='runcell'):
focus_to_editor, function='runcell'):
"""
Run cell in current or dedicated client.
Expand All @@ -618,6 +618,9 @@ def run_cell(self, code, cell_name, filename, run_cell_copy,
run_cell_copy : bool
True if the cell should be executed line by line,
False if the provided `function` should be used.
focus_to_editor: bool
Whether to give focus to the editor after running the cell. If
False, focus is given to the console.
function : str, optional
Name handler of the kernel function to be used to execute the cell
in case `run_cell_copy` is False.
Expand All @@ -629,9 +632,11 @@ def run_cell(self, code, cell_name, filename, run_cell_copy,
"""
self.get_widget().run_cell(
code, cell_name, filename, run_cell_copy, function=function)
code, cell_name, filename, run_cell_copy, focus_to_editor,
function=function)

def debug_cell(self, code, cell_name, filename, run_cell_copy):
def debug_cell(self, code, cell_name, filename, run_cell_copy,
focus_to_editor):
"""
Debug current cell.
Expand All @@ -647,13 +652,17 @@ def debug_cell(self, code, cell_name, filename, run_cell_copy):
run_cell_copy : bool
True if the cell should be executed line by line,
False if the `debugcell` kernel function should be used.
focus_to_editor: bool
Whether to give focus to the editor after debugging the cell. If
False, focus is given to the console.
Returns
-------
None.
"""
self.get_widget().debug_cell(code, cell_name, filename, run_cell_copy)
self.get_widget().debug_cell(code, cell_name, filename, run_cell_copy,
focus_to_editor)

def execute_code(self, lines, current_client=True, clear_variables=False):
"""
Expand Down
10 changes: 6 additions & 4 deletions spyder/plugins/ipythonconsole/widgets/main_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -2085,7 +2085,7 @@ def print_debug_file_msg(self):

# ---- For cells
def run_cell(self, code, cell_name, filename, run_cell_copy,
function='runcell'):
focus_to_editor, function='runcell'):
"""Run cell in current or dedicated client."""

def norm(text):
Expand All @@ -2112,7 +2112,7 @@ def norm(text):
line = code.strip()

try:
self.execute_code(line, set_focus=False)
self.execute_code(line, set_focus=not focus_to_editor)
except AttributeError:
pass
self.sig_switch_to_plugin_requested.emit()
Expand All @@ -2127,9 +2127,11 @@ def norm(text):
QMessageBox.Ok
)

def debug_cell(self, code, cell_name, filename, run_cell_copy):
def debug_cell(self, code, cell_name, filename, run_cell_copy,
focus_to_editor):
"""Debug current cell."""
self.run_cell(code, cell_name, filename, run_cell_copy, 'debugcell')
self.run_cell(code, cell_name, filename, run_cell_copy,
focus_to_editor, 'debugcell')

# ---- For scripts
def run_script(self, filename, wdir, args, debug, post_mortem,
Expand Down

0 comments on commit 1b63a12

Please sign in to comment.