18

When refactoring code it would be useful to be able to swap function arguments.

Changing for eg:

func(foo[0], bar(), baz.spam)

into

func(baz.spam, foo[0], bar())

Is there some way to swap arguments to the left/right, keeping function parentheses and commas in place?


Note, this could become quite involved if you want to account for arguments which themselves are function calls with their own arguments - eg: func(baz->spam, foo[0], bar(a, b, c)) - supporting these cases would likely involve some more comprehensive parsing.

21

Without plugins

| indicates cursor position

func(foo[0], bar(), |baz.spam)

Steps:

  1. dt) will delete baz.spam
  2. Ff will move the cursor to the character f in foo[0]
  3. vt,p will delete foo[0] and replace it with baz.spam
  4. $P will paste the foo[0] before the parens
  5. Repeat steps 1-4 for any others.

With plugins

  • vim-argumentative by Peter Rincker : Provides text objects for moving around function arguments (Default mappings: <, and >,).
  • vim-exchange by Tom McDonald : Provides handy mappings to exchange two selections (Default mappings: cx in normal mode and X in visual mode).
  • vim-sideways by Andrew Radev : Move function arguments (and other delimited-by-something items) left and right (Default mappings: NA).
  • vim-swap by machakann : Reorder delimited items (Default mappings: g< and g>).
  • 6
    the non-plugin solution is very specific for the case... – elyashiv Feb 8 '15 at 12:55
  • 3
    @elyashiv the idea is that you can use a similar technique for any function arguments. Basically, yank a word, visually select another word, paste, which Vim will yank the deleted character to the register, and then paste where you first yanked from. – akshay Feb 8 '15 at 12:57
  • 1
    +1 for vim-sideways! The last section describes a very nice feature: cia to "change in argument". ❤️ – Martijn Courteaux Mar 14 '18 at 16:30
5

I present 3 methods. The first two are particular cases, which require less keystrokes. The last one is generic. | represents the cursor position.


Swap adjacent arguments (doesn't work for last two)

function func(foo[0], |bar(), baz.spam, qux->norf)

Steps:

  1. dW delete the current Word (argument)
  2. W go to the first char of the next argument
  3. P paste before the cursor

Swap last two arguments

function func(foo[0], bar()|, baz.spam, qux->norf)

Steps:

  1. dt, delete until next comma
  2. E go to last character of the next argument
  3. P paste before the cursor

Swap any two arguments

function func(|foo[0], bar(), baz.spam, qux->norf)

Steps:

  1. vt,d visually delete until comma
  2. W several times until you reach the argument you want to swap with
  3. gP paste before cursor and place cursor on the char after pasted content
  4. dt, delete until next comma. replace , by ) if this is the last argument
  5. `< go back to the beggining of the last visual area (cursor will be placed at the comma)
  6. P paste before the cursor

Edit: as pointed by @aharris88 the OP wants the last argument to be the first and move all the others right.

Rotate arguments to the right

function func(foo[0], bar(), baz.spam|, qux->norf)

Steps:

  1. dw delete ,␣
  2. dt) delete last argument
  3. %p jump to opening parentheses and paste last argument
  4. a,␣ insert a comma and space
  5. <Esc> return to normal mode

Or, if you don't want to ever leave normal mode:

  1. "rdw delete ,␣ into a register r
  2. dt) delete last argument
  3. %p jump to opening parentheses and paste last argument
  4. "rp paste content of register r

Bonus: a GIF for each case: swap1, swap2, swap3 and rotate

  • While this answer does swap arguments, it doesn't answer the question, which is how to move the last argument to the beginning. – aharris88 Feb 9 '15 at 18:38
  • @aharris88, you are right. I edited my answer. – Gonçalo Ribeiro Feb 9 '15 at 19:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.