" tcomment.vim " @Author: Tom Link (mailto:micathom AT gmail com?subject=[vim]) " @Website: http://www.vim.org/account/profile.php?user_id=4037 " @License: GPL (see http://www.gnu.org/licenses/gpl.txt) " @Created: 2007-09-17. " @Last Change: 2012-12-10. " @Revision: 0.0.614 " call tlog#Log('Load: '. expand('')) " vimtlib-sfile if !exists("g:tcommentBlankLines") " If true, comment blank lines too let g:tcommentBlankLines = 1 "{{{2 endif if !exists("g:tcommentModeExtra") " Modifies how commenting works. " > ... Move the cursor to the end of the comment " >> ... Like above but move the cursor to the next line " # ... Move the cursor to the position of the commented text " (NOTE: this only works when creating empty comments using " |:TCommentInline| from normal or insert mode and should " not be set here as a global option.) let g:tcommentModeExtra = '' "{{{2 endif if !exists("g:tcommentOpModeExtra") " Modifies how the operator works. " See |g:tcommentModeExtra| for a list of possible values. let g:tcommentOpModeExtra = '' "{{{2 endif if !exists('g:tcommentOptions') " Other key-value options used by |tcomment#Comment()|. " " Example: If you want to put the opening comment marker always in " the first column regardless of the block's indentation, put this " into your |vimrc| file: > " let g:tcommentOptions = {'col': 1} let g:tcommentOptions = {} "{{{2 endif if !exists('g:tcomment#ignore_char_type') " |text-objects| for use with |tcomment#Operator| can have different " types: line, block, char etc. Text objects like aB, it, at etc. " have type char but this may not work reliably. By default, " tcomment handles those text objects most often as if they were of " type line. Set this variable to 0 in order to change this " behaviour. Be prepared that the result may not always match your " intentions. let g:tcomment#ignore_char_type = 1 "{{{2 endif if !exists("g:tcommentGuessFileType") " Guess the file type based on syntax names always or for some fileformat only " If non-zero, try to guess filetypes. " tcomment also checks g:tcommentGuessFileType_{&filetype} for " filetype specific values. " " Values: " 0 ... don't guess " 1 ... guess " FILETYPE ... assume this filetype let g:tcommentGuessFileType = 0 "{{{2 endif if !exists("g:tcommentGuessFileType_dsl") " For dsl documents, assume filetype = xml. let g:tcommentGuessFileType_dsl = 'xml' "{{{2 endif if !exists("g:tcommentGuessFileType_php") " In php documents, the php part is usually marked as phpRegion. We " thus assume that the buffers default comment style isn't php but " html. let g:tcommentGuessFileType_php = 'html' "{{{2 endif if !exists("g:tcommentGuessFileType_html") let g:tcommentGuessFileType_html = 1 "{{{2 endif if !exists("g:tcommentGuessFileType_tskeleton") let g:tcommentGuessFileType_tskeleton = 1 "{{{2 endif if !exists("g:tcommentGuessFileType_vim") let g:tcommentGuessFileType_vim = 1 "{{{2 endif if !exists("g:tcommentGuessFileType_django") let g:tcommentGuessFileType_django = 1 "{{{2 endif if !exists("g:tcommentGuessFileType_eruby") let g:tcommentGuessFileType_eruby = 1 "{{{2 endif if !exists("g:tcommentGuessFileType_smarty") let g:tcommentGuessFileType_smarty = 1 "{{{2 endif if !exists("g:tcommentIgnoreTypes_php") " In php files, some syntax regions are wrongly highlighted as sql " markup. We thus ignore sql syntax when guessing the filetype in " php files. let g:tcommentIgnoreTypes_php = 'sql' "{{{2 endif if !exists('g:tcomment#syntax_substitute') " :read: let g:tcomment#syntax_substitute = {...} "{{{2 " Perform replacements on the syntax name. let g:tcomment#syntax_substitute = { \ '\C^javaScript': {'sub': 'javascript'} \ } endif if !exists('g:tcommentSyntaxMap') " tcomment guesses filetypes based on the name of the current syntax " region. This works well if the syntax names match " /filetypeSomeName/. Other syntax names have to be explicitly " mapped onto the corresponding filetype. " :read: let g:tcommentSyntaxMap = {...} "{{{2 let g:tcommentSyntaxMap = { \ 'vimMzSchemeRegion': 'scheme', \ 'vimPerlRegion': 'perl', \ 'vimPythonRegion': 'python', \ 'vimRubyRegion': 'ruby', \ 'vimTclRegion': 'tcl', \ 'Delimiter': { \ 'filetype': { \ 'php': 'php', \ }, \ }, \ 'phpRegionDelimiter': { \ 'prevnonblank': [ \ {'match': '', 'filetype': 'html'}, \ ], \ 'nextnonblank': [ \ {'match': '?>', 'filetype': 'php'}, \ {'match': '#', \ } endif if !exists("g:tcommentLineC") " Generic c-like block comments. " :read: let g:tcommentBlockC = {...} "{{{2 let g:tcommentLineC = { \ 'commentstring': '/* %s */', \ 'replacements': g:tcomment#replacements_c \ } endif if !exists("g:tcommentBlockC") let g:tcommentBlockC = { \ 'commentstring': '/*%s */', \ 'middle': ' * ', \ 'rxbeg': '\*\+', \ 'rxend': '\*\+', \ 'rxmid': '\*\+', \ 'replacements': g:tcomment#replacements_c \ } endif if !exists("g:tcommentBlockC2") " Generic c-like block comments (alternative markup). " :read: let g:tcommentBlockC2 = {...} "{{{2 let g:tcommentBlockC2 = { \ 'commentstring': '/**%s */', \ 'middle': ' * ', \ 'rxbeg': '\*\+', \ 'rxend': '\*\+', \ 'rxmid': '\*\+', \ 'replacements': g:tcomment#replacements_c \ } endif if !exists("g:tcommentInlineC") " Generic c-like comments. let g:tcommentInlineC = g:tcommentLineC "{{{2 endif if !exists("g:tcommentBlockXML") " Generic xml-like block comments. let g:tcommentBlockXML = "\n " "{{{2 endif if !exists("g:tcommentInlineXML") " Generic xml-like comments. let g:tcommentInlineXML = "" "{{{2 endif let s:typesDirty = 1 let s:definitions = {} " If you don't explicitly define a comment style, |:TComment| will use " 'commentstring' instead. We override the default values here in order " to have a blank after the comment marker. Block comments work only if " we explicitly define the markup. " " NAME usually is a 'filetype'. You can use special suffixes to define " special comment types. E.g. the name "FILETYPE_block" is used for " block comments for 'filetype'. The name "FILETYPE_inline" is used for " inline comments. If no specialized comment definition exists, the " normal one with name "FILETYPE" is used. " " The comment definition can be either a string or a dictionary. " " If it is a string: " The format for block comments is similar to 'commentstrings' with the " exception that the format strings for blocks can contain a second line " that defines how "middle lines" (see :h format-comments) should be " displayed. " " Example: If the string is "--%s--\n-- ", lines will be commented as " "--%s--" but the middle lines in block comments will be commented as " "--%s". " " If it is a dictionary: " See the help on the args argument of |tcomment#Comment| (see item 1, " args is a list of key=value pairs) to find out which fields can be " used. function! tcomment#DefineType(name, commentdef) if !has_key(s:definitions, a:name) if type(a:commentdef) == 4 let cdef = copy(a:commentdef) else let cdef = a:0 >= 1 ? a:1 : {} let cdef.commentstring = a:commentdef endif let s:definitions[a:name] = cdef endif let s:typesDirty = 1 endf " :nodoc: " Return comment definition function! tcomment#GetCommentDef(name) return get(s:definitions, a:name, "") endf " :nodoc: " Return 1 if a comment type is defined. function! tcomment#TypeExists(name) return has_key(s:definitions, a:name) endf " :doc: " A dictionary of NAME => COMMENT DEFINITION (see |tcomment#DefineType|) " that can be set in vimrc to override tcomment's default comment " styles. " :read: let g:tcomment_types = {} "{{{2 if exists('g:tcomment_types') for [s:name, s:def] in items(g:tcomment_types) call tcomment#DefineType(s:name, s:def) endfor unlet! s:name s:def endif call tcomment#DefineType('aap', '# %s' ) call tcomment#DefineType('ada', '-- %s' ) call tcomment#DefineType('apache', '# %s' ) call tcomment#DefineType('autoit', '; %s' ) call tcomment#DefineType('asm', '; %s' ) call tcomment#DefineType('awk', '# %s' ) call tcomment#DefineType('catalog', '-- %s --' ) call tcomment#DefineType('catalog_block', "--%s--\n " ) call tcomment#DefineType('cpp', '// %s' ) call tcomment#DefineType('cpp_inline', g:tcommentInlineC ) call tcomment#DefineType('cpp_block', g:tcommentBlockC ) call tcomment#DefineType('css', '/* %s */' ) call tcomment#DefineType('css_inline', g:tcommentInlineC ) call tcomment#DefineType('css_block', g:tcommentBlockC ) call tcomment#DefineType('c', g:tcommentLineC ) call tcomment#DefineType('c_inline', g:tcommentInlineC ) call tcomment#DefineType('c_block', g:tcommentBlockC ) call tcomment#DefineType('cfg', '# %s' ) call tcomment#DefineType('clojure', {'commentstring': '; %s', 'count': 2}) call tcomment#DefineType('clojure_inline', '; %s' ) call tcomment#DefineType('clojurescript', ';; %s' ) call tcomment#DefineType('clojurescript_inline', '; %s' ) call tcomment#DefineType('coffee', '# %s' ) call tcomment#DefineType('conf', '# %s' ) call tcomment#DefineType('conkyrc', '# %s' ) call tcomment#DefineType('crontab', '# %s' ) call tcomment#DefineType('cs', '// %s' ) call tcomment#DefineType('cs_inline', g:tcommentInlineC ) call tcomment#DefineType('cs_block', g:tcommentBlockC ) call tcomment#DefineType('debsources', '# %s' ) call tcomment#DefineType('debcontrol', '# %s' ) call tcomment#DefineType('desktop', '# %s' ) call tcomment#DefineType('dnsmasq', '# %s' ) call tcomment#DefineType('docbk', '' ) call tcomment#DefineType('docbk_inline', g:tcommentInlineXML) call tcomment#DefineType('docbk_block', g:tcommentBlockXML ) call tcomment#DefineType('dosbatch', 'rem %s' ) call tcomment#DefineType('dosini', '; %s' ) call tcomment#DefineType('dsl', '; %s' ) call tcomment#DefineType('dylan', '// %s' ) call tcomment#DefineType('eiffel', '-- %s' ) call tcomment#DefineType('erlang', '%%%% %s' ) call tcomment#DefineType('eruby', '<%%# %s' ) call tcomment#DefineType('fstab', '# %s' ) call tcomment#DefineType('gitcommit', '# %s' ) call tcomment#DefineType('gitignore', '# %s' ) call tcomment#DefineType('gtkrc', '# %s' ) call tcomment#DefineType('go', '// %s' ) call tcomment#DefineType('go_inline', g:tcommentInlineC ) call tcomment#DefineType('go_block', g:tcommentBlockC ) call tcomment#DefineType('groovy', '// %s' ) call tcomment#DefineType('groovy_inline', g:tcommentInlineC ) call tcomment#DefineType('groovy_block', g:tcommentBlockC ) call tcomment#DefineType('groovy_doc_block', g:tcommentBlockC2 ) call tcomment#DefineType('haml', '-# %s' ) call tcomment#DefineType('haskell', '-- %s' ) call tcomment#DefineType('haskell_block', "{-%s-}\n " ) call tcomment#DefineType('haskell_inline', '{- %s -}' ) call tcomment#DefineType('html', '' ) call tcomment#DefineType('html_inline', g:tcommentInlineXML) call tcomment#DefineType('html_block', g:tcommentBlockXML ) call tcomment#DefineType('htmldjango', '{# %s #}' ) call tcomment#DefineType('htmldjango_block', "{%% comment %%}%s{%% endcomment %%}\n ") call tcomment#DefineType('ini', '; %s' ) " php ini (/etc/php5/...) call tcomment#DefineType('io', '// %s' ) call tcomment#DefineType('jasmine', '# %s' ) call tcomment#DefineType('javaScript', '// %s' ) call tcomment#DefineType('javaScript_inline', g:tcommentInlineC ) call tcomment#DefineType('javaScript_block', g:tcommentBlockC ) call tcomment#DefineType('javascript', '// %s' ) call tcomment#DefineType('javascript_inline', g:tcommentInlineC ) call tcomment#DefineType('javascript_block', g:tcommentBlockC ) call tcomment#DefineType('java', '/* %s */' ) call tcomment#DefineType('java_inline', g:tcommentInlineC ) call tcomment#DefineType('java_block', g:tcommentBlockC ) call tcomment#DefineType('java_doc_block', g:tcommentBlockC2 ) call tcomment#DefineType('jproperties', '# %s' ) call tcomment#DefineType('lisp', '; %s' ) call tcomment#DefineType('lynx', '# %s' ) call tcomment#DefineType('matlab', '%% %s' ) call tcomment#DefineType('m4', 'dnl %s' ) call tcomment#DefineType('mail', '> %s' ) call tcomment#DefineType('monkey', ''' %s' ) call tcomment#DefineType('msidl', '// %s' ) call tcomment#DefineType('msidl_block', g:tcommentBlockC ) call tcomment#DefineType('nginx', '# %s' ) call tcomment#DefineType('nroff', '.\\" %s' ) call tcomment#DefineType('nsis', '# %s' ) call tcomment#DefineType('objc', '/* %s */' ) call tcomment#DefineType('objc_inline', g:tcommentInlineC ) call tcomment#DefineType('objc_block', g:tcommentBlockC ) call tcomment#DefineType('ocaml', '(* %s *)' ) call tcomment#DefineType('ocaml_inline', '(* %s *)' ) call tcomment#DefineType('ocaml_block', "(*%s*)\n " ) call tcomment#DefineType('pac', '// %s' ) call tcomment#DefineType('pascal', '(* %s *)' ) call tcomment#DefineType('pascal_inline', '(* %s *)' ) call tcomment#DefineType('pascal_block', "(*%s*)\n " ) call tcomment#DefineType('perl', '# %s' ) call tcomment#DefineType('perl_block', "=cut%s=cut" ) call tcomment#DefineType('php', {'commentstring_rx': '\%%(//\|#\) %s', 'commentstring': '// %s'}) call tcomment#DefineType('php_inline', g:tcommentInlineC ) call tcomment#DefineType('php_block', g:tcommentBlockC ) call tcomment#DefineType('php_2_block', g:tcommentBlockC2 ) call tcomment#DefineType('po', '# %s' ) call tcomment#DefineType('prolog', '%% %s' ) call tcomment#DefineType('puppet', '# %s' ) call tcomment#DefineType('python', '# %s' ) call tcomment#DefineType('rc', '// %s' ) call tcomment#DefineType('readline', '# %s' ) call tcomment#DefineType('resolv', '# %s' ) call tcomment#DefineType('robots', '# %s' ) call tcomment#DefineType('ruby', '# %s' ) call tcomment#DefineType('ruby_3', '### %s' ) call tcomment#DefineType('ruby_block', "=begin rdoc%s=end") call tcomment#DefineType('ruby_nodoc_block', "=begin%s=end" ) call tcomment#DefineType('r', '# %s' ) call tcomment#DefineType('samba', '# %s' ) call tcomment#DefineType('sbs', "' %s" ) call tcomment#DefineType('scheme', '; %s' ) call tcomment#DefineType('scss', '// %s' ) call tcomment#DefineType('scss_inline', g:tcommentInlineC ) call tcomment#DefineType('scss_block', g:tcommentBlockC ) call tcomment#DefineType('sed', '# %s' ) call tcomment#DefineType('sgml', '' ) call tcomment#DefineType('sgml_inline', g:tcommentInlineXML) call tcomment#DefineType('sgml_block', g:tcommentBlockXML ) call tcomment#DefineType('sh', '# %s' ) call tcomment#DefineType('smarty', '{* %s *}' ) call tcomment#DefineType('spec', '# %s' ) call tcomment#DefineType('sps', '* %s.' ) call tcomment#DefineType('sps_block', "* %s." ) call tcomment#DefineType('spss', '* %s.' ) call tcomment#DefineType('spss_block', "* %s." ) call tcomment#DefineType('sql', '-- %s' ) call tcomment#DefineType('squid', '# %s' ) call tcomment#DefineType('st', '" %s "' ) call tcomment#DefineType('tcl', '# %s' ) call tcomment#DefineType('tex', '%% %s' ) call tcomment#DefineType('tpl', '' ) call tcomment#DefineType('typoscript', '# %s' ) call tcomment#DefineType('vhdl', '-- %s' ) call tcomment#DefineType('viki', '%% %s' ) call tcomment#DefineType('viki_3', '%%%%%% %s' ) call tcomment#DefineType('viki_inline', '{cmt: %s}' ) call tcomment#DefineType('vim', '" %s' ) call tcomment#DefineType('vim_3', '""" %s' ) call tcomment#DefineType('websec', '# %s' ) call tcomment#DefineType('x86conf', '# %s' ) call tcomment#DefineType('xml', '' ) call tcomment#DefineType('xml_inline', g:tcommentInlineXML) call tcomment#DefineType('xml_block', g:tcommentBlockXML ) call tcomment#DefineType('xs', '// %s' ) call tcomment#DefineType('xs_block', g:tcommentBlockC ) call tcomment#DefineType('xslt', '' ) call tcomment#DefineType('xslt_inline', g:tcommentInlineXML) call tcomment#DefineType('xslt_block', g:tcommentBlockXML ) call tcomment#DefineType('yaml', '# %s' ) function! s:DefaultValue(option) exec 'let '. a:option .' = &'. a:option exec 'set '. a:option .'&' exec 'let default = &'. a:option exec 'let &'. a:option .' = '. a:option return default endf let s:defaultComments = s:DefaultValue('comments') let s:defaultCommentString = s:DefaultValue('commentstring') let s:nullCommentString = '%s' " tcomment#Comment(line1, line2, ?commentMode, ?commentAnyway, ?args...) " args... are either: " 1. a list of key=value pairs where known keys are (see also " |g:tcommentOptions|): " as=STRING ... Use a specific comment definition " count=N ... Repeat the comment string N times " col=N ... Start the comment at column N (in block " mode; must be smaller than |indent()|) " mode=STRING ... See the notes below on the "commentMode" argument " begin=STRING ... Comment prefix " end=STRING ... Comment postfix " middle=STRING ... Middle line comments in block mode " rxbeg=N ... Regexp to find the substring of "begin" " that should be multiplied by "count" " rxend=N ... The above for "end" " rxmid=N ... The above for "middle" " commentstring_rx ... A regexp format string that matches " commented lines (no new groups may be " introduced, the |regexp| is |\V|; % have " to be doubled); "commentstring", "begin" " and optionally "end" must be defined or " deducible. " 2. 1-2 values for: ?commentPrefix, ?commentPostfix " 3. a dictionary (internal use only) " " commentMode: " G ... guess the value of commentMode " B ... block (use extra lines for the comment markers) " i ... maybe inline, guess " I ... inline " R ... right (comment the line right of the cursor) " v ... visual " o ... operator " By default, each line in range will be commented by adding the comment " prefix and postfix. function! tcomment#Comment(beg, end, ...) let commentMode = (a:0 >= 1 ? a:1 : 'G') . g:tcommentModeExtra let commentAnyway = a:0 >= 2 ? (a:2 == '!') : 0 " TLogVAR a:beg, a:end, commentMode, commentAnyway " save the cursor position let s:current_pos = getpos('.') let cursor_pos = getpos("'>") let s:cursor_pos = [] if commentMode =~# 'i' let commentMode = substitute(commentMode, '\Ci', line("'<") == line("'>") ? 'I' : 'G', 'g') endif let [lbeg, cbeg, lend, cend] = s:GetStartEnd(a:beg, a:end, commentMode) " TLogVAR commentMode, lbeg, cbeg, lend, cend " get the correct commentstring let cdef = copy(g:tcommentOptions) " TLogVAR 1, cdef if exists('b:tcommentOptions') let cdef = extend(cdef, copy(b:tcommentOptions)) " TLogVAR 2, cdef endif if a:0 >= 3 && type(a:3) == 4 call extend(cdef, a:3) " TLogVAR 3, cdef else call extend(cdef, s:GetCommentDefinition(lbeg, lend, commentMode)) " TLogVAR 4, cdef let ax = 3 if a:0 >= 3 && a:3 != '' && stridx(a:3, '=') == -1 let ax = 4 let cdef.begin = a:3 if a:0 >= 4 && a:4 != '' && stridx(a:4, '=') == -1 let ax = 5 let cdef.end = a:4 endif endif " TLogVAR ax, a:0, a:000 if a:0 >= ax let cdef = extend(cdef, s:ParseArgs(lbeg, lend, commentMode, a:000[ax - 1 : -1])) " TLogVAR 5, cdef endif if !empty(get(cdef, 'begin', '')) || !empty(get(cdef, 'end', '')) let cdef.commentstring = s:EncodeCommentPart(get(cdef, 'begin', '')) \ . '%s' \ . s:EncodeCommentPart(get(cdef, 'end', '')) endif let commentMode = cdef.mode endif if exists('s:temp_options') let cdef = s:ExtendCDef(lbeg, lend, commentMode, cdef, s:temp_options) " TLogVAR cdef " echom "DBG s:temp_options" string(s:temp_options) unlet s:temp_options endif " TLogVAR cdef if !empty(filter(['count', 'cbeg', 'cend', 'cmid'], 'has_key(cdef, v:val)')) call s:RepeatCommentstring(cdef) endif " echom "DBG" string(a:000) let cms0 = s:BlockGetCommentRx(cdef) " TLogVAR cms0 " make whitespace optional; this conflicts with comments that require some " whitespace let cmtCheck = substitute(cms0, '\([ ]\)', '\1\\?', 'g') " turn commentstring into a search pattern let cmtCheck = printf(cmtCheck, '\(\_.\{-}\)') " set commentMode and indentStr let [indentStr, uncomment] = s:CommentDef(lbeg, lend, cmtCheck, commentMode, cbeg, cend) " TLogVAR indentStr, uncomment let col = get(cdef, 'col', -1) if col >= 0 let col -= 1 let indent = len(indentStr) if col > indent let cms0 = repeat(' ', col - indent) . cms0 " TLogVAR cms0 else let indentStr = repeat(' ', col) endif endif if commentAnyway let uncomment = 0 endif " go if commentMode =~# 'B' " We want a comment block call s:CommentBlock(lbeg, lend, uncomment, cmtCheck, cdef, indentStr) else " call s:CommentLines(lbeg, lend, cbeg, cend, uncomment, cmtCheck, cms0, indentStr) " We want commented lines " final search pattern for uncommenting let cmtCheck = escape('\V\^\(\s\{-}\)'. cmtCheck .'\$', '"/\') " final pattern for commenting let cmtReplace = s:GetCommentReplace(cdef, cms0) " TLogVAR cmtReplace let s:cdef = cdef let cmd = lbeg .','. lend .'s/\V'. \ s:StartPosRx(commentMode, lbeg, cbeg) . indentStr .'\zs\(\_.\{-}\)'. s:EndPosRx(commentMode, lend, cend) .'/'. \ '\=s:ProcessedLine('. uncomment .', submatch(0), "'. cmtCheck .'", "'. cmtReplace .'")/ge' " TLogVAR cmd exec cmd call histdel('search', -1) unlet s:cdef endif " reposition cursor " TLogVAR commentMode if !empty(s:cursor_pos) let cursor_pos = s:cursor_pos endif if commentMode =~ '>' call setpos('.', cursor_pos) if commentMode !~ 'i' && commentMode =~ '>>' norm! l^ endif elseif commentMode =~ '#' call setpos('.', cursor_pos) else call setpos('.', s:current_pos) endif unlet s:cursor_pos s:current_pos endf function! tcomment#SetOption(name, arg) "{{{3 " TLogVAR a:name, a:arg if !exists('s:temp_options') let s:temp_options = {} endif " if index(['count', 'as'], a:name) != -1 if empty(a:arg) if has_key(s:temp_options, a:name) call remove(s:temp_options, a:name) endif else let s:temp_options[a:name] = a:arg endif " endif endf function! s:GetStartEnd(beg, end, commentMode) "{{{3 " TLogVAR a:beg, a:end, a:commentMode if type(a:beg) == 3 let [lbeg, cbeg] = a:beg let [lend, cend] = a:end else let lbeg = a:beg let lend = a:end let commentMode = a:commentMode " TLogVAR commentMode if commentMode =~# 'R' let cbeg = col('.') let cend = 0 let commentMode = substitute(commentMode, '\CR', 'G', 'g') elseif commentMode =~# 'I' let cbeg = col("'<") if cbeg == 0 let cbeg = col('.') endif let cend = col("'>") if cend < col('$') && (commentMode =~# 'o' || &selection == 'inclusive') let cend += 1 " TLogVAR cend, col('$') endif else let cbeg = 0 let cend = 0 endif endif " TLogVAR lbeg, cbeg, lend, cend return [lbeg, cbeg, lend, cend] endf function! s:RepeatCommentstring(cdef) "{{{3 " TLogVAR a:cdef let cms = s:BlockGetCommentString(a:cdef) let mid = s:BlockGetMiddleString(a:cdef) let cms_fbeg = match(cms, '\s*%\@= 1 ? a:1 : '' let bang = a:0 >= 2 ? a:2 : '' " TLogVAR a:type, commentMode, bang if !exists('w:tcommentPos') let w:tcommentPos = getpos(".") endif let sel_save = &selection set selection=inclusive let reg_save = @@ " let pos = getpos('.') try if a:type == 'line' silent exe "normal! '[V']" let commentMode1 = 'G' elseif a:type == 'block' silent exe "normal! `[\`]" let commentMode1 = 'I' elseif a:type == 'char' && !g:tcomment#ignore_char_type silent exe "normal! `[v`]" let commentMode1 = 'I' else silent exe "normal! `[v`]" let commentMode1 = 'i' endif if empty(commentMode) let commentMode = commentMode1 endif let lbeg = line("'[") let lend = line("']") let cbeg = col("'[") let cend = col("']") " TLogVAR lbeg, lend, cbeg, cend " echom "DBG tcomment#Operator" lbeg col("'[") col("'<") lend col("']") col("'>") norm!  let commentMode .= g:tcommentOpModeExtra if a:type =~ 'line\|block' || g:tcomment#ignore_char_type call tcomment#Comment(lbeg, lend, commentMode.'o', bang) else call tcomment#Comment([lbeg, cbeg], [lend, cend], commentMode.'o', bang) endif finally let &selection = sel_save let @@ = reg_save if g:tcommentOpModeExtra !~ '>' " TLogVAR pos " call setpos('.', pos) if exists('w:tcommentPos') call setpos('.', w:tcommentPos) unlet! w:tcommentPos else echohl WarningMsg echom "TComment: w:tcommentPos wasn't set. Please report this to the plugin author" echohl NONE endif endif endtry endf function! tcomment#OperatorLine(type) "{{{3 call tcomment#Operator(a:type, 'G') endf function! tcomment#OperatorAnyway(type) "{{{3 call tcomment#Operator(a:type, '', '!') endf function! tcomment#OperatorLineAnyway(type) "{{{3 call tcomment#Operator(a:type, 'G', '!') endf " :display: tcomment#CommentAs(beg, end, commentAnyway, filetype, ?args...) " Where args is either: " 1. A count NUMBER " 2. An args list (see the notes on the "args" argument of " |tcomment#Comment()|) " comment text as if it were of a specific filetype function! tcomment#CommentAs(beg, end, commentAnyway, filetype, ...) if a:filetype =~ '_block$' let commentMode = 'B' let ft = substitute(a:filetype, '_block$', '', '') elseif a:filetype =~ '_inline$' let commentMode = 'I' let ft = substitute(a:filetype, '_inline$', '', '') else let commentMode = 'G' let ft = a:filetype endif if a:0 >= 1 if type(a:1) == 0 let cdef = {'count': a:0 >= 1 ? a:1 : 1} else let cdef = s:ParseArgs(a:beg, a:end, commentMode, a:000) endif else let cdef = {} endif " echom "DBG" string(cdef) call extend(cdef, s:GetCommentDefinitionForType(a:beg, a:end, commentMode, ft)) keepjumps call tcomment#Comment(a:beg, a:end, commentMode, a:commentAnyway, cdef) endf " collect all known comment types " :nodoc: function! tcomment#CollectFileTypes() if s:typesDirty let s:types = keys(s:definitions) let s:typesRx = '\V\^\('. join(s:types, '\|') .'\)\(\u\.\*\)\?\$' let s:typesDirty = 0 endif endf call tcomment#CollectFileTypes() " return a list of filetypes for which a tcomment_{&ft} is defined " :nodoc: function! tcomment#Complete(ArgLead, CmdLine, CursorPos) "{{{3 call tcomment#CollectFileTypes() let completions = copy(s:types) let filetype = s:Filetype() if index(completions, filetype) != -1 " TLogVAR filetype call insert(completions, filetype) endif if !empty(a:ArgLead) call filter(completions, 'v:val =~ ''\V\^''.a:ArgLead') endif let completions += tcomment#CompleteArgs(a:ArgLead, a:CmdLine, a:CursorPos) return completions endf " :nodoc: function! tcomment#CompleteArgs(ArgLead, CmdLine, CursorPos) "{{{3 let completions = ['as=', 'col=', 'count=', 'mode=', 'begin=', 'end=', 'rxbeg=', 'rxend=', 'rxmid='] if !empty(a:ArgLead) if a:ArgLead =~ '^as=' call tcomment#CollectFileTypes() let completions += map(copy(s:types), '"as=". v:val') endif call filter(completions, 'v:val =~ ''\V\^''.a:ArgLead') endif return completions endf function! s:EncodeCommentPart(string) return substitute(a:string, '%', '%%', 'g') endf function! s:GetCommentDefinitionForType(beg, end, commentMode, filetype) "{{{3 let cdef = s:GetCommentDefinition(a:beg, a:end, a:commentMode, a:filetype) " TLogVAR cdef let cms = cdef.commentstring let commentMode = cdef.mode let pre = substitute(cms, '%\@= 1 ? a:1 : '' if ft != '' let cdef = s:GetCustomCommentString(ft, a:commentMode) else let cdef = {'mode': a:commentMode} endif " TLogVAR cdef let cms = get(cdef, 'commentstring', '') if empty(cms) let filetype = s:Filetype() if exists('b:commentstring') let cms = b:commentstring " TLogVAR 1, cms return s:GetCustomCommentString(filetype, a:commentMode, cms) elseif exists('b:commentStart') && b:commentStart != '' let cms = s:EncodeCommentPart(b:commentStart) .' %s' " TLogVAR 2, cms if exists('b:commentEnd') && b:commentEnd != '' let cms = cms .' '. s:EncodeCommentPart(b:commentEnd) endif return s:GetCustomCommentString(filetype, a:commentMode, cms) elseif g:tcommentGuessFileType || (exists('g:tcommentGuessFileType_'. filetype) \ && g:tcommentGuessFileType_{filetype} =~ '[^0]') if g:tcommentGuessFileType_{filetype} == 1 let altFiletype = '' else let altFiletype = g:tcommentGuessFileType_{filetype} endif " TLogVAR altFiletype return s:GuessFileType(a:beg, a:end, a:commentMode, filetype, altFiletype) else return s:GetCustomCommentString(filetype, a:commentMode, s:GuessCurrentCommentString(a:commentMode)) endif let cdef.commentstring = cms endif return cdef endf function! s:StartPosRx(mode, line, col) " TLogVAR a:mode, a:line, a:col if a:mode =~# 'I' return s:StartLineRx(a:line) . s:StartColRx(a:col) else return s:StartColRx(a:col) endif endf function! s:EndPosRx(mode, line, col) if a:mode =~# 'I' return s:EndLineRx(a:line) . s:EndColRx(a:col) else return s:EndColRx(a:col) endif endf function! s:StartLineRx(pos) return '\%'. a:pos .'l' endf function! s:EndLineRx(pos) return '\%'. a:pos .'l' endf function! s:StartColRx(pos) if a:pos == 0 return '\^' else return '\%'. a:pos .'c' endif endf function! s:EndColRx(pos) if a:pos == 0 return '\$' else return '\%'. a:pos .'c' endif endf function! s:GetIndentString(line, start) let start = a:start > 0 ? a:start - 1 : 0 return substitute(strpart(getline(a:line), start), '\V\^\s\*\zs\.\*\$', '', '') endf function! s:CommentDef(beg, end, checkRx, commentMode, cstart, cend) let mdrx = '\V'. s:StartColRx(a:cstart) .'\s\*'. a:checkRx .'\s\*'. s:EndColRx(0) " let mdrx = '\V'. s:StartPosRx(a:commentMode, a:beg, a:cstart) .'\s\*'. a:checkRx .'\s\*'. s:EndPosRx(a:commentMode, a:end, 0) let line = getline(a:beg) if a:cstart != 0 && a:cend != 0 let line = strpart(line, 0, a:cend - 1) endif let uncomment = (line =~ mdrx) let indentStr = s:GetIndentString(a:beg, a:cstart) let il = indent(a:beg) let n = a:beg + 1 while n <= a:end if getline(n) =~ '\S' let jl = indent(n) if jl < il let indentStr = s:GetIndentString(n, a:cstart) let il = jl endif if a:commentMode =~# 'G' if !(getline(n) =~ mdrx) let uncomment = 0 endif endif endif let n = n + 1 endwh if a:commentMode =~# 'B' let t = @t try silent exec 'norm! '. a:beg.'G1|v'.a:end.'G$"ty' let uncomment = (@t =~ mdrx) finally let @t = t endtry endif return [indentStr, uncomment] endf function! s:ProcessedLine(uncomment, match, checkRx, replace) " TLogVAR a:uncomment, a:match, a:checkRx, a:replace if !(a:match =~ '\S' || g:tcommentBlankLines) return a:match endif let ml = len(a:match) if a:uncomment let rv = substitute(a:match, a:checkRx, '\1\2', '') let rv = s:UnreplaceInLine(rv) else let rv = s:ReplaceInLine(a:match) let rv = printf(a:replace, rv) endif " TLogVAR rv " let md = len(rv) - ml if s:cdef.mode =~ '>' let s:cursor_pos = getpos('.') let s:cursor_pos[2] += len(rv) elseif s:cdef.mode =~ '#' if empty(s:cursor_pos) let prefix_len = match(a:replace, '%\@ 702 || (v:version == 702 && has('patch407')) let rv = escape(rv, "\r") else let rv = escape(rv, "\\r") endif " TLogVAR rv " let rv = substitute(rv, '\n', '\\\n', 'g') " TLogVAR rv return rv endf function! s:ReplaceInLine(text) "{{{3 if has_key(s:cdef, 'replacements') let text = a:text " TLogVAR text for [token, substitution] in items(s:cdef.replacements) let text = substitute(text, '\V'. escape(token, '\'), substitution, 'g') " TLogVAR token, substitution, text endfor " TLogVAR text return text else return a:text endif endf function! s:UnreplaceInLine(text) "{{{3 if has_key(s:cdef, 'replacements') let text = a:text " TLogVAR text for [substitution, token] in items(s:cdef.replacements) " TLogVAR substitution, token let text = substitute(text, '\V'. escape(token, '\'), substitution, 'g') endfor return text else return a:text endif endf function! s:CommentBlock(beg, end, uncomment, checkRx, cdef, indentStr) " TLogVAR a:beg, a:end, a:uncomment, a:checkRx, a:cdef, a:indentStr let t = @t let sel_save = &selection set selection=exclusive try silent exec 'norm! '. a:beg.'G1|v'.a:end.'G$"td' let ms = s:BlockGetMiddleString(a:cdef) let mx = escape(ms, '\') if a:uncomment let @t = substitute(@t, '\V\^\s\*'. a:checkRx .'\$', '\1', '') if ms != '' let @t = substitute(@t, '\V\n'. a:indentStr . mx, '\n'. a:indentStr, 'g') endif let @t = substitute(@t, '^\n', '', '') let @t = substitute(@t, '\n\s*$', '', '') else let cs = s:BlockGetCommentString(a:cdef) let cs = a:indentStr . substitute(cs, '%\@= 1 ? a:1 : &filetype let ft = substitute(ft, '\..*$', '', '') return ft endf " A function that makes the s:GuessFileType() function usable for other " library developers. " " The argument is a dictionary with the following keys: " " beg ................ (default = line(".")) " end ................ (default = line(".")) " commentMode ........ (default = "G") " filetype ........... (default = &filetype) " fallbackFiletype ... (default = "") " " This function return a dictionary that contains information about how " to make comments. The information about the filetype of the text " between lines "beg" and "end" is in the "filetype" key of the return " value. It returns the first discernible filetype it encounters. " :display: tcomment#GuessFileType(?options={}) function! tcomment#GuessCommentType(...) "{{{3 let options = a:0 >= 1 ? a:1 : {} let beg = get(options, 'beg', line('.')) let end = get(options, 'end', line('.')) let commentMode = get(options, 'commentMode', '') let filetype = get(options, 'filetype', &filetype) let fallbackFiletype = get(options, 'filetype', '') return s:GuessFileType(beg, end, commentMode, filetype, fallbackFiletype) endf " inspired by Meikel Brandmeyer's EnhancedCommentify.vim " this requires that a syntax names are prefixed by the filetype name " s:GuessFileType(beg, end, commentMode, filetype, ?fallbackFiletype) function! s:GuessFileType(beg, end, commentMode, filetype, ...) " TLogVAR a:beg, a:end, a:commentMode, a:filetype, a:000 if a:0 >= 1 && a:1 != '' let cdef = s:GetCustomCommentString(a:1, a:commentMode) if empty(get(cdef, 'commentstring', '')) let cdef.commentstring = s:GuessCurrentCommentString(a:commentMode) endif else let cdef = s:GetCustomCommentString(a:filetype, a:commentMode) if !has_key(cdef, 'commentstring') let cdef = {'commentstring': s:GuessCurrentCommentString(0), 'mode': s:CommentMode(a:commentMode, 'G')} endif endif let beg = a:beg let end = nextnonblank(a:end) if end == 0 let end = a:end let beg = prevnonblank(a:beg) if beg == 0 let beg = a:beg endif endif let n = beg " TLogVAR n, beg, end while n <= end let m = indent(n) + 1 let text = getline(n) let le = len(text) " TLogVAR m, le while m <= le let syntaxName = s:GetSyntaxName(n, m) " TLogVAR syntaxName, n, m let ftypeMap = get(g:tcommentSyntaxMap, syntaxName, '') " TLogVAR ftypeMap if !empty(ftypeMap) && type(ftypeMap) == 4 if n < a:beg let key = 'prevnonblank' elseif n > a:end let key = 'nextnonblank' else let key = '' endif if empty(key) || !has_key(ftypeMap, key) let ftypeftype = get(ftypeMap, 'filetype', {}) " TLogVAR ftypeMap, ftypeftype unlet! ftypeMap let ftypeMap = get(ftypeftype, a:filetype, '') else let mapft = '' for mapdef in ftypeMap[key] if strpart(text, m - 1) =~ '^'. mapdef.match let mapft = mapdef.filetype break endif endfor unlet! ftypeMap if empty(mapft) let ftypeMap = '' else let ftypeMap = mapft endif endif endif if !empty(ftypeMap) " TLogVAR ftypeMap return s:GetCustomCommentString(ftypeMap, a:commentMode, cdef.commentstring) elseif syntaxName =~ s:typesRx let ft = substitute(syntaxName, s:typesRx, '\1', '') " TLogVAR ft if exists('g:tcommentIgnoreTypes_'. a:filetype) && g:tcommentIgnoreTypes_{a:filetype} =~ '\<'.ft.'\>' let m += 1 else return s:GetCustomCommentString(ft, a:commentMode, cdef.commentstring) endif elseif syntaxName == '' || syntaxName == 'None' || syntaxName =~ '^\u\+$' || syntaxName =~ '^\u\U*$' let m += 1 else break endif endwh let n += 1 endwh " TLogVAR cdef return cdef endf function! s:GetSyntaxName(lnum, col) "{{{3 let syntaxName = synIDattr(synID(a:lnum, a:col, 1), 'name') if !empty(g:tcomment#syntax_substitute) for [rx, subdef] in items(g:tcomment#syntax_substitute) if !has_key(subdef, 'if') || eval(subdef.if) let syntaxName = substitute(syntaxName, rx, subdef.sub, 'g') endif endfor endif " TLogVAR syntaxName return syntaxName endf function! s:CommentMode(commentMode, newmode) "{{{3 return substitute(a:commentMode, '\w\+', a:newmode, 'g') endf function! s:GuessCurrentCommentString(commentMode) " TLogVAR a:commentMode let valid_cms = (match(&commentstring, '%\@= 1 let def = {'commentstring': a:1} let commentMode = s:CommentMode(commentMode, 'G') " TLogVAR 4, def else let def = {} let commentMode = s:CommentMode(commentMode, 'G') " TLogVAR 5, def endif let cdef = copy(def) let cdef.mode = commentMode let cdef.filetype = a:ft " TLogVAR cdef return cdef endf function! s:GetCommentReplace(cdef, cms0) if has_key(a:cdef, 'commentstring_rx') let rs = s:BlockGetCommentString(a:cdef) else let rs = a:cms0 endif return escape(rs, '"/') endf function! s:BlockGetCommentRx(cdef) if has_key(a:cdef, 'commentstring_rx') return a:cdef.commentstring_rx else let cms0 = s:BlockGetCommentString(a:cdef) let cms0 = escape(cms0, '\') return cms0 endif endf function! s:BlockGetCommentString(cdef) if has_key(a:cdef, 'middle') return a:cdef.commentstring else return matchstr(a:cdef.commentstring, '^.\{-}\ze\(\n\|$\)') endif endf function! s:BlockGetMiddleString(cdef) if has_key(a:cdef, 'middle') return a:cdef.middle else return matchstr(a:cdef.commentstring, '\n\zs.*') endif endf redraw " vi: ft=vim:tw=72:ts=4:fo=w2croql