Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to efficiently interlace multiple groups of lines in Vim?

Tags:

vim

I am trying to interlace three groups of lines of text. For example, the following text:

a
a
a
b
b
b
c
c
c

is to be transformed into:

a
b
c
a
b
c
a
b
c

Is there an efficient way of doing this?

like image 613
jpiasetz Avatar asked Feb 10 '13 04:02

jpiasetz


1 Answers

Somewhere in the depths of my ~/.vim files I have an :Interleave command (appended below). With out any arguments :Interleave will just interleave just as normal. With 2 arguments how ever it will specify how many are to be grouped together. e.g. :Interleave 2 1 will take 2 rows from the top and then interleave with 1 row from the bottom.

Now to solve your problem

:1,/c/-1Interleave
:Interleave 2 1
  • 1,/c/-1 range starting with the first row and ending 1 row above the first line matching a letter c.
  • :1,/c/-1Interleave basically interleave the groups of a's and b's
  • :Interleave 2 1 the range is the entire file this time.
  • :Interleave 2 1 interleave the group of mixed a's and b's with the group of cs. With a mixing ratio of 2 to 1.

The :Interleave code is below.

command! -bar -nargs=* -range=% Interleave :<line1>,<line2>call Interleave(<f-args>)
fun! Interleave(...) range
  if a:0 == 0
    let x = 1
    let y = 1
  elseif a:0 == 1
    let x = a:1
    let y = a:1
  elseif a:0 == 2
    let x = a:1
    let y = a:2
  elseif a:0 > 2
    echohl WarningMsg
    echo "Argument Error: can have at most 2 arguments"
    echohl None
    return
  endif
  let i = a:firstline + x - 1
  let total = a:lastline - a:firstline + 1
  let j = total / (x + y) * x + a:firstline
  while j < a:lastline
    let range = y > 1 ? j . ',' . (j+y) : j
    silent exe range . 'move ' . i
    let i += y + x
    let j += y
  endwhile
endfun
like image 99
Peter Rincker Avatar answered Sep 19 '22 23:09

Peter Rincker