diff --git a/plugin/refactor.vim b/plugin/refactor.vim index 0a51bd1..a0d9454 100644 --- a/plugin/refactor.vim +++ b/plugin/refactor.vim @@ -1,476 +1,476 @@ -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -" Refactor for vim -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -" INTRODUCTION: -" -" This plugin contains some basic refactoring commands for C/C++(Java, C#). -" For the complexity of C++, instead of really parse the source code, I used -" regular expression matches. But it works well as I tested. -" -" The refactor commands and their default key map currently are: -" 1. e Extract method -" 2. p local variable to Parameter -" 3. r Rename LOCAL variable -" 4. d Delete parameter -" 5. o reOrder parameters -" 6. c introduce Constant -" -" BiDongliang bidongliang_2000@126.com 2007/12/4 -" -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -" LIMITATION: -" 1. Parameter with default value is not supported -" 2. Nested template type are limit to 3 layers, and multiple template -" template parameter is not supported. But you can enable them by modify -" the variable s:TemplateParameterPattern. -" list supported -" list > supported -" list > > supported -" list > supported -" list, list > unsuported -" 3. Rename refactor can only perform on local variables. -" 4. Register z is used when extract method. -" 5. 10 parameter supported at most. -" -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -" BUGS: -" 1. (Fixed) Can not handle 'int a = 0' like statment in local variable to -" parameter, because s:IdentifierPattern can not start with digit. -" 2. (Fixed) Add word boundary to some patterns. (\<\>) -" 3. (Fixed) will expand to whole expression in introducing constant. -" Thus, abc3def[>4<] will parse to 3. Fixed by iteration. -" 4. (Fixed) Parse error of variable defination with initialization. -" -"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" - -" These are the default key mappings -map e :call ExtractMethod() -map p :call LocalVariableToParameter() -map r :call RenameVariable() -map d :call RemoveParameter() -map o :call ReorderParameters() -map c :call IntroduceConstant() - -" Used to prevent the keywords be parsed as variable name -let s:Keywords = ["auto", "const", "double", "float", "int", "short", "struct", "unsigned", "break", "continue", "else", "for", "long", "signed", "switch", "void", "case", "default", "enum", "goto", "register", "sizeof", "typedef", "volatile", "char", "do", "extern", "if", "return", "static", "union", "while", "asm", "dynamic_cast", "namespace", "reinterpret_cast", "try", "bool", "explicit", "new", "static_cast", "typeid", "catch", "false", "operator", "template", "typename", "class", "friend", "private", "this", "using", "const_cast", "inline", "public", "throw", "virtual", "delete", "mutable", "protected", "true", "wchar_t", "size_t"] - -" Patterns used to match language element -let s:IdentifierPattern = '\<\h\w*\>' -let s:TypePostfixPattern = '\s*[*&]*\s*' -let s:TypeElementPattern = s:IdentifierPattern . s:TypePostfixPattern -let s:TemplateParameterPattern = '\%(<[^<>]*>\|<[^<>]*<[^<>]*>[^<>]\+>\|<[^<>]*<[^<>]*<[^<>]*>[^<>]*>[^<>]\+>\)' "'<\s*' . s:TypeElementPattern . '\%(\s*,\s*' . s:TypeElementPattern . '\)*>' -let s:TypeIdentifierPattern = '\%(' . s:TypeElementPattern . '\%(' . s:TemplateParameterPattern . s:TypePostfixPattern . '\)*' . s:TypePostfixPattern . '\)\+' -let s:MissableSeperatorPattern = '\%(\s*\n*\s*\)' "'\s*\n*\s*' -let s:SeperatorPattern = '\%(\s\+\n*\s*\|\n\+\|\s*\n*\s\+\)' -let s:VariableDeclarationPattern = s:TypeIdentifierPattern . s:MissableSeperatorPattern . s:IdentifierPattern . '\%\(\[\d*\]\)*' -let s:FunctionPerfixPattern = '^\s*\%(' . s:TypeIdentifierPattern . s:SeperatorPattern. '\|' . s:IdentifierPattern . '::\)\+' -let s:ParameterListPattern = '(' . s:MissableSeperatorPattern . '\%(' . s:VariableDeclarationPattern . '\%(\s*,' . s:MissableSeperatorPattern . s:VariableDeclarationPattern . '\)*\)*\s*)' -let s:FunctionPattern = s:FunctionPerfixPattern . s:MissableSeperatorPattern . s:IdentifierPattern . s:MissableSeperatorPattern . s:ParameterListPattern . '[^(){;]*' -let s:FunctionDeclarationPattern = s:FunctionPattern . s:MissableSeperatorPattern . '\%(;\)\@=' -let s:FunctionDefinationPattern = s:FunctionPattern . s:MissableSeperatorPattern . '\%({\)\@=' - -function! IntroduceConstant() - let NumberPattern = '\%(\d\+\.\?\d*\|\d*\.\d\+\)\%(f\|F\|L\|l\|U\|u\|ul\|UL\|uL\|Ul\)\?' "'\d\+\%(L\|l\|U\|u\|ul\|UL\|uL\|Ul\)\?\|\d\+\.\d\+[Ff]\?\|\.\d\+[Ff]\?' - let text = getline('.') - let position = col('.') - 1 - while strpart(text, position) =~ '^' . NumberPattern && position > 0 - let position = position - 1 - endwhile - let matched = matchstr(strpart(text, position), NumberPattern) - if matched == "" - call confirm('Can not parse a constant under cursor!') - return - endif - let constantName = inputdialog('Input the name for ' . matched . ' :') - if constantName != "" - let type = "" - if match(matched, 'ul\|UL\|uL\|Ul') >= 0 - let type = 'unsigned long' - elseif match(matched, '[Uu]') >= 0 - let type = 'unsigned int' - elseif match(matched, '[Ll]') >= 0 - let type = 'long' - elseif match(matched, '[fF]') >= 0 - let type = 'float' - elseif match(matched, '\.') >= 0 - let type = 'double' - else - let type = 'int' - endif - call GotoBeginingBracketOfCurrentFunction() - call search(matched, 'W') - exec 'normal! [{' - exec "normal! oconst " . type . " " . constantName . ' = ' . matched . ";\e" - let startLine = line('.') + 1 - let replace = confirm('Replate all ' . matched .' in this function with "' . constantName . '"?', "&Yes\n&No") - if replace == 1 - call GotoBeginingBracketOfCurrentFunction() - normal! % - let stopLine = line('.') - exec 'normal! :' . startLine . ',' . stopLine . 's/\<' . matched . '\>\%(\.\)\@!/' . constantName . "/g\r" - endif - endif -endfunction - -function! ReorderParameters() - let originLine = line('.') - let originCol = col('.') - let parameterList = GetParameterListOfCurrentFunction() - if len(parameterList) == 1 - if parameterList[0] == 'NONE' - call confirm('There is no parameter to reorder!') - else - call confirm('Can not reorder the only parameter!') - endif - return - endif - if len(parameterList) > 0 - if len(parameterList) > 10 - call confirm('Parameter count should less than 10!') - return - endif - let text = "Parameters of current function are:" - let start = 0 - while start < len(parameterList) - let text = text . "\n" . start . ': ' . parameterList[start] - let start = start + 1 - endwhile - let text = text . "\nInput the index of parameteres in new order:" - let processed = 0 - while processed == 0 - let order = inputdialog(text) - if order != "" - if order =~ '\D' - call confirm('Just input the indexes without seperator, please!') - continue - endif - let processed = 1 - let index = 0 - while index < len(parameterList) - if stridx(order, index) < 0 - call confirm('You missed parameter ' . index) - let processed = 0 - break - endif - let index = index + 1 - endwhile - if processed == 1 - call cursor(originLine, originCol) - call GotoBeginingBracketOfCurrentFunction() - exec "normal! ?(\r" - exec "normal! d/)\ri(\e" - let index = 0 - while index < strlen(order) - let current = strpart(order, index, 1) - exec "normal! a" . parameterList[current] . "\e" - if index < strlen(order) - 1 - exec "normal! a, \e" - let currentCol = col('.') - if currentCol > 80 - exec "normal! a\r\e" - endif - endif - let index = index + 1 - endwhile - endif - else - let processed = 1 - endif - endwhile - endif -endfunction - -function! RemoveParameter() - let parameterList = GetParameterListOfCurrentFunction() - if len(parameterList) == 1 && parameterList[0] == 'NONE' - call confirm('There is no parameter to remove!') - return - endif - - if len(parameterList) > 0 - let text = "Parameters of current function are:" - let start = 0 - while start < len(parameterList) - let text = text . "\n" . start . ': ' . parameterList[start] - let start = start + 1 - endwhile - let text = text . "\nInput the index of parameter to remove:" - let index = inputdialog(text) - if index != "" && index >= 0 && index < len(parameterList) - call search(s:FunctionPattern, 'bW') - let parameter = escape(parameterList[index], '*') - if search(parameter, 'W') > 0 - let text = getline('.') - if match(text, parameter . '\s*,') >= 0 - normal! df, - else - let startCol = match(text, ',\s*' . parameter) - let matched = matchstr(text, '\(,\s*\)*' . parameter) - if startCol >= 0 - let text = strpart(text, 0, startCol) . strpart(text, startCol + strlen(matched)) - call setline('.', text) - endif - endif - endif - endif - else - call confirm("Sorry, I can not parse the function parameter list!") - endif -endfunction - -function! RenameVariable() - let originRow = line('.') - let originCol = col('.') - let variableName = expand('') - let variableType = GetCurrentVariableType(0) - if variableType == "" - call confirm("Can not rename because ". variableName . " is not a local variable!") - return - endif - let newName = inputdialog("Input new name for ". variableName . ":") - if newName != "" - call GotoBeginingBracketOfCurrentFunction() - let startLine = line('.') - exec "normal! %" - let stopLine = line('.') - exec startLine . ',' . stopLine . ':s/\<' . variableName . '\>/'. newName .'/g' - endif - call cursor(originRow, originCol) -endfunction - -function! LocalVariableToParameter() - let variableName = expand('') - let variableType = GetCurrentVariableType(0) - call GotoBeginingBracketOfCurrentFunction() - exec "normal! ?(\r" - if match(getline('.'), '(\s*)') >= 0 - call search(')') - exec "normal! i" . variableType . ' ' . variableName . "\e" - else - call search(')') - exec "normal! i, " . variableType . ' ' . variableName . "\e" - endif - call search('{') - call search('\<' . variableName . '\>') - let currentLine = getline('.') - if match(currentLine, variableType . '\s*\<' . variableName . '\>\s*;') >= 0 - call search(variableType, 'bW') - exec "normal! df;" - if match(getline('.'), '^\s*$') >= 0 - exec "normal! dd" - endif - else - if match(currentLine, '\<' . variableName . '\>\s*=') >= 0 - let variableDefination = matchstr(currentLine, '\<' . variableName . '\>\s*=\s*.\{-\}\([,;]\)\@=') - let remainStart = match(currentLine, '\<' . variableName . '\>\s*=\s*\((.*)\)*') + strlen(variableDefination) - let remain = strpart(currentLine, remainStart) - if match(remain, s:IdentifierPattern) >= 0 - call setline('.', variableType . strpart(remain, stridx(remain, ',') + 1)) - exec "normal! O" . variableDefination . ';' - exec "normal! 2==" - else - call setline('.', variableDefination . ';') - exec "normal! ==" - endif - else - if match(currentLine, '\<' . variableName . '\>\s*,') <0 - call confirm("I can not erase the variable defination, \nplease do it yourself!") - else - exec "normal! cf," - exec "normal! ==" - endif - endif - endif -endfunction - -function! ExtractMethod() range - let scopeIdentifier = GetScopeIdentifierOfCurrentMethod() - let variableList = [] - let varableLocalScopeType = [] - let variableParentScopeType = [] - while 1 - let variableName = MoveToNextVariable(a:lastline) - if variableName == "" - break - endif - if index(variableList, variableName) < 0 - call add(variableList, variableName) - let type = GetCurrentVariableType(0) - call add(variableParentScopeType, type) - let type = GetCurrentVariableType(a:firstline) - call add(varableLocalScopeType, type) - endif - endwhile - let methodName = inputdialog("Input the function name:") - if methodName != "" - " use register z to yank the texts - exec "normal! " . a:firstline ."G0\"zy" . a:lastline . "G" - if scopeIdentifier == "" - call GotoBeginingBracketOfCurrentFunction() - exec "normal! %" - exec "normal! 2o\ei//\e78a-\eo\eccvoid ". methodName . "(\e" - else - call GotoBeginingBracketOfCurrentFunction() - exec "normal! %" - exec "normal! 2o\ei//\e78a-\eo\eccvoid ". scopeIdentifier . "::" . methodName . "(\e" - endif - let idx = 0 - let parameterCount = 0 - while idx < len(variableList) - if varableLocalScopeType[idx] == "" && variableParentScopeType[idx] != "" - if parameterCount > 0 - exec "normal! a, \e" - endif - if col('.') > 80 && idx < len(variableList) - 1 - exec "normal! ==A\r\e" - endif - if variableParentScopeType[idx] =~ '\[\d*\]' - let postfix = matchstr(variableParentScopeType[idx], '\[\d*\]') - let type = strpart(variableParentScopeType[idx], 0, match(variableParentScopeType[idx], '\[\d*\]')) - exec "normal! a" . type . " " . variableList[idx] . postfix . "\e" - else - exec "normal! a" . variableParentScopeType[idx] . " " . variableList[idx] . "\e" - endif - let parameterCount = parameterCount + 1 - endif - let idx = idx + 1 - endwhile - exec "normal! a)\e==A\r{\r}\ek\"zp=']" - - if confirm("Replace selection with function call?", "&Yes\n&No", 1) == 1 - exec "normal! " . a:firstline ."G0c" . a:lastline . "G" - exec "normal! a" . methodName . "(" - let idx = 0 - let parameterCount = 0 - while idx < len(variableList) - if varableLocalScopeType[idx] == "" && variableParentScopeType[idx] != "" - if parameterCount > 0 - exec "normal! a, \e" - endif - exec "normal! a" . variableList[idx] . "\e" - let parameterCount = parameterCount + 1 - endif - let idx = idx + 1 - endwhile - exec "normal! a);\e==" - endif - endif -endfunction - -function! MoveToNextVariable(endLine) - let identifier = "" - while search('\([)]\s*\)\@ 0 - let identifier = expand('') - if index(s:Keywords, expand('')) >= 0 - let identifier = "" - continue - endif - break - endwhile - return identifier -endfunction - -" search variable defination in current function scope -function! GetCurrentVariableType(topestLine) - let variableType = "" - let startRow = line('.') - let startCol = col('.') - let variableName = expand("") - normal! e - call GotoBeginingBracketOfCurrentFunction() - exec "normal! ?(\r" - let stopRow = line('.') - if a:topestLine > stopRow - let stopRow = a:topestLine - endif - call cursor(startRow, 1000) - - - let DeclarationPattern = s:TypeIdentifierPattern . '\s*\%(' . s:IdentifierPattern . '[^()]*,\s*\)*\<' . variableName . '\>\%(\[\d*\]\)*' - while search(DeclarationPattern, "bW", stopRow) > 0 - if expand('') =~ 'return' - continue - endif - let currentLine = getline('.') - let commentStart = match(currentLine, '//') - if commentStart >= 0 && commentStart < match(currentLine, DeclarationPattern) - continue - endif - let matched = matchstr(currentLine, DeclarationPattern) - let typeend = match(matched, '\(\s*' . s:IdentifierPattern . '\s*[=,][^<>]*\)*\<'. variableName . '\>') - let variableType = strpart(matched, 0, typeend) - if matched =~ '\[\d*\]' - let postfix = matchstr(matched, '\[\d*\]') - let variableType = variableType . postfix - endif - break - endwhile - call cursor(startRow, startCol) - return variableType -endfunction - -function! GetScopeIdentifierOfCurrentMethod() - let scopeIdentifier = "" - let originRow = line('.') - let originCol = col('.') - call GotoBeginingBracketOfCurrentFunction() - exec "normal! ?(\r" - if search(s:IdentifierPattern . '::', 'bW', line('.') - 2) > 0 - let scopeIdentifier = expand('') - endif - call cursor(originRow, originCol) - return scopeIdentifier -endfunction - -function! GotoBeginingBracketOfCurrentFunction() - if search(s:FunctionPattern, 'bW') > 0 - if search('{', 'W') <= 0 - exec 'normal! [[' - endif - endif -endfunction - -function! GetParameterListOfCurrentFunction() - let parameterList = [] - if search(s:FunctionPattern, 'bW') > 0 - call search('(') - let startLine = line('.') - let startCol = col('.') - normal! % - let stopLine = line('.') - let stopCol = col('.') - - let closeBraceIndex = 0 - let lineIter = startLine - let text = "" - while lineIter < stopLine - let text = text . getline(lineIter) - let closeBraceIndex = closeBraceIndex + strlen(getline(lineIter)) - let lineIter = lineIter + 1 - endwhile - let text = text . getline(stopLine) - let closeBraceIndex = closeBraceIndex + stopCol - - let emptyPair = match(text, '(\s*)') - if emptyPair >= 0 && emptyPair <= startCol + 2 - call add(parameterList, 'NONE') - return parameterList - endif - - let start = startCol - 1 - while 1 - let parameter = matchstr(text, s:VariableDeclarationPattern, start) - let start = match(text, s:VariableDeclarationPattern, start) - let start = start + strlen(parameter) - if start >= closeBraceIndex || start < 0 - break - endif - if parameter != "" - call add(parameterList, parameter) - else - break - endif - endwhile - endif - return parameterList -endfunction +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +" Refactor for vim +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +" INTRODUCTION: +" +" This plugin contains some basic refactoring commands for C/C++(Java, C#). +" For the complexity of C++, instead of really parse the source code, I used +" regular expression matches. But it works well as I tested. +" +" The refactor commands and their default key map currently are: +" 1. e Extract method +" 2. p local variable to Parameter +" 3. r Rename LOCAL variable +" 4. d Delete parameter +" 5. o reOrder parameters +" 6. c introduce Constant +" +" BiDongliang bidongliang_2000@126.com 2007/12/4 +" +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +" LIMITATION: +" 1. Parameter with default value is not supported +" 2. Nested template type are limit to 3 layers, and multiple template +" template parameter is not supported. But you can enable them by modify +" the variable s:TemplateParameterPattern. +" list supported +" list > supported +" list > > supported +" list > supported +" list, list > unsuported +" 3. Rename refactor can only perform on local variables. +" 4. Register z is used when extract method. +" 5. 10 parameter supported at most. +" +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +" BUGS: +" 1. (Fixed) Can not handle 'int a = 0' like statment in local variable to +" parameter, because s:IdentifierPattern can not start with digit. +" 2. (Fixed) Add word boundary to some patterns. (\<\>) +" 3. (Fixed) will expand to whole expression in introducing constant. +" Thus, abc3def[>4<] will parse to 3. Fixed by iteration. +" 4. (Fixed) Parse error of variable defination with initialization. +" +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +" These are the default key mappings +map e :call ExtractMethod() +map p :call LocalVariableToParameter() +map r :call RenameVariable() +map d :call RemoveParameter() +map o :call ReorderParameters() +map c :call IntroduceConstant() + +" Used to prevent the keywords be parsed as variable name +let s:Keywords = ["auto", "const", "double", "float", "int", "short", "struct", "unsigned", "break", "continue", "else", "for", "long", "signed", "switch", "void", "case", "default", "enum", "goto", "register", "sizeof", "typedef", "volatile", "char", "do", "extern", "if", "return", "static", "union", "while", "asm", "dynamic_cast", "namespace", "reinterpret_cast", "try", "bool", "explicit", "new", "static_cast", "typeid", "catch", "false", "operator", "template", "typename", "class", "friend", "private", "this", "using", "const_cast", "inline", "public", "throw", "virtual", "delete", "mutable", "protected", "true", "wchar_t", "size_t"] + +" Patterns used to match language element +let s:IdentifierPattern = '\<\h\w*\>' +let s:TypePostfixPattern = '\s*[*&]*\s*' +let s:TypeElementPattern = s:IdentifierPattern . s:TypePostfixPattern +let s:TemplateParameterPattern = '\%(<[^<>]*>\|<[^<>]*<[^<>]*>[^<>]\+>\|<[^<>]*<[^<>]*<[^<>]*>[^<>]*>[^<>]\+>\)' "'<\s*' . s:TypeElementPattern . '\%(\s*,\s*' . s:TypeElementPattern . '\)*>' +let s:TypeIdentifierPattern = '\%(' . s:TypeElementPattern . '\%(' . s:TemplateParameterPattern . s:TypePostfixPattern . '\)*' . s:TypePostfixPattern . '\)\+' +let s:MissableSeperatorPattern = '\%(\s*\n*\s*\)' "'\s*\n*\s*' +let s:SeperatorPattern = '\%(\s\+\n*\s*\|\n\+\|\s*\n*\s\+\)' +let s:VariableDeclarationPattern = s:TypeIdentifierPattern . s:MissableSeperatorPattern . s:IdentifierPattern . '\%\(\[\d*\]\)*' +let s:FunctionPerfixPattern = '^\s*\%(' . s:TypeIdentifierPattern . s:SeperatorPattern. '\|' . s:IdentifierPattern . '::\)\+' +let s:ParameterListPattern = '(' . s:MissableSeperatorPattern . '\%(' . s:VariableDeclarationPattern . '\%(\s*,' . s:MissableSeperatorPattern . s:VariableDeclarationPattern . '\)*\)*\s*)' +let s:FunctionPattern = s:FunctionPerfixPattern . s:MissableSeperatorPattern . s:IdentifierPattern . s:MissableSeperatorPattern . s:ParameterListPattern . '[^(){;]*' +let s:FunctionDeclarationPattern = s:FunctionPattern . s:MissableSeperatorPattern . '\%(;\)\@=' +let s:FunctionDefinationPattern = s:FunctionPattern . s:MissableSeperatorPattern . '\%({\)\@=' + +function! IntroduceConstant() + let NumberPattern = '\%(\d\+\.\?\d*\|\d*\.\d\+\)\%(f\|F\|L\|l\|U\|u\|ul\|UL\|uL\|Ul\)\?' "'\d\+\%(L\|l\|U\|u\|ul\|UL\|uL\|Ul\)\?\|\d\+\.\d\+[Ff]\?\|\.\d\+[Ff]\?' + let text = getline('.') + let position = col('.') - 1 + while strpart(text, position) =~ '^' . NumberPattern && position > 0 + let position = position - 1 + endwhile + let matched = matchstr(strpart(text, position), NumberPattern) + if matched == "" + call confirm('Can not parse a constant under cursor!') + return + endif + let constantName = inputdialog('Input the name for ' . matched . ' :') + if constantName != "" + let type = "" + if match(matched, 'ul\|UL\|uL\|Ul') >= 0 + let type = 'unsigned long' + elseif match(matched, '[Uu]') >= 0 + let type = 'unsigned int' + elseif match(matched, '[Ll]') >= 0 + let type = 'long' + elseif match(matched, '[fF]') >= 0 + let type = 'float' + elseif match(matched, '\.') >= 0 + let type = 'double' + else + let type = 'int' + endif + call GotoBeginingBracketOfCurrentFunction() + call search(matched, 'W') + exec 'normal! [{' + exec "normal! oconst " . type . " " . constantName . ' = ' . matched . ";\e" + let startLine = line('.') + 1 + let replace = confirm('Replate all ' . matched .' in this function with "' . constantName . '"?', "&Yes\n&No") + if replace == 1 + call GotoBeginingBracketOfCurrentFunction() + normal! % + let stopLine = line('.') + exec 'normal! :' . startLine . ',' . stopLine . 's/\<' . matched . '\>\%(\.\)\@!/' . constantName . "/g\r" + endif + endif +endfunction + +function! ReorderParameters() + let originLine = line('.') + let originCol = col('.') + let parameterList = GetParameterListOfCurrentFunction() + if len(parameterList) == 1 + if parameterList[0] == 'NONE' + call confirm('There is no parameter to reorder!') + else + call confirm('Can not reorder the only parameter!') + endif + return + endif + if len(parameterList) > 0 + if len(parameterList) > 10 + call confirm('Parameter count should less than 10!') + return + endif + let text = "Parameters of current function are:" + let start = 0 + while start < len(parameterList) + let text = text . "\n" . start . ': ' . parameterList[start] + let start = start + 1 + endwhile + let text = text . "\nInput the index of parameteres in new order:" + let processed = 0 + while processed == 0 + let order = inputdialog(text) + if order != "" + if order =~ '\D' + call confirm('Just input the indexes without seperator, please!') + continue + endif + let processed = 1 + let index = 0 + while index < len(parameterList) + if stridx(order, index) < 0 + call confirm('You missed parameter ' . index) + let processed = 0 + break + endif + let index = index + 1 + endwhile + if processed == 1 + call cursor(originLine, originCol) + call GotoBeginingBracketOfCurrentFunction() + exec "normal! ?(\r" + exec "normal! d/)\ri(\e" + let index = 0 + while index < strlen(order) + let current = strpart(order, index, 1) + exec "normal! a" . parameterList[current] . "\e" + if index < strlen(order) - 1 + exec "normal! a, \e" + let currentCol = col('.') + if currentCol > 80 + exec "normal! a\r\e" + endif + endif + let index = index + 1 + endwhile + endif + else + let processed = 1 + endif + endwhile + endif +endfunction + +function! RemoveParameter() + let parameterList = GetParameterListOfCurrentFunction() + if len(parameterList) == 1 && parameterList[0] == 'NONE' + call confirm('There is no parameter to remove!') + return + endif + + if len(parameterList) > 0 + let text = "Parameters of current function are:" + let start = 0 + while start < len(parameterList) + let text = text . "\n" . start . ': ' . parameterList[start] + let start = start + 1 + endwhile + let text = text . "\nInput the index of parameter to remove:" + let index = inputdialog(text) + if index != "" && index >= 0 && index < len(parameterList) + call search(s:FunctionPattern, 'bW') + let parameter = escape(parameterList[index], '*') + if search(parameter, 'W') > 0 + let text = getline('.') + if match(text, parameter . '\s*,') >= 0 + normal! df, + else + let startCol = match(text, ',\s*' . parameter) + let matched = matchstr(text, '\(,\s*\)*' . parameter) + if startCol >= 0 + let text = strpart(text, 0, startCol) . strpart(text, startCol + strlen(matched)) + call setline('.', text) + endif + endif + endif + endif + else + call confirm("Sorry, I can not parse the function parameter list!") + endif +endfunction + +function! RenameVariable() + let originRow = line('.') + let originCol = col('.') + let variableName = expand('') + let variableType = GetCurrentVariableType(0) + if variableType == "" + call confirm("Can not rename because ". variableName . " is not a local variable!") + return + endif + let newName = inputdialog("Input new name for ". variableName . ":") + if newName != "" + call GotoBeginingBracketOfCurrentFunction() + let startLine = line('.') + exec "normal! %" + let stopLine = line('.') + exec startLine . ',' . stopLine . ':s/\<' . variableName . '\>/'. newName .'/g' + endif + call cursor(originRow, originCol) +endfunction + +function! LocalVariableToParameter() + let variableName = expand('') + let variableType = GetCurrentVariableType(0) + call GotoBeginingBracketOfCurrentFunction() + exec "normal! ?(\r" + if match(getline('.'), '(\s*)') >= 0 + call search(')') + exec "normal! i" . variableType . ' ' . variableName . "\e" + else + call search(')') + exec "normal! i, " . variableType . ' ' . variableName . "\e" + endif + call search('{') + call search('\<' . variableName . '\>') + let currentLine = getline('.') + if match(currentLine, variableType . '\s*\<' . variableName . '\>\s*;') >= 0 + call search(variableType, 'bW') + exec "normal! df;" + if match(getline('.'), '^\s*$') >= 0 + exec "normal! dd" + endif + else + if match(currentLine, '\<' . variableName . '\>\s*=') >= 0 + let variableDefination = matchstr(currentLine, '\<' . variableName . '\>\s*=\s*.\{-\}\([,;]\)\@=') + let remainStart = match(currentLine, '\<' . variableName . '\>\s*=\s*\((.*)\)*') + strlen(variableDefination) + let remain = strpart(currentLine, remainStart) + if match(remain, s:IdentifierPattern) >= 0 + call setline('.', variableType . strpart(remain, stridx(remain, ',') + 1)) + exec "normal! O" . variableDefination . ';' + exec "normal! 2==" + else + call setline('.', variableDefination . ';') + exec "normal! ==" + endif + else + if match(currentLine, '\<' . variableName . '\>\s*,') <0 + call confirm("I can not erase the variable defination, \nplease do it yourself!") + else + exec "normal! cf," + exec "normal! ==" + endif + endif + endif +endfunction + +function! ExtractMethod() range + let scopeIdentifier = GetScopeIdentifierOfCurrentMethod() + let variableList = [] + let varableLocalScopeType = [] + let variableParentScopeType = [] + while 1 + let variableName = MoveToNextVariable(a:lastline) + if variableName == "" + break + endif + if index(variableList, variableName) < 0 + call add(variableList, variableName) + let type = GetCurrentVariableType(0) + call add(variableParentScopeType, type) + let type = GetCurrentVariableType(a:firstline) + call add(varableLocalScopeType, type) + endif + endwhile + let methodName = inputdialog("Input the function name:") + if methodName != "" + " use register z to yank the texts + exec "normal! " . a:firstline ."G0\"zy" . a:lastline . "G" + if scopeIdentifier == "" + call GotoBeginingBracketOfCurrentFunction() + exec "normal! %" + exec "normal! 2o\ei//\e78a-\eo\eccvoid ". methodName . "(\e" + else + call GotoBeginingBracketOfCurrentFunction() + exec "normal! %" + exec "normal! 2o\ei//\e78a-\eo\eccvoid ". scopeIdentifier . "::" . methodName . "(\e" + endif + let idx = 0 + let parameterCount = 0 + while idx < len(variableList) + if varableLocalScopeType[idx] == "" && variableParentScopeType[idx] != "" + if parameterCount > 0 + exec "normal! a, \e" + endif + if col('.') > 80 && idx < len(variableList) - 1 + exec "normal! ==A\r\e" + endif + if variableParentScopeType[idx] =~ '\[\d*\]' + let postfix = matchstr(variableParentScopeType[idx], '\[\d*\]') + let type = strpart(variableParentScopeType[idx], 0, match(variableParentScopeType[idx], '\[\d*\]')) + exec "normal! a" . type . " " . variableList[idx] . postfix . "\e" + else + exec "normal! a" . variableParentScopeType[idx] . " " . variableList[idx] . "\e" + endif + let parameterCount = parameterCount + 1 + endif + let idx = idx + 1 + endwhile + exec "normal! a)\e==A\r{\r}\ek\"zp=']" + + if confirm("Replace selection with function call?", "&Yes\n&No", 1) == 1 + exec "normal! " . a:firstline ."G0c" . a:lastline . "G" + exec "normal! a" . methodName . "(" + let idx = 0 + let parameterCount = 0 + while idx < len(variableList) + if varableLocalScopeType[idx] == "" && variableParentScopeType[idx] != "" + if parameterCount > 0 + exec "normal! a, \e" + endif + exec "normal! a" . variableList[idx] . "\e" + let parameterCount = parameterCount + 1 + endif + let idx = idx + 1 + endwhile + exec "normal! a);\e==" + endif + endif +endfunction + +function! MoveToNextVariable(endLine) + let identifier = "" + while search('\([)]\s*\)\@ 0 + let identifier = expand('') + if index(s:Keywords, expand('')) >= 0 + let identifier = "" + continue + endif + break + endwhile + return identifier +endfunction + +" search variable defination in current function scope +function! GetCurrentVariableType(topestLine) + let variableType = "" + let startRow = line('.') + let startCol = col('.') + let variableName = expand("") + normal! e + call GotoBeginingBracketOfCurrentFunction() + exec "normal! ?(\r" + let stopRow = line('.') + if a:topestLine > stopRow + let stopRow = a:topestLine + endif + call cursor(startRow, 1000) + + + let DeclarationPattern = s:TypeIdentifierPattern . '\s*\%(' . s:IdentifierPattern . '[^()]*,\s*\)*\<' . variableName . '\>\%(\[\d*\]\)*' + while search(DeclarationPattern, "bW", stopRow) > 0 + if expand('') =~ 'return' + continue + endif + let currentLine = getline('.') + let commentStart = match(currentLine, '//') + if commentStart >= 0 && commentStart < match(currentLine, DeclarationPattern) + continue + endif + let matched = matchstr(currentLine, DeclarationPattern) + let typeend = match(matched, '\(\s*' . s:IdentifierPattern . '\s*[=,][^<>]*\)*\<'. variableName . '\>') + let variableType = strpart(matched, 0, typeend) + if matched =~ '\[\d*\]' + let postfix = matchstr(matched, '\[\d*\]') + let variableType = variableType . postfix + endif + break + endwhile + call cursor(startRow, startCol) + return variableType +endfunction + +function! GetScopeIdentifierOfCurrentMethod() + let scopeIdentifier = "" + let originRow = line('.') + let originCol = col('.') + call GotoBeginingBracketOfCurrentFunction() + exec "normal! ?(\r" + if search(s:IdentifierPattern . '::', 'bW', line('.') - 2) > 0 + let scopeIdentifier = expand('') + endif + call cursor(originRow, originCol) + return scopeIdentifier +endfunction + +function! GotoBeginingBracketOfCurrentFunction() + if search(s:FunctionPattern, 'bW') > 0 + if search('{', 'W') <= 0 + exec 'normal! [[' + endif + endif +endfunction + +function! GetParameterListOfCurrentFunction() + let parameterList = [] + if search(s:FunctionPattern, 'bW') > 0 + call search('(') + let startLine = line('.') + let startCol = col('.') + normal! % + let stopLine = line('.') + let stopCol = col('.') + + let closeBraceIndex = 0 + let lineIter = startLine + let text = "" + while lineIter < stopLine + let text = text . getline(lineIter) + let closeBraceIndex = closeBraceIndex + strlen(getline(lineIter)) + let lineIter = lineIter + 1 + endwhile + let text = text . getline(stopLine) + let closeBraceIndex = closeBraceIndex + stopCol + + let emptyPair = match(text, '(\s*)') + if emptyPair >= 0 && emptyPair <= startCol + 2 + call add(parameterList, 'NONE') + return parameterList + endif + + let start = startCol - 1 + while 1 + let parameter = matchstr(text, s:VariableDeclarationPattern, start) + let start = match(text, s:VariableDeclarationPattern, start) + let start = start + strlen(parameter) + if start >= closeBraceIndex || start < 0 + break + endif + if parameter != "" + call add(parameterList, parameter) + else + break + endif + endwhile + endif + return parameterList +endfunction