Start Edit 1
To answer questions.
Emacs Versions:
- GNU Emacs 25.2.2 (x86_64-pc-linux-gnu, GTK+ Version 3.22.21) of 2017-09-22, modified by Debian
- GNU Emacs 26.3 (build 1, x86_64-w64-mingw32) of 2019-08-29
python-mode version (from C-c C-v) on both platforms:
- Using python-mode version 6.2.3
However, M-x describe-package for python-mode on the Windows shows:
python-mode is an installed package. Status: Installed in python-mode-6.2.3/ (unsigned). Delete Version: 6.2.3 Summary: Python major mode Other versions: 6.2.3 (melpa). [...] Whereas on Linux, M-x describe-package for python-mode says I can install it (even though I'm using 6.2.3 as per C-c C-v above:
python-mode is an available package. Status: Available from melpa -- [Install] Archive: melpa [...] Changing backspace behavior
Changing normal-erase-is-backspace so that backspace deletes forward results in expected behavior (it deletes forward and not also backward), as far as I can tell, though the macro weirdness persists.
I am updating to the Melpa version 20200224.1148 on Linux and trying it out now to see if it changes anything.
Output of describe-key
On Linux
In python-mode on Linux, C-h deletes backward. I ran M-x describe-key on Backspace and got:
DEL runs the command delete-backward-char (found in global-map), which is an interactive compiled Lisp function in simple.el . It is bound to DEL. (delete-backward-char N &optional KILLFLAG) This function is for interactive use only; in Lisp code use delete-char instead. Delete the previous N characters (following if N is negative). If Transient Mark mode is enabled, the mark is active, and N is 1, delete the text in the region and deactivate the mark instead. To disable this, set option delete-active-region to nil. Optional second arg KILLFLAG, if non-nil, means to kill (save in kill ring) instead of delete. Interactively, N is the prefix arg, and KILLFLAG is set if N is explicitly specified. When killing, the killed text is filtered by filter-buffer-substring before it is saved in the kill ring, so the actual saved text might be different from what was killed. In Overwrite mode, single character backward deletion may replace tabs with spaces so as to back over columns, unless point is at the end of the line. NB, M-x describe-key on C-h in python-mode results in nothing but prints You can run the command describe-key with C-h k (in *Messages* as well as the mini-buffer)
Whereas running M-x describe-key-briefly on C-h AND Backspace prints DEL runs the command backward-delete-char-untabify to the mini-buffer.
I am thoroughly confused.
On Windows
C-h k Backspace works! Go figure. I use the exact same .emacs and install packages using the Emacs package manager from Melpa on both OSes (they're in a Git repo). Output:
<backspace> runs the command py-electric-backspace (found in python-mode-map), which is an interactive compiled Lisp function in python-mode.el . It is bound to <backspace>, <menu-bar> <Python> <Other> <Electric> <Electric backspace>. (py-electric-backspace &optional ARG) Delete preceding character or level of indentation. When delete-active-region and (use-region-p), delete region. Unless at indentation: With py-electric-kill-backward-p delete whitespace before point. With py-electric-kill-backward-p at end of a list, empty that list. Returns column reached. [back] M-x describe-key on Backspace does the same while M-x describe-key on Backspace prints <backspace> runs the command py-electric-backspace.
End Edit 1
Start Edit 2
A few more updates (so far ony trouble shooting on Linux):
- Looking at the output of
M-x describe-bindingswhile inpython-modeclearly shows<backspace>bound topy-electric-backspace - Running
M-x py-electric-backspacealways does the right thing - If I bind
py-electric-backspacefrom within the buffer to some other key (e.g. by runningM-x eval-expressionthen(define-key python-mode-map "\C-n" 'py-electric-backspace)), it works as expected. - Removing all key-bindings in my
~/.emacsdoes not solve this M-x describe-bindingsalso shows<backspace>mapped toDELunder theFunction key map translations:section.- Manually setting the
normal-erase-is-backspaceviaM-x set-variable(0 = Off,1 = Maybe,2 = Onor eventornil) does nothing to solve the problem but does toggleBackspacebetweenBackspaceandDEL. - Manually running
M-x normal-erase-is-backspaceturnsBackspaceintoC-h
End Edit 2
EDIT 3 {
I don't believe the root of the problem has really been found. This problem manifests independently of any terminals. It also occurs in graphical Emacs. I decided to try to trace what Emacs was doing using a pre-command-hook:
(defvar *event-log* nil) (defun log-commands nil (let ((buf (current-buffer))) (cl-push `(,buf ,this-command ,(this-command-keys)) *event-log*))) (add-hook 'pre-command-hook 'log-commands) This causes Emacs to log every single keypress to an in-memory list.
From there, I opened a Python source file and put the cursor where the block appears:
def foobar(baz,qux): try: quux.xyzzy()▋ except: pass From there, I added .foobar and then tried to delete it by pressing Backspace twice (enough to reproduce the behavior and also revert back to the correct behavior). The resulting event log, which is in reverse chronological order:
(#<buffer foobar.py> python-indent-dedent-line-backspace "^?") (#<buffer foobar.py> delete-char "^D") (#<buffer foobar.py> self-insert-command "r") (#<buffer foobar.py> self-insert-command "a") (#<buffer foobar.py> self-insert-command "b") (#<buffer foobar.py> self-insert-command "o") (#<buffer foobar.py> self-insert-command "o") (#<buffer foobar.py> self-insert-command "f") (#<buffer foobar.py> self-insert-command ".") It clearly shows that the same key is being received as two distinct keys, and therefore it's executing two different functions. Why this happens remains a mystery, but because it can happen in a GUI session, we can rule out the possibility of terminal settings being to blame. Also note that it's impossible for things like terminal settings or X11 keymap bindings to suddenly change as a result of Emacs keypresses, and even if it was, the behavior would not be consistent between terminals, local X11 sessions, and X11-forwarded sessions.
}
As the title says. Sometimes when I press Backspace, it deletes the character after the cursor (to the right) usually also deleting the character before it (to the left) in python-mode. This seems to happen only on some lines and after at least a 0.25 pause (does not happen when typing quickly).
I have only observed this in python-mode. At first, I thought it might be the python-mode and elpy-mode combo, but it persists with elpy-mode disabled and unloaded.
This seems to happen more frequently when within an f-string (python), at the end of a line, or at the end of a bracket or parentheses pair. I suspect that it might have something to do with hitting the backspace key when python-mode is "thinking" (e.g. trying to autocomplete).
Incidentally, python-mode also seems to make keyboard macros useless, causing all sorts of errors. I often find myself setting the buffer to text-mode, running a macro, and then setting it back to python-mode.
I've tried to set various py-* variables that have to do with delaying or reducing autocomplete, but they don't seem to do anything.
I was not having all these problems with my old and now deprecated python-mode, but it is no more.
Apparently, there is no python-mode tag.
python-modes around, so please clarify exactly which one you're using.C-h k <backspace>tell you? Which command is that key bound to in python mode?normal-erase-is-backspace?python-modeversion 6.2.3 on both platforms. Added Emacs versions tooBackspaceand macro weirdness happens in both.