Swap selection around the rod

(NOT a possible duplicate. Exchange text around an equal sign :)

Very often I find that I exchange things. This is a pain in the ass.

Say right after I write this piece of code

tmp = realloc (words, sizeof (char **) * (*count + 1)); 

I noticed that there are too many stars in the line, I don’t like it, and you want to change two factors around the multiplication asterisk.

Or I write

 #if !defined(_CONSOLE_H_) && defined (__MINGW32__) 

but I suddenly realize that defined (__MINGW32__) should be the first for some reason.

I think it would be great if I could do something like this:

(The cursor position is indicated on x , [x] . <S> stands for this hypothetical swap around command)

 #if [!]defined(_CONSOLE_H_) && defined (__MINGW32__) 

command: vf&<S>$ => select from the cursor to the pivot point (word && ) and change the selection around the text to the end of the line.

Or, for the previous example:

 tmp = realloc (words, [s]izeof (char **) * (*count + 1)); 

: v3f*<S>f) => select from here to the third * , replace the text with ) text forward.

It would be incredibly useful to me. Is there something like this, or should I write my own plugin?

Thanks!

EDIT -

Like @ib. says in the comments on his answer, I need to be more specific as to what is the core.

The summary can also be a symbol, for example here:

 static char ** tokenize_input (char * input, PDWORD count); 

I can swap two arguments around "," . More precisely, ", " .

So maybe I 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. how about the last word ? :)

+4
source share
4 answers

This seems to work here, let me know how this is done:

 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. eg: the comma in the given example. vmap <silent> <leader>s1 :<CU>call Swap()<CR> " Use \S\+ (WORD) as pivot. eg: && vmap <silent> <leader>ss :<CU>call Swap('\S')<CR> " Use \w\+ as pivot. vmap <silent> <leader>sw :<CU>call Swap('\w')<CR> 

No need to press enter to indicate movement. "Pivot" always includes any surrounding spaces, and it can be defined using a single character class specified as an argument to Swap () in the mapping.

If you want to see it highlighted, check https://gist.github.com/1921196

+5
source

Let me suggest the following mapping as an implementation of a hypothetical <S> .

 vnoremap <silent> <leader>m xm':<cu>set opfunc=PasteAfter<cr> g@ function! PasteAfter(type) let [sl, sc] = getpos("'[")[1:2] let [cl, cc] = getpos("''")[1:2] let back = sl < cl || (sl == cl && sc < cc) undojoin | exe 'norm!' ['`]p`[', '`[P`]'][back] endfunction 

This implementation works not only for individual selection on one line, but also for linear and block selection.

+1
source

I am using the following plugin that was inspired by vim content.

At first I delete (with one hit - diw also considered as one, but xx ) is not the first part that I want to change. Then I visually select the second part. And finally, I hit g" . g"

Et voilΓ ! These two texts have been superseded.

Of course, this is not as simple as selecting a rod. This is normal, since this is not only about the core: we must indicate at one time or another when both swap texts start and end, as well as cases where the rotation axis is zero (ed?).

+1
source

I came up with a solution with a slightly different workflow. You select the text in visual mode, and then specify the character / text you want to rotate. In most cases, I needed to consider spaces, so by default spaces around the summary text are included as part of the actual bar. I matched it with sequences like \ a to rotate around the comma (with explicit comparisons for ',', ';', '.' And spaces), and \ aa asks for the summary text, so you can use \ aaand to rotate around the word "and."

Here's the vimscript:

 vmap <silent> <leader>aa :call SwapAround()<CR> vmap <silent> <leader>a, :call SwapAround(',')<CR> vmap <silent> <leader>a. :call SwapAround('\.')<CR> vmap <silent> <leader>a; :call SwapAround(';')<CR> vmap <silent> <leader>a<Space> :call SwapAround("[ \t\n]*")<CR> function! SwapAround(...) range if 1 == a:0 let exp = a:1 else call inputsave() let exp = input('pivot:') call inputrestore() endif if exp !~ '[ \t\n]' let exp = '[ \t\n]*'.exp.'[ \t\n]*' endif call s:SwapAroundBase(exp, getpos("'<"), getpos("'>")) endfunction function! s:SwapAroundBase(sepExp, start, end) range let save_a = @a try let originalText = s:getText(a:start, a:end) let sepStart = match(originalText, a:sepExp) let sepEnd = matchend(originalText, a:sepExp) let firstOne = strpart(originalText, 0, sepStart) let sep = strpart(originalText, sepStart, sepEnd - sepStart) let secondOne = strpart(originalText, sepEnd) let @a = secondOne.sep.firstOne let posStatus = setpos(".", a:start) normal! v let posStatus = setpos(".", a:end) normal "ap finally let @a = save_a endtry endfunction function! s:getText(start, end) let lines = getline(a:start[1], a:end[1]) let lines[-1] = lines[-1][: a:end[2] - 1] let lines[0] = lines[0][a:start[2] - 1:] return join(lines, "\n") endfunction 

This works well for single-line sharing, but I think multi-line cases need to be cleaned up.

+1
source

Source: https://habr.com/ru/post/1398514/


All Articles