3

In traditional text editors, whenever I needed to open a string or parentheses and type something between it I used to do:

  1. Type () or ""
  2. Press left
  3. Type in what I need
  4. Press right

But in vim (that is if I followed the vim way) the process becomes quite tedious as I have to enter the normal mode to move a whole bunch of times:

  1. Type () or ""
  2. Press <ESC>
  3. Press i
  4. Type what I need
  5. Press <ESC>
  6. Press l
  7. Press a

If it is not a good practice to use the arrow keys at any time, is there a more efficient way of doing this kind of task in vim?

Community
  • 1
  • 1

3 Answers3

4

No. Doing it in Vim is exactly the same as in your "traditional" editor:

  1. Type () or ""
  2. Press left
  3. Type in what you need
  4. Press right

But… why don't you type the opening character, what you want inside the pair and then the closing character?

  1. Type ( or "
  2. Type what you need
  3. Type ) or "

Too simple?

romainl
  • 186,200
  • 21
  • 280
  • 313
  • 2
    It is actually a good habit to immediately close things again, so one cannot forget any closing. It is well worth the effort of pressing left and right once more. – Zelphir Kaltstahl Oct 23 '16 at 20:57
3

It is actually quite easy to automatically append those closing characters in a mapping, and put your cursor where you want it. The trick is to do that, without also messing up the undo/redo/repeat actions. The problem is that cursor movement commands in insert mode will break the "undo sequence" so that any change you make after moving the cursor is undone separately from changes made before moving the cursor.

Warning: the following information may become dated

There are plenty of plugins available to automatically append these characters (see the partial list at the Vim wiki page for appending closing characters), and prior to Vim 7.4, some of them even had complicated workarounds for keeping the undo sequence intact. Unfortunately, they all relied on a bug in Vim that got fixed in version 7.4 for this.

A patch is available to add a cursor movement that does not break undo, so if you want to compile Vim yourself, you can grab that patch and use mappings like the following (no plugin required!) to do what you want:

inoremap            (          ()<C-G>U<Left> 
inoremap <expr>     )          strpart(getline('.'), col('.')-1, 1) == ")" ? "\<C-G>U\<Right>" : ")" 

These mappings will insert "()" when you type an opening (, placing the cursor in between the parentheses. When you type ')' and there is already a closing ')' after the cursor, Vim will skip over the parenthesis instead of inserting a new one. Cursor movement is preceded by <C-G>U which is the feature the aforementioned patch adds, allowing the following cursor movement to not break the undo sequence (as long as the movement is all in a single line).

As of Vim 7.4.663, this patch has still not been officially included.

Ben
  • 8,725
  • 1
  • 30
  • 48
0

I think using arrow keys to move around is bad practice in normal mode but in your case; moving one space while in insert mode, I would hazard to say using the arrow keys is probably best practice.

That being said if you are dead set on avoiding them you could use <i_ctrl-o>.

:help i_ctrl_o

CTRL-O      execute one command, return to Insert mode   *i_CTRL-O*

So, while in insert mode, you could type: ()<ctrl-o>h<xxx><ctrl-o>l, where <xxx> is whatever you want in the brackets.

Unfortunately that doesn't work if you cursor is on the last character of the line, which if you are typing it most likely is.

To solve that problem do :set virtualedit+=onemore or add it to your ~/.vimrc file.

Note that this solution is more keystrokes than simply using the arrow keys but you don't need to move your hands away from the home row so it may be faster anyway.

Brett Y
  • 7,171
  • 1
  • 28
  • 42