Repository: spyder-ide/spyder

Issue:
Cannot create Shift+Del as a shortcut for delete line
## Description of your problem

shift+del doesn't work as a shortcut
A very common shortcut (default in sublime and jupyter notebook) for deleting a line is shift +del. changing the shortcut doesn't work
**What steps will reproduce the problem?**
1. change the shortcut for delete line to shift delete
2. try to delete a line
3. it doesn't work

**Please provide any additional information below**
I think shift del should be the default, I think it is the default in sublime and almost every other ide. but ctrl D is also common, so who knows...
## Versions and main components

I tried it on both linux, windows, 3.0 and 2.3.8 and 2.3.9
- Spyder Version:both 3.0.0dev (I took it today from the git) and the stable 2.3.9
- Python Version:2.7
- Operating system:  tested windows and linux
## Dependencies

Please go to the menu entry `Help > Optional Dependencies` (or
`Help > Dependencies`), press the button `Copy to clipboard`
and paste the contents below:
for 2.3.9
IPython >=1.0      :  5.1.0 (OK)
jedi >=0.8.1;<0.9.0:  0.9.0 (NOK)
matplotlib >=1.0   :  1.5.0 (OK)
pandas >=0.13.1    :  0.17.1 (OK)
pep8 >=0.6         :  1.6.2 (OK)
psutil >=0.3       :  4.3.0 (OK)
pyflakes >=0.5.0   :  1.0.0 (OK)
pygments >=1.6     :  2.0.2 (OK)
pylint >=0.25      :  None (NOK)
qtconsole >=4.0    :  4.1.1 (OK)
rope >=0.9.2       :  0.9.4 (OK)
sphinx >=0.6.6     :  1.3.1 (OK)
sympy >=0.7.3      :  0.7.6.1 (OK)
zmq >=2.1.11       :  14.7.0 (OK)



Discussion:
Thanks for reporting. I don't know if we can make a shortcut composed of modifiers only.

@goanpeca, is this possible in Qt?

It should be possible :-|, I will take this after 3.0

well, adding this to codeeditor@keyPressEvent

```
        elif shift and key == Qt.Key_Delete:
            self.delete_line()
```

works

> well, adding this to codeeditor@keyPressEvent [...] works

Is it possible to use `config_shortcut()` so that the user can change the shortcut?

@jitseniesen, yes, there are two things here:
1. We are not using `config_shortcut` for this shortcut
2. I think our shortcuts dialog doesn't admit a sequence like `Shift+Del`, but that should be an easy fix :-)

@malliwi88, this one is easy, please work on it :-)
That's right @ccordoba12 `config_shortcut` has been used only define shortcuts on Spyder plugins, but in this case, our function `delete line` is just defined on widget/editor and It just doesn't have access to `register_shortcuts` function, Which I think might be the most appropriate solution.

What do you think about it @ccordoba12?
@andfoy, please work on this one.
Ctrl+D is deleting characters and lines.

Resolving patch:
diff --git a/spyder/plugins/shortcuts.py b/spyder/plugins/shortcuts.py
--- a/spyder/plugins/shortcuts.py
+++ b/spyder/plugins/shortcuts.py
@@ -61,6 +61,17 @@
 VALID_ACCENT_CHARS = "ÁÉÍOÚáéíúóàèìòùÀÈÌÒÙâêîôûÂÊÎÔÛäëïöüÄËÏÖÜñÑ"
 VALID_FINDER_CHARS = "[A-Za-z\s{0}]".format(VALID_ACCENT_CHARS)
 
+BLACKLIST = {
+    'Shift+Del': _('Currently used to delete lines on editor')
+}
+
+if os.name == 'nt':
+    BLACKLIST['Alt+Backspace'] = _('We cannot support this '
+                                   'shortcut on Windows')
+
+BLACKLIST['Shift'] = _('Shortcuts that use Shift and another key'
+                       ' are unsupported')
+
 
 class CustomLineEdit(QLineEdit):
     """QLineEdit that filters its key press and release events."""
@@ -112,7 +123,8 @@ def keyPressEvent(self, event):
 
 
 # Error codes for the shortcut editor dialog
-NO_WARNING, SEQUENCE_LENGTH, SEQUENCE_CONFLICT, INVALID_KEY = [0, 1, 2, 3]
+(NO_WARNING, SEQUENCE_LENGTH, SEQUENCE_CONFLICT,
+ INVALID_KEY, IN_BLACKLIST, SHIFT_BLACKLIST) = [0, 1, 2, 3, 4, 5]
 
 
 class ShortcutEditor(QDialog):
@@ -317,6 +329,24 @@ def update_warning(self, warning_type=NO_WARNING, conflicts=[]):
             tip_body = tip_body[:-4]  # Removing last <br>
             tip = template.format(tip_title, tip_body)
             warn = True
+        elif warning_type == IN_BLACKLIST:
+            template = '<i>{0}<b>{1}</b></i>'
+            tip_title = _('Forbidden key sequence!') + '<br>'
+            tip_body = ''
+            use = BLACKLIST[self.new_sequence]
+            if use is not None:
+                tip_body = use
+            tip = template.format(tip_title, tip_body)
+            warn = True
+        elif warning_type == SHIFT_BLACKLIST:
+            template = '<i>{0}<b>{1}</b></i>'
+            tip_title = _('Forbidden key sequence!') + '<br>'
+            tip_body = ''
+            use = BLACKLIST['Shift']
+            if use is not None:
+                tip_body = use
+            tip = template.format(tip_title, tip_body)
+            warn = True
         elif warning_type == SEQUENCE_LENGTH:
             # Sequences with 5 keysequences (i.e. Ctrl+1, Ctrl+2, Ctrl+3,
             # Ctrl+4, Ctrl+5) are invalid
@@ -365,8 +395,14 @@ def set_sequence(self, sequence):
         self.new_sequence = sequence
 
         conflicts = self.check_conflicts()
+        blacklist = self.new_sequence in BLACKLIST
+        individual_keys = self.new_sequence.split('+')
         if conflicts and different_sequence:
             warning_type = SEQUENCE_CONFLICT
+        elif blacklist:
+            warning_type = IN_BLACKLIST
+        elif len(individual_keys) == 2 and individual_keys[0] == 'Shift':
+            warning_type = SHIFT_BLACKLIST
         else:
             warning_type = NO_WARNING
 
diff --git a/spyder/widgets/sourcecode/codeeditor.py b/spyder/widgets/sourcecode/codeeditor.py
--- a/spyder/widgets/sourcecode/codeeditor.py
+++ b/spyder/widgets/sourcecode/codeeditor.py
@@ -2764,6 +2764,10 @@ def keyPressEvent(self, event):
                 self.run_cell_and_advance.emit()
             elif ctrl:
                 self.run_cell.emit()
+        elif shift and key == Qt.Key_Delete:
+            # Shift + Del is a Key sequence reserved by most OSes
+            # https://github.com/spyder-ide/spyder/issues/3405
+            self.delete_line()
         elif key == Qt.Key_Insert and not shift and not ctrl:
             self.setOverwriteMode(not self.overwriteMode())
         elif key == Qt.Key_Backspace and not shift and not ctrl:


Test patch: