dotfiles/vim/plugins/GoldenView/autoload/GoldenView.vim
2018-04-05 13:06:54 +02:00

530 lines
15 KiB
VimL

" =============== ============================================================
" Name : GoldenView
" Description : Always have a nice view for vim split windows
" Author : Zhao Cai <caizhaoff@gmail.com>
" HomePage : https://github.com/zhaocai/GoldenView.Vim
" Date Created : Tue 18 Sep 2012 10:25:23 AM EDT
" Last Modified : Fri 19 Oct 2012 05:55:17 PM EDT
" Tag : [ vim, window, golden-ratio ]
" Copyright : © 2012 by Zhao Cai,
" Released under current GPL license.
" =============== ============================================================
" ============================================================================
" Initialization And Profile: ⟨⟨⟨1
" ============================================================================
function! GoldenView#ExtendProfile(name, def)
let default = get(s:goldenview__profile, a:name,
\ copy(s:goldenview__profile['default']))
let s:goldenview__profile[a:name] = extend(default, a:def)
endfunction
function! GoldenView#Init()
if exists('g:goldenview__initialized') && g:goldenview__initialized == 1
return
endif
let s:goldenview__golden_ratio = 1.618
lockvar s:goldenview__golden_ratio
set equalalways
set eadirection=ver
let s:goldenview__profile = {
\ 'reset' : {
\ 'focus_window_winheight' : &winheight ,
\ 'focus_window_winwidth' : &winwidth ,
\ 'other_window_winheight' : &winminheight ,
\ 'other_window_winwidth' : &winminwidth ,
\ },
\ 'default' : {
\ 'focus_window_winheight' : function('GoldenView#GoldenHeight') ,
\ 'focus_window_winwidth' : function('GoldenView#TextWidth') ,
\ 'other_window_winheight' : function('GoldenView#GoldenMinHeight') ,
\ 'other_window_winwidth' : function('GoldenView#GoldenMinWidth') ,
\ },
\
\ }
call GoldenView#ExtendProfile('golden-ratio', {
\ 'focus_window_winwidth' : function('GoldenView#GoldenWidth') ,
\ })
let s:goldenview__ignore_nrule = GoldenView#zl#rule#norm(
\ g:goldenview__ignore_urule, {
\ 'logic' : 'or',
\ }
\ )
let s:goldenview__restore_nrule = GoldenView#zl#rule#norm(
\ g:goldenview__restore_urule, {
\ 'logic' : 'or',
\ }
\ )
let g:goldenview__initialized = 1
endfunction
" ============================================================================
" Auto Resize: ⟨⟨⟨1
" ============================================================================
function! GoldenView#ToggleAutoResize()
if exists('s:goldenview__auto_resize') && s:goldenview__auto_resize == 1
call GoldenView#DisableAutoResize()
call GoldenView#zl#print#moremsg('GoldenView Auto Resize: Off')
else
call GoldenView#EnableAutoResize()
call GoldenView#zl#print#moremsg('GoldenView Auto Resize: On')
endif
endfunction
function! GoldenView#EnableAutoResize()
call GoldenView#Init()
let active_profile = s:goldenview__profile[g:goldenview__active_profile]
call s:set_focus_window(active_profile)
call s:set_other_window(active_profile)
augroup GoldenView
au!
" Enter
autocmd VimResized * call GoldenView#Enter({'event' : 'VimResized'})
autocmd BufWinEnter * call GoldenView#Enter({'event' : 'BufWinEnter'})
autocmd WinEnter * call GoldenView#Enter({'event' : 'WinEnter'})
" Leave
autocmd WinLeave * call GoldenView#Leave()
augroup END
let s:goldenview__auto_resize = 1
endfunction
function! GoldenView#DisableAutoResize()
au! GoldenView
call GoldenView#ResetResize()
let s:goldenview__auto_resize = 0
endfunction
function! GoldenView#Leave(...)
" GoldenViewTrace 'WinLeave', a:000
" Do nothing if there is no split window
" --------------------------------------
if winnr('$') < 2
return
endif
call GoldenView#Diff()
if GoldenView#IsIgnore()
" Record the last size of ignored windows. Restore there sizes if affected
" by GoldenView.
" For new split, the size does not count, which is highly possible
" to be resized later. Should use the size with WinLeave event.
"
call GoldenView#initialize_tab_variable()
let t:goldenview['bufs'][bufnr('%')] = {
\ 'winnr' : winnr() ,
\ 'winwidth' : winwidth(0) ,
\ 'winheight' : winheight(0) ,
\ }
let t:goldenview['cmdheight'] = &cmdheight
end
endfunction
function! GoldenView#Diff()
" Diff Mode: auto-resize to equal size
if ! exists('b:goldenview_diff')
let b:goldenview_diff = 0
endif
if &diff
if ! b:goldenview_diff
for nr in GoldenView#zl#list#uniq(tabpagebuflist())
if getbufvar(nr, '&diff')
call setbufvar(nr, 'goldenview_diff', 1)
endif
endfor
exec 'wincmd ='
endif
return 1
else
if b:goldenview_diff
let b:goldenview_diff = 0
endif
endif
return 0
endfunction
function! GoldenView#Enter(...)
if GoldenView#Diff()
return
endif
if &lazyredraw
return
endif
return call('GoldenView#Resize', a:000)
endfunction
function! GoldenView#Resize(...)
"--------- ------------------------------------------------
" Desc : resize focused window
"
" Args : {'event' : event}
" Return : none
"
" Raise : none from this function
"
" Pitfall :
" - Can not set winminwith > winwidth
" - AutoCmd Sequence:
" - `:copen` :
" 1. WinEnter (&ft inherited from last buffer)
" 2. BufWinEnter (&ft == '')
" 3. BufWinEnter (&ft == 'qf', set winfixheight)
" - `:split`
" 1. WinLeave current window
" 2. WinEnter new split window with current buffer
" 3. `split` return, user script may change the buffer
" type, width, etc.
"
"
"--------- ------------------------------------------------
" GoldenViewTrace 'GoldenView Resize', a:000
let opts = {'is_force' : 0}
if a:0 >= 1 && GoldenView#zl#var#is_dict(a:1)
call extend(opts, a:1)
endif
let winnr_diff = s:winnr_diff()
if winnr_diff > 0
" Plus Split Window:
" ++++++++++++++++++
" GoldenViewTrace '+++ winnr +++', a:000
return
elseif winnr_diff < 0
" Minus Split Window:
" -------------------
call GoldenView#initialize_tab_variable()
let saved_lazyredraw = &lazyredraw
set lazyredraw
let current_winnr = winnr()
" Restore: original size based on "g:goldenview__restore_urule"
" ------------------------------------------------------------
for winnr in range(1, winnr('$'))
let bufnr = winbufnr(winnr)
let bufsaved = get(t:goldenview['bufs'], bufnr, {})
" Ignored Case: same buffer displayed in multiply windows
" -------------------------------------------------------
if ! empty(bufsaved) && bufsaved['winnr'] == winnr
silent noautocmd exec winnr 'wincmd w'
if GoldenView#IsRestore()
silent exec 'vertical resize ' . bufsaved['winwidth']
silent exec 'resize ' . bufsaved['winheight']
" GoldenViewTrace 'restore buffer:'. nr, a:000
endif
endif
endfor
if &cmdheight != t:goldenview['cmdheight']
exec 'set cmdheight=' . t:goldenview['cmdheight']
endif
silent exec current_winnr 'wincmd w'
redraw
let &lazyredraw = saved_lazyredraw
" GoldenViewTrace '--- winnr ---', a:000
return
endif
if ! opts['is_force']
" Do nothing if there is no split window
if winnr('$') < 2
return
endif
if GoldenView#IsIgnore()
" GoldenViewTrace 'Ignored', a:000
return
endif
endif
let active_profile = s:goldenview__profile[g:goldenview__active_profile]
call s:set_focus_window(active_profile)
" GoldenViewTrace 'Set Focuse', a:000
" reset focus windows minimal size
let &winheight = &winminheight
let &winwidth = &winminwidth
" GoldenViewTrace 'Reset Focus', a:000
endfunction
function! GoldenView#IsIgnore()
return GoldenView#zl#rule#is_true(s:goldenview__ignore_nrule)
endfunction
function! GoldenView#IsRestore()
return GoldenView#zl#rule#is_true(s:goldenview__restore_nrule)
endfunction
function! GoldenView#ResetResize()
let reset_profile = s:goldenview__profile[g:goldenview__reset_profile]
call s:set_other_window(reset_profile, {'force' : 1})
call s:set_focus_window(reset_profile, {'force' : 1})
endfunction
function! GoldenView#GoldenHeight(...)
return float2nr(&lines / s:goldenview__golden_ratio)
endfunction
function! GoldenView#GoldenWidth(...)
return float2nr(&columns / s:goldenview__golden_ratio)
endfunction
function! GoldenView#GoldenMinHeight(...)
return float2nr(GoldenView#GoldenHeight()/(5*s:goldenview__golden_ratio))
endfunction
function! GoldenView#GoldenMinWidth(...)
return float2nr(GoldenView#GoldenWidth()/(3*s:goldenview__golden_ratio))
endfunction
function! GoldenView#TextWidth(...)
let tw = &l:textwidth
if tw != 0
return float2nr(tw * 4/3)
else
let tw = float2nr(80 * 4/3)
let gw = GoldenView#GoldenWidth()
return tw > gw ? gw : tw
endif
endfunction
function! s:set_focus_window(profile,...)
let opts = {
\ 'force' : 0
\ }
if a:0 >= 1 && GoldenView#zl#var#is_dict(a:1)
call extend(opts, a:1)
endif
try
if !&winfixwidth || opts['force']
let &winwidth =
\ s:eval(a:profile, a:profile['focus_window_winwidth'])
endif
if !&winfixheight || opts['force']
let &winheight =
\ s:eval(a:profile, a:profile['focus_window_winheight'])
endif
catch /^Vim\%((\a\+)\)\=:E36/ " Not enough room
call GoldenView#zl#print#warning('GoldenView: ' . v:exception)
endtry
endfunction
function! s:set_other_window(profile,...)
let opts = {
\ 'force' : 0
\ }
if a:0 >= 1 && GoldenView#zl#var#is_dict(a:1)
call extend(opts, a:1)
endif
try
if !&winfixwidth || opts['force']
let &winminwidth =
\ s:eval(a:profile, a:profile['other_window_winwidth'])
endif
if !&winfixheight || opts['force']
let &winminheight =
\ s:eval(a:profile, a:profile['other_window_winheight'])
endif
catch /^Vim\%((\a\+)\)\=:E36/ " Not enough room
call GoldenView#zl#print#warning('GoldenView: ' . v:exception)
endtry
endfunction
" ============================================================================
" Split: ⟨⟨⟨1
" ============================================================================
function! GoldenView#Split()
call GoldenView#zl#window#split_nicely()
endfunction
" ============================================================================
" Switch: ⟨⟨⟨1
" ============================================================================
function! GoldenView#SwitchMain(...)
let opts = {
\ 'from_bufnr' : bufnr('%') ,
\}
if a:0 >= 1 && type(a:1) == type({})
call extend(opts, a:1)
endif
let window_count = winnr('$')
if window_count < 2
return
endif
let current_winnr = winnr()
let switched = 0
let saved_lazyredraw = &lazyredraw
set lazyredraw
for i in range(1, window_count)
silent noautocmd exec i 'wincmd w'
if ! GoldenView#IsIgnore()
let switched = GoldenView#zl#window#switch_buffer(
\ opts['from_bufnr'], winbufnr(i))
break
endif
endfor
redraw
let &lazyredraw = saved_lazyredraw
if switched
call GoldenView#Resize({'event' : 'WinEnter'})
else
silent noautocmd exec current_winnr 'wincmd w'
endif
endfunction
" ============================================================================
" Helper Functions: ⟨⟨⟨1
" ============================================================================
function! s:eval(profile, val)
if GoldenView#zl#var#is_number(a:val)
return a:val
elseif GoldenView#zl#var#is_funcref(a:val)
return a:val(a:profile)
else
try
return eval(a:val)
catch /^Vim\%((\a\+)\)\=:E/
throw 'GoldenView: invalid profile value type!'
endtry
endif
endfunction
function! GoldenView#initialize_tab_variable()
if !exists('t:goldenview')
let t:goldenview = {
\ 'nrwin' : winnr('$') ,
\ 'cmdheight' : &cmdheight ,
\ 'bufs' : {} ,
\ }
endif
endfunction
function! s:winnr_diff()
call GoldenView#initialize_tab_variable()
let nrwin = winnr('$')
if nrwin != t:goldenview['nrwin']
let diff = nrwin - t:goldenview['nrwin']
let t:goldenview['nrwin'] = nrwin
return diff
else
return 0
endif
endfunction
" ============================================================================
" Debug: ⟨⟨⟨1
" ============================================================================
function! GoldenView#Info()
return {
\ 'buffer' : {
\ 'filetype' : &ft ,
\ 'buftype' : &buftype ,
\ 'bufname' : bufname('%') ,
\ 'winwidth' : winwidth(0) ,
\ 'winheight' : winheight(0) ,
\ },
\ 'goldenview' : get(t:, 'goldenview', GoldenView#initialize_tab_variable()),
\ 'setting' : {
\ 'win_count' : winnr('$') ,
\ 'lazyredraw' : &lazyredraw ,
\ 'cmdheight' : &cmdheight ,
\ 'winfixwidth' : &winfixwidth ,
\ 'winfixheight' : &winfixheight ,
\ 'winwidth' : &winwidth ,
\ 'winminwidth' : &winminwidth ,
\ 'winheight' : &winheight ,
\ 'winminheight' : &winminheight ,
\ }
\}
endfunction
function! GoldenView#Trace(...)
" -------- - -----------------------------------------------
" Example : >
" GoldenViewTrace 'WinLeave', a:000
" -------- - -----------------------------------------------
call GoldenView#initialize_tab_variable()
let info = GoldenView#Info()
let info['context'] = get(g:,'GoldenView_zl_context','')
let info['args'] = a:000
call GoldenView#zl#log#debug(info)
endfunction
command! -nargs=* -complete=expression GoldenViewTrace
\ exec GoldenView#zl#vim#context() | call GoldenView#Trace(<args>)
" ============================================================================
" Modeline: ⟨⟨⟨1
" ============================================================================
" vim: set ft=vim ts=4 sw=4 tw=78 fdm=syntax fmr=⟨⟨⟨,⟩⟩⟩ fdl=1 :