4

An operation I do often in vim is to replace the word at the cursor with a single letter.

Currently, I do this via:

cw x Esc

(Where x is my replacement letter).

This isn't bad, but is there a way to do this without entering insert mode, so that I don't have to hit Escape when I'm done?

1
  • 1
    Most answers here will make the workflow like 2 keystrokes, e.g. ,x (if I mapped the script to , and x is the replacement letter) and would definitely help -- Just to mention, you may also want to do inoremap jk <esc> so it won't feel too much a burden to exit from insert mode.
    – Sunny Pun
    Nov 21, 2017 at 6:25

6 Answers 6

9

rXldw

Replace the first character with X then move right and delete the rest of the word. No insert mode required.

rXlde is actually needed if you are working with a word with trailing space, rather than a delimiter.

3
  • 1
    This fails if the word is only two characters long. You can obviously do rXlx instead in that situation, but now you have two different series of keystrokes. :(
    – Rich
    Nov 21, 2017 at 13:21
  • I like this solution since it will work at ANY vim I happen to sit down at, not just "my" vim. Thanks! Nov 23, 2017 at 15:07
  • 1
    @JonSchneider It works with any vi because I'm an ancient vi guy who doesn't know vim at all. So all I have to work with is the original vanilla product.
    – Sinc
    Dec 21, 2017 at 21:51
6

I couldn't find a way to do this in the docs, so I created a mapping to do it. You can type this into your .vimrc file:

nnoremap <leader>rw vwhhc.<esc>r

Let me break it down:

vw -> highlight a word
hh -> go left twice because highlighting a word puts your cursor on the next word, and you don't want to change it
c  -> change what's highlighted (this will delete the word)
.  -> put a period there
<esc> -> go to normal mode
r -> press r on the period.  The next button you press will replace that . with the character you want.
1
  • 6
    The idea is good, but it could be simplified into ciw.<esc>r. If you want to replace a word, ciw is the sequence with the less side-effects. You could also have kept OP's cw -> cw.<esc>r Nov 20, 2017 at 18:05
5

There is no builtin solution. And I fail to find a one liner. If I put eatchar() directly in a mapping, it'll see what follows in the mapping instead of what the user will type.

The following isn't very ergonomic, but it'll work:

function! s:repl1() abort
  let c = nr2char(getchar())
  exe "normal! ciw".c."\<esc>"
endfunction

" use anything you wish instead of "µ" to trigger the mapping    
nnoremap <silent> µ :call <sid>repl1()<cr>

EDIT: See Daniel Kaplan's answer for a oneliner

BTW, it's also possible to define our own operator (:h g@), so instead of µ, we could type µiw (for the current word), µw (from the cursor position to the end of the current word), and so on.

function! s:opfunc(type) abort
  let motion = a:type == 'line' ? "'[v']" : '`[v`]'
  silent exe "normal! ".motion."c".nr2char(getchar())."\<esc>"
endfunction

nnoremap <silent> µ :set opfunc=<sid>opfunc<cr>g@

Note that, I've still haven't found how to force a redraw where we see we're in REPLACE-mode. The best I can come up with is the following, inspired by Daniel Kaplan's solution.

  silent exe "normal! ".motion."c¤\<esc>"
  redraw
  silent exe "normal! r".nr2char(getchar())
4

This is an improvement on Daniel Kaplan's answer.

nnoremap <expr> <leader>rw "ciw".nr2char(getchar())."\<esc>"

There are a couple improvements here:

  1. This uses ciw instead of vwhhc. This is shorter and more idiomatic, doesn't move your visual selection marks '<,'>, and more importantly, works at the end of a word instead of just at the beginning.

  2. This doesn't do anything until you choose what character you're replacing the word with.

2

I would do it this way (overkill perhaps):

command -nargs=1 RW :call ReplaceWord(<f-args>)
fun! ReplaceWord(char)
    sil exe "s/" . expand('<cword>') . "/" . a:char . "/"
endfun

Now you can just type :RW x with your cursor over the word you want to replace. RW stands for "replace word" but you could choose your own preferred command name.

1
:map , cwx<esc>r

x is a temporary replacement character. The r at the end leaves it in replace mode to replace the temporary character x.

So to change asdf to y with the cursor on a type ,y

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.