165

Vim is my preferred text editor when I program, and thus I always run into a particularly annoying issue.

Frequently, when I quickly need to save the buffer and continue on to some other miscellaneous task, I do the typical

:w

However, I always — what seems to be like more than 50% of the time — manage to capitalize that :w. Naturally, Vim yells at me because W is an invalid command:

E492: Not an editor command: W

My question is how can one alias colon-commands in Vim. Particularly, could you exemplify how to alias W to w.

I am aware of the process to map keys to certain commands, but that is not what I’m looking for.

ib.
  • 25,324
  • 10
  • 71
  • 97
Sean
  • 4,973
  • 5
  • 20
  • 26
  • 1
    possible duplicate of [Can I (re-) map commands in vim?](http://stackoverflow.com/questions/117150/can-i-re-map-commands-in-vim) – Chris Morgan May 23 '12 at 13:46
  • 1
    To avoid `:W` you could a map a key to perform the saving. If you are used to some program that saves with Ctrl-s, there are these mappings from $VIM/mswin.vim: `" Use CTRL-S for saving, also in Insert mode` `noremap :update` `vnoremap :update` `inoremap :update` – mMontu May 23 '12 at 14:21
  • Similar question on Vi Stack exchange: https://vi.stackexchange.com/q/2665/7244 – Flimm Aug 24 '18 at 12:23

7 Answers7

138

To leave completion untouched, try using

cnoreabbrev W w

It will replace W in command line with w, but only if it is neither followed nor preceded by word character, so :W<CR> will be replaced with :w<CR>, but :Write won’t. (Note that this affects any commands that match, including ones that you might not expect. For example, the command :saveas W Z will be replaced by :saveas w Z, so be careful with this.)

Update

Here is how I would write it now:

cnoreabbrev <expr> W ((getcmdtype() is# ':' && getcmdline() is# 'W')?('w'):('W'))

As a function:

fun! SetupCommandAlias(from, to)
  exec 'cnoreabbrev <expr> '.a:from
        \ .' ((getcmdtype() is# ":" && getcmdline() is# "'.a:from.'")'
        \ .'? ("'.a:to.'") : ("'.a:from.'"))'
endfun
call SetupCommandAlias("W","w")

This checks that the command type is : and the command is W, so it’s safer than just cnoreabbrev W w.

ib.
  • 25,324
  • 10
  • 71
  • 97
ZyX
  • 49,123
  • 7
  • 101
  • 128
  • 2
    This answer is the safest and most reliable for me. – Sean Oct 13 '10 at 01:57
  • 2
    Actually, this would mean W will be replaced *anywhere* in the command bar, including, for example, in searches, so s/W foo/bar/g would be turned into s/w foo/bar/g. this can get annoying really fast. see my answer for a comprehensive solution. – airstrike May 22 '12 at 19:17
  • 4
    Absolutely; this is a *horrible* idea. You should *never*, **ever**, ***ever*** do this. – Chris Morgan May 23 '12 at 13:43
  • 2
    If you use the recommended solution, please, be aware both of the two below commands will work as the lower one which may present an unexpected result depending on the actual buffer content and VIM settings: `:%s/W/foo/g` `:%s/w/foo/g` – cprn Apr 25 '12 at 02:00
  • 4
    `:cnoreabbrev W getcmdtype()==':'&&getcmdline()=~#'^W'?'w':'W'` – kev Jul 27 '12 at 13:32
  • 1
    @kev Strange manner of saying “you’ve case problems here”. And an abbreviation with another problem: type `:W W` But thanks, that was fixed. // I had two errors: `getcmdline() is# 'w'` which is impossible and swapped `'w'` and `'W'` in result. – ZyX Jul 27 '12 at 14:02
  • @kev By the way, using regular expressions where they are not needed is bad for performance. This is not perl, `getcmdline()[0] is# 'W'` serves the same purpose. – ZyX Jul 27 '12 at 14:05
  • @CelsoDantas Replace `cnoreabbrev` with `cnoremap` then. With `getcmdtype() …` condition it should not be too intrusive. Or define two abbreviations. – ZyX Apr 26 '13 at 19:44
  • @CelsoDantas Altering a file with some kind of custom command and then immediately quitting is dangerous anyway.... – Kyle Strand Jun 20 '13 at 18:02
  • 1
    You can use [cmdalias](http://www.vim.org/scripts/script.php?script_id=746) to simplify this to `:Alias W w` and it will do the getcmdline magic for you. – idbrii Dec 13 '13 at 19:09
  • With regards to your edit, my only regret is that the ```fun!``` had to eventually come to an end. – Seldom 'Where's Monica' Needy Mar 20 '15 at 22:22
  • I have a command without any arguments and to get it expanded I need to hit `space`. Is it possible to avoid this? – user14416 Jun 06 '16 at 16:32
  • @user14416 To *verify* that it gets expanded, not to *get* it expanded. `` expands abbreviations just as good as a space, just you are unable to check or react if expansion is unwanted. – ZyX Jun 07 '16 at 00:57
  • @ZyX Sorry, I have not fully understand your answer. I am using `:Alias q qall`. And `:q` only does `q`, but not `:qall`, am I missing something? – user14416 Jun 07 '16 at 10:12
  • @user14416 What is “:Alias”? If I use `cnoreabbrev q ((getcmdtype() is# ':' && getcmdline() is# 'q')?('echo 1'):('echo 2'))` I get `1` when typing `:q` as expected. If I use `call SetupCommandAlias('q', 'echo 1')` (with function from my answer) I get `1` as expected. If you got buggy command somewhere not from this answer why are you asking here? – ZyX Jun 07 '16 at 14:35
  • @ZyX The reason was that I had mapping `cmap `. Why it is not supposed to work when I have this kind of mapping? – user14416 Jun 10 '16 at 15:00
  • @user14416 `cmap ` is not interferring with such aliases. What is is `cnoremap`. Check what is the difference in the help. – ZyX Jun 10 '16 at 18:16
105

With supplementary searching, I've found that someone asked nearly the same question as I.

:command <AliasName> <string of command to be aliased>

will do the trick.

Please be aware that, as Richo points out, the user command must begin with a capital letter.

Community
  • 1
  • 1
Sean
  • 4,973
  • 5
  • 20
  • 26
25

I find that mapping the ; key to : would be a better solution, and would make you more productive for typing other commands.

nnoremap ; :
vnoremap ; :
fent
  • 16,873
  • 14
  • 78
  • 88
9

The best solution involves writing a custom function for handling abbreviations that only take place in the beginning of the command bar.

For this, add the following your vimrc file or anywhere else.

" cabs - less stupidity                                                      {{{
fu! Single_quote(str)
  return "'" . substitute(copy(a:str), "'", "''", 'g') . "'"
endfu
fu! Cabbrev(key, value)
  exe printf('cabbrev <expr> %s (getcmdtype() == ":" && getcmdpos() <= %d) ? %s : %s',
    \ a:key, 1+len(a:key), Single_quote(a:value), Single_quote(a:key))
endfu
"}}}

 

" use this custom function for cabbrevations. This makes sure that they only
" apply in the beginning of a command. Else we might end up with stuff like
"   :%s/\vfoo/\v/\vbar/
" if we happen to move backwards in the pattern.

" For example:
call Cabbrev('W', 'w')

A few useful abbreviations from the source material where I found this stuff:

call Cabbrev('/',   '/\v')
call Cabbrev('?',   '?\v')

call Cabbrev('s/',  's/\v')
call Cabbrev('%s/', '%s/\v')

call Cabbrev('s#',  's#\v')
call Cabbrev('%s#', '%s#\v')

call Cabbrev('s@',  's@\v')
call Cabbrev('%s@', '%s@\v')

call Cabbrev('s!',  's!\v')
call Cabbrev('%s!', '%s!\v')

call Cabbrev('s%',  's%\v')
call Cabbrev('%s%', '%s%\v')

call Cabbrev("'<,'>s/", "'<,'>s/\v")
call Cabbrev("'<,'>s#", "'<,'>s#\v")
call Cabbrev("'<,'>s@", "'<,'>s@\v")
call Cabbrev("'<,'>s!", "'<,'>s!\v")
jdhao
  • 13,374
  • 7
  • 87
  • 151
airstrike
  • 2,001
  • 22
  • 24
  • 1
    There is a built-in function `string()` that does the same thing as yours `Single_quote()`. – ZyX May 23 '12 at 00:57
7

Suppose you want to add alias for tabnew command in gvim. you can simply type the following command in your .vimrc file (if not in home folder than create one)

cabbrev t tabnew
Andrew Barber
  • 37,547
  • 20
  • 91
  • 118
Sandip
  • 79
  • 1
  • 1
  • 1
    This will cause a command like `:saveas t example` to be replaced with `:saveas tabnew example` – Flimm Aug 24 '18 at 11:56
6

Maybe you would like to map one of your function keys (F1..F12) to :w ? Then put this into your .vimrc:

noremap  <f1> :w<return>
inoremap <f1> <c-o>:w<return>

(ctrl-o in insert mode switches temporarily to normal mode).

Benoit
  • 70,220
  • 21
  • 189
  • 223
5

Safest and easiest is a plugin such as cmdalias.vim or my recent update vim-alias of it that take into account

  • preceding blanks or modifiers such as :sil(ent)(!) or :redi(r),
  • range modifiers such as '<,'> for the current visual selection,
  • escape special characters such as quotes, and
  • check if the chosen alias is a valid command line abbreviation.
Enno
  • 238
  • 2
  • 5