Repository: spyder-ide/spyder
Pull request: PR: Add message when the debug mode is on and the file cannot be closed
<!--- Make sure to read the Contributing Guidelines:                   --->
<!--- https://github.com/spyder-ide/spyder/blob/master/CONTRIBUTING.md --->
<!--- and follow PEP 8, PEP 257 and Spyder's code style:               --->
<!--- https://github.com/spyder-ide/spyder/wiki/Dev:-Coding-Style      --->

## Description of Changes


* [ ] Wrote at least one-line docstrings (for any new functions)
* [ ] Added unit test(s) covering the changes (if testable)
<!--- Remember that an image/animation is worth a thousand words! --->
* [ ] Included a screenshot or animation (if affecting the UI, see [Licecap](https://www.cockos.com/licecap/))


<!--- Explain what you've done and why --->
If the file is in debug mode and the user tries to close that file an informative message will appear in the ipython console.

![debug](https://user-images.githubusercontent.com/20992645/84196250-936c7980-aa65-11ea-8da5-4adda6c9b705.gif)

![image](https://user-images.githubusercontent.com/20992645/84196492-e9412180-aa65-11ea-840a-72286b5f05ca.png)

### Issue(s) Resolved

<!--- List the issue(s) below, in the form "Fixes #1234"; one per line --->

Fixes #12810


### Affirmation

By submitting this Pull Request or typing my (user)name below,
I affirm the [Developer Certificate of Origin](https://developercertificate.org)
with respect to all commits and content included in this PR,
and understand I am releasing the same under Spyder's MIT (Expat) license.

<!--- TYPE YOUR USER/NAME AFTER THE FOLLOWING: --->
I certify the above statement is true and correct: Steff456

<!--- Thanks for your help making Spyder better for everyone! --->


Problem statement:
Can't close any editor tab when in debug mode
## Description

### What steps will reproduce the problem?

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

Tabs can't be closed when code is run in debug mode.



## Versions

* Spyder version: 4.1.3 
* Python version: 3.7.7
* Qt version: 5.9.6
* PyQt5 version: 5.9.2
* Operating System: Linux 5.3.0-53-generic

### Dependencies

```

# Mandatory:
atomicwrites >=1.2.0           :  1.3.0 (OK)
chardet >=2.0.0                :  3.0.4 (OK)
cloudpickle >=0.5.0            :  1.4.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.10 (OK)
qdarkstyle >=2.8               :  2.8.1 (OK)
qtawesome >=0.5.7              :  0.7.0 (OK)
qtconsole >=4.6.0              :  4.7.3 (OK)
qtpy >=1.5.0                   :  1.9.0 (OK)
rtree >=0.8.3                  :  0.9.4 (OK)
sphinx >=0.6.6                 :  3.0.3 (OK)
spyder_kernels >=1.9.1;<1.10.0 :  1.9.1 (OK)
watchdog                       :  None (OK)
xdg >=0.26                     :  0.26 (OK)
zmq >=17                       :  18.1.1 (OK)

# Optional:
cython >=0.21                  :  0.29.17 (OK)
matplotlib >=2.0.0             :  3.1.3 (OK)
numpy >=1.7                    :  1.18.1 (OK)
pandas >=0.13.1                :  1.0.3 (OK)
scipy >=0.17.0                 :  1.4.1 (OK)
sympy >=0.7.3                  :  1.5.1 (OK)
```

Hints from issue discussion:
@ma-sadeghi thanks for your report.

Could you please post an animations using https://www.cockos.com/licecap/ or similar to better understand the current issue.

Thanks!
@goanpeca There you go:
![gif](https://i.imgur.com/DjlBF0K.gif)
This is done by design in order to prevent that a console goes out of sync with the file it's being debugged on it. So you need to go out of the debugger in order to close your file.

@goanpeca, perhaps we should show a message about this?
1 Like a popup? Or 
2 something that gets printed to the console the user is working?

Probably 2 would be nicer and less invasive?
Yeah, I agree with point 2, good idea!

Commit message: add message when the debug mode is on and the file cannot be closed

Patch to review:
diff --git a/spyder/plugins/editor/plugin.py b/spyder/plugins/editor/plugin.py
index 08cad25483f..a11fba4b119 100644
--- a/spyder/plugins/editor/plugin.py
+++ b/spyder/plugins/editor/plugin.py
@@ -85,6 +85,7 @@ class Editor(SpyderPluginWidget):
     breakpoints_saved = Signal()
     run_in_current_extconsole = Signal(str, str, str, bool, bool)
     open_file_update = Signal(str)
+    debugging_file_msg = Signal()
 
     # This signal is fired for any focus change among all editor stacks
     sig_editor_focus_changed = Signal()
@@ -2060,8 +2061,10 @@ def can_close_file(self, filename=None):
         if debugging and 'fname' in last_pdb_step and filename:
             if osp.normcase(last_pdb_step['fname']) == osp.normcase(filename):
                 can_close = False
+                self.debugging_file_msg.emit()
         elif debugging:
             can_close = False
+            self.debugging_file_msg.emit()
         return can_close
 
     @Slot()
diff --git a/spyder/plugins/ipythonconsole/plugin.py b/spyder/plugins/ipythonconsole/plugin.py
index e7660aef78a..462a9c78837 100644
--- a/spyder/plugins/ipythonconsole/plugin.py
+++ b/spyder/plugins/ipythonconsole/plugin.py
@@ -128,6 +128,8 @@ def __init__(self, parent, testing=False, test_dir=None,
 
         self.tabwidget.set_close_function(self.close_client)
 
+        self.main.editor.debugging_file_msg.connect(self.print_debug_file_msg)
+
         if sys.platform == 'darwin':
             tab_container = QWidget()
             tab_container.setObjectName('tab-container')
@@ -1602,3 +1604,12 @@ def _remove_old_stderr_files(self):
                         os.remove(osp.join(tmpdir, fname))
                     except Exception:
                         pass
+
+    def print_debug_file_msg(self):
+        """Print message in the current console when a file can't be closed."""
+        debug_msg = _('<br><hr>'
+                      '\nThe current file cannot be closed because it is '
+                      'in debug mode. \n'
+                      '<hr><br>')
+        self.get_current_client().shellwidget._append_html(
+                    debug_msg, before_prompt=True)


Code review comments:
diff_hunk: @@ -85,6 +85,7 @@ class Editor(SpyderPluginWidget):
     breakpoints_saved = Signal()
     run_in_current_extconsole = Signal(str, str, str, bool, bool)
     open_file_update = Signal(str)
+    debugging_file_msg = Signal()
path: spyder/plugins/editor/plugin.py
text: @user1:
We have for some time now an "unwritten rule" of naming signals starting with the `sig_` prefix and trying to use a name that is like, saved, requested, moved, etc.

So in this case, I suggest we use something like:

`sig_file_debug_message_requested = Signal()`

I know it is a bit long but the idea of having the `requested` in there is that the widget that emits this thing cannot actually perform the action but requests the action to someone else listening to that signal.