3

Please forgive me, I'm relatively new to Vim.

I'm editing my .vimrc file. I'm adding the following lines:

nnoremap <up>    <nop>
nnoremap <down>  <nop>
nnoremap <left>  <nop>
nnoremap <right> <nop>
inoremap <up>    <nop>
nnoremap <down>  <nop>                                                                              
nnoremap <left>  <nop>
nnoremap <right> <nop>

I just used cli<Esc> to change nnoremap to inoremap on the fifth line. I'd like to continue through to the end of the document.

I thought to do this with Visual mode (Cntl-VG.) but that doesn't seem to work. I also know I could have done this in Visual mode from the beginning (Cntl-VGci<Esc><Esc>), but I've heard that Visual mode is a sloppy way to do things that can be more "Vim-minded."

With all that being said, what's the best way of performing a command on the first letter of each line until the end of a file?

1
  • I know what you mean about Visual mode being less pure though, IMO, that applies less to Visual block mode and more to line- or character-wise usage since there are fewer options available for column-oriented operations. That being said, a simple substitution seems like the most straightforward way to handle this particular case unless I'm misunderstanding the problem you want to solve. – B Layer Jan 1 at 20:04
2

Using Visual mode (in particular Blockwise Visual mode) seems to be a perfect solution for me, here.

Since you're only replacing a single character, personally I'd go with Ctrl+V followed by the motion (such as G for the end of the buffer), then ri. That replaces a single character and doesn't go into Insert mode, so you don't need an <Esc> to leave it.

Using . to repeat a command isn't really directly available in Visual mode... There's something you can do (and it turns out it works in this case), but it's somewhat different. In this case, you could have selected the lines visually (any of the three Visual modes would work), then press : (shows up as :'<,'>) and then complete that command to:

:'<,'>norm .

This uses the :normal command with a range (which is the range of the Visual selection), to run the . Normal-mode command at the beginning of each line.

In this case, this works well because you want to execute this command once per line and it turns out you want to execute it exactly on the first non-blank character of a line. (In the more general case of using :normal with a range, you might want to use a seeking motion with f or t etc. to locate the proper location in each line.)

Rather than using a Visual selection, you could also have used a count of 3 followed by :, which Vim expands to :.,.+2 for the three lines between the current one and two below it. Or you could have used :.,$ (which you need to enter yourself) for a range going from the current line to the end of the file.

I've heard that Visual mode is a sloppy way to do things that can be more "Vim-minded."

I haven't really seen this argument and I definitely disagree with the feeling. I don't think using Visual mode is sloppy at all and it can unleash some of the most useful features in Vim. In particular Blockwise Visual mode allows you to easily accomplish some tasks that would take so much more work otherwise.

I think the argument might be that it's sloppy to start Visual mode and use arrows to select the text to act upon instead of using more efficient motions such as iw or 3E or ap or }. But the sloppiness there doesn't come from Visual mode, but from using inefficient motions. (I think using v3Ec is about as good as using c3E even if the latter is one character shorter.)

In any case, if Visual does the job for you, go ahead and make the best use of it as you can!

1
  • Back in the early 2000s I used to avoid Visual mode on Vim, but mostly because I had to manage many servers of different OS's (FreeBSD, Solaris, AIX, etc.) and I often had to use old vi. So I tried not to create habits that wouldn't work on those boxes. In hindsight, that's so very silly, I should have just installed Vim everywhere. To be fair, back in those days solutions to distribute and manage software on hundreds of boxes wasn't as good as it is today, much easier to accomplish that nowadays (even though it's rare to see a non-Linux server now, so that's less of an issue.) – filbranden Jan 1 at 21:25
2

filbranden’s answer is more general for acting on a range of lines when you’ve already done one command.

Some alternatives, some general, some specific:

  • record a macro: qq.jq and then @q followed by @@ to replay. But you can give a large count in this case; the macro will fail (and thus the counted macro) when it reaches the end of the file. It may stop at the end of the block, but I’m not convinced.
  • similarly, a recursive macro (need to be more careful about stopping conditions here, so not my preferred choice): qqqqq.j@qq and then @q and watch
  • a substitute: by far the lightest solution. You need the appropriate range, but I would probably do vip: for that and then :substitute/^./i (you can abbreviate as far as :s).
0

A programmatic approach:

for mode in ['n', 'i']
  for key in ['<up>', '<down>', '<left>', '<right>']
    execute printf('%snoremap %s <nop>', mode, key)
  endfor
endfor

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.