Vim: record macro entering insert mode via mapping - vim

I'm trying to have remap i/c/o/a and friends to always record a macro. But the keypress that actually brings me into insert mode is not recorded (explained below).
For example, if we have:
nnoremap i qzi
inoremap <esc> <esc>q
Ideally, this means that when I enter insert mode (i), I also start recording to register z. And when I leave (<esc>), we stop recording. So register z should have the entire sequence needed to repeat what I did in insert mode.
But then if I try to type in insert mode (e.g., ihelloworld<esc>) and then check :registers a, I get
---Registers---
"z helloworld^[
Notice how the i command is not included -- only what i typed in insert mode is.
Why is this happening? What can I do to get around it?
I also noticed that if I just typed qzihelloworld<esc> normally, the z register DOES contain ihelloworld<esc> (with the i).
For those interested, I'm doing trying to do this because certain operations break 'repeat last command (the period key .)'. For example, if you use <c-o> or move around while insert-mode, . will only repeat the last segment of your insert mode. In particular, I'm trying to find a workaround for an autoclosing plugin

As #Carpetsmoker explains why it doesn't get recorded:
From :help q
The 'q' command is disabled while executing a register, and it doesn't work inside a mapping and :normal.
So that explains why it doesn't work ...
A solution:
As the command (e.g., i) in the mapping is not recorded, a solution is to prepend it to the recorded buffer when leaving insert mode.
To distinguish between i, a, o, etc, you can store the command in a variable, and then prepend that to the recorded macro:
nnoremap i :let b:mode="i"<cr>qzi
nnoremap a :let b:mode="a"<cr>qza
nnoremap o :let b:mode="o"<cr>qzo
inoremap <Esc> <Esc>q :let #z=":normal! ".b:mode.#z<CR>
Simply prepending i (etc.) to the macro doesn't work (for me) since it triggers the mapping for i. Calling it with normal! fixes that.
Another option is to modify the macro to enter insert using startinsert (combined with suitable movements to emulate i, a, o, etc.) by prepending the macro like this
:let #z=":startinsert^M".#z
caveat: Your rationale for wanting this:
For example, if you use <c-o> or move around while insert-mode, . will only repeat the last segment of your insert mode.
(my emphasis) needs the warning that "moving around" (with arrow keys) does not work (at least in my quick tests) without additional hacking, as the arrow keys send an <esc> ... sequence, triggering the end of the recording mapping for <esc>. c-o will work though, so you can move around (slowly) with e.g. <c-o> h (for moving left).
Another problem is that replaying it as a macro does not work (with this solution at least, perhaps due to the use of normal!) if you have newlines, etc., in the recorded macro. A solution to that is to execute the buffer instead of replaying it as a macro. That is, :exe #z instead of #z for instance with the mapping
nnoremap <space>z :execute #z<cr>

Related

How to use v:count in Vim to switch line with line n lines away?

I would like to create a mapping in vim that would switch the current line with a line that is n lines away.
So far, I have something like this:
:nnoremap gl:<C-U> dd{v:count1}jO<Esc>pjdd{v:count1}o<Esc>p
But it does not work. How can I use the v:count variable in this context?
Mappings are evaluated exactly as typed. Things like v:count are special Vimscript variables, so its value somehow needs to be interpolated into the keys of the right-hand side. With mappings, there are two possibilities:
execute
With :execute, you can break out from the normal mode (started by :nnoremap) into Ex mode and assemble the command; you need :normal! to run the normal mode command(s) that were previously just put as the right-hand side. As Vim automatically translates any [count] given to the mapping into an Ex range, <C-u> is necessary to clear that.
nnoremap <silent> gl :<C-u>execute 'normal! yyma' . v:count1 . "jVp'aVp"<CR>
map-expr
The <expr> modifier adds a layer of indirection to mappings: the right-hand side is evaluated and only the result is taken as the commands to run. There's a similar complication with [count] here; a preceding <Esc> command cancels it (so you only yank a single line).
nnoremap <expr> gl '<Esc>yyma' . v:count1 . "jVp'aVp"
your implementation
I assume you chose gl as the left-hand side, and the :<C-U> is an attempt at escaping, like I've done with my first approach. The space that separates left-hand side from right-hand side is missing there, and the :normal, too.
I've made the following changes to the implementation:
Deleting and pasting next to it complicates the counting; instead, I've used paste over a visual selection (Vp); this automatically puts the removed text into the unnamed register (so it can be reused for the second part of the swap).
Instead of using the count a second time to jump back, I've set a mark (ma) for simplicity. You might also be able to employ the jump list (<C-o>) for this.
other implementations
For simple swaps, your implementation might suffice, but it's far from perfect. There might be a desire to swap multiple (e.g. visually selected) lines, redo a swap elsewhere with ., and check that the destination line actually exists.
The unimpaired.vim plugin has a swap mapping [e. My LineJuggler plugin also has a robust and universal implementation (as well as many other related ones).

Insert a whitespace in normal mode (used in insert mode)

Based on the idea of quick command in insert mode I want to insert my OS clipboard when I am in the insert mode. To make that happen as I want, I have to add a whitespace in the inoremap call, but I do not know how?
This is done with
inoremap VV <Esc>"+gP
Using this:
"vim" is in the OS clipboard
Typing in insert mode "work smart with VV"
leads to the result
work smart withvim
What I want is a whitespace between with and vim
work smart with vim
Any suggestions?
Your issue is caused by the P in "+gP and by the fact that leaving insert mode moves the cursor one character to the left, on the <space>.
P pastes before the cursor so your mapping pastes before the <space>. Changing the P to p should "fix" your problem, in a superficial way.
Here is a more solid alternative that inserts the content of the clipboard register right after the cursor without leaving insert mode:
inoremap VV <C-r>+
Well… what about simply using <C-r>+?
Working around a side effect (here, pasting after the cursor) is not the same as avoiding that side effect (here, not leaving insert mode to begin with). Guess which one is the right approach? ;-)
Use
inoremap VV <Esc>"+gp
P places the clipboard before cursor, p after cursor.
Option 1.
inoremap VV <C-R><C-o>+
Ctrl-R tells vim to insert the contents of a register, and + is the OS clipboard register. It inserts the clipboard contents as if you typed them. The additional <c-o> makes the register contents get inserted literally, so that things like <esc> or ^H (backspace) aren't interpreted like you typed them, but are inserted as text.
Option 2.
inoremap VV <C-o>"+gp
C-o tells vim to go to normal mode for just one command, so you don't need to add <Esc> at start, or i at the end.

vim: how to select pasted block

Is there a vim command to directly select a block of text which has just been pasted?
ps. I know about gv to reselect a block after exiting visual mode. It doesn't apply to this case.
If you want to select it just after paste (before you change anything else), use
nnoremap <expr> gV "`[".getregtype(v:register)[0]."`]"
. [ and ] marks point to start and end of the last change, v:register is set to the last register used (which is register used for the paste command unless you, for example, yank something), [0] selects only first byte of register type (it is required because for blockwise register it returns <C-v>{width}) and register type is one byte which is just the same as the keystroke you should use in normal mode to invoke visual mode.
I saw this solution somewhere on SO, you may want to search for it in order to get some alternatives.
In my case I have this map:
:nnoremap gp `[v`]
After more research I think the better solution is:
" https://vim.fandom.com/wiki/Selecting_your_pasted_text
nnoremap <expr> gp '`[' . strpart(getregtype(), 0, 1) . '`]'
I have had the following maps in my vimrc forever:
nnoremap <leader>p `[V`]
nnoremap <leader>[ `[V`]<
nnoremap <leader>] `[V`]>
They do the following:
visually select the recently pasted block
de-indent the recently pasted block
indent the recently pasted block
I probably use the indent ones even more than the selection one.

How to paste in a new line with vim?

I often have to paste some stuff on a new line in vim. What I usually do is:
o<Esc>p
Which inserts a new line and puts me in insertion mode, than quits insertion mode, and finally pastes.
Three keystrokes. Not very efficient. Any better ideas?
Shortly after :help p it says:
:[line]pu[t] [x] Put the text [from register x] after [line] (default
current line). This always works |linewise|, thus
this command can be used to put a yanked block as
new lines.
:[line]pu[t]! [x] Put the text [from register x] before [line]
(default current line).
Unfortunately it’s not shorter than your current solution unless you combined it with some keyboard map as suggested in a different answer. For instance, you can map it to any key (even p):
:nmap p :pu<CR>
Options:
1) Use yy to yank the whole line (including the end of line character). p will then paste the line on a new line after the current one and P (Shift-P) will paste above the current line.
2) Make a mapping: then it's only one or two keys:
:nmap ,p o<ESC>p
:nmap <F4> o<ESC>p
3) The function version of the mapping (unnecessary really, but just for completeness):
:nmap <F4> :call append(line('.'), #")<CR>
" This one may be a little better (strip the ending new-line before pasting)
:nmap <F4> :call append(line('.'), substitute(#", '\n$', '', ''))<CR>
:help let-register
:help :call
:help append()
:help line()
:help nmap
You can paste a buffer in insert mode using <C-R> followed by the name of the buffer to paste. The default buffer is ", so you would do
o<C-R>"
I found that I use <C-R>" very often and bound that to <C-F> in my vimrc:
inoremap <C-F> <C-R>"
This still uses three keystrokes, but I find it easier than Esc:
o<Alt-p>
Since you're in insert mode after hitting o, the Alt modifier will allow you to use a command as if you weren't.
Using this plugin: https://github.com/tpope/vim-unimpaired
]p pastes on the line below
[p pastes on the line above
advantages:
works on all yanked text (word, line, character, etc)
indents the pasted text to match the indentation of the text
around it
2 keystrokes instead of 3 and much "easier" strokes
fast
Personally I've nmapped Enter (CR) like this:
nmap <CR> o<Esc>k
...based on this Vim Wikia article.
This way I can make newlines directly from normal mode, and combining this with wanting to paste to a newline below I'd do:
<CR>jp
You could also skip k in the nmap above, depending on what functionality you prefer from Enter, so it would just be <CR>p.
I've also imapped jj to Esc, which would also assist in this case. Esc is way too far away from the home row for how significant it is in vim.
Not shorter than the other solutions, but I do think it feels less clunky than some of them, and it has other uses too.
If you wanted to stay in the insert mode, you can do o ctrl+o p
o – insert mode and go to the new line
ctrl+o – run a single command
like in normal mode
p – paste
It's three keystrokes but you stay in insert mode and also o ctrl+o is quite fast so I personally treat it as 2.5 keystrokes.
If you're copying a whole line then pasting a whole line, use Y to yank the line or lines, including line break, in the first place, and p to paste. You can also use V, which is visual line mode, in contrast with plain v for visual mode.
I have mapping inoremap jj <ESC>. So it is easy to insert new line with ojj and Ojj and then p.
so ojjp paste new a newline. it have one more stroke then o<esc>p but ojjp is easy for me.
I found an elegant solution to this. If you are putting the yank register in your OS's clipboard (which is great anyway), with
set clipboard+=unnamed
than you can do o<Ctl-v>.
Besides being fewer strokes, this improves on both o<Esc>p and :pu because it preserves indenting: both of the other options start you at character zero on the new line.
Caveat is that this may or may not be OS dependent. All I know is that it works on recent version of OS X, but clipboard is just one of many ways to get yank in the OS clipboard.
If you want to paste in a new line and still keep indentation, create this mapping:
nnoremap <leader>p oq<BS><Esc>p
Prerequisite: you have leader mapped and you have set autoindent in your .vimrc.
Explanation: a new line is created with 'o', 'q' is typed and then back-spaced on (to keep indentation), and 'esc' brings you back to normal mode where you finally paste.
If you also want to end in insert mode, it is possible to paste while in insert mode using CTRL-R ". https://stackoverflow.com/a/2861909/461834
Still three keystrokes, but no escape, and you save a keystroke if you want to end in insert anyway.
I use the following mapping in my Neovim config:
nnoremap <leader>p m`o<ESC>p``
nnoremap <leader>P m`O<ESC>p``
A little explanation:
m`: set a mark in the current cursor position.
o<Esc>p: create a new line below and paste the text in this line
O<Esc>P: create a new line above and paste the text in this line
``: put the cursor in the original position
See :h mark for more information about marks in Vim.
This solution only seems to apply when the block of copied text starts on a new line (as opposed to grabbing a snippet of text somewhere within a line), but you can always start your copy on the last character you want to grab, then navigate to the last character at the end of line prior to the start of your desired copy block. Then when you want to paste it, place the cursor at the end of the line under which you want your text to be pasted and hit p. If I haven't screwed up the explanation, this should provide the effect you're looking for.

Traversing text in Insert mode

While in Insert Mode in Vim, is there any way to traverse the text moving some characters forward and backward other than using the arrow keys?
If I press h, j, k and l while in Insert mode, the actual characters are printed on screen instead of moving through the text.
The way I'm doing it at the moment is having to resort to Ctrl + [ (Esc) and traversing the text then; but obviously that is not productive.
While it may make sense that you should be able to use the h j k l keys to traverse the editor in insert mode, but that is actually not the way Vim is intended to be used! There are many commands that Vim provides to make editing faster and easier.
The right way is to press Esc, go where you want to do a small correction, fix it, go back and keep editing. It is effective because Vim has much more movements than usual character forward/backward/up/down. After you learn more of them, this will happen to be more productive.
Here are a couple of use-cases:
You accidentally typed "accifentally". No problem, the sequence EscFfrdA will correct the mistake and bring you back to where you were editing. The Ff movement will move your cursor backwards to the first encountered "f" character. Compare that with Ctrl+←→→→→DeldEnd, which does virtually the same in a casual editor, but takes more keystrokes and makes you move your hand out of the alphanumeric area of the keyboard.
You accidentally typed "you accidentally typed", but want to correct it to "you intentionally typed". Then Esc2bcw will erase the word you want to fix and bring you to insert mode, so you can immediately retype it. To get back to editing, just press A instead of End, so you don't have to move your hand to reach the End key.
You accidentally typed "mouse" instead of "mice". No problem - the good old Ctrl+w will delete the previous word without leaving insert mode. And it happens to be much faster to erase a small word than to fix errors within it. I'm so used to it that I had closed the browser page when I was typing this message...!
Repetition count is largely underused. Before making a movement, you can type a number; and the movement will be repeated this number of times. For example, 15h will bring your cursor 15 characters back and 4j will move your cursor 4 lines down. Start using them and you'll get used to it soon. If you made a mistake ten characters back from your cursor, you'll find out that pressing the ← key 10 times is much slower than the iterative approach to moving the cursor. So you can instead quickly type the keys 12h (as a rough of guess how many characters back that you need to move your cursor), and immediately move forward twice with ll to quickly correct the error.
But, if you still want to do small text traversals without leaving insert mode, follow rson's advice and use Ctrl+O. Taking the first example that I mentioned above, Ctrl+OFf will move you to a previous "f" character and leave you in insert mode.
While in insert mode, use CtrlO to go to normal mode for just one command:
CTRL-O h move cursor left
CTRL-O l move cursor right
CTRL-O j move cursor down
CTRL-O k move cursor up
which is probably the simplest way to do what you want and is easy to remember.
Other very useful control keys in insert mode:
CTRL-W delete word to the left of cursor
CTRL-O D delete everything to the right of cursor
CTRL-U delete everything to the left of cursor
CTRL-H backspace/delete
CTRL-J insert newline (easier than reaching for the return key)
CTRL-T indent current line
CTRL-D un-indent current line
these will eliminate many wasteful switches back to normal mode.
Insert mode
Movement
hjkl
Notwithstanding what Pavel Shved said - that it is probably more advisable to get used to Escaping Insert mode - here is an example set of mappings for quick navigation within Insert mode:
" provide hjkl movements in Insert mode via the <Alt> modifier key
inoremap <A-h> <C-o>h
inoremap <A-j> <C-o>j
inoremap <A-k> <C-o>k
inoremap <A-l> <C-o>l
This will make Alt+h in Insert mode go one character left, Alt+j down and so on, analogously to hjkl in Normal mode.
You have to copy that code into your vimrc file to have it loaded every time you start vim (you can open that by typing :new $myvimrc starting in Normal mode).
Any Normal mode movements
Since the Alt modifier key is not mapped (to something important) by default, you can in the same fashion pull other (or all) functionality from Normal mode to Insert mode. E.g.:
Moving to the beginning of the current word with Alt+b:
inoremap <A-b> <C-o>b
inoremap <A-w> <C-o>w
(Other uses of Alt in Insert mode)
It is worth mentioning that there may be better uses for the Alt key than replicating Normal mode behaviour: e.g. here are mappings for copying from an adjacent line the portion from the current column till the end of the line:
" Insert the rest of the line below the cursor.
" Mnemonic: Elevate characters from below line
inoremap <A-e>
\<Esc>
\jl
\y$
\hk
\p
\a
" Insert the rest of the line above the cursor.
" Mnemonic: Y depicts a funnel, through which the above line's characters pour onto the current line.
inoremap <A-y>
\<Esc>
\kl
\y$
\hj
\p
\a
(I used \ line continuation and indentation to increase clarity. The commands are interpreted as if written on a single line.)
Built-in hotkeys for editing
CTRL-H delete the character in front of the cursor (same as <Backspace>)
CTRL-W delete the word in front of the cursor
CTRL-U delete all characters in front of the cursor (influenced by the 'backspace' option)
(There are no notable built-in hotkeys for movement in Insert mode.)
Reference: :help insert-index
Command-line mode
This set of mappings makes the upper Alt+hjkl movements available in the Command-line:
" provide hjkl movements in Command-line mode via the <Alt> modifier key
cnoremap <A-h> <Left>
cnoremap <A-j> <Down>
cnoremap <A-k> <Up>
cnoremap <A-l> <Right>
Alternatively, these mappings add the movements both to Insert mode and Command-line mode in one go:
" provide hjkl movements in Insert mode and Command-line mode via the <Alt> modifier key
noremap! <A-h> <Left>
noremap! <A-j> <Down>
noremap! <A-k> <Up>
noremap! <A-l> <Right>
The mapping commands for pulling Normal mode commands to Command-line mode look a bit different from the Insert mode mapping commands (because Command-line mode lacks Insert mode's Ctrl+O):
" Normal mode command(s) go… --v <-- here
cnoremap <expr> <A-h> &cedit. 'h' .'<C-c>'
cnoremap <expr> <A-j> &cedit. 'j' .'<C-c>'
cnoremap <expr> <A-k> &cedit. 'k' .'<C-c>'
cnoremap <expr> <A-l> &cedit. 'l' .'<C-c>'
cnoremap <expr> <A-b> &cedit. 'b' .'<C-c>'
cnoremap <expr> <A-w> &cedit. 'w' .'<C-c>'
Built-in hotkeys for movement and editing
CTRL-B cursor to beginning of command-line
CTRL-E cursor to end of command-line
CTRL-F opens the command-line window (unless a different key is specified in 'cedit')
CTRL-H delete the character in front of the cursor (same as <Backspace>)
CTRL-W delete the word in front of the cursor
CTRL-U delete all characters in front of the cursor
CTRL-P recall previous command-line from history (that matches pattern in front of the cursor)
CTRL-N recall next command-line from history (that matches pattern in front of the cursor)
<Up> recall previous command-line from history (that matches pattern in front of the cursor)
<Down> recall next command-line from history (that matches pattern in front of the cursor)
<S-Up> recall previous command-line from history
<S-Down> recall next command-line from history
<PageUp> recall previous command-line from history
<PageDown> recall next command-line from history
<S-Left> cursor one word left
<C-Left> cursor one word left
<S-Right> cursor one word right
<C-Right> cursor one word right
<LeftMouse> cursor at mouse click
Reference: :help ex-edit-index
If you are a vim purist, skip reading this answer. OTOH, if you are new to vim and are looking for a few helpful tips you wont find in the many hundred of vim tutorials and blogs, read on... :-)
A few un-orthodox (vim) ways
It's 2014, and as someone who's recently gone back to vim I can offer a few, potentially contrarian, points of view and tips.
Use shift+left or shift+right to traverse words
While repetition is a powerful concept in vim, I (personally) find it strange that using it either forces me to count (lines, characters, words, etc.) or make guesses. My brain usually works like "I want the cursor there" and not like "I want the cursor _5_words_to_the_left_". Quickly being able to move the cursor, and visually observe where the insertion point this way allows me to keep my mind on what I'm editing instead of having to count how many hops I need to make to get to where I need to edit.
Turn on mouse mode, and use the mouse wheel and clicking
...to navigate large bodies of text.
Most (all) modern computers have a touchpad that is closely integrated with the keyboard (e.g. MacBooks). Industrial designers have spent many man years optimizing these designs so that the old problem of having to move the hand away from the keyboard is no longer a real issue. Okay, it is if you are used to a mouse and don't like to switch, but for anyone new to vim (like those that might find this post via a search), this should not be much of an issue.
As a bonus, click + drag puts you in visual mode
With mouse enabled, clicking and dragging has the effect of switching to visual mode and marking a region for yanking.
And use the scroll wheel
Using the mouse (wheel) to scroll around, and clicking to position the cursor (duh) just works. See http://usevim.com/2012/05/16/mouse/ for more on this.
And so...
These are what I'd call more modern (using mouse, scroll wheel, etc.) ways of navigating in vim, equally effective depending on your preference of input.
HTH
Many people in the Vim community argue that you should not navigate in Insert mode, that it is not the Vim way. I think this is an incorrect sentiment learned when transitioning from standard editors to Vim.
Vim is most powerful when you use its tools to create atomic, repeatable actions or finds.
It is ok to navigate while in Insert mode if you are fixing a mistake you made in the same Insert session. You should not navigate outside of the range of text you modified.
If you make a mistake while entering text and escape out of Insert mode to fix it you will not be able to repeat the intended action, . will repeat the correction.
Vim does support many Insert mode navigation keys. Obviously there are the arrow keys, Home, and End, but there are also many other shortcuts. See :h ins-special-keys.
To have a little better navigation in insert mode, why not map some keys?
imap <C-b> <Left>
imap <C-f> <Right>
imap <C-e> <End>
imap <C-a> <Home>
" <C-a> is used to repeat last entered text. Override it, if its not needed
If you can work around making the Meta key work in your terminal, you can mock emacs mode even better. The navigation in normal-mode is way better, but for shorter movements it helps to stay in insert mode.
For longer jumps, I prefer the following default translation:
<Meta-b> maps to <Esc><C-left>
This shifts to normal-mode and goes back a word
In GVim, you can use the mouse. But honestly, what's wrong with using the arrow keys? There's a reason why they are on a keyboard.
I believe Home and End (and PageUp/PageDn) also work normally while in insert mode, but aside from that, I don't believe there are any other standard keys defined for text traversal.
Sorry but vim don't work that way.
You should switch to "normal" mode, navigate and then go back to insert again.
You can create mappings that work in insert mode. The way to do that is via inoremap. Note the 'i' at the beginning of the command (noremap is useful to avoid key map collisions). The corollary is 'n' for 'normal' mode. You can surmise what vim thinks is 'normal' ;)
HOWEVER, you really want to navigate around in text using 'normal' mode. Vim is super at this kind of thing and all that power is available from normal mode. Vim already provides easy ways to get from normal mode to insert mode (e.g., i, I, a, A, o, O). The trick is to make it easy to get into normal mode. The way to do that is to remap escape to a more convient key. But you need one that won't conflict with your regular typing. I use:
inoremap jj <Esc>
Since jj (that's 2 j's typed one after the other quickly) doesn't seem to appear in my vocabulary. Other's will remap to where it's comfortable.
The other essential change I make is to switch the CAPSLOCK and CONTROL keys on my keyboard (using the host computer's keyboard configuration) since I almost never use CAPSLOCK and it has that big, beautiful button right where I want it. (This is common for Emacs users. The downside is when you find yourself on an 'unfixed' keyboard! Aaarggh!)
Once you remap CAPSLOCK, you can comfortably use the following insert mode remappings:
Keeping in mind that some keys are already mapped in insert mode (backwards-kill-word is C-w (Control-w) by default, you might already have the bindings you want. That said, I prefer C-h so in my .vimrc I have:
inoremap <C-h> <C-w>
BUT, you probably want the same muscle memory spasm in normal mode, so I also map C-h as:
nnoremap <C-h> db
(d)elete (b)ackwards accomplishes the same thing with the same key chord. This kind of quick edit is one that I find useful in practice for typos. But stick to normal mode for moving around in text and anything more than killing the previous word. Once you get into the habit of changing modes (using a remap of course), it will be much more efficient than remapping insert mode.
Yes, there is a way. You can use gj and gk inside Insert Mode to move up (backwards) and down (forwards) within a single logical-line that wraps around numerous visual-lines. That is handy if you have very long lines and/or a narrow width terminal and can be much faster than the arrow keys, or hitting ESC to use the other navigation shortcuts. Also you can use CTRL-O to issue one normal-mode command. Neither of these navigation movements will escape you out of insert mode.
It can be disruptive to productivity to hit ESC (which was besides home-row on terminal keyboards when Vi was invented). I work with text files that have extremely long logical-lines, whole paragraphs of sentences full of plain text. These two options are a real time saver for me. It's still handy to escape out to normal-mode if I need to hunt for a particular word within the paragraph, but many times I just need to move a visual-line up or down, and then continue inserting.
I actually edit my .vimrc to map out my nearly useless ALT key, so my left hand presses ALT while my right uses the arrow keys. (and it does not escape out of insert-mode: notice the "i" at the end of each entry).
imap <A-UP> <ESC>gki
imap <A-DOWN> <ESC>gji
I also add lines to .vimrc so that my arrow keys work in normal-mode to traverse up and down within many visual-lines that are contained by one logical-line (the code is identical to the above except you use map or nmap rather than imap) And I use keyboard's other navigation keys with the ALT-KEY, all within insert-mode.
I add additional navigation lines for my ALT key, to use with my keyboards preassigned navigation keys, to navigate more quickly within insert-mode. None of these will escape you out of insert-mode:
" <ALT> navigation within insert-mode
imap <A-UP> <ESC>gki
imap <A-DOWN> <ESC>gji
imap <A-LEFT> <ESC>bi
imap <A-RIGHT> <ESC>ea
imap <A-END> <ESC>A
imap <A-PageUp> <ESC>(i
imap <A-PageDown> <ESC>l)i
imap <A-Home> <Esc>I
" so that <ALT> behaves the same in normal mode
nmap <A-UP> gk
nmap <A-DOWN> gj
nmap <A-LEFT> b
nmap <A-RIGHT> le
nmap <A-END> $
nmap <A-PageUp> (
nmap <A-PageDown> )
nmap <A-Home> ^
My "within" insert-mode navigation short cuts utilize the ALT key with PgUp, PgDn, Home & End keys too, to jump around far more quickly. I use alt-pgup and alt-pgdn presses to jump forward or backward by sentences. And, I use alt-home and alt-end to jump to the beginning and end of my paragraph long logical lines. None of this escapes me out of insert mode. (I figured that I might as well program all the preassigned navigation keys to work quickly within insert-mode, without leaving it). And if I want to move one character at a time, I just let up on the ALT key while still using the arrow keys.
All of those are really simple modifications to the .vimrc. You can get creative and do all sorts of things to improve navigation within insert-mode. Otherwise, if you use the plain ole ARROW keys within insert-mode on long lines, then you need a cup of coffee in your left hand to sip while you hold the arrow keys down with the right. That takes forever!
By the way, the key already works with all the other normal mode navigation commands, like h,j,k,l and w,W,b,B,e and search: /,% etc. EXCEPT that it automatically escapes you out of insert mode without having to press the ESC key. So using with the normal-mode navigation characters will leave you stranded in normal-mode, until you take the effort to press i,I,a,A,o,O again, which I find easy to forget to do.
Since the keyboards preassigned navigation commands: arrows: UP, DOWN, RIGHT, LEFT and PGUP, PGDN, HOME, END don't do anything special with the key, I found that I might as well map them out in .vimrc to help my navigation within insert-mode, while staying within insert-mode. And, to reiterate, its helpful to me because I work with very long text documents that have paragraph long logical-lines that span across a lot of visual-lines, and the arrow keys and h,j,k,l don't acknowledge the visual-lines. This fixes that particular problem, both within insert-mode and normal-mode.
I give credit to my knowledge above, which I found in the book HACKING VIM 7.2 by Kim Schulz
You could use imap to map any key in insert mode to one of the cursor keys. Like so:
imap h <Left>
Now h works like in normal mode, moving the cursor. (Mapping h in this way is obviously a bad choice)
Having said that I do not think the standard way of moving around in text using VIM is "not productive". There are lots of very powerful ways of traversing the text in normal mode (like using w and b, or / and ?, or f and F, etc.)
For some frequently used movements and actions, I have defined the following mappings. This saves a keystroke compared to the CTRL+O combination and since I need them frequently, they pay off in the long
run.
inoremap <A-$> <C-o>$
inoremap <A-^> <C-o>^
inoremap <A-h> <Left>
inoremap <A-l> <Right>
inoremap <A-O> <C-O>O
inoremap <A-o> <C-o>o

Resources