On the Fediverse, I had a learning experience:
Another what the heck moment in Fedora 43. In Gnome-terminal (only,
not xterm), hitting 'Delete' in vim insert mode no longer deletes
characters to the left of the cursor, only characters to the
right. Delete is generating ^? in both gnome-terminal and xterm, and
Delete works to delete characters in vim in g-t on the ':' command
prompt.
Whatever vim / gnome-terminal combined stupidity this is, I want it
gone. Now.
Actually I got the name of the key wrong. The key I was hitting is
BackSpace (in X keysym terminology). I thought of it as Delete
because that's what it generates, but the real Delete key is another
key, and this turns out to be relevant. What I described happening
is what I think is normally called as 'forward delete', as opposed
to 'backward delete', the normal BackSpace behavior (and what I
want).
I will skip ahead to the fix: for historical reasons,
I had Gnome-terminal set to generate ASCII DEL for both the BackSpace
and the Delete keys (it's in a per-profile 'Compatibility' tab).
The modern proper setting for Delete is 'escape code'. Setting that
cured the problem, but how we got here is the interesting bit.
Unix has long had both a stty setting for 'what is your backspace
character' and also a termcap/terminfo parameter for 'what does the
backspace key generate' (in terminfo, this is 'kbs'). Things such
as readline, vim and GNU Emacs can use those to determine the
character sequence they should recognize as backspace, or they can
ignore both settings and use hard-coded values. This has historically
been important because there used to be a great split of what
this key generated on serial terminals, and
this split propagated into X and people's X configurations.
(Interestingly, terminfo databases aren't consistent across systems
about what BackSpace is expected to generate in xterm. Linux and
OpenBSD terminfo appears to expect it to generate ^?, but FreeBSD
expects ^H. You can check with 'infocmp | fgrep kbs'. Vim
appears to take its setting from your backspace character from stty,
not terminfo, which is the correct approach.)
Unix has never had a stty setting for 'forward delete', but it did
soon get a terminfo and termcap distinction between the 'backspace'
and 'delete' keys (well, between what character sequences each
sends). In terminfo, what the delete key sends is 'kdch1', and I
don't know when it appeared; in termcap, it is 'kd', which appeared
no latter than 4.3 BSD in 1985, per the 4.3 BSD termcap(5) manual
page.
If your program wants to support forward delete at all (which vim
does) and you can't
see the physical keys being hit, you
have to use 'kdch1'. Well, sort of. You're theoretically supposed
to use kdch1, but in practice kdch1 doesn't necessarily correspond
to the reality of your terminal program and its current settings.
(Termcap was
invented first, in BSD Unix. Terminfo came later and apparently
was first generally available in System V Release 2, in 1984. It's
possible that terminfo had 'kdch1' from the start, since I believe
that by 1984 there were Unix machines with 'full' keyboards with
both BackSpace and Delete. Plus the DEC VT-100 serial terminal also
had both Backspace and Delete keys, and it was introduced in 1978.)
Vim handles keyboard keys through an internal notion of terminal
capabilities and key sequences, and for forward delete the internal
capability is called t_kD. Vim can get its
t_kD value from a number of places; it can get the value from
the regular terminfo kdch1 value, it can derive it from your regular
backspace value (as is done by :fixdel), or it can ask
your terminal program what the various physical keys generate (this is controlled
by the xtermcodes option). When vim
does the last, it will get whatever your terminal program is reporting
about its current settings, not whatever official settings (for
'kdch1' and other things) are published in the system's terminfo
database. This is useful when these settings are controlled through
preferences, instead of being fixed values.
(Specifically, vim and other programs will use xterm's XTGETTCAP
request
to read out various live terminfo settings. This is why it matters
that there is a terminfo thing for the delete key as separate from
the backspace key.)
Vim's xterm-codes
behavior officially happens on 'xterm patchlevel 141 or higher'.
In practice a lot of other terminal emulators imitate xterm here,
and in particular recent enough versions of gnome-terminal do. If
you're curious to see what your terminal program is reporting for
itself, you can start vim and use ':echo v:termresponse' (or
you can run 'tput RV; cat >/dev/null' at your shell command
line, then Ctrl-C it once whatever has echoed). Currently xterm
reports its patchlevel and gnome-terminal reports some sort of VTE
library version, which on
modern versions of Gnome-terminal is (much) larger than '141' (mine
reports '8203'), and triggers vim's behavior of asking the terminal
program for its actual keyboard mapping.
(Technically 'RV' is send device attributes,
not XTVERSION.
You can find programs that query XTVERSION specifically, such as
xtver.)
When Gnome-terminal reported its keyboard mapping to vim, it
apparently reported that both my BackSpace and Delete keys generate
ASCII DEL, which was true (at the time). When vim received this
report, it set both t_kb and t_kD to ASCII DEL (this
is visible with eg ':set t_kb'), and then apparently vim decides
that the <Del> version should take priority over the <BS> version
so that when I hit a key that generates ASCII DEL, vim will do forward
delete instead of backward delete.
(Actual xterm apparently reports something different to vim. Although
both BackSpace and Delete generate ASCII DEL in my xterm setup, vim
reports that t_kD is '^[[3;*~', the normal escape sequence
for it that gnome-terminal will also generate when it's set that
way. This means I have no access to forward delete in vim in xterm,
but that's okay with me; I basically never use it.)
Gnome-terminal support for xterm's XTGETTCAP stuff was apparently
added in mid 2025 through VTE in this feature request and this
commit.
Fedora 42 shipped with a version of gnome-terminal and VTE before
this change, and the Fedora 43 versions are afterward, so now vim
can actually find out what the current key mappings are and trigger
this behavior.
There are at least two ways to fix this through vim in your .vimrc,
and also two ways that don't work. In working ways, if you unset
t_RV ('set
t_RV='), vim never makes the version query and never goes on to
ask for keyboard stuff. If you disable xtermcodes ('set
noxtermcodes'), vim will also never ask for the keyboard mapping,
but now it knows the nominal xterm version number (which isn't
necessarily very useful, given that different projects report wildly
different numbers).
The two ways that don't work in your .vimrc are unsetting t_kD
and using ':fixdel', although both of them work after vim has
finished starting. I assume that both of them don't work because
their effects are being overridden when vim asks the terminal program
for its key bindings. There may be vim magic that you can use to
get around this, but it's better to change your (my) historical
gnome-terminal profile settings so that all profiles have their
'Delete key generates' setting in the Compatibility tab set to
'Escape sequence'.
(There is probably some way to set this preference for all profiles
through the command line but I just did it by hand through the GUI.)
PS: My view is that vim is the party with the bug. Given the behavior
of :fixdel, I think that if vim detects that t_kb and
t_kD are both set to ASCII DEL in the terminal response, it
should either unset t_kD or make it Ctrl-H.
PPS: Since I checked, urxvt (aka rxvt-unicode) does respond to the
xterm RV sequence but reports a version number of '95' as of version
9.31, which is far too low to trigger vim asking for termcap stuff
(and I don't know if urxvt supports that). The Fedora 43 konsole
reports a version number of 115 (for konsole 25.12.3), and I will
leave it up to interested parties to investigate what other terminal
programs report.