Repository: spyder-ide/spyder

Issue:
Commenting lines that include the first one in a file freezes Spyder
## Description

### What steps will reproduce the problem?

<!--- You can use Markdown here --->

If I select more than one line together, but last or first line should partially selected, and if I try to comment out with Ctrl+1, Spyder crashes.



## Versions

* Spyder version: 4.0.0 
* Python version: 3.7.5
* Qt version: 5.9.6
* PyQt5 version: 5.9.2
* Operating System: Windows 10

### Dependencies

```
cloudpickle >=0.5.0          :  1.2.2 (OK)
pygments >=2.0               :  2.5.2 (OK)
qtconsole >=4.6.0            :  4.6.0 (OK)
nbconvert >=4.0              :  5.6.1 (OK)
sphinx >=0.6.6               :  2.2.2 (OK)
pylint >=0.25                :  2.4.4 (OK)
psutil >=0.3                 :  5.6.7 (OK)
qtawesome >=0.5.7            :  0.6.0 (OK)
qtpy >=1.5.0                 :  1.9.0 (OK)
pickleshare >=0.4            :  0.7.5 (OK)
zmq >=17                     :  18.1.0 (OK)
chardet >=2.0.0              :  3.0.4 (OK)
numpydoc >=0.6.0             :  0.9.1 (OK)
spyder_kernels >=1.8.1;<2.0.0:  1.8.1 (OK)
qdarkstyle >=2.7             :  2.7 (OK)
atomicwrites >=1.2.0         :  1.3.0 (OK)
diff_match_patch >=20181111  :  20181111 (OK)
intervaltree                 :  None (OK)
watchdog                     :  None (OK)
keyring                      :  None (OK)
pexpect >=4.4.0              :  4.7.0 (OK)
pympler                      :  None (OK)
sympy >=0.7.3                :  1.4 (OK)
cython >=0.21                :  0.29.14 (OK)
IPython >=4.0                :  7.10.1 (OK)
matplotlib >=2.0.0           :  3.1.1 (OK)
pandas >=0.13.1              :  0.25.3 (OK)
numpy >=1.7                  :  1.17.4 (OK)
scipy >=0.17.0               :  1.3.2 (OK)
pyls >=0.31.2;<0.32.0        :  0.31.2 (OK)
rtree >=0.8.3                :  0.8.3 (OK)
```



Discussion:
I can't reproduce this. Please post a video (animated gif) with the Licecap program to understand how the crash is generated.
I, too, experience this, but rarely - and in Spyder 3; haven't seen it in 4 yet. Per the unpredictable nature of this bug, making a gif would require monitoring the screen 24/7 (or determining steps to reproduce) - but understandably can't fix what can't be seen break.
same issue when i use spyder4
> or determining steps to reproduce

Exactly. We really need a way to reproduce this.

However, this could be generated by #10918 and that's why it's so elusive.
i have reproduced this issue
in my case, this happened in the first row in editor
![image](https://user-images.githubusercontent.com/17247035/71539234-bfdf7e00-297c-11ea-8454-a773b2aea066.png)
I tried this scenario several times, and get crashed every time.

![Untitled-2](https://user-images.githubusercontent.com/40452678/71574150-8c296300-2af8-11ea-847d-6dce204c8173.png)

Thanks @KimByoungmo and @MuratAmca for the reproducible cases. I can generate the error now.

Resolving patch:
diff --git a/spyder/plugins/editor/widgets/codeeditor.py b/spyder/plugins/editor/widgets/codeeditor.py
--- a/spyder/plugins/editor/widgets/codeeditor.py
+++ b/spyder/plugins/editor/widgets/codeeditor.py
@@ -2609,7 +2609,7 @@ def add_prefix(self, prefix):
                     cursor.insertText(prefix)
                 elif '#' not in prefix:
                     cursor.insertText(prefix)
-                if start_pos == 0 and cursor.blockNumber() == 0:
+                if cursor.blockNumber() == 0:
                     # Avoid infinite loop when indenting the very first line
                     break
                 cursor.movePosition(QTextCursor.PreviousBlock)
@@ -2658,7 +2658,7 @@ def __spaces_for_prefix(self):
                         or number_spaces > left_number_spaces)
                         and not line_text.isspace() and line_text != ''):
                     number_spaces = left_number_spaces
-                if start_pos == 0 and cursor.blockNumber() == 0:
+                if cursor.blockNumber() == 0:
                     # Avoid infinite loop when indenting the very first line
                     break
                 cursor.movePosition(QTextCursor.PreviousBlock)
@@ -3256,7 +3256,7 @@ def __is_comment_bar(cursor):
             return
         while not __is_comment_bar(cursor1):
             cursor1.movePosition(QTextCursor.PreviousBlock)
-            if cursor1.atStart():
+            if cursor1.blockNumber() == 0:
                 break
         if not __is_comment_bar(cursor1):
             return False


Test patch:
diff --git a/spyder/plugins/editor/widgets/tests/test_codeeditor.py b/spyder/plugins/editor/widgets/tests/test_codeeditor.py
--- a/spyder/plugins/editor/widgets/tests/test_codeeditor.py
+++ b/spyder/plugins/editor/widgets/tests/test_codeeditor.py
@@ -216,5 +216,22 @@ def test_in_string(editorbot, input_text, expected_state):
         assert widget.in_string(cursor) == expected_state[1]
 
 
+@pytest.mark.skipif(PY2, reason="Doesn't work with python 2 on travis.")
+def test_comment(editorbot):
+    """
+    Test that in_string works correctly.
+    """
+    qtbot, widget = editorbot
+    widget.set_text("import numpy")
+    cursor = widget.textCursor()
+    cursor.setPosition(8)
+    cursor.setPosition(11, QTextCursor.KeepAnchor)
+    widget.setTextCursor(cursor)
+    qtbot.keyPress(widget, "1", modifier=Qt.ControlModifier)
+    assert widget.toPlainText() == "# import numpy"
+    qtbot.keyPress(widget, "1", modifier=Qt.ControlModifier)
+    assert widget.toPlainText() == "import numpy"
+
+
 if __name__ == '__main__':
     pytest.main(['test_codeeditor.py'])