How to show the current Vi mode when using Vi keybindings in the shell?

I use the vi keybindings in my tcsh shell.

Now, I don't know which vi mode I'm in (insert mode or command mode), which leads to a lot of frustration.

Does anyone know of a way to show the current vi mode in the shell? (by including in the prompt or something)


Solution 1:

I don't believe there is any way to determine visually what mode your in, but if you modify your behavior a little it won't matter.

If you want to be in command mode, press ESC before typing a command.

If you want to be in insert mode, press ESC and i before typing content.

You will end up pressing ESC a lot, but every vi user I've ever met does that anyway.

Solution 2:

I've had a look through the documentation, and I'd have to say I couldn't find any way to detect and display the current vi-mode. I do hope you have a pleasant surprise and someone comes up with a solution, but I certainly can't see a way to do what you ask.

I think there is a way to do this, but it is massive overkill for a tiny annoyance, and I don't think that's what you had in mind when you posed this question. If this is true, stop reading now and enjoy your life.

OTOH, if this really is your pet peeve, and it's driving you crazy, and you really absolutely desperately wanna gonna smack this problem, here's my idea of how to go about it:

  1. Get a copy of Advanced Programming in the UNIX(R) Environment by W. Richard Stevens.
  2. Read the chapters on Streams and Terminal I/O.
  3. Download the source code to the aforementioned book, which includes an example of a stream that can be layered onto a terminal.
  4. Implement your handling for the Esc key combination (or both mode change keypresses), and indicate it via a bell or background manipulation of the current line.

In brief, Unix implements terminal I/O as a full-duplex I/O stream between the device driver and the user process, into which modules can be inserted. It is organized as a stack, so you can layer as many streams as you want. The sum of the injected streams creates your terminal I/O behaviour.

When a character is entered, the first module gets to inspect it and pass it on (if it wants to). When the response arrives in the opposite direction, it again gets a chance to inspect and pass it on. This is how a Ctrl-C gets handled at a higher level to a normal character key.

You can create a binary implementing a stream module, that when invoked runs silently in the foreground, inspecting and passing on all keystrokes, performing your preferred action on the keystrokes you care about. For all intents and purposes, it'll appear as if you're working on the shell. Oooh. You can invoke this binary on the last (or first, or any) line of your .tcshrc and you wouldn't even know it's there.

There's a good primer here, but I couldn't find much on this topic, probably because it's past its prime.

Solution 3:

This page has a fairly detailed script which sets up what you want (and more) in zsh. Perhaps it could be adapted to work with tcsh (I am not terribly familiar with that shell).

Solution 4:

To anyone having this exact problem (like myself): I found a solution at stackoverflow. Apparently there is native support for this in readline, so you can just add the following to your ~/.inputrc:

set show-mode-in-prompt on

And to customize the actual character use:

set vi-ins-mode-string "custom-ins"
set vi-cmd-mode-string "custom-cmd"