0

In command mode, r replaces the character under the cursor by the one pressed right after typing r without going into insert mode, so there's no esc to press.

5r replaces the 5 characters starting from the one under the cursor by the same single character typed after 5r (the new character is repeated 5 times).

I would like to replace N characters by N other characters (some or all of them different from each other) without having to press Esc (or any other key) after I typed the N characters, that is, I'd like to avoid using e.g. 5s.

I couldn't find any way to do so. Is it possible? If there's no existing pre-defined command, what key binding could provide this functionality?

2 Answers 2

1

To meet all your requirements a function will probably be needed in addition to a mapping. Put both of these in your Vim start-up file (e.g. .vimrc) and the functionality will be available each time you launch Vim.

func! ReplaceNChars(n)
    let inchars = ""
    let idx = a:n
    echom 'Enter ' . a:n . ' characters: '
    while idx > 0
        let inchars .= nr2char(getchar())
        let idx -= 1
    endwhile
    exec 'norm! R' . inchars
endfunc

This function takes a number and then waits for that many characters to be entered by the user. Then Normal mode R is used to replace whatever is currently under the cursor with the entered text.

The code is very straightforward so I won't go into the details.

Here's the mapping...

nnoremap <expr> <silent> <leader>R ':<C-U>call ReplaceNChars(' . v:count1 . ')<CR>'

To use it, in Normal mode enter the number of characters to replace, then, assuming you have the default leader key, enter \R. (Replace this part with whatever you want.) You'll be taken to the command line. Enter the appropriate number of characters and then the replacement will occur. No extra keys like Esc or Enter are required.

Unlike the code this mapping uses some constructs that may not be well known. Some details (with Vim help links):

  • <expr> : The right side of the mapping is an expression that is evaluated and the result is the actual mapping.
  • <silent> : Prevents the mapped command from being echoed on the command line.
  • <C-U> : Clears the command line before inserting the rest of our command.
  • v:count1 : Variable that contains the last user-entered count. If no count has been entered defaults to 1. In our case the default will mean that the mapping will behave much like the r command.

I haven't done any negative testing or tried any corner case input. Just normal use cases.

2
  • Tested and meets my needs all right (and probably those of many others since performing what I ask seems to have called for elsewhere as well). For anyone wondering where to put the function, it can go in ~/.vimrc (and this .vimrc has to be sourced, ex from within a vi session in command mode, do :source ~/.vimrc).
    – calocedrus
    Jul 27, 2018 at 5:18
  • Note: when the number of characters to be replaced goes beyond the end of the current line, line is expended with the additional character(s) (not a problem at all, it can even be desired).
    – calocedrus
    Jul 27, 2018 at 5:20
1

This is obviously hardcoded to 5. But it should be possible to generalize it to n if you need. It demonstrates the trick.

nmap <F1> :execute "normal c5l".nr2char(getchar()).nr2char(getchar()).nr2char(getchar()).nr2char(getchar()).nr2char(getchar())<CR>
2
  • Interesting trick, but when I test it "live" in a vi session, it hides the 1st line of my file (not really a problem) and when I'm done typing my 5 new characters it asks I press ENTER, so while it does indeed prevent from typing esc I still have to type another key which I'd like to avoid (I'll make my question more precise on this point). Also how could I make the mapping applicable to substituting n characters rather than n being hard-coded?
    – calocedrus
    Jul 27, 2018 at 2:07
  • Weird, I don't experience those behaviors on my system. Anyway, it's moot since the general function has been posted. Jul 27, 2018 at 12:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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