From 79b37fdd282f616714876b97e484d8dcc8a488ab Mon Sep 17 00:00:00 2001 From: Josh Rahm Date: Tue, 13 Sep 2022 14:08:31 -0600 Subject: commenter.vim: much better comment handling with fancier regexes. --- plugin/commenter.vim | 162 ++++++++++++++++++++++++++++++++------------------- plugin/move.vim | 2 - 2 files changed, 102 insertions(+), 62 deletions(-) (limited to 'plugin') diff --git a/plugin/commenter.vim b/plugin/commenter.vim index 982f7c2..c7f30b7 100644 --- a/plugin/commenter.vim +++ b/plugin/commenter.vim @@ -5,57 +5,86 @@ nnoremap cdd set operatorfunc=commentg@_ nnoremap cD set operatorfunc=commentg@$ " Comment out the rest of the line and put the cursor into insert mode -noremap cdC c(comment-change-object-i) +nnoremap cdC c(comment-change-object-i) " Comment out the line and go into insert mode before the first non-blank " character. -noremap cdcc c(comment-change-object-I) +nnoremap cdcc c(comment-change-object-I) onoremap (comment-change-object-i) call change_comment_obj('i') onoremap (comment-change-object-I) call change_comment_obj('I') -onoremap i/ call inner_comment(v:operator) -vnoremap i/ call inner_comment('') +onoremap i/ call comment_obj(v:operator, 'i') +vnoremap i/ call comment_obj('', 'i') +onoremap a/ call comment_obj(v:operator, 'a') +vnoremap a/ call comment_obj('', 'a') noremap czd set operatorfunc=uncommentg@ nnoremap czdd set operatorfunc=uncommentg@_ -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\)\@" - let l = search(printf('\V\^\s\*\S\(%s\)\@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! mm>" + call search(start_regex, 'bW') + exec "normal! m 0 - exec printf("normal! \i%s gv%dll", bcont, len(bcont)) - else - " exec printf("normal! \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)) + " Select line-wise if the comments on on lines. + exec "normal V" endif + + endfunction function! s:change_comment_obj(mv) abort @@ -63,39 +92,52 @@ function! s:change_comment_obj(mv) abort " This is a cheese to allow the cdcc and cdC commands to be repeated with " the dot operator. When in insert mode stop " recording into the redobuff. This is a way to get around that. - " - " exec "normal! i \v" - let [line_com, bstart, bcont, bend, bpad, inl] = - \ get(s:comment_style, &ft, ['#', '#', '#', '#', 0, 0]) - exec printf("normal! %s %s \%dhvl", a:mv, line_com, len(line_com) + 3) + let s = get(s:comment_style, &ft, s:default_style) + exec printf("normal! %s %s \%dhvl", a:mv, s.line, len(s.line) + 3) else endif 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\)\(\/\/\)\@ i% call search('{') normal! v%o vnoremap a% V/{% vnoremap i% /{v%oo - -onoremap gv gv -- cgit