From 249e4b93489d56b10967a1612c033e6d9894d7cf Mon Sep 17 00:00:00 2001 From: Josh Rahm Date: Thu, 15 Sep 2022 12:41:19 -0600 Subject: commenter.vim: better commenting with regexes --- plugin/commenter.vim | 175 ++++++++++++++++++++++++++++++--------------------- 1 file 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 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 call change_comment_obj('i') +nnoremap cdcc call change_comment_obj('I') -" Comment out the line and go into insert mode before the first non-blank -" character. -noremap 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)) + 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 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) - else - endif + let s = get(s:comment_style, &ft, s:default_style) + " U allows ,,etc. to show up in the redo buff. + call feedkeys(printf( + \ "%s %s %s", + \ a:mv, + \ s.line, + \ repeat("\U\", 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\)\(\/\/\)\@