(NOT a possible duplicate of Swap text around equal sign :)
Very often I find myself swapping things around. Which is a pain in the ass.
Let say just after I write this piece of code
tmp = realloc (words, sizeof (char **) * (*count + 1));
I notice there are just too many asterisks in a row, don't like it, and want to swap the two factors around the multiplication asterisk.
Or, I write
#if !defined(_CONSOLE_H_) && defined (__MINGW32__)
but I suddenly realize that defined (__MINGW32__)
must come first for some reason.
I think it would be cool if I could do something like this:
(On a character x
, [x]
indicate cursor position. <S>
stands for this hypothetic "swap around" command)
#if [!]defined(_CONSOLE_H_) && defined (__MINGW32__)
command: vf&<S>$
=> select from cursor to pivot (the word &&
), and swap the selection around with the text till end of line.
Or, for the former example:
tmp = realloc (words, [s]izeof (char **) * (*count + 1));
command: v3f*<S>f)
=> select from here to third *
, swap with text forward to )
.
For me, it would be incredibly useful. Is there something like this out there, or I have to write my own plug-in?
Thanks!
EDIT -
As @ib. says in the comments to his answer, I need to be more specific as to what is the pivot.
The pivot could also be a character, for example here:
static char ** tokenize_input (char * input, PDWORD count);
I may want to swap the two arguments around the ","
. More precisely, the ", "
.
So maybe I'll need two commands:
<s> - char-wise - the pivot is the last character of the selection;
<S> - word-wise - the pivot is the last word of the selection.
Thanks! (ps. what about the last Word? :)
This seems to work here, let me know how it does:
function! Swap(...) "{{{
let start_v = col("'<")
let end_v = col("'>")
let mv = ''
let isMv = 0
while !isMv
let char = s:GetChar()
if char == '<Esc>'
return ''
endif
let mv .= char
let isMv = s:IsMovement(mv)
echon mv."\r"
endwhile
if isMv == 2
return ''
endif
exec "normal! ".end_v.'|'.mv
let lhs = '\%'.start_v.'c\(.\{-}\S\)'
if !a:0
let pivot = '\(\s*\%'.(end_v).'c.\s*\)'
else
let pivot = '\(\s*'.a:1.'*\%'.(end_v).'c'.a:1.'\+\s*\)'
endif
let rhs = '\(.*\%#.\)'
exec 's/'.lhs.pivot.rhs.'/\3\2\1/'
endfunction "Swap }}}
function! s:GetChar() "{{{
let char = getchar()
if type(char) == type(0) && char < 33
return '<Esc>'
elseif char
let char = nr2char(char)
endif
return char
endfunction "GetChar }}}
function! s:IsMovement(mv) "{{{
let ft = a:mv =~ '^\C\d*[fFtT].$'
let ft_partial = a:mv =~ '^\C\d*\%([fFtT].\?\)\?$'
let right = a:mv =~ '^\d*[l$|;,]\|g[m$]$'
let right_partial = a:mv =~ '^\d*\%([l$|;,]\|g[m$]\?\)\?$'
if !right_partial && !ft_partial
return 2
endif
return ft || right
endfunction "IsMovement2Right }}}
" Use last char as pivot. e.g.: the comma in the given example.
vmap <silent> <leader>s1 :<C-U>call Swap()<CR>
" Use \S\+ (WORD) as pivot. e.g.: &&
vmap <silent> <leader>ss :<C-U>call Swap('\S')<CR>
" Use \w\+ as pivot.
vmap <silent> <leader>sw :<C-U>call Swap('\w')<CR>
No need to press enter to specify the movement now. The 'pivot' always includes any surrounding whitespace and it can be defined with a single character class given as argument to Swap() in the mapping.
If you want to see it highlighted, check https://gist.github.com/1921196
I use the following plugin which has been inspired by a vim tip.
First I delete (in one stroke -- diw
also counts as one, while xx
does not) the first part I want to swap. Then I visually select the second part. And finally I hit g"
.
Et voilà! The two texts have been swapped.
Of course, It's not as simple as choosing the pivot. Which is normal, as it's not only about a pivot: we have to specify at one time or another where both texts to swap begin and end, plus the cases when the pivot is zero-length(ed?).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With