I am using zsh on my Mac and after some bindkey trickery I managed to get left/right/delete/backspace to work on zsh (and bash). In git --interactive, this does not work correctly though.

When I try to commit things in interactive mode, only backspace works. When I press left, right, delete I get the ANSI escape sequences for those keys: ^[[D ^[[C ^[[3~. When I look for these in my bindkey list, they seem to be configured correctly though:

% bindkey | \grep -F "^[[D" 
"^[[D" backward-char
% bindkey | \grep -F "^[[C"
"^[[C" forward-char
% bindkey | \grep -F "^[[3~"
"^[[3~" delete-char

This occurs both when I use bash as well as when I use zsh. It also happens when I use X11's xterm instead of Terminal.app. I have found numerous posts regarding these problems in zsh itself (for example this forum, this post or on SU itself), but none of them relate to git.

In short: left/right/delete keys do work in my shell, but not in git --interactive. How can I fix this?


First, special keys are handled by the program itself, not by the tty device. When you press Left, Terminal.app sends ESC [D to bash, and interpreting it is up to bash's Readline library.

The only exceptions are the keys listed in stty -a – when the tty is in "cooked" mode, it itself interprets such keypresses as Backspace. (Bash and Zsh actually use "raw" mode themselves, but switch temporarily to "cooked" before running a program.)

Second, the shells and git --interactive are completely unrelated programs. When you run git, the shell is suspended. All programs get direct access to the tty device, and each uses its own library for interacting with it – bash uses Readline, zsh uses its own ZLE, git --interactive reads from the terminal directly. Bindings made in zsh only apply when zsh, not git, is reading from terminal.

As I said, git --interactive reads from the terminal directly, which means you cannot use Zsh's bindkey or Readline's ~/.inputrc with it. You would have to modify the program to use Readline or a similar library. (Since git-add--interactive is a Perl script, you could rewrite parts of it to use Term::ReadLine, but I don't expect it to be accepted upstream.)

| improve this answer | |
  • Thanks, that clarifies some things! However, unfortunately this does not solve my problem. Is there a way where I can instruct git (or Perl) to interpret my input correctly? Or: why does it go wrong (on my machine) in the first place? – Tim Jul 25 '11 at 10:12
  • @Tim: The post does explain why it goes "wrong" -- the task of interpreting escape sequences is left up to the program itself. git-add--interactive simply reads a line of text without doing any interpretation -- most likely the developers didn't think it was necessary. (And neither do I.) It's not a problem with Git or Perl (in fact, Perl is just a programming language), it's just the way terminals/ttys/programs interact since 1970's or so. As for how to fix it -- see last sentence of last paragraph of the post.) – user1686 Jul 25 '11 at 10:42
  • Grawity: thanks for the elaboration. I do understand your explanation, except I assume that git --interactive printing escape sequences is undesirable behavior. I'm guessing that on other systems this does work as expected, which is why I think the 'problem' might be somewhere on my system, hence my questions. – Tim Jul 25 '11 at 10:58
  • 1
    @Tim: No. It works the same way on all Unix-like systems (BSD, Mac OS X, Linux... they all follow the same terminal/tty/program distinction - which, by the way, is much older than terminals with arrow keys). – user1686 Jul 25 '11 at 11:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.