Repository: spyder-ide/spyder

Issue:
CTRL-S does not save file, if pop-up menu is open
<!--- **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)
* [x] Could not reproduce inside ``jupyter qtconsole`` (if console-related)
* [x] Tried basic troubleshooting (if a bug/error)
    * [x] Restarted Spyder
    * [x] Reset preferences with ``spyder --reset``
    * [x] 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

During the debugging cycle, I sometimes only want to change a tiny detail in a file. When doing this, the command completion menu opens and when I press `CTRL-S` to save the file, the file is not saved. I first have to dismiss the pop-up menu and then I can save the file.

### What steps reproduce the problem?

1. Open a file.
2. Move to a position, where the command completion menu opens and wait for it to pop up.
3. Press `CTRL-S` to save the file.

### What is the expected output? What do you see instead?

I would like the file to be saved immediately when pressing `CTRL-S`, even if a pop-up menu is open, but the file is not saved.

## 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: Spyder 4.2.2  
* Python version: Python 3.8.5 64-bit
* Qt version: Qt 5.12.9
* PyQt version: PyQt5 5.12.3
* Operating System name/version: Linux 5.10.13-surface 

### Dependencies
<!--- Please go to the menu entry Help > Dependencies,
press the Copy to clipboard button and paste below --->

```
# Mandatory:
atomicwrites >=1.2.0            :  1.4.0 (OK)
chardet >=2.0.0                 :  4.0.0 (OK)
cloudpickle >=0.5.0             :  1.6.0 (OK)
diff_match_patch >=20181111     :  20200713 (OK)
intervaltree >=3.0.2            :  3.1.0 (OK)
IPython >=7.6.0                 :  7.20.0 (OK)
jedi =0.17.2                    :  0.17.2 (OK)
jsonschema >=3.2.0              :  3.2.0 (OK)
keyring >=17.0.0                :  22.0.1 (OK)
nbconvert >=4.0                 :  6.0.7 (OK)
numpydoc >=0.6.0                :  1.1.0 (OK)
parso =0.7.0                    :  0.7.0 (OK)
pexpect >=4.4.0                 :  4.6.0 (OK)
pickleshare >=0.4               :  0.7.5 (OK)
psutil >=5.3                    :  5.5.1 (OK)
pygments >=2.0                  :  2.8.0 (OK)
pylint >=1.0                    :  2.7.0 (OK)
pyls >=0.36.2;<1.0.0            :  0.36.2 (OK)
pyls_black >=0.4.6              :  0.4.6 (OK)
pyls_spyder >=0.3.2             :  0.3.2 (OK)
qdarkstyle >=2.8                :  2.8.1 (OK)
qtawesome >=0.5.7               :  1.0.2 (OK)
qtconsole >=5.0.1               :  5.0.2 (OK)
qtpy >=1.5.0                    :  1.9.0 (OK)
setuptools >=39.0.0             :  53.0.0 (OK)
sphinx >=0.6.6                  :  3.5.0 (OK)
spyder_kernels >=1.10.2;<1.11.0 :  1.10.2 (OK)
textdistance >=4.2.0            :  4.2.1 (OK)
three_merge >=0.1.1             :  0.1.1 (OK)
watchdog >=0.10.3;<2.0.0        :  1.0.2 (OK)
xdg >=0.26                      :  0.26 (OK)
zmq >=17                        :  22.0.3 (OK)

# Optional:
cython >=0.21                   :  None (NOK)
matplotlib >=2.0.0              :  3.3.4 (OK)
numpy >=1.7                     :  1.20.1 (OK)
pandas >=1.1.1                  :  1.2.2 (OK)
scipy >=0.17.0                  :  1.6.1 (OK)
sympy >=0.7.3                   :  1.7.1 (OK)
```



Discussion:
Hi @sphh,

I could reproduce this issue, we will work towards enhancing this in one of our future releases.

Thanks for reporting!
I've been bitten by this multiple times! So I totally agree we need to fix it and we'll try to do it in 5.0.1 or 5.0.2.
It is now 24th of February 2022 and the problem still remains with Spyder 5.2.2 :-(
Excellent! :-)

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
@@ -4624,6 +4624,12 @@ def keyPressEvent(self, event):
             # Fixes spyder-ide/spyder#11021
             self._start_completion_timer()
 
+        if event.modifiers() and self.is_completion_widget_visible():
+            # Hide completion widget before passing event modifiers
+            # since the keypress could be then a shortcut
+            # See spyder-ide/spyder#14806
+            self.completion_widget.hide()
+
         if key in {Qt.Key_Up, Qt.Key_Left, Qt.Key_Right, Qt.Key_Down}:
             self.hide_tooltip()
 


Test patch:
diff --git a/spyder/plugins/editor/widgets/tests/test_completions_hide.py b/spyder/plugins/editor/widgets/tests/test_completions_hide.py
--- a/spyder/plugins/editor/widgets/tests/test_completions_hide.py
+++ b/spyder/plugins/editor/widgets/tests/test_completions_hide.py
@@ -6,12 +6,18 @@
 
 """Tests some cases were completions need to be hidden."""
 
+# Standard lirary imports
+import sys
+
 # Third party imports
 from flaky import flaky
 import pytest
 
 from qtpy.QtCore import Qt
 
+# Local imports
+from spyder.config.base import running_in_ci
+
 
 @pytest.mark.slow
 @pytest.mark.order(1)
@@ -105,17 +111,54 @@ def test_automatic_completions_widget_visible(completions_codeeditor, qtbot):
     qtbot.keyPress(code_editor, Qt.Key_Enter, delay=300)  # newline
 
     with qtbot.waitSignal(completion.sig_show_completions,
-                          timeout=10000) as sig:
-        qtbot.keyClicks(code_editor, 'math.aco')
+                          timeout=10000):
+        qtbot.keyClicks(code_editor, 'math.acosh', delay=300)
 
     assert completion.isVisible()
 
     qtbot.keyPress(code_editor, Qt.Key_Backspace, delay=300)
+    qtbot.wait(500)
     assert completion.isVisible()
 
     qtbot.keyPress(code_editor, Qt.Key_Backspace, delay=300)
+    qtbot.wait(500)
     assert completion.isVisible()
 
+    code_editor.toggle_code_snippets(True)
+
+
+@pytest.mark.slow
+@pytest.mark.order(1)
+@flaky(max_runs=5)
+@pytest.mark.skipif(running_in_ci() and sys.platform.startswith('linux'),
+                    reason="Stalls test suite with Linux on CI")
+def test_automatic_completions_hide_on_save(completions_codeeditor, qtbot):
+    """Test on-the-fly completion closing when using save shortcut (Ctrl + S).
+
+    Regression test for issue #14806.
+    """
+    code_editor, _ = completions_codeeditor
+    completion = code_editor.completion_widget
+    code_editor.toggle_code_snippets(False)
+
+    code_editor.set_text('some = 0\nsomething = 1\n')
+    cursor = code_editor.textCursor()
+    code_editor.moveCursor(cursor.End)
+
+    # Complete some -> [some, something]
+    with qtbot.waitSignal(completion.sig_show_completions,
+                          timeout=10000) as sig:
+        qtbot.keyClicks(code_editor, 'some')
+    assert "some" in [x['label'] for x in sig.args[0]]
+    assert "something" in [x['label'] for x in sig.args[0]]
+
+    # Hide completion widget when saving
+    qtbot.keyPress(
+        code_editor, Qt.Key_S, modifier=Qt.ControlModifier, delay=300)
+    qtbot.waitUntil(lambda: completion.isHidden())
+
+    code_editor.toggle_code_snippets(True)
+
 
 if __name__ == '__main__':
     pytest.main(['test_completion.py', '--run-slow'])