aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--plugin/commenter.vim175
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