I am trying to do a comment remap in Vim with an inline if to check if it's already commented or not. This is what I have already and of course it's not working ha ha:

imap <c-c> <Esc>^:if getline(".")[col(".")-1] == '/' i<Delete><Delete> else i// endif

What I want to do is check the first character if it's a / or not. If it's a / then delete the first two characters on that line, if it's not a / then add two // in front of the line.

What I had originally was this:

imap <c-c> <Esc>^i//

And that worked perfectly, but what I want is to be able to comment/uncomment at a whim.

有帮助吗?

解决方案

I completely agree with @Peter Rincker's answer warning against doing this in insert mode, and pointing you to fully-featured plugins.

However, I couldn't resist writing this function to do precisely what you ask for. I find it easier to deal with this kind of mapping with functions. As an added bonus, it returns you to insert mode in the same position on the line as you started (which has been shifted by inserting or deleting the characters).

function! ToggleComment()
    let pos=getpos(".")
    let win=winsaveview()
    if getline(".") =~ '\s*\/\/'
        normal! ^2x
        let pos[2]-=1
    else 
        normal! ^i//
        let pos[2]+=3
    endif
    call winrestview(win)
    call setpos(".",pos)
    startinsert
endfunction   

inoremap <c-c> <Esc>:call ToggleComment()<CR>

Notice the modifications to pos to ensure the cursor is returned to the correct column. The command startinsert is useful in this type of function to return to insert mode. It is always safer to use noremap for mappings, unless there is a very good reason not to.

This seems to work well, but it is not very Vim-like, and you might find other plugins more flexible in the long run.

其他提示

There are many commenting plugins for vim:

I would highly suggest you take a look at some these plugins first before you decide to roll your own. It will save you great effort.

As a side note you typically would want to comment/uncomment in normal mode not insert mode. This is not only the vim way, but will also provide a nicer undo history.

If you are dead set on creating your own mappings I suggest you create a function to do all the hard work and have your mapping call that function via :call. If you think you can get by with simple logic that doesn't need a function then you can use an expression mapping (see :h map-<expr>). You may want organize into a plugin as it could be large. If that is the case look at :h write-plugin to give you a feel for writing plugins the proper way.

Example of a simple expression mapping for toggling comments:

nnoremap <expr> <leader>c getline(".") =~ '\m^\s*\/\/' ? '^"_2x' : 'I//<esc>`['

there's also this vimtip! http://vim.wikia.com/wiki/Comment/UnComment_visually_selected_text

i use the bottom one with the

...
noremap <silent> ,c :<C-B>sil <C-E>s/^/<C-R>=escape(b:comment_leader,'\/')<CR>/<CR>:noh<CR>
noremap <silent> ,u :<C-B>sil <C-E>s/^\V<C-R>=escape(b:comment_leader,'\/')<CR>//e<CR>:noh<CR>

,c comments out a region
,u uncomments a region
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top