Skip to content

Commit 2bb3542

Browse files
authored
Merge pull request #20317 from ccordoba12/issue-20282
PR: Fix restoring current cursor line after autoformat takes place (Editor)
2 parents da661cc + e55be4d commit 2bb3542

File tree

2 files changed

+77
-14
lines changed

2 files changed

+77
-14
lines changed

spyder/plugins/editor/widgets/codeeditor.py

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -526,7 +526,7 @@ def __init__(self, parent=None):
526526
self.format_on_save = False
527527
self.format_eventloop = QEventLoop(None)
528528
self.format_timer = QTimer(self)
529-
self.__cursor_position_before_format = 0
529+
self.__line_number_before_format = 0
530530

531531
# Mouse tracking
532532
self.setMouseTracking(True)
@@ -1804,10 +1804,6 @@ def handle_go_to_definition(self, position):
18041804
# -------------------------------------------------------------------------
18051805
def format_document_or_range(self):
18061806
"""Format current document or selected text."""
1807-
# Save current cursor position to restore it after the current text has
1808-
# been replaced by the auto-formatted one.
1809-
self.__cursor_position_before_format = self.textCursor().position()
1810-
18111807
if self.has_selected_text() and self.range_formatting_enabled:
18121808
self.format_document_range()
18131809
else:
@@ -1816,6 +1812,8 @@ def format_document_or_range(self):
18161812
@schedule_request(method=CompletionRequestTypes.DOCUMENT_FORMATTING)
18171813
def format_document(self):
18181814
"""Format current document."""
1815+
self.__line_number_before_format = self.textCursor().blockNumber()
1816+
18191817
if not self.formatting_enabled:
18201818
return
18211819
if self.formatting_in_progress:
@@ -1849,6 +1847,8 @@ def format_document(self):
18491847
@schedule_request(method=CompletionRequestTypes.DOCUMENT_RANGE_FORMATTING)
18501848
def format_document_range(self):
18511849
"""Format selected text."""
1850+
self.__line_number_before_format = self.textCursor().blockNumber()
1851+
18521852
if not self.range_formatting_enabled or not self.has_selected_text():
18531853
return
18541854
if self.formatting_in_progress:
@@ -2007,18 +2007,22 @@ def _apply_document_edits(self, edits):
20072007
# Insert formatted text in place of the previous one
20082008
cursor.insertText(merged_text)
20092009

2010-
# Don't run the lines below when testing because they give
2011-
# segfaults.
2012-
if not running_under_pytest():
2013-
# Restore previous cursor position and center it.
2014-
# Fixes spyder-ide/spyder#19958
2015-
cursor.setPosition(self.__cursor_position_before_format)
2016-
self.setTextCursor(cursor)
2017-
self.centerCursor()
2018-
20192010
# End text insertion
20202011
cursor.endEditBlock()
20212012

2013+
# Restore previous cursor line and center it.
2014+
# Fixes spyder-ide/spyder#19958
2015+
if self.__line_number_before_format < self.blockCount():
2016+
self.moveCursor(QTextCursor.Start)
2017+
cursor = self.textCursor()
2018+
cursor.movePosition(
2019+
QTextCursor.Down,
2020+
QTextCursor.MoveAnchor,
2021+
self.__line_number_before_format
2022+
)
2023+
self.setTextCursor(cursor)
2024+
self.centerCursor()
2025+
20222026
# ---- LSP: Code folding
20232027
# -------------------------------------------------------------------------
20242028
def compute_whitespace(self, line):

spyder/plugins/editor/widgets/tests/test_formatting.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@
99
# Standard library imports
1010
import os
1111
import os.path as osp
12+
import random
1213

1314
# Third party imports
1415
import pytest
16+
from qtpy.QtCore import Qt
1517
from qtpy.QtGui import QTextCursor
1618
from qtpy.QtWidgets import QMessageBox
1719
import yapf
@@ -257,3 +259,60 @@ def test_closing_document_formatting(
257259
code_editor = editorstack.load(str(file_path)).editor
258260

259261
assert code_editor.get_text_with_eol() == expected
262+
263+
264+
@pytest.mark.order(1)
265+
@pytest.mark.parametrize('formatter', [autopep8, black])
266+
def test_formatting_on_save(completions_editor, formatter, qtbot):
267+
"""
268+
Check that auto-formatting on save works as expected and that we restore
269+
the current line after doing it.
270+
271+
This includes a regression test for issue spyder-ide/spyder#19958
272+
"""
273+
file_path, editorstack, code_editor, completion_plugin = completions_editor
274+
text, expected = get_formatter_values(formatter, newline='\n')
275+
276+
# Set formatter
277+
editorstack.set_format_on_save(True)
278+
CONF.set(
279+
'completions',
280+
('provider_configuration', 'lsp', 'values', 'formatting'),
281+
formatter
282+
)
283+
284+
with qtbot.waitSignal(completion_plugin.sig_editor_rpc):
285+
completion_plugin.after_configuration_update([])
286+
qtbot.wait(2000)
287+
288+
# Set text in editor
289+
code_editor.set_text(text)
290+
291+
# Notify changes
292+
with qtbot.waitSignal(
293+
code_editor.completions_response_signal, timeout=30000):
294+
code_editor.document_did_change()
295+
296+
# Set a random current line
297+
current_line = random.randint(0, code_editor.blockCount())
298+
code_editor.moveCursor(QTextCursor.Start)
299+
cursor = code_editor.textCursor()
300+
cursor.movePosition(QTextCursor.Down, QTextCursor.MoveAnchor, current_line)
301+
code_editor.setTextCursor(cursor)
302+
qtbot.wait(500)
303+
304+
# Make a simple change to the file
305+
code_editor.moveCursor(QTextCursor.EndOfLine)
306+
qtbot.keyPress(code_editor, Qt.Key_Space)
307+
qtbot.wait(500)
308+
309+
# Save the file
310+
with qtbot.waitSignal(
311+
code_editor.completions_response_signal, timeout=30000):
312+
editorstack.save(force=True)
313+
qtbot.wait(500)
314+
315+
# Check that auto-formatting was applied on save and that we restored the
316+
# previous line.
317+
assert code_editor.get_text_with_eol() == expected
318+
assert code_editor.textCursor().blockNumber() == current_line

0 commit comments

Comments
 (0)