Aron Lee
Aron Lee

Reputation: 617

Comment and uncomment css code with vmap in Vim

I try to comment and uncomment css file with vmap

when I select lines in css file and comment them out with 'xx'

autocmd BufEnter *.css vmap  xx  :s/\%V\s*\(\S.*$\)\%V/\/* \1 *\//g <CR>

It works perfectly

But when I try to vmap 'xu' to uncomment the css code,

autocmd BufEnter *.css vmap  xu  :s/\%V\/\*\|**\/\%V//g <CR>


'xx' comment =>   background-color => /*  background-color:red;  */
'xu' uncomment =>  /*  background-color */ => background-color

The mapping is try to remove '/*' and '*/' from my selected lines in css file.

I got following error:

E871: (NFA regexp) Can't have a multi follow a multi !
E61: Nested *
E476: Invalid command

It seems to me I CAN NOT have 'or' operator between '\%V and \%V' which is visual block in Vim.

Anyone know how to solve the problem

Upvotes: 1

Views: 193

Answers (1)

Ingo Karkat
Ingo Karkat

Reputation: 172638

The problem

If you check your mapping, you'll see that it's not defined as expected:

:vmap xu
v  xu            :s/\%V\/\*|**\/\%V//g <CR>

Inside a mapping, the | command separator would end the mapping command, and therefore needs to be escaped. (Cp. :help map-bar). This usually is done via <Bar>, but can also be done by prepending a \. Accidentally, your regular expression had just this, thereby avoided the mapping definition error, but also corrupted the mapping.

vmap  xu  :s/\%V\/\*\<Bar>**\/\%V//g <CR>

You probably should also consistently escape the second literal *; this would have given you a different (pattern not found) error instead of the E871:

vmap  xu  :s/\%V\/\*\<Bar>\**\/\%V//g <CR>

The autocmd

... works, but isn't how it's usually done. Vim has filetype detection, and out of the box detects *.css as filetype=css for you. There's no need to duplicate that information into your autocmd. Instead, you can hook into the FileType event:

autocmd FileType css vmap  xu  :s/\%V\/\*\<Bar>\**\/\%V//g <CR>

Alternative to autocmds

I would recommend putting any settings, mappings, and filetype-specific autocmds into ~/.vim/ftplugin/{filetype}_whatever.vim (or {filetype}/whatever.vim; cp. :help ftplugin-name) instead of defining lots of :autocmd FileType {filetype}; it's cleaner and scales better; requires that you have :filetype plugin on, though. Settings that override stuff in default filetype plugins should go into ~/.vim/after/ftplugin/{filetype}.vim instead.

More small fixes

  • You should use :vnoremap instead of :vmap; it makes the mapping immune to remapping and recursion.
  • After editing a CSS file, the mapping will also be active in any other buffer, because it is a global one. Add the <buffer> argument to limit it to the (CSS) buffer.
  • You can use another separator for :substitute; it avoids the escaping of the / in the pattern and makes this a bit more readable.

Final recommendation

I would put the following into ~/.vim/ftplugin/css_mappings.vim:

vnoremap <buffer> xu :s#\%V/\*\<Bar>\**/\%V##g <CR>

Or use a plugin

(Unless you're a minimalist that avoids plugins at some cost, or if you've done this only for the learning experience.)

Please note that there are several commenter plugins that do this very well, and those are generic (and often extensible) so that they work for any filetype:

Upvotes: 2

Related Questions