diff options
-rw-r--r-- | plugin/commenter.vim | 175 |
1 files changed, 103 insertions, 72 deletions
diff --git a/plugin/commenter.vim b/plugin/commenter.vim index 982f7c2..1855828 100644 --- a/plugin/commenter.vim +++ b/plugin/commenter.vim @@ -5,97 +5,128 @@ nnoremap cdd <cmd>set operatorfunc=<sid>comment<cr>g@_ nnoremap cD <cmd>set operatorfunc=<sid>comment<cr>g@$ " Comment out the rest of the line and put the cursor into insert mode -noremap cdC c<Plug><SID>(comment-change-object-i) +nnoremap cdC <cmd>call <sid>change_comment_obj('i')<cr> +nnoremap cdcc <cmd>call <sid>change_comment_obj('I')<cr> -" Comment out the line and go into insert mode before the first non-blank -" character. -noremap cdcc c<Plug><SID>(comment-change-object-I) - -onoremap <Plug><SID>(comment-change-object-i) <cmd>call <sid>change_comment_obj('i')<cr> -onoremap <Plug><SID>(comment-change-object-I) <cmd>call <sid>change_comment_obj('I')<cr> - -onoremap i/ <cmd>call <sid>inner_comment(v:operator)<cr> -vnoremap i/ <cmd>call <sid>inner_comment('')<cr> +onoremap i/ <cmd>call <sid>comment_obj(v:operator, 'i')<cr> +vnoremap i/ <cmd>call <sid>comment_obj('', 'i')<cr> +onoremap a/ <cmd>call <sid>comment_obj(v:operator, 'a')<cr> +vnoremap a/ <cmd>call <sid>comment_obj('', 'a')<cr> noremap czd <cmd>set operatorfunc=<sid>uncomment<cr>g@ nnoremap czdd <cmd>set operatorfunc=<sid>uncomment<cr>g@_ -function! s:inner_comment(op) - let [line_com, bstart, bcont, bend, bpad, inl] = - \ get(s:comment_style, &ft, ['#', '#', '#', '#', 0, 0]) - let lc = escape(line_com, '/') - - if getline('.') =~ printf('\V\^\s\*%s', lc) - call search(printf('\V\^\s\*\S\(%s\)\@<!', lc), 'W') - exec "normal! k$m>" - let l = search(printf('\V\^\s\*\S\(%s\)\@<!', lc), 'bW') - if l == 0 - normal! 0m< - else - exec "normal! j0m<" - endif +function! s:single_character_style(c) + return { + \ 'block_start_regex': '\(^\s*\(\(\S\)\(' . a:c . '\)\@<!.*\|\S\n\)\_s\+\|\%^\)${as}' . a:c . '\s*${is}\S${ie}', + \ 'block_end_regex': a:c . '.*${is}.${ie}\(\n\s*\)*${as}\n\_s*\S' . a:c . '\@<!', + \ 'line': a:c + \ } +endfunction +let s:default_style = s:single_character_style('#') - normal! gvoh - if a:op == 'c' - exec printf("normal! \<esc>i%s gv%dll", line_com, len(line_com)) - endif +function! s:regex_combine(s1, s2) abort + if a:s1 == "" + return a:s2 + endif + + if a:s2 == "" + return a:s1 + endif + + return printf('\(%s\)\|\(%s\)', a:s1, a:s2) +endfunction + +function! s:comment_obj(op, iOrA) + let style = get(s:comment_style, &ft, s:default_style) + + let start_regex = s:regex_combine( + \ get(style, 'multi_start_regex', ''), + \ get(style, 'block_start_regex', '')) + let end_regex = s:regex_combine( + \ get(style, 'multi_end_regex', ''), + \ get(style, 'block_end_regex', '')) + \ + if a:iOrA == 'i' + let start_regex = + \ substitute( + \ substitute(start_regex, '\V${i\(\[se]\)}', '\\z\1', 'g'), + \ '\V${a\(\[se]\)}', '', 'g') + let end_regex = + \ substitute( + \ substitute(end_regex, '\V${i\(\[se]\)}', '\\z\1', 'g'), + \ '\V${a\(\[se]\)}', '', 'g') else - let cs = escape(bstart, '/') - let ce = escape(bend, '/') + let start_regex = + \ substitute( + \ substitute(start_regex, '\V${a\(\[se]\)}', '\\z\1', 'g'), + \ '\V${i\(\[se]\)}', '', 'g') + let end_regex = + \ substitute( + \ substitute(end_regex, '\V${a\(\[se]\)}', '\\z\1', 'g'), + \ '\V${i\(\[se]\)}', '', 'g') + endif - normal! k - let l2 = search('\V\zs\S\_s\*' . ce, 'Wc') - exec "normal! m>" - let l1 = search('\V' . cs . '\S\*\_s\?\zs', 'bW') - exec "normal! m<gvo" + call search(end_regex, 'c') + exec "normal! v\<esc>m>" + call search(start_regex, 'bW') + exec "normal! m<gv" - if l1 != l2 && len(v:operator) > 0 - exec printf("normal! \<esc>i%s gv%dll", bcont, len(bcont)) - else - " exec printf("normal! \<esc>i%s gv%dllo%dll", bcont, len(bcont), len(bcont)) - endif + let [_, sl, sc, _] = getpos("'<") + let [_, el, ec, _] = getpos("'>") + + if getline(sl)[:sc - 2] =~ '^\s*$' && a:iOrA == 'a' && ec >= len(getline(el)) + exec "normal V" endif endfunction function! s:change_comment_obj(mv) abort - if v:operator == 'c' - " This is a cheese to allow the cdcc and cdC commands to be repeated with - " the dot operator. When in insert mode <left><right><up><down> stop - " recording into the redobuff. This is a way to get around that. - " - " exec "normal! i \<esc>v" - let [line_com, bstart, bcont, bend, bpad, inl] = - \ get(s:comment_style, &ft, ['#', '#', '#', '#', 0, 0]) - exec printf("normal! %s %s \<esc>%dhvl", a:mv, line_com, len(line_com) + 3) - else - endif + let s = get(s:comment_style, &ft, s:default_style) + " <C-g>U<Left> allows <Left>,<Right>,etc. to show up in the redo buff. + call feedkeys(printf( + \ "%s %s %s", + \ a:mv, + \ s.line, + \ repeat("\<C-g>U\<left>", len(s.line) + 2)), 'n') endfunction - " filetype, linecomment, block start, block continue, blockend, blockpad, - " inline_support let s:comment_style = { - \ 'java': ['//', '/*', ' *', '*/', 1, 1], - \ 'c': ['//', '/*', ' *', '*/', 1, 1], - \ 'cpp': ['//', '/*', ' *', '*/', 1, 1], - \ 'vim': ['"', '"', '"', '"', 0, 0] + \ 'java,c,cpp,rust,go': { + \ 'multi_start_regex': '${as}\/\*\([*]\|\_s\)*${is}\S', + \ 'multi_end_regex': '${is}\S\_s*\*\/${as}', + \ 'block_start_regex': '\(^\s*\(\(\S\S\)\(\/\/\)\@<!.*\|\S\n\)\n*${as}\_s\+\|\%^${as}\)\/\/\+\s*${is}\S${ie}', + \ 'block_end_regex': '\/\/.*${is}.${ie}${as}\n\_s*\S\/\@<!', + \ 'line': '//', + \ 'multi_start': '/*', + \ 'multi_cont': ' *', + \ 'multi_end': ' */' + \ }, + \ 'vim': s:single_character_style('"') \ } +let s:comment_style_new = {} +for [langs, i] in items(s:comment_style) + for l in split(langs, ',') + let s:comment_style_new[l] = i + endfor +endfor +let s:comment_style = s:comment_style_new + function! s:uncomment(arg, ...) abort - let [line_com, bstart, bcont, bend, bpad, inl] = - \ get(s:comment_style, &ft, ['#', '#', '#', '#', 0, 0]) + let s = get(s:comment_style, &ft, s:default_style) let l1 = line("'[") let l2 = line("']") - if inl + if has_key(s, 'multi_start') silent exec printf( - \ 'silent! %s,%s s/\V\zs%s\s\?\ze//', l1, l2, escape(bstart, '/')) - silent exec printf('silent! %s,%s s/\V\zs\s\?%s\ze//', l1, l2, escape(bend, '/')) + \ 'silent! %s,%s s/\V\zs%s\s\?\ze//', l1, l2, escape(s.multi_start, '/')) + silent exec printf('silent! %s,%s s/\V\zs\s\?%s\ze//', l1, l2, escape(s.multi_end, '/')) + silent exec printf('silent! %s,%s s/\V\^\s\*\zs%s\s\?\ze//', l1, l2, escape(s.multi_cont, '/')) endif - silent exec printf('silent! %s,%s s/\V\^\s\*\zs%s\s\?\ze//', l1, l2, escape(line_com, '/')) - silent exec printf('silent! %s,%s s/\V\^\s\*\zs%s\s\?\ze//', l1, l2, escape(bcont, '/')) + silent exec printf('silent! %s,%s s/\V\^\s\*\zs%s\s\?\ze//', l1, l2, escape(s.line, '/')) endfunction function! s:comment(arg, ...) abort @@ -103,7 +134,7 @@ function! s:comment(arg, ...) abort normal! m` function! cb.operate(ls, t) dict abort - let [line_com, bstart, bcont, bend, bpad, inl] = get(s:comment_style, &ft, ['#', '#', '#', '#', 0, 0]) + let s = get(s:comment_style, &ft, s:default_style) let smallest = 100 let ls = a:ls @@ -124,26 +155,26 @@ function! s:comment(arg, ...) abort if self.arg == 'line' let i = 0 while i < len(ls) - let ls[i] = substitute(ls[i], printf('\%%%dc', smallest), line_com . ' ', '') + let ls[i] = substitute(ls[i], printf('\%%%dc', smallest), s.line . ' ', '') let i += 1 endwhile else - if self.arg != 'line' && !inl + if self.arg != 'line' && !has_key(s, 'multi_start') throw "Inline comments not allowed" endif - let ls[0] = substitute(ls[0], '^', bstart . ' ', '') - let ls[-1] = substitute(ls[-1], '$', ' ' . bend, '') + let ls[0] = substitute(ls[0], '^', s.multi_start . ' ', '') + let ls[-1] = substitute(ls[-1], '$', ' ' . s.multi_end, '') endif else let l = getline('.') if l[len(l) - len(ls[0]):] ==# ls[0] - let ls[0] = printf("%s %s", line_com, ls[0]) + let ls[0] = printf("%s %s", s.line, ls[0]) else - if !inl + if !has_key(s, 'multi_start') throw "Inline comments not allowed" endif - let ls[0] = printf("%s %s %s", bstart, ls[0], bend) + let ls[0] = printf("%s %s %s", s.multi_start, ls[0], s.multi_end) endif endif |