If you’ve used Unix much you’ll have noticed that programs really don’t agree on the whole backspace and delete thing. Back when I had Debian on my laptop, it generally worked how I expected. OS X’s Terminal isn’t quite so smooth. I decided to finally sort it all out.

If this saves anyone some effort, great. If not, why did I spend all this time writing an unclear explanation of a stupid problem?

what I wanted

  • backspace (“delete” on my keyboard) to mean “delete the character before the cursor”
  • delete (“fn-delete”) to mean “delete the character after the cursor” (not such a big deal since I never use it)
  • have it work everywhere: bash, vi, emacs, mutt, and curses-based programs (like pkr)
  • have it work locally (OS X) and remotely (Debian and Solaris)
  • minimal changes to configuration files

make it work

I’m using Terminal.app, with $TERM set to xterm-color (in Preferences). “Use option keys as meta key” is checked in Window Settings. That isn’t directly related, but it makes using Emacs a lot nicer. By default, backspace (“delete”) sends ^? and delete (“forward delete”, “fn-delete”) sends ^[[3~ (escape, open square bracket, three, tilde). You can see what your terminal is producing with this C program:
void main(void) {int c; while(c = getchar()) printf("%d 0x%02X\n", c, c);}
Run stty erase undef first.

stty has erase = ^?, the default. That’s ASCII DEL (127 or \177), and it should (ha!) work as backspace everywhere. The terminfo entry for xterm-color (and all the other terminals that Terminal.app emulates) reports the kbs (backspace) capability as ^H. To match it should be \177. I could go the other way and use stty erase ^H, but then C-h wouldn’t run help-command in Emacs unless I fucked around with .emacs. Probably curses-based programs (which actually use terminfo, as far as I can tell) will not work properly, but I don’t use any locally. Bash, Emacs, and Vim all do their own thing.

On okcomputer (Debian), I again have erase = ^? in stty. infocmp reports kbs=^H and kdch1=\177. No good. Setting TERM=xterm-debian fixes that. Now kbs=\177 and kdch1=^[[3~, which is what Terminal.app is emitting. The only problem is that $TERM gets passed on if you connect to other systems, and no other system knows what the fuck xterm-debian is. I might end up making my own xterm terminfo entry. Sigh.


29 March 2004