diff --git a/plugin/NERD_commenter.vim b/plugin/NERD_commenter.vim index b9068f0..d2b3e34 100644 --- a/plugin/NERD_commenter.vim +++ b/plugin/NERD_commenter.vim @@ -195,7 +195,7 @@ let s:delimiterMap = { \ 'groovy': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, \ 'gsp': { 'left': '<%--', 'right': '--%>', 'leftAlt': ''}, \ 'gtkrc': { 'left': '#' }, - \ 'haskell': { 'left': '{-','right': '-}', 'leftAlt': '--' }, + \ 'haskell': { 'left': '{-','right': '-}', 'nested': 1, 'leftAlt': '--', 'nestedAlt': 1 }, \ 'hb': { 'left': '#' }, \ 'h': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, \ 'haml': { 'left': '-#', 'leftAlt': '/' }, @@ -240,7 +240,7 @@ let s:delimiterMap = { \ 'lilo': { 'left': '#' }, \ 'lilypond': { 'left': '%' }, \ 'liquid': { 'left': '{% comment %}', 'right': '{% endcomment %}' }, - \ 'lisp': { 'left': ';', 'leftAlt': '#|', 'rightAlt': '|#' }, + \ 'lisp': { 'left': ';', 'nested': 1, 'leftAlt': '#|', 'rightAlt': '|#', 'nestedAlt': 1 }, \ 'llvm': { 'left': ';' }, \ 'lotos': { 'left': '(*', 'right': '*)' }, \ 'lout': { 'left': '#' }, @@ -288,7 +288,7 @@ let s:delimiterMap = { \ 'objc': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, \ 'objcpp': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, \ 'objj': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, - \ 'ocaml': { 'left': '(*', 'right': '*)' }, + \ 'ocaml': { 'left': '(*', 'right': '*)', 'nested': 1 }, \ 'occam': { 'left': '--' }, \ 'octave': { 'left': '%', 'leftAlt': '#' }, \ 'omlet': { 'left': '(*', 'right': '*)' }, @@ -329,7 +329,7 @@ let s:delimiterMap = { \ 'puppet': { 'left': '#' }, \ 'pyrex': { 'left': '# ', 'leftAlt': '#' }, \ 'python': { 'left': '# ', 'leftAlt': '#' }, - \ 'racket': { 'left': ';', 'leftAlt': '#|', 'rightAlt': '|#' }, + \ 'racket': { 'left': ';', 'nested': 1, 'leftAlt': '#|', 'rightAlt': '|#', 'nestedAlt': 1 }, \ 'radiance': { 'left': '#' }, \ 'ratpoison': { 'left': '#' }, \ 'r': { 'left': '#' }, @@ -349,9 +349,9 @@ let s:delimiterMap = { \ 'samba': { 'left': ';', 'leftAlt': '#' }, \ 'sass': { 'left': '//', 'leftAlt': '/*' }, \ 'sather': { 'left': '--' }, - \ 'scala': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/' }, + \ 'scala': { 'left': '//', 'nested': 1, 'leftAlt': '/*', 'rightAlt': '*/', 'nestedAlt': 1 }, \ 'scons': { 'left': '#' }, - \ 'scheme': { 'left': ';', 'leftAlt': '#|', 'rightAlt': '|#' }, + \ 'scheme': { 'left': ';', 'nested': 1, 'leftAlt': '#|', 'rightAlt': '|#', 'nestedAlt': 1 }, \ 'scilab': { 'left': '//' }, \ 'scsh': { 'left': ';' }, \ 'scss': { 'left': '//', 'leftAlt': '/*', 'rightAlt': '*/'}, @@ -373,7 +373,7 @@ let s:delimiterMap = { \ 'smarty': { 'left': '{*', 'right': '*}' }, \ 'smil': { 'left': '' }, \ 'smith': { 'left': ';' }, - \ 'sml': { 'left': '(*', 'right': '*)' }, + \ 'sml': { 'left': '(*', 'right': '*)', 'nested': 1 }, \ 'snippets': { 'left': '#' }, \ 'snnsnet': { 'left': '#' }, \ 'snnspat': { 'left': '#' }, @@ -505,6 +505,11 @@ function s:SetUpForNewFiletype(filetype, forceReset) let b:NERDCommenterDelims[i] = '' endif endfor + for i in ['nested', 'nestedAlt'] + if !has_key(b:NERDCommenterDelims, i) + let b:NERDCommenterDelims[i] = 0 + endif + endfor else let b:NERDCommenterDelims = s:CreateDelimMapFromCms() endif @@ -524,8 +529,10 @@ function s:CreateDelimMapFromCms() return { \ 'left': substitute(&commentstring, '\([^ \t]*\)\s*%s.*', '\1', ''), \ 'right': substitute(&commentstring, '.*%s\s*\(.*\)', '\1', 'g'), + \ 'nested': 0, \ 'leftAlt': '', - \ 'rightAlt': '' } + \ 'rightAlt': '', + \ 'nestedAlt': 0} endfunction " Function: s:SwitchToAlternativeDelimiters(printMsgs) function {{{2 @@ -550,14 +557,18 @@ function s:SwitchToAlternativeDelimiters(printMsgs) "save the current delimiters let tempLeft = s:Left() let tempRight = s:Right() + let tempNested = s:Nested() "swap current delimiters for alternative let b:NERDCommenterDelims['left'] = b:NERDCommenterDelims['leftAlt'] let b:NERDCommenterDelims['right'] = b:NERDCommenterDelims['rightAlt'] + "set information on whether these are nested + let b:NERDCommenterDelims['nested'] = b:NERDCommenterDelims['nestedAlt'] "set the previously current delimiters to be the new alternative ones let b:NERDCommenterDelims['leftAlt'] = tempLeft let b:NERDCommenterDelims['rightAlt'] = tempRight + let b:NERDCommenterDelims['nestedAlt'] = tempNested "tell the user what comment delimiters they are now using if a:printMsgs @@ -755,7 +766,7 @@ function s:CommentLines(forceNested, align, firstLine, lastLine) if s:CanCommentLine(a:forceNested, currentLine) "if the user has specified forceNesting then we check to see if we "need to switch delimiters for place-holders - if a:forceNested && g:NERDUsePlaceHolders + if a:forceNested && g:NERDUsePlaceHolders && !s:Nested() let theLine = s:SwapOuterMultiPartDelimsForPlaceHolders(theLine) endif @@ -801,9 +812,11 @@ function s:CommentLinesMinimal(firstLine, lastLine) throw 'NERDCommenter.Delimiters exception: Minimal comments can only be used for filetypes that have multipart delimiters' endif + let sexyNested = s:SexyNested() + "if we need to use place holders for the comment, make sure they are - "enabled for this filetype - if !g:NERDUsePlaceHolders && s:DoesBlockHaveMultipartDelim(a:firstLine, a:lastLine) + "enabled for this filetype, or the delims allow nesting + if !g:NERDUsePlaceHolders && !sexyNested && s:DoesBlockHaveMultipartDelim(a:firstLine, a:lastLine) throw 'NERDCommenter.Settings exception: Place holders are required but disabled.' endif @@ -813,13 +826,15 @@ function s:CommentLinesMinimal(firstLine, lastLine) "make sure all multipart delimiters on the lines are replaced with "placeholders to prevent illegal syntax - let currentLine = a:firstLine - while(currentLine <= a:lastLine) - let theLine = getline(currentLine) - let theLine = s:ReplaceDelims(left, right, g:NERDLPlace, g:NERDRPlace, theLine) - call setline(currentLine, theLine) - let currentLine = currentLine + 1 - endwhile + if !sexyNested + let currentLine = a:firstLine + while(currentLine <= a:lastLine) + let theLine = getline(currentLine) + let theLine = s:ReplaceDelims(left, right, g:NERDLPlace, g:NERDRPlace, theLine) + call setline(currentLine, theLine) + let currentLine = currentLine + 1 + endwhile + endif "add the delimiter to the top line let theLine = getline(a:firstLine) @@ -859,7 +874,7 @@ function s:CommentLinesSexy(topline, bottomline) throw 'NERDCommenter.Delimiters exception: cannot perform sexy comments with available delimiters.' endif - "make sure the lines aren't already commented sexually + "make sure the lines aren't already commented sexually or we can nest if !s:CanSexyCommentLines(a:topline, a:bottomline) throw 'NERDCommenter.Nesting exception: cannot nest sexy comments' endif @@ -884,7 +899,9 @@ function s:CommentLinesSexy(topline, bottomline) if lineHasTabs let theLine = s:ConvertLeadingTabsToSpaces(theLine) endif - let theLine = s:SwapOuterMultiPartDelimsForPlaceHolders(theLine) + if !s:SexyNested() + let theLine = s:SwapOuterMultiPartDelimsForPlaceHolders(theLine) + endif let theLine = s:AddLeftDelimAligned(left . spaceString, theLine, leftAlignIndx) if lineHasTabs let theLine = s:ConvertLeadingSpacesToTabs(theLine) @@ -898,7 +915,9 @@ function s:CommentLinesSexy(topline, bottomline) if lineHasTabs let theLine = s:ConvertLeadingTabsToSpaces(theLine) endif - let theLine = s:SwapOuterMultiPartDelimsForPlaceHolders(theLine) + if !s:SexyNested() + let theLine = s:SwapOuterMultiPartDelimsForPlaceHolders(theLine) + endif endif let theLine = s:AddRightDelim(spaceString . right, theLine) if lineHasTabs @@ -943,7 +962,9 @@ function s:CommentLinesSexy(topline, bottomline) let theLine = s:ConvertLeadingTabsToSpaces(theLine) endif - let theLine = s:SwapOuterMultiPartDelimsForPlaceHolders(theLine) + if !s:SexyNested() + let theLine = s:SwapOuterMultiPartDelimsForPlaceHolders(theLine) + endif " add the sexyComMarker let theLine = repeat(' ', leftAlignIndx) . repeat(' ', strlen(left)-strlen(sexyComMarker)) . sexyComMarkerSpaced . strpart(theLine, leftAlignIndx) @@ -985,7 +1006,7 @@ function s:CommentLinesToggle(forceNested, firstLine, lastLine) "if the user has specified forceNesting then we check to see if we "need to switch delimiters for place-holders - if g:NERDUsePlaceHolders + if g:NERDUsePlaceHolders && !s:Nested() let theLine = s:SwapOuterMultiPartDelimsForPlaceHolders(theLine) endif @@ -1305,7 +1326,7 @@ function s:RemoveDelimiters(left, right, line) endif "look for the right delimiter, if we find it, remove it - let rightIndx = s:FindDelimiterIndex(a:right, line) + let rightIndx = s:LastIndexOfDelim(a:right, line) if rightIndx != -1 let line = strpart(line, 0, rightIndx) . strpart(line, rightIndx+lenRight) @@ -1537,8 +1558,8 @@ function s:UncommentLineNormal(line) "get the positions of all delimiter types on the line let indxLeft = s:FindDelimiterIndex(s:Left(), line) let indxLeftAlt = s:FindDelimiterIndex(s:Left({'alt': 1}), line) - let indxRight = s:FindDelimiterIndex(s:Right(), line) - let indxRightAlt = s:FindDelimiterIndex(s:Right({'alt': 1}), line) + let indxRight = s:LastIndexOfDelim(s:Right(), line) + let indxRightAlt = s:LastIndexOfDelim(s:Right({'alt': 1}), line) "get the comment status on the line so we know how it is commented let lineCommentStatus = s:IsCommentedOutermost(s:Left(), s:Right(), s:Left({'alt': 1}), s:Right({'alt': 1}), line) @@ -1671,6 +1692,12 @@ function s:AltMultipart() return b:NERDCommenterDelims['rightAlt'] != '' endfunction +" Function: s:AltNested() {{{2 +" returns 1 if the alternate multipart (if any) delims allow nesting +function s:AltNested() + return b:NERDCommenterDelims['nestedAlt'] +endfunction + " Function: s:CanCommentLine(forceNested, line) {{{2 "This function is used to determine whether the given line can be commented. "It returns 1 if it can be and 0 otherwise @@ -1701,7 +1728,7 @@ function s:CanCommentLine(forceNested, lineNum) endif "if the line is commented but nesting is allowed then return true - if a:forceNested && (!s:Multipart() || g:NERDUsePlaceHolders) + if s:Nested() || (a:forceNested && (!s:Multipart() || g:NERDUsePlaceHolders)) return 1 endif @@ -1723,6 +1750,11 @@ endfunction " Return: 1 if the given lines can be commented sexually, 0 otherwise function s:CanSexyCommentLines(topline, bottomline) " see if the selected regions have any sexy comments + " however, if the language allows nested comments, + " we allow nested sexy comments + if s:SexyNested() + return 1 + endif let currentLine = a:topline while(currentLine <= a:bottomline) if s:IsInSexyComment(currentLine) @@ -2056,6 +2088,29 @@ function s:GetSexyComMarker(space, esc) return sexyComMarker endfunction +" Function: s:SexyNested() {{{2 +" Returns 1 if the sexy delimeters allow nesting +" TODO this is ugly copy&paste from the GetSexyComLeft/Right functions, +" these could all be cleaned up +function s:SexyNested() + let lenLeft = strlen(s:Left()) + let lenLeftAlt = strlen(s:Left({'alt': 1})) + + "assume c style sexy comments if possible + if s:HasCStyleComments() + return (s:Left() == '/*' && s:Nested()) || (s:Left({'alt': 1}) == '/*' && s:AltNested()) + else + "grab the longest left delim that has a right + if s:Multipart() && lenLeft >= lenLeftAlt + return s:Nested() + elseif s:AltMultipart() + return s:AltNested() + else + return 0 + endif + endif +endfunction + " Function: s:GetSexyComLeft(space, esc) {{{2 " Returns the left delimiter for sexy comments for this filetype or -1 if " there is none. C style sexy comments are used if possible @@ -2183,7 +2238,7 @@ endfunction " -left/right: the left and right delimiters to check for function s:IsCommented(left, right, line) "if the line isn't commented return true - if s:FindDelimiterIndex(a:left, a:line) != -1 && (s:FindDelimiterIndex(a:right, a:line) != -1 || !s:Multipart()) + if s:FindDelimiterIndex(a:left, a:line) != -1 && (s:LastIndexOfDelim(a:right, a:line) != -1 || !s:Multipart()) return 1 endif return 0 @@ -2407,7 +2462,7 @@ function s:IsSexyComment(topline, bottomline) endif "if there is a right delimiter on the top line then this isn't a sexy comment - if s:FindDelimiterIndex(right, getline(a:topline)) != -1 + if s:LastIndexOfDelim(right, getline(a:topline)) != -1 return 0 endif @@ -2436,7 +2491,7 @@ function s:IsSexyComment(topline, bottomline) "if there is a right delimiter in an intermediate line then the block isn't "a sexy comment - if s:FindDelimiterIndex(right, theLine) != -1 + if s:LastIndexOfDelim(right, theLine) != -1 return 0 endif @@ -2573,6 +2628,12 @@ function s:NerdEcho(msg, typeOfMsg) endif endfunction +" Function: s:Nested() {{{2 +" returns 1 if the current multipart (if any) delims allow nesting +function s:Nested() + return b:NERDCommenterDelims['nested'] +endfunction + " Function: s:NumberOfLeadingTabs(s) {{{2 " returns the number of leading tabs in the given string function s:NumberOfLeadingTabs(s)