4

A common task I run into is having to change the order of arguments. So, for example, I might have something like this:

stringInsert( "text to insert", buffer );

and need to change it into this:

stringInsert( buffer, "text to insert" );

Typically the way I do this is:

  1. da" (or whatever is required to delete the first arg)
  2. f)h (or f, if I am inserting in the middle of the arg list)
  3. p
  4. Enter insert, insert any necessary spaces in insert mode, leave insert mode
  5. Go back to beginning and delete unnecessary commas and spaces from beginning of arglist with x

Obviously, this is kind of tedious. What is a better way?

UPDATE

I have been trying out a macro that looks like this and so far it seems to be working pretty well:

da"2f_i,<ESC>p2F_x
  • Why can't you use a mapping if you want to use this multiple times and in different files? – SibiCoder Jul 7 '16 at 16:39
5

You can try to put this function in your .vimrc:

function! InvertArgs()
    " Get the arguments of the current line (remove the spaces)
    let args=substitute(matchstr(getline('.'), '(\zs.*\ze)'), '\s', '', 'g')

    " Split the arguments as a list and reverse the list
    let argsList=split(args, ',')
    call reverse(argsList)

    " Join the reversed list with a comma and a space separing the arguments
    let invertedArgs=join(argsList, ', ')

    " Remove the old arguments and put the new list
    execute "normal! 0f(ci(" . invertedArgs
endfunction

Go to the a line containing function (arg1, arg2, arg3) and call the function with

:call InvertArgs()

The main advantage of this function is that the number of arguments in your funciton doesn't matter.

You can also create a mapping like nnoremap <key> :call InvertArgs()<CR>


Edit: I just noticed that your example has a string with withe spaces in it: the function will mess with it, thus the subtitution in the first line should be removed like this:

let args=matchstr(getline('.'), '(\zs.*\ze)')
5

Statox's is much more robust, but if you only wanted to ever do two arguments a lighter solution could be:

noremap <key> :s/(\(.*\), \(.*\))/(\2, \1)/e<CR>

This uses the search and replace function.

  • \(\) captures output
  • \1 recalls the 1st capture
  • e flag makes it not complain if the search fails

See :h :s for more info.

  • For two arguments your solution is way lighter than mine :-) I wonder if it would be possible to create patterns which would adapt to any number of arguments... – statox Jul 7 '16 at 14:17
  • Maybe submatch() could be used? I have very little experience with it though. It's a function I've been meaning to look into for a while now but never have. – Tumbler41 Jul 7 '16 at 14:19
  • Same here: I know that I'm often impressed when I see people using submatch() cleverly but I've never trained myself enough to make it work properly. When I'll have time I'll check if I can find a way to do that! – statox Jul 7 '16 at 14:25
  • 1
    I don't know how robust it is, but using the atom \%# to describe the current cursor position, maybe you could create a mapping which would adapt to any number of arguments: nnoremap <key> :s/\v[(, ]+\zs(\k*%#\k+)(,\s*)(\k+)/\3\2\1/<CR><C-O> – user9433424 Jul 7 '16 at 14:44
2

sideways.vim is nice for this. You can use :SidewaysLeft or :SidewaysRight to shift arguments and it's repeatable if you have vim-repeat installed.

Text objects you could map:

omap aa <Plug>SidewaysArgumentTextobjA
xmap aa <Plug>SidewaysArgumentTextobjA
omap ia <Plug>SidewaysArgumentTextobjI
xmap ia <Plug>SidewaysArgumentTextobjI

Limitations I noticed:

  • The text objects seem to be sensitive about where the cursor is placed.
  • Selected text objects don't shrink or expand when repeated.

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.