"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" " swap_parameters.vim - swap parameters - fun(arg2, arg1, arg3) " Author: Kamil Dworakowski " Version: 1.1.1 " Last Change: 2008-01-29 " URL: http://blog.kamil.dworakowski.name " Requires: Python and Vim compiled with +python option " Licence: This script is released under the Vim License. " Installation: Put into plugin directory " Basic Usecase: Place the cursor inside the parameter you want to swap " with the next one, and press gs " Description: " " It is a versatile script to swap parameters of a function " or, generally speaking, any coma seperated list of elements. " " key bindings (normal mode): " [count]gs -- where count defaults to 1 -- swap the argument under " the cursor with the [count] next one " [count]gS -- swap with the previous " " Below are exaples of what happens after pressing gr (equivalent to 1gr). " On each line the lefthand side shows the line before typing gr, and " the righthand side shows the effect. The cursor position is depicted " with || symbols. par|m|1 means that the cursor is on the character m. " " fun(par|m|1, parm2) fun(parm2, parm|1|) " fun(par|m|1(), parm2) fun(parm2, parm1(|)|) " fun(parm1(|)|, parm2) fun(parm2, parm1(|)|) " fun(parm|1|(arg,arg2), parm2) fun(parm2, parm1(arg,arg2|)|) " fun(parm1|(|arg,arg2), parm2) fun(parm2, parm1(arg,arg2|)|) " fun(parm1(arg,arg2|)|, parm2) fun(parm2, parm1(arg,arg2|)|) " fun(parm1(arg, arg2|)|, parm2) fun(parm2, parm1(arg, arg2|)|) " fun(arg1, ar|g|2, arg3) fun(arg1, arg3, arg|2|) " array[a|r|g1, arg2] array[arg2, arg|1|] " fun(par|m|1[], parm2) fun(parm2, parm1[|]|) " fun(parm1[|]|, parm2) fun(parm2, parm1[|]|) " fun(par|m|1, array[]) fun(array[], parm|1|) " fun(|a|,b) fun(b,|a|) " [(p1, p2|)|, p3] [p3, (p1, p2|)|] " for |a|, b in some_dict.items() for b, |a| in some_dict.items() " " The following lines demonstrate using gS (swap with previous). " " fun(parm2, par|m|1) fun(|p|arm1, parm2) " fun(parm2, par|m|1()) fun(|p|arm1(), parm2) " fun(parm2, parm1(|)|) fun(|p|arm1(), parm2) " fun(parm2, parm|1|(arg,arg2)) fun(|p|arm1(arg,arg2), parm2) " fun(parm2, parm1|(|arg,arg2)) fun(|p|arm1(arg,arg2), parm2) " fun(parm2, parm1(arg,arg2|)|) fun(|p|arm1(arg,arg2), parm2) " fun(parm2, parm1(arg, arg2|)|) fun(|p|arm1(arg, arg2), parm2) " fun(arg1, ar|g|2, arg3) fun(|a|rg2, arg1, arg3) " fun(arg1, arg2, ar|g|3) fun(arg1, |a|rg3, arg2) " array[arg2, a|r|g1] array[|a|rg1, arg2] " fun(parm2, par|m|1[]) fun(|p|arm1[], parm2) " fun(parm2, parm1[|]|) fun(|p|arm1[], parm2) " fun(array[], par|m|1) fun(|p|arm1, array[]) " fun(b,|a|) fun(|a|,b) " for a, |b| in some_dict.items() for |b|, a in some_dict.items() " " The above exaples are autogenerated from the tests. " " A useful, however unexpected by the author, feature of this script is that " on pressing j to move cursor to the line below the column of the cursor is " restored to the position before the swap. This allows for streamlined " swaping of parameters in the case like this: " " fun(arg2, blah) " fun(arg2, blahble) " fun(arg2, blahblahblah) " " You would put cursor on arg2, and the gsjgsjgs " " " This script is written in python. Therefore it needs " vim copiled with +python option, as well as python installed " in the system. Sorry for those of you who don't have it " already installed. " """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" if !has('python') s:ErrMsg( "Error: Required vim compiled with +python" ) finish endif function! SwapParams(directionName) python << EOF leftBrackets = ['[', '('] rightBrackets = [']', ')'] class Direction(object): def isOpenBracket(self, char): return char in self.openingBrackets def isCloseBracket(self, char): return char in self.closingBrackets class RightwardDirection(Direction): openingBrackets = leftBrackets closingBrackets = rightBrackets def isBackwards(self): return False class LeftwardDirection(Direction): openingBrackets = rightBrackets closingBrackets = leftBrackets def isBackwards(self): return True def findFirst(predicate, input, direction=None, eolIsDelimiter=False): def find(pos=0): try: head = input.next() if predicate(head): return pos elif direction and direction.isOpenBracket(head): afterBracketGroup = \ findFirst(direction.isCloseBracket, input, direction) return find(pos + afterBracketGroup + 2) else: return find(pos+1) except: if eolIsDelimiter: return pos return -1 return find() def SwapParams(direction, line, col): if direction.isBackwards(): noEnclosingBrackets = findFirst(lambda x: x in rightBrackets, iter(line[col:]), RightwardDirection()) == -1 else: noEnclosingBrackets = findFirst(lambda x: x in leftBrackets, reversed(line[:col+1]), LeftwardDirection()) == -1 prefix = reversed(line[:col + 1]) toTheLeft = 0 if line[col] in leftBrackets: prefix.next() toTheLeft += 1 def findNextLeftSeparator(separator=None): if not separator: separator = leftBrackets + [','] return findFirst(lambda x: x in separator, prefix, LeftwardDirection() ) if not direction.isBackwards() and noEnclosingBrackets: toTheLeft += findNextLeftSeparator(separator=[' ']) else: toTheLeft += findNextLeftSeparator() if direction.isBackwards() and noEnclosingBrackets: toTheLeft += 1 + findNextLeftSeparator(separator=[' ']) elif direction.isBackwards(): toTheLeft += 1 + findNextLeftSeparator() start = col - toTheLeft + 1 nonwhitespace = lambda x: x not in (' ', '\t') input = iter(line[start:]) param1start = start + findFirst(nonwhitespace, input) param1end = param1start + findFirst(lambda x: x == ',', iter(line[param1start:]), RightwardDirection() ) - 1 param2start = param1end + 2 + findFirst(nonwhitespace, iter(line[param1end+2:])) rightSeparators = rightBrackets + [','] if noEnclosingBrackets: rightSeparators = [' '] param2end = param2start + findFirst(lambda x: x in rightSeparators, iter(line[param2start:]), RightwardDirection(), eolIsDelimiter=True) - 1 if not direction.isBackwards(): cursorPos = param2end else: cursorPos = param1start return (line[:param1start] + line[param2start: param2end+1] + line[param1end+1: param2start] + line[param1start: param1end+1] + line[param2end+1:], cursorPos ) def Swap(line, col): return SwapParams(RightwardDirection(), line, col) def SwapBackwards(line, col): return SwapParams(LeftwardDirection(), line, col) EOF if a:directionName == 'backwards' python Swap = SwapBackwards endif python << EOF if __name__ == '__main__': import vim (row,col) = vim.current.window.cursor line = vim.current.buffer[row-1] try: (line, newCol) = Swap(line,col) vim.current.buffer[row-1] = line vim.current.window.cursor = (row, newCol) except Exception, e: print e EOF endfunction noremap gb :call SwapParams("forwards") map gs @='gb' noremap gB :call SwapParams("backwards") map gS @='gB'