Automatic real nesting for languages with support

Removes the placeholder workaround (forceNested) for languages which
allow truly nested comments and automatically applies them.
Enabled for haskell, racket, scheme, scala, lisp, ocaml, sml.
Fixes issue #131
This commit is contained in:
Klaas Boesche 2014-05-21 17:52:04 +02:00
parent 2b3714bff6
commit c2fc065b33

View File

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