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: Fix pasting code in the Editor #16164

Merged
merged 5 commits into from
Aug 13, 2021
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
57 changes: 35 additions & 22 deletions spyder/plugins/editor/widgets/codeeditor.py
Original file line number Diff line number Diff line change
Expand Up @@ -2803,33 +2803,46 @@ def paste(self):
first_line_selected, *remaining_lines = (text + eol_chars).splitlines()
first_line = preceding_text + first_line_selected

lines_adjustment = CLIPBOARD_HELPER.remaining_lines_adjustment(
preceding_text)

if preceding_text.strip() == "" and first_line.strip != "":
# The indent is controlled by preceding_text. Remove extra indent
extra_indent = self.get_line_indentation(first_line_selected)
lines_adjustment -= extra_indent
first_line = self.adjust_indentation(
first_line, -extra_indent)

# Fix indentation of multiline text
if self.is_python_like() and len(preceding_text.strip()) == 0:
first_line_adjustment = 0

# Dedent if automatic indentation makes code invalid
# Minimum indentation = max of current and paster indentation
if (self.is_python_like() and len(preceding_text.strip()) == 0
and len(first_line.strip()) > 0):
# Correct indentation
desired_indent = self.find_indentation()
if desired_indent:
# minimum indentation is either the current indentation
# or the indentation of the paster text
desired_indent = max(
desired_indent,
self.get_line_indentation(first_line_selected),
self.get_line_indentation(preceding_text))
first_line_adjustment = (
desired_indent - self.get_line_indentation(first_line))
if first_line_adjustment < 0:
# Only dedent, don't indent
lines_adjustment += first_line_adjustment
first_line = self.adjust_indentation(
first_line, first_line_adjustment)

# Get new text
remaining_lines = [
self.adjust_indentation(line, lines_adjustment)
for line in remaining_lines]
# Only dedent, don't indent
first_line_adjustment = min(first_line_adjustment, 0)
# Only dedent, don't indent
first_line = self.adjust_indentation(
first_line, first_line_adjustment)

# Fix indentation of multiline text based on first line
if len(remaining_lines) > 0 and len(first_line.strip()) > 0:
lines_adjustment = first_line_adjustment
lines_adjustment += CLIPBOARD_HELPER.remaining_lines_adjustment(
preceding_text)

# Make sure the code is not flattened
max_dedent = min(
[self.get_line_indentation(line)
for line in remaining_lines if line.strip() != ""])
lines_adjustment = max(lines_adjustment, -max_dedent)

# Get new text
remaining_lines = [
self.adjust_indentation(line, lines_adjustment)
for line in remaining_lines]

text = eol_chars.join([first_line, *remaining_lines])

self.skip_rstrip = True
Expand Down
43 changes: 37 additions & 6 deletions spyder/plugins/editor/widgets/tests/test_codeeditor_1.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,26 +159,57 @@ def test_paste_text(code_editor_bot, text, line_ending_char):
def test_copy_paste_autoindent(code_editor_bot):
"""Test copy pasting text into the editor at different indent."""
editor = code_editor_bot[0]
text = ("if a:\n b\n if c:\n d\n e\n")
expected_text = ("if a:\n b\n d\ne\n if c:\n d\n e\n")
text = ("if a:\n b\n if c:\n d\n if e:\n f\n")
editor.set_text(text)
# Copy
cursor = editor.textCursor()
cursor.setPosition(30)
cursor.setPosition(45, QTextCursor.KeepAnchor)
cursor.setPosition(59, QTextCursor.KeepAnchor)
editor.setTextCursor(cursor)
cb = QApplication.clipboard()
cb.setText("d\n e", mode=cb.Clipboard)
cb.setText("d\n if e:\n f", mode=cb.Clipboard)
editor.copy()

d = {
0: "if a:\n b\nd\nif e:\n f\n if c:\n d\n if e:\n f\n",
4: "if a:\n b\n d\nif e:\n f\n if c:\n d\n if e:\n f\n",
8: "if a:\n b\n d\n if e:\n f\n if c:\n d\n if e:\n f\n",
}
# Paste
for indent in d.keys():
editor.set_text(text)
cursor = editor.textCursor()
cursor.setPosition(11)
cursor.insertText("\n" + indent * ' ')
editor.setTextCursor(cursor)
editor.paste()
assert editor.toPlainText() == d[indent]

# Same thing but with copying the spaces
editor.set_text(text)
# Copy
cursor = editor.textCursor()
cursor.setPosition(30-4)
cursor.setPosition(59, QTextCursor.KeepAnchor)
editor.setTextCursor(cursor)
cb = QApplication.clipboard()
cb.setText(" d\n if e:\n f", mode=cb.Clipboard)
editor.copy()

d = {
0: "if a:\n b\n d\nif e:\n f\n if c:\n d\n if e:\n f\n",
4: "if a:\n b\n d\nif e:\n f\n if c:\n d\n if e:\n f\n",
8: "if a:\n b\n d\n if e:\n f\n if c:\n d\n if e:\n f\n",
}
# Paste
for indent in [4, 8]:
for indent in d.keys():
editor.set_text(text)
cursor = editor.textCursor()
cursor.setPosition(11)
cursor.insertText("\n" + indent * ' ')
editor.setTextCursor(cursor)
editor.paste()
assert editor.toPlainText() == expected_text
assert editor.toPlainText() == d[indent]


if __name__ == "__main__":
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -375,8 +375,6 @@ def test_editor_outlineexplorer(qtbot, completions_codeeditor_outline):
qtbot.keyPress(code_editor, Qt.Key_Return)

qtbot.keyPress(code_editor, Qt.Key_Up)
# Add a tab for correct indentation
qtbot.keyPress(code_editor, Qt.Key_Tab)
code_editor.paste()
qtbot.wait(3000)

Expand Down