Repository: spyder-ide/spyder

Issue:
New automatic completion makes it hard to work
<!--- **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

## Problem Description
While I in many ways appreciate the new automatic completion stuff, it also introduced a few challenges. Two which I have isolated and lists here.

It is crucial that Ctrl+s is passed through to the editor. It has happened quite a few times that I have edited a file and pressed Ctrl+s, just to later find out that the file is still marked as modified. (One reason for the many test runs for #9870...)

The behavior below is a bit annoying. What happens is that I press backspace one time to many (in this case it is a Mickey Mouse example) and press return as I would like to insert a line break here again. Not sure what the proper solution is here though (except that I am surprised that the completions start with the first letter of the, earlier, next line, which doesn't really make sense).

![autocompletion](https://user-images.githubusercontent.com/8114497/61584134-18dff600-ab43-11e9-89b2-b7a8a860e763.gif)








Discussion:
I think you can turn it off!
@andfoy, please take look at this one.
After some more use I think a way forward may be:

1) Do not show the completions after a backspace as this happens also for other cases, such as deciding to break a line and backspacing to get rid of the trailing space before pressing return.

2) Pass all(?) command keys (Ctrl+.. etc) to the editor. (I can live with that home, end, page up, and page down are not passed through. After all, hard to guess what the user is thinking...)

I also noted a third issue: the completion does not consider case. If there are two completion entries, say foo and FOO, typing foo and pressing enter will lead to FOO (as that is sorted firstly). In fact, foo is not longer shown among the possible completions at that stage. I think that at least exact matches should be considered.

Code for testing:
```
foo = 1
FOO = 2
```
now type `foo`.


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
@@ -3356,19 +3356,8 @@ def keyPressEvent(self, event):
             word_text = to_text_string(cursor.selectedText())
             # Perform completion on the fly
             if self.automatic_completions:
-                if text == '\b' or text == ' ':
-                    offset = 1 + (text == ' ')
-                    if len(word_text) > 0:
-                        prev_char = word_text[-1]
-                    else:
-                        prev_char = self.get_character(
-                            cursor.position() - offset)
-                    if (prev_char.isalpha() or
-                            (prev_char in self.auto_completion_characters)):
-                        self.do_completion(automatic=True)
-                else:
-                    if text.isalpha():
-                        self.do_completion(automatic=True)
+                if text.isalpha():
+                    self.do_completion(automatic=True)
         if not event.modifiers():
             # Accept event to avoid it being handled by the parent
             # Modifiers should be passed to the parent because they


Test patch:
diff --git a/spyder/plugins/editor/widgets/tests/test_introspection.py b/spyder/plugins/editor/widgets/tests/test_introspection.py
--- a/spyder/plugins/editor/widgets/tests/test_introspection.py
+++ b/spyder/plugins/editor/widgets/tests/test_introspection.py
@@ -13,6 +13,7 @@
 import sys
 
 # Third party imports
+from flaky import flaky
 import pytest
 import pytestqt
 
@@ -98,6 +99,7 @@ def test_hide_widget_completion(lsp_codeeditor, qtbot):
 
 @pytest.mark.slow
 @pytest.mark.first
+@flaky(max_runs=5)
 def test_automatic_completions(lsp_codeeditor, qtbot):
     """Test on-the-fly completions."""
     code_editor, _ = lsp_codeeditor
@@ -131,13 +133,7 @@ def test_automatic_completions(lsp_codeeditor, qtbot):
 
     with qtbot.waitSignal(completion.sig_show_completions,
                           timeout=10000) as sig:
-        qtbot.keyClicks(code_editor, ' ')
-
-    assert "os" in [x['label'] for x in sig.args[0]]
-
-    with qtbot.waitSignal(completion.sig_show_completions,
-                          timeout=10000) as sig:
-        qtbot.keyClicks(code_editor, 'n')
+        qtbot.keyClicks(code_editor, ' n')
 
     assert "ntpath" in [x['label'] for x in sig.args[0]]
 
@@ -149,13 +145,7 @@ def test_automatic_completions(lsp_codeeditor, qtbot):
 
     with qtbot.waitSignal(completion.sig_show_completions,
                           timeout=10000) as sig:
-        qtbot.keyPress(code_editor, Qt.Key_Backspace)
-
-    assert "numbers" in [x['label'] for x in sig.args[0]]
-
-    with qtbot.waitSignal(completion.sig_show_completions,
-                          timeout=10000) as sig:
-        qtbot.keyClicks(code_editor, 'py')
+        qtbot.keyClicks(code_editor, 'y')
 
     # Due to automatic completion, the completion widget may appear before
     stop = False
@@ -170,13 +160,7 @@ def test_automatic_completions(lsp_codeeditor, qtbot):
 
     with qtbot.waitSignal(completion.sig_show_completions,
                           timeout=10000) as sig:
-        qtbot.keyClicks(code_editor, ' ')
-
-    assert "import" in [x['label'] for x in sig.args[0]]
-
-    with qtbot.waitSignal(completion.sig_show_completions,
-                          timeout=10000) as sig:
-        qtbot.keyClicks(code_editor, 'imp')
+        qtbot.keyClicks(code_editor, ' imp')
 
     with qtbot.waitSignal(completion.sig_show_completions,
                           timeout=10000) as sig:
@@ -197,7 +181,7 @@ def test_automatic_completions(lsp_codeeditor, qtbot):
 
     with qtbot.waitSignal(completion.sig_show_completions,
                           timeout=10000) as sig:
-        qtbot.keyClicks(code_editor, ' ')
+        qtbot.keyClicks(code_editor, ' r')
 
     assert "random" in [x['label'] for x in sig.args[0]]
 
diff --git a/spyder/plugins/editor/widgets/tests/test_warnings.py b/spyder/plugins/editor/widgets/tests/test_warnings.py
--- a/spyder/plugins/editor/widgets/tests/test_warnings.py
+++ b/spyder/plugins/editor/widgets/tests/test_warnings.py
@@ -11,6 +11,7 @@
 import sys
 
 # Third party imports
+from flaky import flaky
 import pytest
 from qtpy.QtCore import Qt
 
@@ -193,6 +194,7 @@ def test_update_warnings_after_delete_line(qtbot, lsp_codeeditor):
 
 @pytest.mark.slow
 @pytest.mark.second
+@flaky(max_runs=5)
 def test_update_warnings_after_closequotes(qtbot, lsp_codeeditor):
     """
     Test that code errors are correctly updated after activating closequotes
diff --git a/spyder/plugins/projects/tests/test_plugin.py b/spyder/plugins/projects/tests/test_plugin.py
--- a/spyder/plugins/projects/tests/test_plugin.py
+++ b/spyder/plugins/projects/tests/test_plugin.py
@@ -295,6 +295,7 @@ def test_project_explorer_tree_root(projects, tmpdir, qtbot):
         assert topleft_index.data() == osp.basename(ppath)
 
 
+@flaky(max_runs=5)
 def test_filesystem_notifications(qtbot, projects, tmpdir):
     """
     Test that filesystem notifications are emitted when creating,