let s:Dict = vital#gina#import('Data.Dict') let s:File = vital#gina#import('System.File') let s:String = vital#gina#import('Data.String') let s:DIRECTION_PATTERN = printf('\<\%%(%s\)\>', join([ \ 'lefta\%[bove]', \ 'abo\%[veleft]', \ 'rightb\%[elow]', \ 'bel\%[owright]', \ 'to\%[pleft]', \ 'bo\%[tright]', \], '\|') \) let s:t_list = type([]) let s:timer_syncbind = v:null let s:timer_diffupdate = v:null function! gina#util#contain_direction(mods) abort return a:mods =~# s:DIRECTION_PATTERN endfunction function! gina#util#get(obj, key, ...) abort let val = get(a:obj, a:key, v:null) return val is# v:null ? get(a:000, 0, '') : val endfunction function! gina#util#map(lhs, rhs, ...) abort let options = extend({ \ 'mode': '', \ 'noremap': 0, \ 'buffer': 1, \ 'nowait': 0, \ 'silent': 0, \ 'special': 0, \ 'script': 0, \ 'unique': 0, \ 'expr': 0, \}, get(a:000, 0, {}) \) let command = join([ \ options.mode . (options.noremap ? 'noremap' : 'map'), \ options.buffer ? '<buffer>' : '', \ options.nowait ? '<nowait>' : '', \ options.silent ? '<silent>' : '', \ options.special ? '<special>' : '', \ options.script ? '<script>' : '', \ options.unique ? '<unique>' : '', \ options.expr ? '<expr>' : '', \ a:lhs, a:rhs \]) execute command endfunction function! gina#util#yank(value) abort call setreg(v:register, a:value) endfunction function! gina#util#open(uri) abort call s:File.open(a:uri) endfunction function! gina#util#filter(arglead, candidates, ...) abort let hidden_pattern = get(a:000, 0, '') let pattern = '^' . s:String.escape_pattern(a:arglead) let candidates = copy(a:candidates) if empty(a:arglead) && !empty(hidden_pattern) call filter(candidates, 'v:val !~# hidden_pattern') endif call filter(candidates, 'v:val =~# pattern') return candidates endfunction function! gina#util#shellescape(value, ...) abort if empty(a:value) return '' endif let value = type(a:value) == s:t_list \ ? join(map(copy(a:value), 'shellescape(v:val)')) \ : shellescape(a:value) let prefix = get(a:000, 0, '') return prefix . value endfunction function! gina#util#fnameescape(value, ...) abort if empty(a:value) return '' endif let value = type(a:value) == s:t_list \ ? join(map(copy(a:value), 'fnameescape(v:val)')) \ : fnameescape(a:value) let prefix = get(a:000, 0, '') return prefix . value endfunction function! gina#util#windo(expr) abort let winid = win_getid() try execute printf('windo %s', a:expr) finally call win_gotoid(winid) endtry endfunction function! gina#util#bufdo(expr, ...) abort let bang = a:0 ? '!' : '' let winid = win_getid() try execute printf('bufdo%s %s', bang, a:expr) finally call win_gotoid(winid) endtry endfunction function! gina#util#doautocmd(name, ...) abort let pattern = get(a:000, 0, '') let expr = '#' . a:name let eis = split(&eventignore, ',') if index(eis, a:name) != -1 || index(eis, 'all') != -1 || !exists(expr) " the specified event is ignored or does not exists return endif let is_pseudo_required = empty(pattern) && !exists('#' . a:name . '#*') if is_pseudo_required " NOTE: " autocmd XXXXX <pattern> exists but not sure if the current buffer name " match with the <pattern> so register an empty autocmd to prevent " 'No matching autocommands' warning augroup gina_internal_util_doautocmd autocmd! * execute printf('autocmd %s * :', a:name) augroup END endif let nomodeline = has('patch-7.4.438') && a:name ==# 'User' \ ? '<nomodeline> ' \ : '' try execute printf('doautocmd %s %s %s', nomodeline, a:name, pattern) finally if is_pseudo_required augroup gina_internal_util_doautocmd autocmd! * augroup END endif endtry endfunction function! gina#util#winwidth(winnr) abort let width = winwidth(a:winnr) let width -= &foldcolumn let width -= s:is_sign_visible(winbufnr(a:winnr)) ? 2 : 0 let width -= (&number || &relativenumber) \ ? len(string(line('$'))) + 1 \ : 0 return width endfunction function! gina#util#syncbind() abort " NOTE: " 'syncbind' does not work just after a buffer has opened " so use timer to delay the command. silent! call timer_stop(s:timer_syncbind) let s:timer_syncbind = timer_start(50, function('s:syncbind')) endfunction function! gina#util#diffthis() abort diffthis augroup gina_internal_util_diffthis_local autocmd! * <buffer> autocmd BufReadPost <buffer> \ if &diff && &foldmethod !=# 'diff' | \ setlocal foldmethod=diff | \ endif augroup END endfunction function! gina#util#diffupdate() abort " NOTE: " 'diffupdate' does not work just after a buffer has opened " so use timer to delay the command. silent! call timer_stop(s:timer_diffupdate) let s:timer_diffupdate = timer_start(100, function('s:diffupdate', [bufnr('%')])) endfunction " Private -------------------------------------------------------------------- function! s:syncbind(...) abort syncbind silent! wincmd p silent! wincmd p endfunction function! s:diffoff(update) abort augroup gina_internal_util_diffthis autocmd! * <buffer> augroup END diffoff if a:update call s:diffupdate(bufnr('%')) endif endfunction function! s:diffoff_all() abort let winid = win_getid() for winnr in range(1, winnr('$')) if getwinvar(winnr, '&diff') call win_gotoid(win_getid(winnr)) call s:diffoff(0) endif endfor call win_gotoid(winid) call s:diffupdate(bufnr('%')) endfunction function! s:diffupdate(bufnr, ...) abort let winid = bufwinid(a:bufnr) if winid == -1 return endif let winid_saved = win_getid() try if winid != winid_saved call win_gotoid(winid) endif diffupdate syncbind finally call win_gotoid(winid_saved) endtry endfunction function! s:diffcount() abort let indicators = map( \ range(1, winnr('$')), \ 'getwinvar(v:val, ''&diff'')' \) let indicators = filter(indicators, 'v:val') return len(indicators) endfunction function! s:call_super(cls, method, ...) abort dict return call(a:cls.__super[a:method], a:000, self) endfunction function! s:is_sign_visible(bufnr) abort if !exists('&signcolumn') || &signcolumn ==# 'auto' return len(split(execute('sign place buffer=' . a:bufnr), '\r\?\n')) > 1 else return &signcolumn ==# 'yes' endif endfunction