Skip to content

Instantly share code, notes, and snippets.

@kamichidu
Last active August 29, 2015 14:06
Show Gist options
  • Save kamichidu/c5d059a16387ff2fe6ad to your computer and use it in GitHub Desktop.
Save kamichidu/c5d059a16387ff2fe6ad to your computer and use it in GitHub Desktop.
let s:V= vital#of('vital')
let s:L= s:V.import('Data.List')
unlet s:V
function! s:is_most_left(winnr)
let save_winnr= winnr()
try
execute a:winnr 'wincmd w'
wincmd h
return winnr() == a:winnr
finally
execute save_winnr 'wincmd w'
endtry
endfunction
function! s:is_most_top(winnr)
let save_winnr= winnr()
try
execute a:winnr 'wincmd w'
wincmd k
return winnr() == a:winnr
finally
execute save_winnr 'wincmd w'
endtry
endfunction
function! s:is_most_right(winnr)
let save_winnr= winnr()
try
execute a:winnr 'wincmd w'
wincmd l
return winnr() == a:winnr
finally
execute save_winnr 'wincmd w'
endtry
endfunction
function! s:is_most_bottom(winnr)
let save_winnr= winnr()
try
execute a:winnr 'wincmd w'
wincmd j
return winnr() == a:winnr
finally
execute save_winnr 'wincmd w'
endtry
endfunction
function! s:compute_left(winnr)
let save_winnr= winnr()
try
execute a:winnr 'wincmd w'
let left= 0
while !s:is_most_left(winnr())
wincmd h
let left+= winwidth('.')
" border
let left+= 1
endwhile
return left
finally
execute save_winnr 'wincmd w'
endtry
endfunction
function! s:compute_top(winnr)
let save_winnr= winnr()
try
execute a:winnr 'wincmd w'
let top= 0
while !s:is_most_top(winnr())
wincmd k
let top+= winheight('.')
" statusline
let top+= 1
endwhile
return top
finally
execute save_winnr 'wincmd w'
endtry
endfunction
function! s:winpos()
let save_winnr= winnr()
try
let positions= []
for winnr in range(1, winnr('$'))
let positions+= [{
\ 'winnr': winnr,
\ 'left': s:compute_left(winnr),
\ 'top': s:compute_top(winnr),
\ 'width': winwidth(winnr),
\ 'height': winheight(winnr),
\}]
endfor
return positions
finally
execute save_winnr 'wincmd w'
endtry
endfunction
function! s:snapshot()
let g:winlay_snapshot= s:winpos()
endfunction
function! s:winmark()
if !exists('s:seq')
let s:seq= 0
endif
let s:seq+= 1
let w:hogehoge_mark= s:seq
return s:seq
endfunction
function! s:wingomark(mark)
for winnr in range(1, winnr('$'))
if getwinvar(winnr, 'hogehoge_mark', -1) == a:mark
execute winnr 'wincmd w'
return
endif
endfor
endfunction
function! s:restore_layout(data)
" search horizontal border
" find windows have same top
let tops= s:L.uniq(map(copy(a:data), 'v:val.top'))
let candidates= []
for top in tops
let positions= filter(copy(a:data), 'v:val.top == top')
if !empty(positions)
let candidates+= [{'top': top, 'positions': positions}]
endif
endfor
let widths= map(copy(candidates), "{'top': v:val.top, 'width': s:L.foldl('v:memo + v:val.width', 0, v:val.positions) + (len(v:val.positions) - 1)}")
let widths= filter(copy(widths), "v:val.width == max(map(copy(widths), 'v:val.width'))")
" search vertical border
" find windows have same left
let lefts= s:L.uniq(map(copy(a:data), 'v:val.left'))
let candidates= []
for left in lefts
let positions= filter(copy(a:data), 'v:val.left == left')
if !empty(positions)
let candidates+= [{'left': left, 'positions': positions}]
endif
endfor
unlet left
let heights= map(copy(candidates), "{'left': v:val.left, 'height': s:L.foldl('v:memo + v:val.height', 0, v:val.positions) + (len(v:val.positions) - 1)}")
let heights= filter(copy(heights), "v:val.height == max(map(copy(heights), 'v:val.height'))")
if len(widths) > 1
let widths= s:L.sort(widths, 'a:a.top - a:b.top')
for i in range(len(widths))
let above= widths[i]
let below= get(widths, i + 1, {'top': &lines})
let inside= filter(copy(a:data), "v:val.top >= above.top && v:val.top < below.top")
let save_winnr= s:winmark()
if i < len(widths) - 1
aboveleft split
endif
if len(inside) > 1
call s:restore_layout(inside)
endif
call s:wingomark(save_winnr)
endfor
elseif len(heights) > 1
let heights= s:L.sort(heights, 'a:a.left - a:b.left')
for i in range(len(heights))
let left= heights[i]
let right= get(heights, i + 1, {'left': &columns})
let inside= filter(copy(a:data), "v:val.left >= left.left && v:val.left < right.left")
let save_winnr= s:winmark()
if i < len(heights) - 1
aboveleft vsplit
endif
if len(inside) > 1
call s:restore_layout(inside)
endif
call s:wingomark(save_winnr)
endfor
endif
endfunction
function! s:restore_size(data)
if winnr('$') != len(a:data)
throw 'Mismatch number of windows'
endif
let data= s:L.sort(a:data, 'a:a.winnr - a:b.winnr')
let save_winnr= winnr()
try
for state in data
execute state.winnr 'wincmd w'
execute 'vertical resize' state.width
execute 'resize' state.height
endfor
finally
execute save_winnr 'wincmd w'
endtry
endfunction
function! s:restore()
try
call s:restore_layout(g:winlay_snapshot)
call s:restore_size(g:winlay_snapshot)
catch
echomsg v:throwpoint
echomsg v:exception
endtry
endfunction
let g:winlay_stack= []
command! WinLaySnapshot call s:snapshot()
command! WinLayRestore call s:restore()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment