简体   繁体   中英

“Do what I mean, not what I say” when fat-fingering the write command in Vim

Even though I am a relatively precise typist, it is a common error for me to wallop the apostrophe character when I go to hit a carriage return in Vim. This happens especially when I am trying to type :w<CR> or wq<CR> . I end up typing :w'<CR> , or even worse, :wq'<CR> , which gives a couple big red error messages in addition to not doing what I intend. Is there a mapping or some other technique that can be used to overcome this? I can't imagine why I would ever want to write a file named ' , so I am not concerned about blocking that possibility entirely.

You could just do cnoremap '<cr> <cr> . I can't imagine many times a command-mode command would end in ' . Usually if quotes are needed I use double quotes. If there is one, just wait a second before hitting enter or ''<bs><cr> or something.

You must be careful with using command mappings (and abbreviations), they often fire when they are not supposed to for example during a search or in the middle of a command argument. I typically prefer to use a expression abbreviation.

Put the following in your ~/.vimrc :

cnoreabbrev <expr> w getcmdtype() == ':' && getcmdline() ==# 'w' ? 'w' . EatChar("'") : 'w'
cnoreabbrev <expr> wq getcmdtype() == ':' && getcmdline() ==# 'wq' ? 'wq' . EatChar("'") : 'wq'

function! EatChar(pat)
  let c = nr2char(getchar(0))
  return (c =~ a:pat) ? '' : c
endfunction

This abbreviation uses a function called EatChar which takes a pattern that will be "eaten" or ignored after the abbreviation is expanded. See :helpg Eatchar for an different example of its usage.

The abbreviations will only expand and look to "eat" a quote when all the following criteria is met:

  • is in normal ex mode: getcmdtype() == ':'
  • at the beginning of the command: getcmdline() ==# 'w'

Otherwise the abbreviation is expanded to the same as the {lhs} ie w or wq

Disadvantages to this approach:

  • expression abbrevations require vim 7+
  • if for whatever reason you really do want to type :w' you will have to type the quote twice , use a space to separate the command form the filename, or type Ctrl + v followed by '
  • must create an additional abbreviation for each fat fingering senario

For more information see:

:h abbreviations
:h :map-<expr>
:h getcmdtype(
:h getcmdline(
:helpg Eatchar

Here is a workaround:

cnoremap w'<CR> w<CR>
cnoremap wq'<CR> wq<CR>

This creates a command-mode mapping which converts my mistaken commands into what I intended. However, it has two disadvantages:

  1. It means that the apostrophe has to be typed directly after the other characters. If there is a pause and then I flail for the Enter key, hitting the apostrophe key, I will have the same problem.
  2. In the interim, while Vim is giving you a moment to type the apostrophe, the cursor will not be advanced (this is the typical behavior for mappings). If you are someone who watches the commands you are typing, this could mess you up in other ways.

I know this isn't the exact answer you were asking for but I might have a different solution for you.

In your case you are asking about saving the file and saving and exiting. Maybe using one of the other methods to do these task would work out better for you.

Z Z will save the file if modified and then quit the window.

For saving a file, I have made a leader command to shorten the number of keys I have to press

nnoremap <silent> <leader><leader> :write<cr>

You just need to hit your leader key twice to save the file. My leader is , . So I just hit , , and the file is saved.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM