mirror of
https://github.com/SpaceVim/SpaceVim.git
synced 2025-01-24 09:50:04 +08:00
280 lines
8.0 KiB
VimL
Vendored
280 lines
8.0 KiB
VimL
Vendored
" Vars:
|
|
" Max font size used to determine appropriate font size for each window.
|
|
let s:FONT_MAX = {
|
|
\ 'small': { 'width': 5, 'height': 8 },
|
|
\ 'large': { 'width': 16, 'height': 10 },
|
|
\ }
|
|
|
|
" These are variables that need to be changed for overlay work properly.
|
|
let s:vim_options = {}
|
|
let s:vim_options.global = {
|
|
\ '&cursorline': 0,
|
|
\ '&cursorcolumn': 0,
|
|
\ '&scrolloff': 0,
|
|
\ '&lazyredraw': 1,
|
|
\ }
|
|
let s:vim_options.buffer = {
|
|
\ '&modified': 0,
|
|
\ '&modifiable': 1,
|
|
\ '&readonly': 0,
|
|
\ '&buftype': '',
|
|
\ }
|
|
let s:vim_options.window = {
|
|
\ '&wrap': 0,
|
|
\ '&list': 0,
|
|
\ '&foldenable': 0,
|
|
\ '&conceallevel': 0,
|
|
\ '&colorcolumn': '',
|
|
\ }
|
|
|
|
" Util:
|
|
let s:_ = choosewin#util#get()
|
|
|
|
function! s:template(string, data) "{{{1
|
|
" String interpolation from vars Dictionary.
|
|
" ex)
|
|
" string = "%{L+1}l%{C+2}c"
|
|
" data = { "L+1": 1, "C+2", 2 }
|
|
" Result => "%1l%2c"
|
|
let mark = '\v\{(.{-})\}'
|
|
return substitute(a:string, mark,'\=a:data[submatch(1)]', 'g')
|
|
endfunction
|
|
|
|
function! s:vars(pos, font) "{{{1
|
|
" Return Dictionary which is used for string inerpolation.
|
|
" For only necessary lines and columns to render " passed font.
|
|
" ex)
|
|
" { "L+1": 1, "C+2", 2 }
|
|
let [line, col] = a:pos
|
|
let R = {}
|
|
for [var, val] in map(copy(a:font.line_used), '["L+". v:val, line + v:val ]')
|
|
let R[var] = val
|
|
endfor
|
|
for [var, val] in map(copy(a:font.col_used), '["C+". v:val, col + v:val ]')
|
|
let R[var] = val
|
|
endfor
|
|
return R
|
|
endfunction
|
|
"}}}
|
|
|
|
" Undo:
|
|
function! s:undobreak() "{{{1
|
|
let &undolevels = &undolevels
|
|
" silent exec 'normal!' "i\<C-g>u\<ESC>"
|
|
endfunction
|
|
|
|
function! s:undoclear() "{{{1
|
|
let undolevels_org = &undolevels
|
|
let &undolevels = -1
|
|
noautocmd execute "normal! a \<BS>\<Esc>"
|
|
let &undolevels = undolevels_org
|
|
endfunction
|
|
"}}}
|
|
|
|
" Overlay:
|
|
let s:Overlay = {}
|
|
|
|
function! s:Overlay.get() "{{{1
|
|
if !has_key(self, '_font_table')
|
|
call s:Overlay.init()
|
|
endif
|
|
return self
|
|
endfunction
|
|
|
|
function! s:Overlay.init() "{{{1
|
|
let self._font_table = {
|
|
\ 'small': choosewin#font#small(),
|
|
\ 'large': choosewin#font#large(),
|
|
\ }
|
|
endfunction
|
|
|
|
function! s:Overlay.start(wins, conf) "{{{1
|
|
call self.setup(a:wins, a:conf)
|
|
call self.setup_window()
|
|
call self.setup_buffer()
|
|
call self.label_show()
|
|
endfunction
|
|
|
|
function! s:Overlay.setup(wins, conf) "{{{1
|
|
let self.conf = a:conf
|
|
let self.wins = a:wins
|
|
let self.winnr_org = winnr()
|
|
let self.bufs = s:_.uniq(tabpagebuflist(tabpagenr()))
|
|
let self.options_global =
|
|
\ s:_.buffer_options_set(bufnr(''), s:vim_options.global)
|
|
|
|
for bufnr in self.bufs
|
|
call setbufvar(bufnr, 'choosewin', {
|
|
\ 'render_lines': [],
|
|
\ 'winwidth': [],
|
|
\ 'offset': [],
|
|
\ 'options': {},
|
|
\ 'undofile': tempname(),
|
|
\ 'font_width': [],
|
|
\ })
|
|
endfor
|
|
endfunction
|
|
|
|
function! s:Overlay.setup_window() "{{{1
|
|
let font_idx = 0
|
|
for winnr in self.wins
|
|
noautocmd execute winnr 'wincmd w'
|
|
|
|
let wv = {}
|
|
let wv.winnr = winnr
|
|
let wv.pos_org = getpos('.')
|
|
let wv.winview = winsaveview()
|
|
let wv.options = s:_.window_options_set(winnr, s:vim_options.window)
|
|
let wv['w0'] = line('w0')
|
|
let wv['w$'] = line('w$')
|
|
let font_size =
|
|
\ self.conf['overlay_font_size'] isnot 'auto' ?
|
|
\ self.conf['overlay_font_size'] :
|
|
\ winheight(0) > s:FONT_MAX.large.height ? 'large' : 'small'
|
|
let char = self.conf['label'][font_idx]
|
|
let font = self._font_table[font_size][char]
|
|
let font_idx += 1
|
|
let wv.font = font
|
|
let line_s = line('w0') + max([ 1 + (winheight(0) - font.height)/2, 0 ])
|
|
let line_e = line_s + font.height - 1
|
|
let offset = col('.') - wincol()
|
|
let col = max([(winwidth(0) - font.width)/2 , 1 ]) + offset
|
|
let wv.matchids = []
|
|
let wv.pattern = s:template(font.pattern, s:vars([line_s, col], font))
|
|
let w:choosewin = wv
|
|
|
|
let b:choosewin.font_width += [font.width]
|
|
let b:choosewin.render_lines += range(line_s, line_e)
|
|
let b:choosewin.offset += [offset]
|
|
let b:choosewin.winwidth += [winwidth(0)]
|
|
endfor
|
|
noautocmd execute self.winnr_org 'wincmd w'
|
|
endfunction
|
|
|
|
function! s:Overlay.setup_buffer() "{{{1
|
|
for bufnr in self.bufs
|
|
noautocmd execute bufwinnr(bufnr) 'wincmd w'
|
|
|
|
execute 'wundo' b:choosewin.undofile
|
|
let b:choosewin.options = s:_.buffer_options_set(bufnr, s:vim_options.buffer)
|
|
call s:undobreak()
|
|
|
|
let render_lines = s:_.uniq(b:choosewin.render_lines)
|
|
let append = max([max(render_lines) - line('$'), 0 ])
|
|
call append(line('$'), map(range(append), '""'))
|
|
call self._fill_space(
|
|
\ render_lines,
|
|
\ max(b:choosewin.font_width), max(b:choosewin.winwidth), max(b:choosewin.offset))
|
|
endfor
|
|
noautocmd execute self.winnr_org 'wincmd w'
|
|
endfunction
|
|
|
|
function! s:Overlay._fill_space(lines, font_width, width, offset) "{{{1
|
|
let width = (a:width + a:font_width) / 2 + a:offset
|
|
for line in a:lines
|
|
let line_s = getline(line)
|
|
if self.conf['overlay_clear_multibyte'] && s:_.include_multibyte_char(line_s)
|
|
let line_new = repeat(' ', width)
|
|
else
|
|
let line_new = substitute(line_s, "\t", repeat(" ", &tabstop), 'g')
|
|
let line_new .= repeat(' ' , max([ width - len(line_new), 0 ]))
|
|
endif
|
|
call setline(line, line_new)
|
|
endfor
|
|
endfunction
|
|
|
|
function! s:Overlay.label_show() "{{{1
|
|
for winnr in self.wins
|
|
noautocmd execute winnr 'wincmd w'
|
|
|
|
" Shade overall window
|
|
if self.conf['overlay_shade']
|
|
let pattern = '\v%'. w:choosewin['w0'] .'l\_.*%'. w:choosewin['w$'] .'l'
|
|
call self.matchadd("ChooseWinShade", pattern, self.conf['overlay_shade_priority'])
|
|
endif
|
|
|
|
" Hide Trailing white space.
|
|
call self.matchadd("ChooseWinShade",'\s\+$', self.conf['overlay_shade_priority'])
|
|
|
|
" Show Label
|
|
call self.matchadd(
|
|
\ "ChooseWinOverlay". ( winnr is self.winnr_org ? 'Current' : ''),
|
|
\ w:choosewin.pattern,
|
|
\ self.conf['overlay_label_priority'])
|
|
endfor
|
|
noautocmd execute self.winnr_org 'wincmd w'
|
|
redraw
|
|
endfunction
|
|
"}}}
|
|
|
|
" Overlay Restore:
|
|
function! s:Overlay.restore() "{{{1
|
|
try
|
|
call self.restore_buffer()
|
|
call self.restore_window()
|
|
finally
|
|
call s:_.buffer_options_set(bufnr(''), self.options_global)
|
|
endtry
|
|
endfunction
|
|
|
|
function! s:Overlay.restore_buffer() "{{{1
|
|
for bufnr in self.bufs
|
|
noautocmd execute bufwinnr(bufnr) 'wincmd w'
|
|
try
|
|
if !exists('b:choosewin') | continue | endif
|
|
if &modified
|
|
noautocmd keepjump silent undo
|
|
endif
|
|
if filereadable(b:choosewin.undofile)
|
|
silent execute 'rundo' b:choosewin.undofile
|
|
else
|
|
call s:undoclear()
|
|
endif
|
|
call s:_.buffer_options_set(str2nr(bufnr), b:choosewin.options)
|
|
unlet b:choosewin
|
|
catch
|
|
call s:_.debug("Overlay restore_buffer():" . v:exception)
|
|
unlet b:choosewin
|
|
endtry
|
|
endfor
|
|
endfunction
|
|
|
|
function! s:Overlay.restore_window() "{{{1
|
|
for winnr in self.wins
|
|
noautocmd execute winnr 'wincmd w'
|
|
if !exists('w:choosewin')
|
|
call s:_.debug('Overlay: w:choosewin not exist winnr = ' . winnr)
|
|
continue
|
|
endif
|
|
|
|
try
|
|
call map(w:choosewin.matchids,'matchdelete(v:val)')
|
|
call s:_.window_options_set(winnr, w:choosewin.options)
|
|
call winrestview(w:choosewin.winview)
|
|
call setpos('.', w:choosewin.pos_org)
|
|
unlet w:choosewin
|
|
catch
|
|
call s:_.debug("Overlay restore_window():" . v:exception)
|
|
unlet w:choosewin
|
|
endtry
|
|
endfor
|
|
noautocmd execute self.winnr_org 'wincmd w'
|
|
endfunction
|
|
"}}}
|
|
|
|
" Highight:
|
|
function! s:Overlay.matchadd(color, pattern, priority) "{{{1
|
|
call add(w:choosewin.matchids,
|
|
\ matchadd(a:color, a:pattern, a:priority))
|
|
endfunction
|
|
"}}}
|
|
call s:Overlay.init()
|
|
|
|
" API:
|
|
function! choosewin#overlay#get() "{{{1
|
|
return s:Overlay.get()
|
|
endfunction
|
|
"}}}
|
|
|
|
" vim: foldmethod=marker
|