1

Example scenario

I have this text consisting of two columns with different words of different lengths and alignments:

asdf     foo
bar   qwer
zzzzz   xx

Let's say I want to abbreviate the first column to a single character, insert a comma between the columns, and align the words.

I had imagined to do it like this:

  • Place the cursor on the second character of the line:

      asdf     foo
       ^
    
  • Type cw, <ESC> to get:

      a, foo
        ^
    
  • Type jh. repeatedly to do the same action for all other lines:

      a, foo
      b, qwer
      z, xx
        ^
    

However, it does not work, because typing cw in this situation

asdf     foo
 ^

leads to

a    foo
 I

and not

afoo
 I

(where I means the cursor in insert mode).

Question

As I expect, typing only w in the same situation leads to

asdf     foo
         ^

and typing dw leads to

afoo
 ^

Why does cw behave differently and delete only until the end of the current word instead of the beginning of the next word, and if possible, how can I make it do what I expect or replace it with a different single movement command I'm currently not aware of?

cw is essentially the same as ce in this case.

I'm using Vim 8.1 and confirmed this behaviour with vim -u NONE.

1
  • :h cw also suggests workarounds that do not quite work in this case: :map cw dwi is not repeatable with . as a single action, and caw also removes the first character of the word. An option to remove the special case exists in Neovim: github.com/neovim/neovim/issues/6234
    – mkrieger1
    Feb 25 at 11:45
2

See :h cw:

                        *cw* *cW*
Special case: When the cursor is in a word, "cw" and "cW" do not include the
white space after a word, they only change up to the end of the word.  This is
because Vim interprets "cw" as change-word, and a word does not include the
following white space.

However rather than using a macro you should go with a substitution command that will be less troubles:

%s/\(.\)\w\+\s\+/\1, /

%                        Adapt the range to the lines you want to change
   \(.\)                  Capture the first character to reuse it in the second part with \1
        \w\+              match the following word characters
            \s\+          match the following withespaces
                /\1, /   replace what was matched by the captured character, a comma and a whitespace
2
  • 1
    Might also do c/ \S<cr>, ...which is repeatable.... j.j.j.j etc.
    – B Layer
    Feb 25 at 11:59
  • Sure there are a lot of ways, I'd still rather use a subsitution but don't hesitate to post your own answer @BLayer
    – statox
    Feb 25 at 12:22

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