17

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)

7 Answers 7

4
+100

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.

5
  • 1
    The problem is that, in the shell, the extra ESCs are not ignored - when I give an extra ESC, then type a command (say h to move left), it simply gives a beep and doesn't do anything.
    – Sundar R
    Aug 13, 2009 at 12:50
  • 2
    By "extra ESC", I mean pressing ESC when I'm already in command mode - which I do a lot since I don't know what mode I'm in.
    – Sundar R
    Aug 13, 2009 at 12:50
  • You are correct. I've used it so long that I don't even notice that behaviour any longer. Again, the simplest answer. If you hit ESC and h and nothing happens, hit h again. I think that opens up another question. Why does pressing ESC while in the 'command' mode of the vi keybindings cause the next character to not be interpreted correctly? vi itself doesn't do this. I can type ESC 10 times and the next command still works as anticipated.
    – Bob Weber
    Aug 13, 2009 at 22:54
  • Another tip, turn off the bell. It is incredibly annoying just for the reason you describe - and because it beeps on tab completion. There are various ways of doing this depending on your environment.
    – Bob Weber
    Aug 13, 2009 at 23:01
  • 1
    Ok, I'm currently giving this solution a try. Mapping Caps Lock to Escape has made implementing this easier, but I'm yet to get used to ESC-i for insert mode. I hope I will soon. >If you hit ESC and h and nothing happens, hit h again The problem with this is, it is quite frustrating and breaks the flow a lot. It's an extra thing that I have to think about in addition to the command I'm forming. I prefer vi keybindings for the very reason that they're in my muscle memory and give one less thing to think about - this sort of breaks that purpose itself...
    – Sundar R
    Aug 16, 2009 at 23:56
6

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"
1
  • In bash 5.1.8, I am getting @ symbol before my terminal $PS1 prompt. Mar 24, 2022 at 13:22
3

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.

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).

1
  • I'm not familiar with tcsh either, but I think the page you showed uses zsh widgets (with zle). I don't think other shells have that, but if they do, that would definitely do the trick.
    – BrianH
    Aug 14, 2009 at 19:21
0

Command-Line Editing with tcsh

There are two main modes for editing the command line,
based on the two most commonly used text editors, Emacs and vi.

With the vi bindings, you must switch between insert and command modes;
different commands are useful in each mode.

vi mode has two submodes, insert and command mode.

  • Default mode is insert.
  • You can toggle between the modes by pressing Esc.
  • Alternatively, in command mode,
    typing 'a' (append) or 'i' (insert) will return you to insert mode
    .

More notes on the tcsh customization page already linked above.

1
  • 2
    Your links go to copyrighted O'Reilly books...
    – BrianH
    Aug 14, 2009 at 19:20
0

I had the same exact problem and by accident have found the solution. Although this thread is old, I couldn't find any other website that offered a solution, so I assume posting on this thread is okay.

Just reset the settings of your terminal program or shell. I'm currently using PuTTY, and I just deleted my saved settings for my saved connection, and recreated a saved session. Worked like a charm.

Hope this helps!

0

Please see my answer on SO. Bash 4.4 / Readline 7.0 will add support for this functionality, and in the interim I've published patched versions of Bash 4.3 / Readline 6.3 to github.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .