views:

309

answers:

2

I'd like to be able to switch temporarily from emacs mode to vi mode, since vi mode is sometimes better, but I'm usually half-way through typing something before I realize I want

I don't want to switch permanently to vi mode, because I normally prefer emacs mode on the command line, mostly because it's what I'm used to, and over the years many of the keystrokes have become second nature. (As an editor I generally use emacs in viper mode, so that I can use both vi and emacs keystrokes, since I found myself accidentally using them in vi all the time, and screwing things up, and because in some cases I find vi keystrokes more memorable and handy, and in other cases emacs.)

+2  A: 

Aha! I looked at the readline source, and found out that you can do this:

 "\M-v": vi-editing-mode
 "\M-e": emacs-editing-mode

There doesn't appear to be a toggle, but that's probably good enough!

For posterity's sake, here's my original answer, which could be useful for people trying to do things for which there is no readline function.

Here's a way you could set it up, clearing the current command line in the process. Not what you want, I know, but maybe it'll help someone else who finds this question. In ~/.inputrc:

"\M-v": "\C-k\C-uset -o vi\C-j" # alt (meta)-v: set vi mode
"\M-e": "\C-k\C-uset -o vi\C-j" # alt (meta)-e: set emacs mode

or to toggle...this should work:

"\M-t": "\C-k\C-u[[ \"$SHELLOPTS\" =~ '\\bemacs\\b' ]] && set -o vi || set -o emacs\C-j"

These are essentially aliases, taken one step farther to map to keys in readline so that you don't have to type an alias name and hit enter.

Jefromi
+3  A: 

You can create a toggle since the key bindings are separate between vi mode and emacs mode.

$ set -o emacs
$ bind '"\ee": vi-editing-mode'
$ set -o vi
$ bind '"\ee": emacs-editing-mode'

Now Alt-e (or Esc e) will toggle between modes.

Add this somewhere in your definition for PS1 so you have an indicator in your prompt of which mode you're in. It won't show the change immediately when you toggle modes, but it will update when a new prompt is issued.

$(set -o | grep emacs.*on >/dev/null 2>&1 && echo E || echo V)
Dennis Williamson
Brandon
The Zsh line editor doesn't seem to support 'vi-editing-mode', only 'vi-cmd-mode'. (You can, however, still use 'set -o vi' or 'bindkey -v' to effectively get a full vi mode.)^xv is bound to vi-cmd-mode in zsh by default. It only lasts for the line it is executed on, and you just hit 'i' to get out of it, which puts you back in emacs mode.In contrast, the bash solution lasts until you switch modes explicitly, and hitting 'i' will put you in vi insert mode.
Brandon
If you put the `$(command)` in the definition of your `PS1` variable, the command will be immediately evaluated - thus your prompt is statically defined, and you have to source your `~/.zshrc` to regenerate the prompt. If you want your prompt to dynamically display a variable/command, you have to modify the `precmd` function which Zsh runs before the prompt is displayed. Put this in your zshrc to fix the mode indicator:
Jabir Ali Ouassou
Jabir Ali Ouassou
`PROMPT="%1v >"`
Jabir Ali Ouassou
By the way, I think you're looking for the ZLE mode `vi-insert` and not `vi-editing-mode` ;)
Jabir Ali Ouassou
@Jabir Ali Ouassou: You can escape the dollar sign (or enclose the command substitution in single quotes) and the command substitution will be evaluated when the prompt is issued rather than when it's defined. Bash requires `shopt -s promptvars` (which is the default). Zsh requires `setopt promptsubst`.
Dennis Williamson
@Dennis Williamson: Thanks a lot, I didn't know that was possible!
Jabir Ali Ouassou