Repository: spyder-ide/spyder

Issue:
'Replace selection' reduces selected range
<!--- **PLEASE READ:** When submitting here, please ensure you've completed the following checklist and checked the boxes to confirm. Issue reports without it may be closed. Thanks! --->

### Issue Report Checklist

* [x] Searched the [issues page](https://github.com/spyder-ide/spyder/issues?q=is%3Aissue) for similar reports
* [x] Read the relevant sections of the [Spyder Troubleshooting Guide](https://github.com/spyder-ide/spyder/wiki/Troubleshooting-Guide-and-FAQ) and followed its advice
* [x] Reproduced the issue after updating with ``conda update spyder`` (or ``pip``, if not using Anaconda)
* [ ] Could not reproduce inside ``jupyter qtconsole`` (if console-related)
* [ ] Tried basic troubleshooting (if a bug/error)
    * [x] Restarted Spyder
    * [ ] Reset preferences with ``spyder --reset``
    * [ ] Reinstalled the latest version of [Anaconda](https://www.anaconda.com/download/)
    * [x] Tried the other applicable steps from the Troubleshooting Guide
* [x] Completed the **Problem Description**, **Steps to Reproduce** and **Version** sections below


## Problem Description

When replacing a simple string in selected text with `Replace selection`, Spyder changes the amount of text selected.


### What steps reproduce the problem?

1. Open a new Python file (or use `temp.py`)
2. Write five lines with `# Spyder is not great`
3. Select the five lines
4. Press `Ctrl-R` and enter `not ` and `` in the text boxes
5. Press `Replace selection`

### What is the expected output? What do you see instead?

I would expect that Spyder keeps the selection of the five lines, but after the replacement operation, just  four lines and part of the fifth line (`# Spyder is g`) is selected.


## Versions
<!--- You can get this information from Help > About Spyder...
or (if Spyder won't launch) the "conda list" command
from the Anaconda Prompt/Terminal/command line. --->

* Spyder version: 4.1.2
* Python version: 3.6.9. 64-bit
* Qt version: 5.12.7
* PyQt version: 5.12.3
* Operating System name/version: Linux Mint 19.3 Cinnamon

### Dependencies
<!--- Please go to the menu entry Help > Dependencies,
press the Copy to clipboard button and paste below --->

```

# Mandatory:
atomicwrites >=1.2.0           :  1.3.0 (OK)
chardet >=2.0.0                :  3.0.4 (OK)
cloudpickle >=0.5.0            :  1.3.0 (OK)
diff_match_patch >=20181111    :  20181111 (OK)
intervaltree                   :  None (OK)
IPython >=4.0                  :  7.13.0 (OK)
jedi =0.15.2                   :  0.15.2 (OK)
keyring                        :  None (OK)
nbconvert >=4.0                :  5.6.1 (OK)
numpydoc >=0.6.0               :  0.9.2 (OK)
parso =0.5.2                   :  0.5.2 (OK)
pexpect >=4.4.0                :  4.8.0 (OK)
pickleshare >=0.4              :  0.7.5 (OK)
psutil >=5.3                   :  5.7.0 (OK)
pygments >=2.0                 :  2.6.1 (OK)
pylint >=0.25                  :  2.4.4 (OK)
pyls >=0.31.9;<0.32.0          :  0.31.9 (OK)
qdarkstyle >=2.8               :  2.8 (OK)
qtawesome >=0.5.7              :  0.7.0 (OK)
qtconsole >=4.6.0              :  4.7.1 (OK)
qtpy >=1.5.0                   :  1.9.0 (OK)
sphinx >=0.6.6                 :  2.4.4 (OK)
spyder_kernels >=1.9.0;<1.10.0 :  1.9.0 (OK)
watchdog                       :  None (OK)
xdg >=0.26                     :  0.26 (OK)
zmq >=17                       :  19.0.0 (OK)

# Optional:
cython >=0.21                  :  None (OK)
matplotlib >=2.0.0             :  None (OK)
numpy >=1.7                    :  1.18.2 (OK)
pandas >=0.13.1                :  None (OK)
scipy >=0.17.0                 :  1.4.1 (OK)
sympy >=0.7.3                  :  None (OK)
```



Discussion:
Thanks for reporting. We have confirmed your bug and we'll try to solve it soon.

Resolving patch:
diff --git a/spyder/widgets/findreplace.py b/spyder/widgets/findreplace.py
--- a/spyder/widgets/findreplace.py
+++ b/spyder/widgets/findreplace.py
@@ -612,9 +612,7 @@ def replace_find_selection(self, focus_replace_text=False):
                 cursor.insertText(replacement)
                 # Restore selection
                 self.editor.set_cursor_position(start_pos)
-                newl_cnt = replacement.count(self.editor.get_line_separator())
-                sel_len = len(replacement) - newl_cnt
-                for c in range(sel_len):
+                for c in range(len(replacement)):
                     self.editor.extend_selection_to_next('character', 'right')
                 cursor.endEditBlock()
 


Test patch:
diff --git a/spyder/widgets/tests/test_findreplace.py b/spyder/widgets/tests/test_findreplace.py
--- a/spyder/widgets/tests/test_findreplace.py
+++ b/spyder/widgets/tests/test_findreplace.py
@@ -57,5 +57,30 @@ def test_findreplace_multiline_replacement(findreplace_editor, qtbot):
     assert editor.toPlainText() == expected
 
 
+def test_replace_selection(findreplace_editor, qtbot):
+    """Test find replace final selection in the editor.
+    For further information see spyder-ide/spyder#12745
+    """
+    expected = 'Spyder is greit!\nSpyder is greit!'
+
+    findreplace, editor = findreplace_editor
+    editor.set_text('Spyder as great!\nSpyder as great!')
+    editor.show()
+    editor.select_lines(0, 2)
+
+    findreplace.show()
+    findreplace.show_replace()
+
+    edit = findreplace.search_text.lineEdit()
+    edit.clear()
+    edit.setText('a')
+
+    findreplace.replace_text.setCurrentText('i')
+    findreplace.replace_find_selection()
+    qtbot.wait(1000)
+    assert editor.get_selected_text() == expected
+    assert len(editor.get_selected_text()) == len(expected)
+
+
 if __name__ == "__main__":
     pytest.main([os.path.basename(__file__)])